Vue2、Vue3

文章目录[x]
  1. 1:1.1 什么是 vue
  2. 2:1.2 vue 的特性
  3. 2.1:1.2.1 数据驱动视图
  4. 2.2:1.2.2 双向数据绑定
  5. 2.3:1.2.3 MVVM
  6. 2.4:1.2.4 MVVM 的工作原理
  7. 3:3.1 内容渲染指令
  8. 4:3.2 属性绑定指令
  9. 5:3.3 事件绑定指令
  10. 6:3.4 双向绑定指令
  11. 7:3.5 条件渲染指令
  12. 8:3.6 列表渲染指令
  13. 9:4.1 定义过滤器
  14. 10:4.2 私有过滤器和全局过滤器
  15. 11:4.3 连续调用多个过滤器
  16. 12:4.4 过滤器传参
  17. 13:4.5 过滤器的兼容性
  18. 14:5.1 什么是 watch 侦听器
  19. 15:5.2 使用 watch 检测用户名是否可用
  20. 16:5.3 immediate 选项
  21. 17:5.4 deep 选项
  22. 18:5.5 监听对象单个属性的变化
  23. 19:6.1 什么是计算属性
  24. 20:6.2 计算属性的特点
  25. 21:7.1 什么是 vue-cli
  26. 22:7.2 安装和使用
  27. 23:7.3 vue 项目的运行流程
  28. 24:8.1 什么是组件化开发
  29. 25:8.2 vue 中的组件化开发
  30. 26:8.3 vue 组件的三个组成部分
  31. 26.1:8.3.1 template
  32. 26.2:8.3.2 script
  33. 26.3:8.3.3 style
  34. 27:8.4组件之间的父子关系
  35. 27.1:8.4.1 使用组件的三个步骤
  36. 27.2:8.4.2 注册全局组件
  37. 28:8.5组件的 props
  38. 28.1:8.5.1 props 是只读的
  39. 28.2:8.5.2 props 的 default 默认值
  40. 28.3:8.5.3 props 的 type 值类型
  41. 28.4:8.5.4 props 的 required 必填项
  42. 29:8.6 组件之间的样式冲突问题
  43. 29.1:8.6.1 自定义属性
  44. 29.2:8.6.2 style 节点的 scoped 属性
  45. 29.3:8.6.3 /deep/ 样式穿透
  46. 30:9.1 生命周期 & 生命周期函数
  47. 31:9.2 组件生命周期函数的分类
  48. 32:10.1 Vue 3 的 Template 支持多个根标签,Vue 2 不支持
  49. 33:10.2 Composition API
  50. 34:10.3 建立数据 data
  51. 35:10.4 父子传参不同,setup() 函数特性

1. Vue简介

1.1 什么是 vue

官方给出的概念:Vue是一套用于构建用户界面的前端框架

1.2 vue 的特性

vue 框架的特性,主要体现在如下两方面: ① 数据驱动视图 ② 双向数据绑定

1.2.1 数据驱动视图

在使用了 vue 的页面中,vue 会监听数据的变化,从而自动重新渲染页面的结构。

好处:当页面数据发生变化时,页面会自动重新渲染!

注意:数据驱动视图是单向的数据绑定。

1.2.2 双向数据绑定

在填写表单时,双向数据绑定可以辅助开发者在不操作 DOM 的前提下,自动把用户填写的内容同步到数据源 中。示意图如下

好处:开发者不再需要手动操作 DOM 元素,来获取表单元素最新的值!

1.2.3 MVVM

MVVM 是 vue 实现数据驱动视图和双向数据绑定的核心原理。MVVM 指的是 Model、View 和 ViewModel, 它把每个 HTML 页面都拆分成了这三个部分,如图所示

在 MVVM 概念中:

  • Model 表示当前页面渲染时所依赖的数据源。
  • View 表示当前页面所渲染的 DOM 结构。
  • ViewModel 表示 vue 的实例,它是 MVVM 的核心。

