≡
  • 网络编程
  • 数据库
  • CMS技巧
  • 软件编程
  • PHP笔记
  • JavaScript
  • MySQL
位置:首页 > 网络编程 > vue.js

简单实现vue中的依赖收集与响应的方法

人气:545 时间:2019-04-15

这篇文章主要为大家详细介绍了简单实现vue中的依赖收集与响应的方法,具有一定的参考价值,可以用来参考一下。

感兴趣的小伙伴,下面一起跟随四海网的小编两巴掌来看看吧!

 

开始

 

声明一个对象man,可以视为vue中的data

代码如下:


let man = {
 height: 180,
 weight: 70,
 wealth: 100000000
}

 

添加Observer

 

作用在于将参数对象的属性变为响应式,只要对象的属性被读取或者被修改都能观察到。然后新建一个Observer实例,将man作为参数扔进去。这里的proxyData是将man的属性代理到以man为参数的Observer实例上去。

代码如下:


class Observer {
 constructor(obj) {
  this.walk(obj)
 }
 walk(obj) {
  Object.keys(obj).forEach(prop => {
   this[prop] = obj[prop]
   this.proxyData(obj, prop)
   this.defineReactive(this, prop, obj[prop])   
  })
 }
 proxyData(obj, prop) {
  let _this = this
  Object.defineProperty(obj, prop, {
   get() {
    return _this[prop]
   },
   set(newVal) {
    _this[prop] = newVal
   }
  })
 }
 defineReactive(obj, prop, val) {
  Object.defineProperty(obj, prop, {
   get() {
    console.log(`${prop} - 被读取!`)
    return val
   },
   set(newVal) {
    if (newVal == val) return
    val = newVal
    console.log(`${prop} - 被修改!`)
   }
  })
 }
}

new Observer(man)

这时打印一下man

【图片暂缺】

现在man的属性都是由Observer实例所对应的属性的getter来返回,只有在查看时会被触发

【图片暂缺】

对man的属性进行修改也会触发实例对应属性的setter

【图片暂缺】

 

添加Watcher

 

现在的Watcher有点像vue中的computed,实际上就是定义一个计算属性,这个计算属性依赖于前面man中的某些属性,由他们计算而得。

代码如下:


class Watcher {
 constructor(obj, prop, computed) {
  this.getVal(obj, prop, computed)
 }

 getVal(obj, prop, computed) {
  Object.defineProperty(obj, prop, {
   get() {
    console.log(`computed属性 - ${prop}被读取!`)
    return computed()
   },
   set() {
    console.error('计算属性不可被修改!')
   }
  })
 }
}

new Watcher(man, 'strength', () => {
 let {height, weight} = man
 if (height > 160 && weight > 70) return 'strong'
 return 'weak'
})

【图片暂缺】

看起来没什么问题,所依赖的属性如果变了,计算属性只要再被查看(get方法)一次就可以更新了。但vue中的视图渲染是实时的,视图层依赖于数据层,数据变化了,视图层也会跟着变化,不需要手动更新。类比到这个例子就是计算属性如何才能在其所依赖的属性发生变化时被通知从而触发应有的事件?

 

这时我们先给Watcher加多一个callback,用于处理当依赖的数据被修改时,我这个计算属性该怎么响应

 

比如当依赖被修改时,我们就把这个计算属性的值打印出来

代码如下:


