这里的知识是结合视频以及其他文章一起学习,仅用于个人复习记录
ref 和reactive
ref 用于基本类型
reactive 用于引用类型
如果使用ref 传递对象,修改值时候需要写为obj.value.attr 方式修改属性值
如果使用reactive 处理对象,直接obj.attr 即可 达到响应式效果
watch
watch 监听多个基本值,返回的newValue 和 oldValue是一个数组
watch 监听reactive 对象 无法正确获取oldValue(如果不需要考虑oldValue,那么这个问题影响不大)
watch 第一个参数只能是ref reactive返回值,如果想监听对象里边某个属性,则需要通过函数返回,如果该属性指向的是一个引用类型,则需要开启深度监听才能监听到变化
如果watch 监听ref(对象),如果监听对象 深层的变化,则需要传递deep(此时监听的是ref 对象,对于value指向的对象的属性变化变化需要开启deep)
如果watch 监听ref(对象),如果监听对象.value 深层的变化,则不需要传递deep (此时监听的是.value 也就是 reactive 对象不需要开启deep)
javascript
// 下面两个都满足第一个参数是ref 或者reactive对象,一个监听的是ref对象一个是reactive对象
// 需要开启deep 才能监听到age变化
watch(obj, (newValue, oldValue) => {
console.log(newValue, oldValue);
}, { deep: true })
//
watch(obj.value, (newValue, oldValue) => {
console.log(newValue, oldValue);
})
watchEffect
watch 既要指明监听的属性也要指明监听的回调,而watchEffect不用指明监听哪个属性,我感觉watchEffect更好用
回调里边,用到哪个值就监听哪个值,如果被监听的值发生变化时候,回调就会触发,比如监听查询关键字变化来决定触发查询操作
javascript
watchEffect(() => {
if (keywords.value != '') {
console.log('开始搜索', keywords.value);
}
})
onActivated 和 onDeactivated(还没使用过)
补充生命周期函数activated和deactivated
这两个是路由组件所独有的两个钩子,用于捕获路由组件的激活状态,因为跳进另一个路由组件的时候,前一个路由组件会被销毁,但是加了缓存的路由,则不会被触发销毁流程;使用这两个替代销毁时的生命周期函数;
onActivated:表示路由组件被激活时触发;
onDeactivated:表示路由组件失活时触发;
这个在编写uniapp 时候有个类似的东西,比如push 到其他页面时候,前面一个页面并不会被销毁,而是只是触发了隐藏,我觉得这两个周期函数类似uniapp 当中的onShow 和 onHide 周期
自定义hook
相当于vue2的mixins,如果要实现一个鼠标打点功能,可以将这个功能相关的函数周期状态等封装到一个hook里边,这样子方便维护,也可以复用
toRef toRefs
将一个对象的某个属性,设置为响应式的
javascript
function change() {
// 修改时候会修改person里边的salary,
// person里边的salary发生变化时候,也会触发页面的salary发生变化
salary.value = 12;
}
const salary = toRef(person.job, 'salary');
toRefs 会将对象的第一层弄成响应式的,
需要进行解构
javascript
return {
change,
...toRefs(person)
}
shallowRef 和 shallowReactive
浅层次处理响应式
shallowReactive 只会处理第一层属性
shallowRef 传递的对象,只处理 .value 响应式,其中属性是没有响应式的
shallowRef 如果传递的是基本数据,跟使用ref是没有区别的。
readonly 和 shallowReadonly
readonly 深层次只读
shallowReadonly 浅层次只读
对于基本类型两个的使用都可以,建议readonly
对于引用类型,使用readonly 全部只读,如果使用shallowReadonly 那么只有第一层属性只读
一般来说,如果别人定义的响应式数据,只可以给你使用,但是不允许你去修改,他只需要暴露出通过readonly 包裹的数据即可
比如前面写的usePoint hook 咱们使用别的hook ,里边暴露出来的数据,可以通过readonly 包裹
javascript
import { onMounted, onUnmounted, reactive, readonly } from "vue";
export default function () {
const point = reactive({
x: 0, y: 0
})
function savePoint(event) {
point.x = event.pageX;
point.y = event.pageY;
}
onMounted(() => {
window.addEventListener('click', savePoint)
})
onUnmounted(() => {
window.removeEventListener('click', savePoint)
})
return readonly(point);
}
toRaw 和 markRaw
toRaw 将响应式对象(由 reactive定义的响应式)转换为普通对象
makRaw 将数据标记为永远不能追踪的数据, 一般在编写自己的第三方库时使用
比如一个用户的信息,通过接口请求回来该用户的基本信息,而且该信息不可以被修改,但是用户的其他信息是可以进行修改的, 可以将请求的数据标记为不可追踪,这样子不会被处理为响应式的
javascript
person.company = markRaw({
name: '字节跳动',
desc: '神与我同在'
})
person.age = 22; // 发生变化
person.company.name = 'fuck'; // 数据发生变化了,但是页面不会变化
customRef
javascript
function myRef(value) {
return (track, trigger) => {
return {
get() {
track();// 告诉vue需要追踪value 变化,否则其他地方无法获取变化后的value
return value;
},
set(newValue) {
value = newValue;
trigger();// 通知重新解析模板
}
}
}
}
inject 和 provide
可以实现祖孙组件通信,祖先组件提供数据,孙组件获取数据
如果是父子组件传递数据,直接使用props即可
javascript
provide({
person: person
})
//得到的是响应式数据,祖组件修改时候,这里也会发生变化
const person = inject('person')
其他
isRef isReactive isProxy isReadonly 如果写的数据很多,忘记某些数据的是否为响应数据等可以通过前面这个进行判断
组合api 的优势:
使用传统的OptionsAPI,新增或者修改一个需求,就需要分别在data、methods、computed里修改
而组合api 可以更加优雅的组织我们的代码、函数,让相关功能的代码更加有序的组织在一起