setup
vue3中的一个新的配置项,值为一个函数,所有的组合api都要结合它使用。
使用介绍:1、使用时,把变量或者方法return出去即可在模板中使用
export default {
setup() {
let name = 'zhang'
function at() {
console.log(1)
}
return {
name,
at,
}
},
}
setup函数有两种返回值,一种就是上面的常规的返回一个对象,则对象中的属性,方法在模板中均可使用,还有一种是返回一个函数。
// 若返回一个渲染函数:则可以自定义渲染内容
import { h } from 'vue'
export default {
setup() {
return () => h('h1', '你好')
},
}
setup 的注意点
setup 执行的时机是最早的,在 beforeCreate 之前执行,所以此时 this 是 undefined
参数问题 setup 接收 2 个参数
props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。
context:上下文对象
- attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于 ```this.$attrs```。
- slots: 收到的插槽内容, 相当于 ```this.$slots```。
- emit: 分发自定义事件的函数, 相当于 ```this.$emit```
// 在子组件中
export default {
props: ['msg', 'school'],
emits: ['hello'],
setup(props, context) {
// props接收props配置项中的相应式数据{msg:'',school:''}
// context相当于上下文对象,里面有三个值attrs,slots,emit
//方法
function test() {
// 调用父组件方法
context.emit('hello', 666)
}
return {
test,
}
},
}
ref函数
作用:定义一个响应式的数据(主要针对基础数据类型)
方法:引入ref函数,const xxx = ref(initValue) 模板中读取数据不需要.value,直接<div>{{xxx}}</div>
处理基本数据类型
RefImpl 对象中.value 是基础类型时,用的是 Object.defineProperty 通过 get 和 set 实现的响应式数据
打印如下图:
import { ref } from 'vue'
export default {
setup() {
let name = ref('vue3.0')
function change() {
console.log(name, 'name')
//ref加工之后生成一个 RefImpl引用对象,该对象的原型对象上可以发现,底层其实还是Object.defineProperty通过
// get 和set实现的响应式数据
// 因此改变基本数据需要用到RefImpl引用对象中的value属性
name.value = '小明'
}
return {
name,
change,
}
},
}
处理对象类型
RefImpl 对象中.value 是对象类型时,用的是 proxy实现的响应式数据
import { ref } from 'vue'
export default {
setup() {
let obj = ref({
name: '小明',
age: 20,
})
function change() {
obj.value.name = '小工'
obj.value.age++
console.log(obj.value)
//可以发现是一个Proxy 对象,其本质其实调用的是```reactive```函数实现Proxy代理响应式对象
}
return {
obj,
change,
}
},
}
reactive函数
作用:定义一个对象类型的响应式数据(基本类型不要用它,要用ref函数)
方法:constxxx = reactive(源对象)接受一个对象(或数组),返回一个代理对象(proxy的实例对象,简称proxy对象)
特点:可以实现数组、深层对象的响应式数据,这是vue2.0中无法实现的,底层基于proxy
export default {
setup() {
let obj = reactive({
name: '小明',
age: 20,
})
function change() {
console.log(obj, 'obj')
//可以发现obj此时就是一个Proxy的实例对象可以直接修改对象内部属性
obj.name = '小三'
obj.age++
}
return {
obj,
change,
}
},
}
总结ref和reactive
从定义数据角度对比
const x1= ref(initValue) ----àref
const x2 = reactive(源对象) (源对象可指对象或者数组) ----àreactive
ref用来定义:基本数据类型
reavtive用来定义:对象(或数组)类型数据
备注:ref也可以用来定义对象(或数组)类型数据,它内部会自动通过reactive转为代理对象
从原理角度对比
ref通过Object.defineProperty()的get和set来实现响应式(数据劫持)
reactive通过使用Proxy来实现响应式(数据劫持),并通过Reflect操作源对象内部的数据
计算属性
computed函数
// 1.直接读取(简写)
import { reactive,computed } from 'vue'
export default {
setup () {
let obj = reactive({
name: 'haha',
age: 18
})
let ages = computed(() => {
return obj.age + 1
})
return {
ages
}
},
}
// 1.计算属性修改情况(完整版)
export default {
setup () {
let obj = reactive({
name: 'haha',
age: 18
})
let fullName = computed({
get () {
return obj.age + 1
},
set (value) {
obj.age = value
}
})
return {
obj,
fullName
}
},
}
watch函数
watch接受三个参数监听的对象 监听的回调和监视的配置参数
//watch('被监听的对象',()=>{},{immediate:'立即监听',deep:'深度监听'})
export default {
setup () {
let age = ref(18)
let name = ref('小明')
let obj = reactive({
money: 100
})
function change () {
obj.money += 100
age.value++
name.value += '-'
}
//情况一:监视ref所定义的一个响应式数据
watch(age, (newValue, oldValue) => {
console.log('age', newValue, oldValue)
},{immediate:true})
//情况二:监视ref所定义的多个响应式数据
watch([age, name], (newValue, oldValue) => {
console.log('age-name', newValue, oldValue)//也是数组形式返回
})
// 情况三:监视reactive所定义的一个响应式数据的全部属性
watch(obj, (newValue, oldValue) => {
// 如果监听的是正规响应式对象的话
// 1.注意:此处无法正确的获取oldValue
// 2.注意:强制开启了深度监视(deep配置无效)
})
// 情况四:监视reactive所定义的一个响应式数据中的某个属性
watch(() => obj.money, (newValue, oldValue) => {
// [()=>person.name,()=>person.age]多参数时候也需要数组
// 监听的参数需要以函数的形式返回才可以监听到
//当监听的参数是深层对象,需要配置deep为true
})
return {
obj,
name,
age,
change
}
},
}
watchEffect函数
不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。watchEffect有点像computed: - 但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值。 - 而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。
watchEffect(() => {
let a = obj.money
console.log('改变了')
//默认是立即监听,当使用的数据改变时,就会触发。可以用于关联数据改变回调方法等场景
})
自定义hook函数
什么是hook: 本质是一个函数,把setup函数中使用的Composition API进行了封装。
特点:类似于vue2.x中的mixin 优势: 复用代码, 让setup中的逻辑更清楚易懂。
1、新建hooks文件夹,新增usePoint.js
import {onBeforeMount, onBeforeUnmount, reactive} from 'vue'
export default function () {
const point = reactive({
x:0,
y:0
})
function savePoint (event) {
point.y = event.pageY
point.x = event.pageX
console.log('x,y', point.y, point.x)
}
onBeforeMount(() => {
// 监听click事件
window.addEventListener('click',savePoint)
})
onBeforeUnmount(() => {
window.removeEventListener('click',savePoint)
})
return point
}
在vue文件中导入js
import usePoint from "../hooks/usePoint";
//具体使用
<template>
<div>
<h2>当前求和为:{{ sum }}</h2>
<button @click="sum++">点我+1</button>
<h2>{{ point }}</h2>
</div>
</template>
<script>
import usePoint from "../hooks/usePoint";
import {ref} from 'vue'
export default {
setup() {
//数据
let sum = ref(0);
// 引用公共hook函数
let point = usePoint();
return {
sum,
point,
};
},
};
</script>
<style>
</style>