class Watcher {
 constructor(obj, prop, computed, callback) {
  this.getVal(obj, prop, computed, callback)
 }

new Watcher(man, 'strength', () => {
 let {height, weight} = man
 if (height > 160 && weight > 70) return 'strong'
 return 'weak'
}, () => {
 console.log(`i am so ${man.strength} !`)
})

一切都准备好了,接下来就是该如何实现?

我们先看下Watcher中getVal这个方法

代码如下:


getVal(obj, prop, computed, callback) {
 Object.defineProperty(obj, prop, {
  get() {
   console.log(`computed属性 - ${prop}被读取!`)
   return computed()
  },
  set() {
   console.error('计算属性不可被修改!')
  }
 })
}

当我们查看计算属性时,会调用computed这个方法,相当于查看了其所依赖的height和weight属性,而在上面我们已经让man的所有属性都拥有了get方法,即他们被查看时我们是不是可以把callback塞给他们?
这时候我们引进一个桥梁,来连接Watcher和Observer。

 

添加Dep

 

Dep的用处在于当某一个属性(以下称‘自己')被依赖了,将依赖自己的粉丝(们)--也就是Watcher(s),收集起来,假如自己发生了变化,能够及时通知粉丝们。

代码如下:


class Dep {
 constructor() {
  this.deps = []
 }
 getDeps() {
  if (!Dep.target || this.deps.includes(Dep.target)) return
  console.log('依赖添加', Dep.target)
  this.deps.push(Dep.target)
 }
 notify() {
  this.deps.forEach(dep => {
   dep()
  })
 }
}

这里的Dep.target就是前面所说的callback方法了。这时我们改一下Watcher中的getVal

代码如下:


getVal(obj, prop, computed, callback) {
 Object.defineProperty(obj, prop, {
  get() {
   Dep.target = callback
   console.log(`computed属性 - ${prop}被读取!`)
   return computed()
  },
  set() {
   console.error('计算属性不可被修改!')
  }
 })
}

在计算属性被查看时,将callback赋值给Dep.target,接下来就会调用其所依赖属性的getter,我们只要在getter里把callback给收集起来就行了。接下来修改依赖属性的getter方法。

代码如下:


defineReactive(obj, prop, val) {
 let dep = new Dep()
 Object.defineProperty(obj, prop, {
  get() {
   console.log(`${prop} - 被读取!`)
   dep.getDeps() // 依赖收集
   return val
  },
  set(newVal) {
   if (newVal == val) return
   val = newVal
   console.log(`${prop} - 被修改!`)    
  }
 })
}

这时watcher的callback都被依赖属性给收集起来了,当依赖属性发生变化时只要去运行这些callback就可以了。接下来就是修改依赖属性的setter方法。

代码如下:


defineReactive(obj, prop, val) {
 let dep = new Dep()
 Object.defineProperty(obj, prop, {
  get() {
   console.log(`${prop} - 被读取!`)
   dep.getDeps()
   return val
  },
  set(newVal) {
   if (newVal == val) return
   val = newVal
   console.log(`${prop} - 被修改!`)
   dep.notify() // 运行所有callback
  }
 })
}

运行看看

【图片暂缺】

我们加多一个Watcher试试

代码如下:


new Watcher(man, 'isGreat', () => {
 let {height, weight, wealth} = man
 if (height > 180 && weight > 70 && wealth > 100000) return 'Great!'
 return 'not good enough ...'
}, () => {
 console.log(`they say i am ${man.isGreat}`)
})

【图片暂缺】

这就是vue中的一个依赖对应多个Watcher

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持四海网。

本文来自:http://www.q1010.com/184/6873-0.html

注:关于简单实现vue中的依赖收集与响应的方法的内容就先介绍到这里,更多相关文章的可以留意四海网的其他信息。

关键词:vue.js

您可能感兴趣的文章

  • 分析关于Vuex的action传入多个参数的问题
  • vue动态添加路由addRoutes之不能将动态路由存入缓存的解决
  • Vue 组件注册实例分析
  • 分析TypeScript+Vue 插件 vue-class-component的使用总结
  • 记一次vue-webpack项目优化实践分析
  • Vue框架TypeScript装饰器使用指南小结
  • 分析Element 指令clickoutside源码分析
  • 深入理解vue-class-component源码阅读
  • vue使用Font Awesome的方法步骤
  • Vue多组件仓库开发与发布分析
上一篇:vue工程全局设置ajax的等待动效的方法
下一篇:深入理解vue-class-component源码阅读
热门文章
  • Vue 报错TypeError: this.$set is not a function 的解决方法
  • vue实现动态添加数据滚动条自动滚动到底部的示例代码
  • vue项目设置scrollTop不起作用(总结)
  • vue项目中使用vue-i18n报错的解决方法
  • iview实现select tree树形下拉框的示例代码
  • 分析关于element级联选择器数据回显问题
  • vue项目打包后打开页面空白解决办法
  • 解决element ui select下拉框不回显数据问题的解决
  • element-ui table span-method(行合并)的实现代码
  • element-ui 设置菜单栏展开的方法
  • 最新文章
    • 理解vue ssr原理并自己搭建简单的ssr框架
    • vue favicon设置以及动态修改favicon的方法
    • vue-router启用history模式下的开发及非根目录部署方法
    • 从零开始在NPM上发布一个Vue组件的方法步骤
    • Element input树型下拉框的实现代码
    • Vue 报错TypeError: this.$set is not a function 的解决方法
    • Vue.js组件高级特性实例分析
    • 浅谈VueJS SSR 后端绘制内存泄漏的相关解决经验
    • 分析Vue.js自定义tipOnce指令用法实例
    • 浅谈vuex actions和mutation的异曲同工

四海网收集整理一些常用的php代码,JS代码,数据库mysql等技术文章。