自定义hook函数
自定义hook函数概念
- 什么是hook?
——本质是一个函数,把setup函数中使用的Composition APl
进行了封装。类似于vue2.x中的mixin。
自定义hook的使用
就是把setup中具有一定逻辑功能的代码提取出去,放在hooks的函数中,以后哪个组件需要使用该功能,就直接调用该hook函数即可。
hook函数一般放在src文件夹下的hooks中。
eg:
hooks/usePoint.js(定义hooks函数:获取鼠标点击坐标)
import {onBeforeUnmount, onMounted, reactive} from 'vue'
export default function () {
// 实现鼠标打点的数据
let point = reactive({
x: 0,
y:0
})
// 实现鼠标打点的函数
function savePoint(event){
point.x = event.pageX
point.y = event.pageY
}
// 实现鼠标打点的相关方法
// 哪个组件调用,onMounted就是指的是那个组件的挂载
onMounted(() => {
console.log("---onMounted---")
// 监视整个页面所以给windown绑定
window.addEventListener('click', savePoint)
})
onBeforeUnmount(() => {
window.removeEventListener('click', savePoint)
})
return point
}
Demo.vue (调用hooks函数)
<template>
<h1>Demo组件</h1>
<h2>当前求和为:{{sum}}</h2>
<button @click="sum++">点我+1</button>
<hr/>
<h2>当前点击时鼠标的坐标为:(x:{{point.x}},y:{{point.y}})</h2>
</template>
<script>
import { ref } from 'vue'
import usePoint from "../hooks/usePoint"
export default {
name: 'DemoVue',
setup() {
console.log("---setup---")
// 数据
let sum = ref(0)
let point = usePoint()
return {
sum,
point
}
},
}
</script>
效果:
自定义hook的优势
复用代码,让setup中的逻辑更清楚易懂。
toRef和toRefs
引出
需求:
实现如上功能,代码如下:
<template>
<h2>姓名:{{ person.name }}</h2>
<h2>年龄:{{ person.age }}</h2>
<h2>薪资:{{ person.job.j1.salary }}</h2>
<button @click="person.name += '~'">修改姓名</button>
<button @click="person.age += 1">增长年龄</button>
<button @click="person.job.j1.salary++">涨薪</button>
</template>
<script>
import { reactive,} from 'vue'
export default {
name: 'DemoVue',
setup() {
// 数据
let person = reactive({
name: 'yang',
age: 18,
job: {
j1: {
salary: 20
}
}
})
return {
person
}
}
}
</script>
模板中使用属性的时候必须person.属性
但是我不想这样写了,太麻烦了,能不能直接使用属性在模板中进行渲染呢?
- 尝试不直接暴露person,而是将属性暴露出去:
return {
name: person.name,
age: person.age,
salary:person.job.j1.salary
}
产生问题,person是响应式数据,但是person.name获取到的就是一个字符串的值,使用name: person.name,
就相当于暴露出去一个基本类型的字符串,没有响应式。所以不能这样写。
- 尝试使用ref对属性进行封装
return {
name: ref(person.name) ,
age: ref(person.name),
salary: ref(person.job.j1.salary)
}
产生问题,这样确实是实现了响应式,但是使用ref就代表新创建出了一个响应式的对象,和person就脱节了,也就是说,当暴露出去的name发生变化的时候,ref所包装的数据确实是发生变化了,但是person的name属性就不会改变了。
- 解决——使用toRef
toRef
(1)作用:创建一个ref对象,其value值指向另一个对象中的某个属性
。
(2)toRef与ref最大的区别是:
- ref:创建一个ref对象,value的值就是创建对象时传过来的值了
- toRef:创建一个ref对象,value的值可以指向
另一个对象中的某个属性
,即实现桥接效果。当toRef所管理的对象的值发生了变化,其value的值指向的对象的属性
的值也发生变化。
(3)语法:const name = toRef(指向的对象 , '对象的属性')
(4)应用: 要将响应式对象中的某个属性单独提供给外部使用时。
(5)使用
eg:上述例子的toRef实现
<template>
<h2>姓名:{{ person.name }}</h2>
<h2>年龄:{{ person.age }}</h2>
<h2>薪资:{{ person.job.j1.salary }}</h2>
<button @click="person.name += '~'">修改姓名</button>
<button @click="person.age += 1">增长年龄</button>
<button @click="person.job.j1.salary++">涨薪</button>
</template>
<script>
import { reactive, toRef } from 'vue'
export default {
name: 'DemoVue',
setup() {
// 数据
let person = reactive({
name: 'yang',
age: 18,
job: {
j1: {
salary: 20
}
}
})
return {
name: toRef(person,'name') ,
age: toRef(person, 'age'),
salary: toRef(person.job.j1,'salary')
}
}
}
</script>
toRefs
toRefs与toRef功能一致,但可以批量创建多个ref对象
,toRefs可以将整个响应式对象以属性的形式暴露出去
语法: toRefs(对象)
eg:上述例子的toRefs实现
<template>
<h2>姓名:{{name }}</h2>
<h2>年龄:{{age }}</h2>
<h2>薪资:{{job.j1.salary }}</h2>
<button @click="name += '~'">修改姓名</button>
<button @click="age += 1">增长年龄</button>
<button @click="job.j1.salary++">涨薪</button>
</template>
<script>
import { reactive, toRefs } from 'vue'
export default {
name: 'DemoVue',
setup() {
// 数据
let person = reactive({
name: 'yang',
age: 18,
job: {
j1: {
salary: 20
}
}
})
return {
...toRefs(person)
}
}
}
</script>