setup
概括
setup 函数其实是一个生命周期钩子,它对应的其实就是 Vue2 中的 beforeCreate 和 create。在vue3中我们通过这个函数来定义 Vue2 中的 data, methods, watch, computed 属性(数据定义与处理相关)
作用:业务分离
下面是一段描述vue2代码的伪代码
new Vue({data () {数据项1:[],数据项2:{}},methods: {与数据1相关的操作 () {}与数据2相关的操作 () {}},computed: {与数据1相关的计算属性:(){}与数据2相关的计算属性:(){}}})
缺点:与数据1相关的代码分散在不同的配置项中,并没有集中起来,不方便写代码:你往往需在不同配置项中跳转。例如:添加一个数据要去data中,添加对应的操作方法要在methods中。
在 Vue3,我们可以这样写
- 它的典型特点是,可以把业务相关的代码在放在同一个位置来写。
const use数据项1 = function() {const 数据项1 = reactive({})const 计算属性1 = computed(()=>{})const 操作1 = ()=>{}return { 数据项1, 计算属性1,操作1 }}const use数据项2 = function() {return { 数据项2, 计算属性2,操作2 }}new Vue({data () {},setup () {const { 数据项1, 计算属性1,操作1 } = use数据项1()const { 数据项2, 计算属性2,操作2 } = use数据项2()return { 数据项1, 计算属性1,操作1 , 数据项2, 计算属性2,操作2}}})
语法
- 它的典型特点是,可以把业务相关的代码在放在同一个位置来写。
setup(props,context) { const title = ref(0); return { title } }- setup 函数含有两个参数,并且必须返回一个对象,对象里包含所有在 template 模板中需要使用到的属性(包含data,methods 等),可直接在 template 中使用。
```javascript
{{ log }} {{ count }}
<a name="Cn7mb"></a>## 最新语法糖- 当 `<script>` SFC中的变量具有 `setup` 属性时,将对其进行编译,以使代码在 `setup()` 组件功能的上下文中运行。所有ES模块导出均被视为要暴露给渲染上下文并包含在 `setup()` 返回对象中的值。```javascript<script setup="props, { emit }">import { watchEffect } from 'vue'watchEffect(() => console.log(props.msg))emit('foo')</script>
参数(props,context)
props
用于接收 props,也就是定义在组件上的属性(同vue2),接收的 props 必须先在 props 属性中定义,否则不会被接收到
export default{props: {title: String},setup(props,context) {console.log(props.title)}}
解构:因为 props 是响应式的,所以不能使用 ES6 解构,因为它会消除 prop 的响应性。
toRefs
import { toRefs } from 'vue'setup(props) {const { title } = toRefs(props)console.log(title.value)}
toRef:如果 title 是可选的 prop,则传入的 props 中可能没有 title 。在这种情况下,toRefs 将不会为 title 创建一个 ref 。需要使用 toRef 替代它。
import { toRef } from 'vue'setup(props) {const title = toRef(props, 'title')console.log(title.value)}
context
context 是一个普通的 JavaScript 对象,它暴露三个组件的 property:
export default {setup(props, context) {// Attribute (非响应式对象)console.log(context.attrs)// 触发事件 (方法)console.log(context.emit)// 插槽 (非响应式对象)console.log(context.slots)}}
响应式 API
ref
接受一个参数并返回一个响应式且可变的 ref 对象,用 ref 定义的变量,如果需要取到其变量值,需要使用 .value 属性
```javascript
<a name="b0rT4"></a>### reactive- reactive 函数和 ref 作用非常接近,但是它的参数是一个对象,我们可以在对象中定义其方法,通过这个形式,就不需要再对其进行进行 .value 调用```javascript<template><button @click="data.changeCount">count is: {{ data.count }}</button></template><script>import { reactive } from "vue";export default {setup(props) {const data = reactive({count: 0,changeCount: () => { data.count++ },});return {data};},};</script>
由于 reactive 返回的对象本质上已经是一个 Proxy 对象,所以通过 … 扩展符号展开的属性,是无法进行响应式的,解构时需要使用 toRefs
const refData = toRefs(data);return {...refData,};
Vue3 的生命周期
Vue2 的所有生命周期写法与 Vue3 兼容
- 在 Vue3 中,生命周期添加了 on 前缀,需要导入并写在 setup 函数中
- 开始创建组件—— - setup()
- 组件挂载到页面之前执行—— - onBeforeMount()
- 组件挂载到页面之后执行—— - onMounted()
- 组件更新之前—— - onBeforeUpdate()
- 组件更新之后—— - onUpdated()
Vue2 对比 Vue3
Vue2--------------vue3beforeCreate -> setup()created -> setup()beforeMount -> onBeforeMountmounted -> onMountedbeforeUpdate -> onBeforeUpdateupdated -> onUpdatedbeforeDestroy -> onBeforeUnmountdestroyed -> onUnmountedactivated -> onActivateddeactivated -> onDeactivatederrorCaptured -> onErrorCaptured
示例
<template><h1>{{ msg }}</h1></template><script>import { onMounted } from "vue";export default {props: {msg: String,},mounted() {console.log("mounted outside setup <vue2>");},setup(props) {onMounted(() => { //等同于 Vue2 的 mounted()console.log("onMounted in setup <vue3>")});return {};},};</script>