1.2.4 MVVM 的工作原理

ViewModel 作为 MVVM 的核心,是它把当前页面的数据源(Model)和页面的结构(View)连接在了一起。

数据源发生变化时,会被 ViewModel 监听到,VM 会根据最新的数据源自动更新页面的结构

表单元素的值发生变化时,也会被 VM 监听到,VM 会把变化过后最新的值自动同步到 Model 数据源中

2. Vue2的基本使用

  • 1.导入vue.js文件,或通过链接导入
  • 2.new Vue()构造函数,得到vm实例对象
  • 3.声明el和data数据节点
  • el:控制区域 data:数据源 methods:处理函数
  • 4.MVVM的对应关系
  • M:model(指data数据源) V:view(el所控制的区域) VM:view model核心(vue实例对象)

3. Vue2的常见指令

指令(Directives)是 vue 为开发者提供的模板语法,用于辅助开发者渲染页面的基本结构。

vue 中的指令按照不同的用途可以分为如下 6 大类:

  • ① 内容渲染指令
  • ② 属性绑定指令
  • ③ 事件绑定指令
  • ④ 双向绑定指令
  • ⑤ 条件渲染指令
  • ⑥ 列表渲染指令

3.1 内容渲染指令

内容渲染指令用来辅助开发者渲染 DOM 元素的文本内容。常用的内容渲染指令有如下 3 个:

  • v-text:覆盖元素内默认的值。
  • {{ }}:差值表达式,不会覆盖元素中默认的文本内容,只能用在内容节点
  • v-html:v-text 指令和插值表达式只能渲染纯文本内容。如果要把包含 HTML 标签的字符串渲染为页面的 HTML 元素

3.2 属性绑定指令

  • v-bind(缩写 : ):如果需要为元素的属性动态绑定属性值,则需要用到 v-bind 属性绑定指令,用在绑定属性节点

3.3 事件绑定指令

  • v-on(缩写@) :用来辅助程序员为 DOM 元素绑定事件监听,通过 v-on 绑定的事件处理函数,需要在 methods 节点中进行声明

注意:原生 DOM 对象有 onclick、oninput、onkeyup 等原生事件,替换为 vue 的事件绑定形式后, 分别为:v-on:click、v-on:input、v-on:keyup

在事件处理函数中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。因此, vue 提供了事件修饰符的概念,来辅助程序员更方便的对事件的触发进行控制。常用的 5 个事件修饰符如下:

事件修饰符说明
.prevent阻止默认行为(例如:阻止 a 连接的跳转、阻止表单的提交等)
.stop阻止事件冒泡
.capture以捕获模式触发当前的事件处理函数
.once绑定的事件只触发1次
.self只有在 event.target 是当前元素自身时触发事件处理函数

语法格式如下:

<a href="https://www.baidu.com" @click.prevent="onLinkClcik">百度首页</a>
//触发click点击事件,阻止a链接的默认跳转行为

3.4 双向绑定指令

  • v-model:双向绑定,对于v-bind,他是单向的,是从model到view即数据到视图。
修饰符作用示例
.number自动将用户的输入值转为数值类型<input v-model.number="age" />
.trim自动过滤用户输入的首尾空白字符<input v-model.trim="msg" />
.lazy在“change”时而非“input”时更新<input v-model.lazy="msg" />

3.5 条件渲染指令

  • v-if、v-show:按条件渲染
    • v-if:会动态地创建或移除 DOM 元素,频繁使用会损耗性能
    • v-show:相当于在其样式上添加行内样式:display:none
    • 一般性能不用考虑可直接使用v-if

3.6 列表渲染指令

  • v-for :需要循环创建相似的UI结构

v-for 指令需要使 用 item in items 形式的特殊语法,其中:

  • items 是待循环的数组
  • item 是被循环的每一项
data:{
  list:[
    { id:1,name'zs' },
    { id:2,name'ls' }
       ]
     }

