vue3 中的setup
vue3中所有的属性、方法、生命周期等皆定义在setup函数中,可以说setup是vue3中组合api的入口函数
vue3中使用内置的api需要引入
import { ref } from 'vue'
ref
定义一个响应式的简单数据类型(Number,String)
// 模板
<template>
<h3>
{{ name }}
</h3>
<button @cilck="changeName">点我改变姓名</button>
</template>
import { ref } from 'vue'
export defaule {
name: 'App',
setup() {
let name = ref('张三') // 定义一个响应式的变量
// 定义方法
function changeName() {
name.value = '李四' // ref包装后的值,访问必须通过 .value
}
// 在vue3中定义的变量,函数模板中使用setup函数必须返回
return {
name,
changeName
}
}
}
reactive
定义一个复杂的响应式数据类型(Object,Array)
// 模板
<template>
<h3>
{{ person.name }}
</h3>
<button @cilck="changeName">点我改变姓名</button>
</template>
import { reactive } from 'vue'
export defaule {
name: 'App',
setup() {
// 定义一个响应式的person对象
let person = reactive({
name: '张三',
age: 25
})
// 定义方法
function changeName() {
person.name = '李四' // reactive包装后的值,可以直接点属性名访问
}
// 在vue3中定义的变量,函数模板中使用setup函数必须返回
return {
person
}
}
}
备注:
ref:用来定义简单类型的响应式数据
reactive: 用来定义复杂的响应式数据,不管嵌套多深vue都可以监测到数据变化
如果用reactive定义简单的数据类型,该数据被改变时将不会触发页面更新,也就是说该数据不是响应式的
vue3 响应式原理
vue3内部借助了Proxy拦截对源对象属性的改变(增删改查)
通过Reflect(反射) 改变源对象的值
// 源对象
let person = {
name: '张三',
age: 18
}
// Proxy 接收两个参数,第一个是target代理的目标对象,第二个是实现增删改查的对象
let p = new Proxy(person, {
// 读取属性值,target目标对象,propName是读取的该对象中属性名
get(target, propName) {
// return target[propName]
return Reflect.get(target,propName)
},
// 修改和新增时会触发set方法
set(target, propName, value) {
// return target[propName] = value
return Reflect.set(target, propName, value)
},
// 删除时触发
deleteProperty(target, propName) {
// return delete target[propName]
return Reflect.deleteProperty(target, propName)
}
})
setup函数注意点
1.setup执行的时机是在beforeCreate()之前
2. setup函数接收两个函数
// props,父组件传进来的参数
// context 上下文对象包含了,attrs/emit/slots
props: ['msg']// 子组件必须声明,否则会报警告
setup(props, context) {
}
vue3中的computed计算属性
import { reactive, computed } from 'vue'
export default {
setup() {
let person = reactive({
firstName:'张',
lastName: '三'
})
// 简写形式
let fullName = computed(()=>{
return person.firstName + person.lastName
})
// 完整写法
let fullName = computed({
get() {
return person.firstName + person.lastName
},
set(value) {
person.firstName = value
person.lastName = value
}
})
return {
fullName
}
}
}
vue3中的watch函数
import { ref, watch, reactive } from "vue";
export default {
setup() {
let sum = ref(0);
let msg = ref("你好");
let person = reactive({
name: "张三",
age: 18,
job: {
address: "长沙",
hobby: {
number: "篮球"
}
}
});
// 以下是监听ref包装的简单数据
// 情况一,简单监听, vue3中watch是一个函数
// watch(sum, (newValue, oldValue) => {
// console.log(newValue, oldValue);
// });
// 情况二 vue3中watch监听多个值
// watch([sum, msg], (newValue, oldValue) => {
// console.log(newValue, oldValue);//[0, "你好!"] [0, "你好"]
// });
//情况三, 开启监听的配置项
// watch(sum, (newValue, oldValue) => {
// console.log(newValue, oldValue)
// }, {
// immediate: true, // 监听的值没有改变页面已加载就触发一次
// deep: true // 开启深度监听
// })
/*
watch监听reactive响应式数据
// 情况1 默认强制开始深度监听deep,无法改变。且监测不到oldValue
*/
// watch(person, (newValue, oldValue) => {
// console.log(newValue, oldValue)
// })
/*
watch监听reactive响应式数据
// 情况2 想要监听对象中某一个值,第一个参数必须是一个函数且要返回要监听的属性
*/
// watch(
// () => person.name,
// (newValue, oldValue) => {
// console.log(newValue, oldValue)
// }
// );
/*
watch监听reactive响应式数据
// 情况3 想要监听对象中某一个属性时,且该属性是又是一个对象,需要开启deep才能生效
*/
watch(
() => person.job,
(newValue, oldValue) => {
console.log(newValue, oldValue)
},
{ deep: true }
);
return {
sum,
msg,
person
};
}
}
vue3中的watchEffect函数
该函数也用于监听,和watch不同的是,该函数参数只有一个回调函数,监听的对象取决于回调函数中所用到的有哪些属性
该函数和computed属性有些类似,不同点在于computed属性必须有返回值,注重的是返回的结果。watchEffect函数没有返回值,注重的是函数执行时的逻辑过程。
import { reactive,watchEffect } from "vue";
export default {
setup() {
let sum = ref(0);
let msg = ref("你好");
let person = reactive({
name: "张三",
age: 18,
job: {
address: "长沙",
hobby: {
number: "篮球"
}
}
});
// 只有一个参数回调函数,监听取决于回调函数中用到的属性。sum和hobby改变会被监听到
watchEffect(() =>{
const x1 = sum.value
const x2 = person.job.hobby.number
})
return {
person
};
}
}
vue3 生命周期
和vue2相比vue3生命周期函数有两个改变
1. beforeDestroy >>> beforeUnmount // 卸载之前
2. destroyed >>> unmounted // 卸载之后
组合API中使用生命周期函数
import { onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted } from "vue";
export default {
setup() {
onBeforeMount(()=>{
console.log("挂在之前")
})
onMounted(()=>{
console.log("挂在之后")
})
}
}
备注:
- 在setup函数中使用钩子函数,名称有所改变如上所示。
- 之前的配置项写法生命周期依然可用,两种写法同时存在时,组合API中的写法优先级高!但不建议两种写法同时存在!
- 组合API中beforeCreate、created => setup()
vue3中的toRef/toRefs
作用:把一个对象或者属性转变为ref响应式数据
语法:toRef(person,'name')
toRefs,批量转换,同时把多个转换为ref类型
语法:toRefs(person),转换后为一个对象,使用时通过 ...toRefs(person)展开
vue3中的shallowReactive/shallowRef
shallowReactive: 定义复杂数据对象时,只有第一层数据是响应式的,里面嵌套的数据改变不会响应。
shallowRef: 定义数字类型数据是响应式的,定义对象数据类型时,不是响应式的,数据改变但页面不会响应。
vue3 中的readonly/shallowReadonly
let person = reactive({
name: '张三'
hobby: {
sports:'篮球'
}
})
const person1 = readonly(person)
return { person1 }
作用: 把一个响应式的数据变为只读(不可修改)
场景:当一个数据是外部引入的,多个地方要用,但在某个地方只能读不能改时。
provide/inject
作用:用于祖组件和后代组件传递数据
// 祖组件传值
import { provide, reactive} form 'vue'
export default {
setup() {
let car = reactive({name:'宝马',price:'40W'})
provide('car',car) // 传递
}
}
// 后代组件接收
import { inject } form 'vue'
export default {
setup() {
let car = inject('car')
return {car}
}
}
备注: provide传递的数据是响应式的数据
teleport
作用:vue3内置组件,可以用来包括一组标签,通过to=“#app”
属性,把包括的标签脱离原来的文本流显示在对应位置
<template>
<div>
<button @click="isShow = true">点我开启dailog</button>
<teleport to=".app">
<div v-if="isShow" class="dailog">
<div class="content">
<p>你好,我是弹窗内容哦</p>
<button @click="isShow = false">点我关闭弹窗</button>
</div>
</div>
</teleport>
</div>
</template>