您现在的位置是:首页 >技术交流 >手写vue-watch网站首页技术交流
手写vue-watch
简介手写vue-watch
一、watch的使用
watch有多重形式,可能是字符串、函数、数组
// 函数形式 数组形式 vm.$watch
// 最终调用的都是vm.$watch
watch:{
firstname(newValue,oldValue){
// 观察者 观察变量改变 执行回调函数
console.log(newValue,oldValue)
}
}
vm.$watch(()=>vm.firstname,(newValue,oldValue)=>{
console.log(newValue,oldValue,11)
})
二、实现原理
本质是一个Wathcer
,观测一个响应式数据,当数据发生变化时通知并执行相应的回调函数。
在监听对象变化的时候,加上 deep
这个属性即可深度监听对象数据;如果你想在页面进来时就执行 watch
方法,加上 immediate
即可。值得注意的是,设置了 immediate
属性的 watch
的执行顺序是在 created
生命周期之前的
三、实现watch
3.1初始化
export function initState(vm) {
const opts = vm.$options;
...
if (opts.watch) {
// 初始化watch
initWatch(vm);
}
}
createWatcher
中会判断 handler
是否是对象,如果是对象将 handler
挂载到 options
这个属性,再将对象的 handler
属性提取出来;如果 handler
是一个字符串的话,会从 Vue
实例找到这个方法赋值给 handler
。从这里我们也能看出来,watch
还可以支持字符串的写法。执行 Vue
实例上的 $watch
方法。
function initWatch(vm){
let watch = vm.$options.watch
for(let key in watch){ //字符串 数组 函数
const handler = watch[key]
if(Array.isArray(handler)){
// 循环创建watch
for(let i=0;i<handler.length;i++){
createWatcher(vm,key,handler[i])
}
}else{
createWatcher(vm,key,handler)
}
}
}
// 字符串 函数
function createWatcher(vm,key,handler){
if(typeof handler === 'string'){
handler = vm[handler]
}
return vm.$watch(key,handler)
}
// 监控的某个值,回调
Vue.prototype.$watch = function (expreOrFn, cb) {
// firstname
// ()=>vm.firstname
// 表示用户自己写的watcher
// firstname的值变化直接执行cb函数
new Watcher(this,expreOrFn,{user:true},cb)
}
class Watcher {
constructor(vm, exprOrFn, options, cb) {
this.id = id++;
this.renderWatcher = options; //标识是一个渲染watcher
if (typeof exprOrFn === 'string') {
this.getter = function () {
return vm[exprOrFn]
}
} else {
this.getter = exprOrFn; //getter意味着调用这个函数可以发生取值操作
}
this.deps = []; // watcher记住dep,比如计算属性和组件卸载,希望watcher清理掉所有响应式数据
this.depsId = new Set(); //去掉重复的dep
this.vm = vm
this.user = options.user //标识是否是用户自己的watcher
this.cb = cb
this.lazy = options.lazy;
this.dirty = options.lazy;
this.value = this.lazy ? undefined : this.get(); //此处先调用get是因为,首次渲染组件需要去取到数据放到页面上
}
run() {
let newValue = this.get(); // 渲染的时候用的是最新的vm来渲染的
if(this.user){
this.cb.call(this.vm,newValue,this.value)
}
}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。