<ul>
  <li v-for="item in list" :key="item.id">姓名是:{{ item.name }}</li>
</ul>

v-for 指令还支持一个可选的第二个参数,即当前项的索引。语法格式为 (item, index) in items

注意:v-for 指令中的 item 项和 index 索引都是形参,可以根据需要进行重命名。例如 (user, i) in userlist

  • :key:可以使用序号,但是没有意义,但是一般用id来绑定,因为如果序号出现删除后再增加,会出现key相同的情况。

4. 过滤器

过滤器(Filters)是 vue 为开发者提供的功能,常用于文本的格式化。过滤器可以用在两个地方:插值表达式 和 v-bind 属性绑定。

过滤器应该被添加在 JavaScript 表达式的尾部,由“管道符”进行调用,示例代码如下:

//双大括号中通过“管道符”调用capitalize过滤器,对message的值进行格式化
<p>{{ message| capitalize }}</p>

//在v-bind中通过“管道符”调用formatID过滤器,对rawID的值进行格式化
<div v-bind:id="rawID | formatID"></div>

4.1 定义过滤器

在创建 vue 实例期间,可以在 filters 节点中定义过滤器,示例代码如下:

const vm = new Vue ({
 el:'#app',
 data: {
   message:hellow
   info:'title info'
},
  filters: {                //在filters 节点下定义"过滤器
    capitalize(str) {      // 把首字母转为大写的过滤器
     return str . charAt(0). toUpperCase() + str .slice(1)
  }
})

4.2 私有过滤器和全局过滤器

在 filters 节点下定义的过滤器,称为“私有过滤器”,因为它只能在当前 vm 实例所控制的 el 区域内使用。 如果希望在多个 vue 实例之间共享过滤器,则可以按照如下的格式定义全局过滤器:

//全局过滤器-独立于每个Vm实例之外
// Vue. filter()方法接收两个参数: 
//第1个参数,是全局过滤器的"名字”
//第2个参数,是全局过滤器的"处理函数”
Vue. filter('capitalize', (str) => {
  return str . charAt(0). toUpperCase() + str .slice(1) + '--'
})

4.3 连续调用多个过滤器

过滤器可以串联地进行调用,例如

//把message的值交给filterA进行处理
//把filterA处理的结果再交给filterB进行处理
//最终把filterB处理的结果作为最终的值渲染到页面上
{{ message | filterA | filterB }}

4.4 过滤器传参

过滤器的本质是 JavaScript 函数,因此可以接收参数,格式如下:

<!-- arg1 和arg2是传递给filterA的参数-->
<p>{{ message | filterA(arg1 ,arg2) }}</p>
//过滤器处理函数的形参列表中:
//第一个参数:永远都是”管道符”前面待处理的值
//从第二个参数开始,才是调用过滤器时传递过来的arg1和arg2 参数
Vue. filter('filterA', (msg, arg1, arg2) => {
//过滤器的代码逻辑...
})

4.5 过滤器的兼容性

过滤器仅在 vue 2.x 和 1.x 中受支持,在 vue 3.x 的版本中剔除了过滤器相关的功能。

5. watch 侦听器

5.1 什么是 watch 侦听器

watch 侦听器允许开发者监视数据的变化,从而针对数据的变化做特定的操作,语法格式:

const Vm = new Vue({
 el: ' #app',
 data: { username: ' },
 watch: {
//监听username值的变化
// newVal 是"变化后的新值”,oldVal 是"变化之前的旧值”
  username(newVal, oldVal) {
   console. log(newVal, oldVal)
  }
 }
})

5.2 使用 watch 检测用户名是否可用

监听 username 值的变化,并使用 axios 发起 Ajax 请求,检测当前输入的用户名是否可用:

watch: {
// 监听 username 值的变化
 async username(newVal) {
  if (newVal === '') return
// 使用 axios 发起请求,判断用户名是否可用
   const { data: res } = await axios.get('https://www.escook.cn/api/finduser/' + newVal)
   console.log(res)
  }
}

5.3 immediate 选项

默认情况下,组件在初次加载完毕后不会调用 watch 侦听器。如果想让 watch 侦听器立即被调用,则需要使用 immediate 选项。

immediate: true

5.4 deep 选项

如果 watch 侦听的是一个对象,如果对象中的属性值发生了变化,则无法被监听到。此时需要使用 deep 选项

deep: true

5.5 监听对象单个属性的变化

如果只想监听对象中单个属性的变化,则可以按照如下的方式定义 watch 侦听器:

const Vm = new Vue({
 el:' #app',
 data: {
  info: { username: 'admin' }
},
 watch: {
  'info.username ': {
    handler(newVal) {
     console. log(newVal)
    }
   }
 }
})

6. 计算属性

6.1 什么是计算属性

计算属性指的是通过一系列运算之后,最终得到一个属性值。

这个动态计算出来的属性值可以被模板结构或 methods 方法使用。示例代码如下:

var Vm = new Vue({
 el: ' #app '
 data: {
   r:0,g:0,b:0
 },
 computed: {
  rgb() { return rgb(${this.r}, ${this.g}, ${this.b}) }
 },
 methods: {
  show() { console. log(this.rgb) }
 },
})

6.2 计算属性的特点

  • ① 虽然计算属性在声明的时候被定义为方法,但是计算属性的本质是一个属性
  • ② 计算属性会缓存计算的结果,只有计算属性依赖的数据变化时,才会重新进行运算

7. vue-cli

7.1 什么是 vue-cli

vue-cli 是 Vue.js 开发的标准工具。它简化了程序员基于 webpack 创建工程化的 Vue 项目的过程。程序员可以专注在撰写应用上,而不必花好几天去纠结 webpack 配置的问题。

7.2 安装和使用

vue-cli 是 npm 上的一个全局包,使用 npm install 命令,即可方便的把它安装到自己的电脑上:

npm install -g @vue/cli

基于 vue-cli 快速生成工程化的 Vue 项目:

vue create 项目的名称

7.3 vue 项目的运行流程

在工程化的项目中,vue 要做的事情很单纯:通过 main.js 把 App.vue 渲染到 index.html 的指定区域中。

其中:

  • App.vue 用来编写待渲染的模板结构
  • index.html 中需要预留一个 el 区域
  • main.js 把 App.vue 渲染到了 index.html 所预留的区域中

8. vue 组件

8.1 什么是组件化开发

组件化开发指的是:根据封装的思想,把页面上可重用的 UI 结构封装为组件,从而方便项目的开发和维护。

8.2 vue 中的组件化开发

vue 是一个支持组件化开发的前端框架。

vue 中规定:组件的后缀名是 .vue。之前接触到的 App.vue 文件本质上就是一个 vue 的组件。

8.3 vue 组件的三个组成部分

每个 .vue 组件都由 3 部分构成,分别是:

  • template -> 组件的模板结构
  • script -> 组件的 JavaScript 行为
  • style -> 组件的样式

其中,每个组件中必须包含 template 模板结构,而 script 行为和 style 样式是可选的组成部分。

8.3.1 template

vue 规定:每个组件对应的模板结构,需要定义到 <template> 节点中。

<template>
<!--当前组件的DOM结构,需要定义到template 标签的内部--> 
</ template>

注意:

  • template 是 vue 提供的容器标签,只起到包裹性质的作用,它不会被渲染为真正的 DOM 元素
  • template 中只能包含唯一的根节点

8.3.2 script

vue 规定:开发者可以在 <script> 节点中封装组件的 JavaScript 业务逻辑。

<script > 节点的基本结构如下:

<script>
//今后,组件相关的data数据、methods 方法等,
//都需要定义到export default 所导出的对象中。
export default {}
</script>

.vue 组件中的 data 必须是函数

vue 规定:.vue 组件中的 data 必须是一个函数,不能直接指向一个数据对象。

因此在组件中定义 data 数据节点时,下面的方式是错误的:

data: { //组件中,不能直接让data 指向一个数据对象(会报错)
 count: 0
}


data(){//正确
return {
  count:0
 }
}

8.3.3 style

vue 规定:组件内的 <style> 节点是可选的,开发者可以在 <style> 节点中编写样式美化当前组件的 UI 结构。

<script > 节点的基本结构如下:

<style>
h1 {
 font -weight:normal;
}
</style>

让 style 中支持 less 语法

在 <style> 标签上添加 lang="less" 属性,即可使用 less 语法编写组件的样式:

<style lang="less">
h1 {
 font -weight:
  span {
   color: red;
  }
}
</style>

8.4组件之间的父子关系

组件在被封装好之后,彼此之间是相互独立的,不存在父子关系
在使用组件的时候,根据彼此的嵌套关系,形成了父子关系、兄弟关系

8.4.1 使用组件的三个步骤

以上components节点注册的组件,均为私有节点

8.4.2 注册全局组件

在 vue 项目的 main.js 入口文件中,通过 Vue.component() 方法,可以注册全局组件。示例代码如下:

//导入需要全局注册的组件
import Count from " @/ components/ Count .vue 
//参数1:字符串格式,表示组件的“注册名称"
//参数2:需要被全局注册的那个组件
Vue.component('MyCount',Count)

8.5组件的 props

props 是组件的自定义属性,在封装通用组件的时候,合理地使用 props 可以极大的提高组件的复用性!

它的语法格式如下:

export default {
//组件的自定义属性
 props: ['自定义属性A', '自定义属性B','其它自定义属性...'],
//组件的私有数据
 data() {
  return { }
 }
}

8.5.1 props 是只读的

vue 规定:组件中封装的自定义属性是只读的,程序员不能直接修改 props 的值。否则会直接报错

要想修改 props 的值,可以把 props 的值转存到 data 中,因为 data 中的数据都是可读可写的!

8.5.2 props 的 default 默认值

在声明自定义属性时,可以通过 default 来定义属性的默认值。示例代码如下

export default {
 props: {
  init: {
//用default 属性定义属性的默认值
    default: 0
   }
  }
}

8.5.3 props 的 type 值类型

在声明自定义属性时,可以通过 type 来定义属性的值类型。示例代码如下:

export default {
 props: {
  init: {
//用default 属性定义属性的默认值
    default: 0,
//用type属性定义属性的值类型
//如果传递过来的值不符合此类型,会终端报错
    type:Number
   }
  }
}

8.5.4 props 的 required 必填项

在声明自定义属性时,可以通过 required 选项,将属性设置为必填项,强制用户必须传递属性的值。

示例代码:

export default {
 props: {
  init: {
    type:Number
//必填项
    required: true
   }
  }
}

8.6 组件之间的样式冲突问题

默认情况下,写在 .vue 组件中的样式会全局生效,因此很容易造成多个组件之间的样式冲突问题。

导致组件之间样式冲突的根本原因是:

  • ① 单页面应用程序中,所有组件的 DOM 结构,都是基于唯一的 index.html 页面进行呈现的
  • ② 每个组件中的样式,都会影响整个 index.html 页面中的 DOM 元素

8.6.1 自定义属性

为每个组件分配唯一的自定义属性,在编写组件样式时,通过属性选择器来控制样式的作用域,示例代码如下:

<template>
 <div class=" container" data-v-001>
  <h3 data-v-001>轮播 图组件</h3>
 </div>
</template>

<style>
/*通过中括号"属性选择器",来防止组件之间的"样式冲突问题",因为每个组件分配的自定义属性是"唯一-的" */
.container [data-v-0001] {
 border: 1px solid red;
}
</style>

8.6.2 style 节点的 scoped 属性

为了提高开发效率和开发体验,vue 为 style 节点提供了 scoped 属性,从而防止组件之间的样式冲突问题:

<template>
 <div class=" container">
  <h3>轮播 图组件</h3>
 </div>
</template>

<style scoped>

/* style节点的scoped 属性,用来自动为每个组件分配唯一的“自定 义属性”,并自动为当前组件的DOM标签和style样式应用这个自定义属性,防止组件的样式冲突问题*/

.container {
 border: 1px solid red;
}
</style>

8.6.3 /deep/ 样式穿透

如果给当前组件的 style 节点添加了 scoped 属性,则当前组件的样式对其子组件是不生效的。如果想让某些样 式对子组件生效,可以使用 /deep/ 深度选择器。

<style lang="less" scoped>
.title {
 color: blue; /*不加/deep/ 时,生成的选择器格式为. title[ data-v-052242de ]
}

/deep/ .title {
 color: blue; /*加上/deep/ 时,生成的选择器格式为[data-v-052242de] .title */
}
</style>

9. 组件的生命周期

9.1 生命周期 & 生命周期函数

生命周期(Life Cycle)是指一个组件从 创建 -> 运行 -> 销毁的整个阶段,强调的是一个时间段

生命周期函数:是由 vue 框架提供的内置函数,会伴随着组件的生命周期,自动按次序执行

注意:生命周期强调的是时间段生命周期函数强调的是时间点

9.2 组件生命周期函数的分类

10.Vue2与Vue3的区别

10.1 Vue 3 的 Template 支持多个根标签,Vue 2 不支持

Vue2只能在 Template 节点下只能放一个根标签、Vue3可以放多个根标签

vue2:

<template>
  <div class='form-element'>
  <h2> {{ title }} </h2>
  </div>
</template>

vue3:

<template>
  <div class='form-element'>
  </div>
   <h2> {{ title }} </h2>
</template>

10.2 Composition API

Vue2与Vue3 最大的区别 — Vue2使用选项类型API(Options API)对比Vue3合成型API(Composition API)

旧的选项型API在代码里分割了不同的属性: data,computed属性,methods,等等。新的合成型API能让我们用方法(function)来分割,相比于旧的API使用属性来分组,这样代码会更加简便和整洁。

vue2:

export default {
  props: {
    title: String
  },
  data () {
    return {
      username: '',
      password: ''
    }
  },
  methods: {
    login () {
      // 登陆方法
    }
  },
  components:{
            "buttonComponent":btnComponent
        },
  computed:{
	  fullName(){
	    return this.firstName+" "+this.lastName;     
	  }
}
 
}

vue3:

export default {
  props: {
    title: String
  },
  
  setup () {
    const state = reactive({ //数据
      username: '',
      password: '',
      lowerCaseUsername: computed(() => state.username.toLowerCase()) //计算属性
    })
     //方法
    const login = () => {
      // 登陆方法
    }
    return { 
      login,
      state
    }
  }
}

10.3 建立数据 data

Vue2 - 这里把数据放入data属性中

export default {
  props: {
    title: String
  },
  data () {
    return {
      username: '',
      password: ''
    }
  }
}

在Vue3.0,我们就需要使用一个新的setup()方法,此方法在组件初始化构造的时候触发。

使用以下三步来建立反应性数据:

  1. 从vue引入reactive
  2. 使用reactive()方法来声名我们的数据为响应性数据
  3. 使用setup()方法来返回我们的响应性数据,从而我们的template可以获取这些响应性数据
import { reactive } from 'vue'

export default {
  props: {
    title: String
  },
  setup () {
    const state = reactive({
      username: '',
      password: ''
    })

    return { state }
  }
}

template使用,可以通过state.username和state.password获得数据的值。

<template>
  <div>
    <h2> {{ state.username }} </h2>
  </div>
</template>

vue2:

vue3:

setup() :开始创建组件之前,在beforeCreate和created之前执行。创建的是data和method

onBeforeMount() : 组件挂载到节点上之前执行的函数。

onMounted() : 组件挂载完成后执行的函数。

onBeforeUpdate(): 组件更新之前执行的函数。

onUpdated(): 组件更新完成之后执行的函数。

onBeforeUnmount(): 组件卸载之前执行的函数。

onUnmounted(): 组件卸载完成后执行的函数

onActivated(): 被包含在中的组件,会多出两个生命周期钩子函数。被激活时执行。

onDeactivated(): 比如从 A 组件,切换到 B 组件,A 组件消失时执行。

onErrorCaptured(): 当捕获一个来自子孙组件的异常时激活钩子函数。

生命周期函数Vue2Vue3
开始创建组件之前beforeCreate()use setup()
创建组件完成created()use setup()
组件挂载到节点上之前执行beforeMount()onBeforeMount
组件挂载完成后执行mounted()onMounted
组件更新之前执行beforeUpdate()onBeforeUpdate
组件更新完成之后执行updated()onUpdated
组件销毁之前执行beforeDestory()onBeforeUnmount
组件销毁完成后执行destoryed()onUnmounted
被包含在中的组件,会多出两个生命周期钩子函数。被激活时执行activated()onActivated
比如从 A 组件,切换到 B 组件,A 组件消失时执行deactivated()onDeactivated
当捕获一个来自子孙组件的异常时激活钩子函数errorCaptured()onErrorCaptured
 onRenderTracked(新增) — DebuggerEvent 调试用
 onRenderTriggered(新增) — DebuggerEvent 调试用

10.4 父子传参不同,setup() 函数特性

总结:
1、setup 函数时,它将接受两个参数:(props、context(包含attrs、slots、emit))

2、setup函数是处于 生命周期函数 beforeCreate 和 Created 两个钩子函数之前的函数

3、执行 setup 时,组件实例尚未被创建(在 setup() 内部,this 不会是该活跃实例的引用,即不指向vue实例,Vue 为了避免我们错误的使用,直接将 setup函数中的this修改成了 undefined)

4、与模板一起使用:需要返回一个对象 (在setup函数中定义的变量和方法最后都是需要 return 出去的 不然无法再模板中使用)

5、使用渲染函数:可以返回一个渲染函数,该函数可以直接使用在同一作用域中声明的响应式状态1

注意事项:

1、setup函数中不能使用this。Vue 为了避免我们错误的使用,直接将 setup函数中的this修改成了 undefined)

2、setup 函数中的 props 是响应式的,当传入新的 prop 时,它将被更新。但是,因为 props 是响应式的,你不能使用 ES6 解构,因为它会消除 prop 的响应性。

如果需要解构 prop,可以通过使用 setup 函数中的toRefs 来完成此操作:

父传子,props

import { toRefs } from 'vue'
 
setup(props) {
	const { title } = toRefs(props)
 
	console.log(title.value)
	 onMounted(() => {
      console.log('title: ' + props.title)
    })

}

子传父,事件 - Emitting Events

举例,现在我们想在点击提交按钮时触发一个login的事件。

1、在 Vue2 中我们会调用到this.$emit然后传入事件名和参数对象。

login () {
      this.$emit('login', {
        username: this.username,
        password: this.password
      })
 }

2、在setup()中的第二个参数content对象中就有emit,这个是和this.$emit是一样的。那么我们只要在setup()接收第二个参数中使用分解对象法取出emit就可以在setup方法中随意使用了。

然后我们在login方法中编写登陆事件
另外:context 是一个普通的 JavaScript 对象,也就是说,它不是响应式的,这意味着你可以安全地对 context 使用 ES6 解构

setup (props, { attrs, slots, emit }) {
    // ...
    const login = () => {
      emit('login', {
        username: state.username,
        password: state.password
      })
    }

    // ...
}

3、 setup()内使用响应式数据时,需要通过.value获取

import { ref } from 'vue'
 
const count = ref(0)
console.log(count.value) // 0

4、从 setup() 中返回的对象上的 property 返回并可以在模板中被访问时,它将自动展开为内部值。不需要在模板中追加 .value

5、setup函数只能是同步的不能是异步的