理解:Vue3.0中一个新的配置项,值为一个函数。
setup是所有composition API “表演的舞台”。
组件中所用到的数据、方法等,均要配置在setup中。
setup函数的两种返回值:
1.若返回一个对象,则对象中的属性、方法,在模板中均可以直接使用。
2.若返回一个渲染函数,则可以自定义渲染内容(了解)。
注意点:
1. 尽量不要与vue2的配置项混合使用
Vue2配置(data 、methds 、computed)中可以访问到setup中的属性、方法。但在setup中不能访问到Vue配置的属性方法等(data 、methds 、computed)等。如果有重名,setup优先
2. setup不能是一个asnyc函数,因为返回值不再是一个return对象,而是promise,模板看不到return对象中的属性
作用:定义一个响应式的数据
语法:const xxx = ref(value)
1.创建一个包含响应式数据的引用对象(reference对象,简称ref对象)。
2.JS中操作数据:xxx.value。
3.模板中读取数据:不需要.value直接{{xxx}}。
从定义数据角度对比:
reactive
转为代理对象。从原理角度对比:
Object.defineProperty()
的get
与set
来实现响应式(数据劫持)。从使用角度对比:
.value
,读取数据时模板中直接读取不需要.value
。.value
。一般将数据封装在一个data对象中,利用reactive函数将该对象变为响应式数据对象
实现原理:
Object.defineProperty(data,'count',{
get(){},
set(){}
})
存在问题:
data() {
return {
person: {
name: '张三',
age: 18,
hobby: ['学习', '唱歌']
}
}
},
methods: {
//添加属性
addSex() {
// this.person.sex = '男' vue监测不到页面不更新
this.$set(this.person, 'sex', '男') //$set()可以更新
// Vue.set(this.person, 'sex', '男')
},
//删除属性
deleteName() {
// delete this.person.name //vue监测不到页面不更新
this.$delete(this.person, 'name')
// Vue.delete(this.person, 'name')
},
//数组下标方式修改属性
updateHobby(){
// this.person.hobby[0] = '打球' vue监测不到页面不更新
// this.$set(this.person.hobby, 0, '打球')
this.person.hobby.splice(0,1,'打球')
}
}
在Vue3中不存在“新增属性、删除属性, 界面不会更新”与“直接通过下标修改数组, 界面不会自动更新”的问题。
setup() {
let person = reactive({
name: '张三',
age: 18,
hobby: ['学习', '唱歌']
})
const addSex = () => {
person.sex = '男'
}
const deleteName = () => {
delete person.name
}
const updateHobby = () => {
person.hobby[0] = '打球'
}
return{
person,
addSex,
deleteName,
updateHobby
}
实现原理:
通过Proxy(代理):拦截对象中任意属性的变化,包括:属性值的读写、属性的添加、属性的删除等。
//源数据
let person = {
name:'张三',
age:18
}
//模拟Vue3中实现响应式
//Proxy对属性的增删改查都可以监测得到
const p = new Proxy(person,{
//有人读取p的某个属性时调用
get(target,propName){
console.log(`有人读取了p身上的${propName}属性`)
return target[propName]
},
//有人修改p的某个属性、或给p追加某个属性时调用
set(target,propName,value){
console.log(`有人修改了p身上的${propName}属性,我要去更新界面了!`)
target[propName] = value
},
//有人删除p的某个属性时调用
deleteProperty(target,propName){
console.log(`有人删除了p身上的${propName}属性,我要去更新界面了!`)
return delete target[propName]
}
})
通过Reflect(反射):对被代理对象的属性进行操作。
// Reflect(反射)
const p = new Proxy(person,{
//有人读取p的某个属性时调用
get(target,propName){
console.log(`有人读取了p身上的${propName}属性`)
return Reflect.get(target,propName)
},
//有人修改p的某个属性、或给p追加某个属性时调用
set(target,propName,value){
console.log(`有人修改了p身上的${propName}属性,我要去更新界面了!`)
Reflect.set(target,propName,value)
},
//有人删除p的某个属性时调用
deleteProperty(target,propName){
console.log(`有人删除了p身上的${propName}属性,我要去更新界面了!`)
return Reflect.deleteProperty(target,propName)
}
})
new Proxy(data, {
// 拦截读取属性值
get (target, prop) {
return Reflect.get(target, prop)
},
// 拦截设置属性值或添加新属性
set (target, prop, value) {
return Reflect.set(target, prop, value)
},
// 拦截删除属性
deleteProperty (target, prop) {
return Reflect.deleteProperty(target, prop)
}
})
proxy.name = 'tom'
setup执行的时机
setup的参数
this.$attrs
。存放没有被组件props配置项接收的数据,如果组件外部传递过来的数据都被组件props配置项接收,则该对象为空。this.$slots
。Vue3中具名插槽使用v-slot:插槽名
this.$emit
。Vue3绑定的自定义事件在组件中需要使用emits配置项接收。App.vue:
<template>
<Demo @hello="showHelloMsg" msg="你好啊" school="尚硅谷">
<!-- Vue3中具名插槽使用 `v-slot:插槽名` -->
<template v-slot:qwe>
<span>尚硅谷</span>
</template>
<template v-slot:asd>
<span>尚硅谷</span>
</template>
</Demo>
</template>
<script>
import Demo from './components/Demo'
export default {
name: 'App',
components:{Demo},
setup(){
// 自定义事件的处理函数
function showHelloMsg(value){
alert(`你好啊,你触发了hello事件,我收到的参数是:${value}!`)
}
return {
showHelloMsg
}
}
}
</script>
Demo.vue:
<template>
<h1>一个人的信息</h1>
<h2>姓名:{{person.name}}</h2>
<h2>年龄:{{person.age}}</h2>
<button @click="test">测试触发一下Demo组件的Hello事件</button>
</template>
<script>
import {reactive} from 'vue'
export default {
name: 'Demo',
props:['msg','school'],
emits:['hello'], // 绑定的自定义事件在组件中需要使用emits配置项接收
setup(props,context){
// console.log('---setup---',props)
// console.log('---setup---',context)
// console.log('---setup---',context.attrs) //相当与Vue2中的$attrs
// console.log('---setup---',context.emit) //触发自定义事件的。
console.log('---setup---',context.slots) //插槽
//数据
let person = reactive({
name:'张三',
age:18
})
//方法
function test(){
// 触发自定义事件
context.emit('hello',666)
}
//返回一个对象(常用)
return {
person,
test
}
}
}
</script>