当前位置: 首页 > news >正文

玉树藏族自治州网站建设_网站建设公司_前后端分离_seo优化

淄博有做网站的吗,大连网站程序开发,打开网站后直接做跳转,企管宝作者#xff1a;Naicehttps://segmentfault.com/a/1190000023196603这篇文章将带大家全面理解vue的watcher、computed和user watcher#xff0c;其实computed和user watcher都是基于Watcher来实现的#xff0c;我们通过一个一个功能点去敲代码#xff0c;让大家全面理解其中… 作者Naicehttps://segmentfault.com/a/1190000023196603这篇文章将带大家全面理解vue的watcher、computed和user watcher其实computed和user watcher都是基于Watcher来实现的我们通过一个一个功能点去敲代码让大家全面理解其中的实现原理和核心思想。所以这篇文章将实现以下这些功能点实现数据响应式基于渲染wather实现首次数据渲染到界面上数据依赖收集和更新实现数据更新触发渲染watcher执行从而更新ui界面基于watcher实现computed基于watcher实现user watcher废话不要多说先看下面的最终例子。例子看完之后我们就直接开工了。准备工作首先我们准备了一个index.html文件和一个vue.js文件先看看index.html的代码htmlen  UTF-8  全面理解vue的渲染watcher、computed和user atcher  root    index.html里面分别有一个id是root的div节点这是跟节点然后在script标签里面引入了vue.js里面提供了Vue构造函数然后就是实例化Vue参数是一个对象对象里面分别有data 和 render 函数。然后我们看看vue.js的代码function Vue (options) {vue.js代码里面就是执行this._init()和this.$mount()this._init的方法就是对我们的传进来的配置进行各种初始化包括数据初始化initState(vm)、计算属性初始化initComputed(vm)、自定义watch初始化initWatch(vm)。this.$mount方法把render函数渲染到页面中去、这些方法我们后面都写到先让让大家了解整个代码结构。下面我们正式去填满我们上面写的这些方法。实现数据响应式要实现这些watcher首先去实现数据响应式也就是要实现上面的initState(vm)这个函数。相信大家都很熟悉响应式这些代码下面我直接贴上来。function initState(vm) {重要的点都在注释里面主要核心就是给递归给data里面的数据设置get和set然后设置数据代理让 this.name 等同于 this._data.name。设置完数据观察我们就可以看到如下图的数据了。console.log(vue.name) // 张三console.log(vue.age) // 10ps: 数组的数据观察大家自行去完善哈这里重点讲的是watcher的实现。首次渲染数据观察搞定了之后我们就可以把render函数渲染到我们的界面上了。在Vue里面我们有一个this.$mount()函数所以要实现Vue.prototype.$mount函数// 挂载方法Vue.prototype.$mount  function () {  const vm  this  new Watcher(vm, vm.$options.render, ()  {}, true)}以上的代码终于牵扯到我们Watcher这个主角了这里其实就是我们的渲染wather这里的目的是通过Watcher来实现执行render函数从而把数据插入到root节点里面去。下面看最简单的Watcher实现let wid  0通过上面的一顿操作终于在render中终于可以通过this.name 读取到data的数据了也可以插入到root.innerHTML中去。阶段性的工作我们完成了。如下图完成的首次渲染✌️数据依赖收集和更新首先数据收集我们要有一个收集的地方就是我们的Dep类下面呢看看我们去怎么实现这个Dep。// 依赖收集let dId  0class Dep{  constructor() {    this.id  dId // 每次实例化都生成一个id    this.subs  [] // 让这个dep实例收集watcher  }  depend() {    // Dep.target 就是当前的watcher    if (Dep.target) {      Dep.target.addDep(this) // 让watcher,去存放dep然后里面dep存放对应的watcher两个是多对多的关系    }  }  notify() {    // 触发更新    this.subs.forEach(watcher  watcher.update())  }  addSub(watcher) {    this.subs.push(watcher)  }}let stack  []// push当前watcher到stack 中并记录当前watcerfunction pushTarget(watcher) {  Dep.target  watcher  stack.push(watcher)}// 运行完之后清空当前的watcherfunction popTarget() {  stack.pop()  Dep.target  stack[stack.length - 1]}Dep收集的类是实现了但是我们怎么去收集了就是我们数据观察的get里面实例化Dep然后让Dep收集当前的watcher。下面我们一步步来1、在上面this.$mount()的代码中我们运行了new Watcher(vm, vm.$options.render, () {}, true)这时候我们就可以在Watcher里面执行this.get()然后执行pushTarget(this)就可以执行这句话Dep.target watcher把当前的watcher挂载Dep.target上。下面看看我们怎么实现。class Watcher {  constructor(vm, exprOrFn, cb, options) {    this.vm  vm    if (typeof exprOrFn  function) {      this.getter  exprOrFn    }    this.cb  cb    this.options  options    this.id  wid    this.id  wId    this.deps  []    this.depsId  new Set() // dep 已经收集过相同的watcher 就不要重复收集了    this.value  this.get()  }  get() {    const vm  this.vm   pushTarget(this)    let value  this.getter.call(vm, vm) // 执行函数   popTarget()    return value  }  addDep(dep) {    let id  dep.id    if (!this.depsId.has(id)) {      this.depsId.add(id)      this.deps.push(dep)      dep.addSub(this);    }  }  update(){    this.get()  }}2、知道Dep.target是怎么来之后然后上面代码运行了this.get()相当于运行了vm.$options.render在render里面回执行this.name这时候会触发Object.defineProperty·get方法我们在里面就可以做些依赖收集(dep.depend)了如下代码function defineReactive(data, key, value) {3、调用的dep.depend() 实际上是调用了 Dep.target.addDep(this), 此时Dep.target等于当前的watcher然后就会执行addDep(dep) {  let id  dep.id  if (!this.depsId.has(id)) {    this.depsId.add(id)    this.deps.push(dep) // 当前的watcher收集dep    dep.addSub(this); // 当前的dep收集当前的watcer  }}这里双向保存有点绕大家可以好好去理解一下。下面我们看看收集后的des是怎么样子的。4、数据更新调用this.name 李四的时候回触发Object.defineProperty.set方法里面直接调用dep.notify()然后循环调用所有的watcer.update方法更新所有watcher例如这里也就是重新执行vm.$options.render方法。有了依赖收集个数据更新我们也在index.html增加修改data属性的定时方法:// index.htmlchangeData()改变name和age// -----// .....省略代码function changeData() {  vue.name  李四  vue.age  20}运行效果如下图到这里我们渲染watcher就全部实现了。实现computed首先我们在index.html里面配置一个computedscript标签的代码就如下#root)上面的代码注意computed是在render里面使用了。在vue.js中之前写了下面这行代码。if (options.computed) {我们现在就实现这个initComputed代码如下// 初始化computedfunction initComputed(vm) {  const computed  vm.$options.computed // 拿到computed配置  const watchers  vm._computedWatchers  Object.create(null) // 给当前的vm挂载_computedWatchers属性后面会用到  // 循环computed每个属性  for (const key in computed) {    const userDef  computed[key]    // 判断是函数还是对象    const getter  typeof userDef  function ? userDef : userDef.get    // 给每一个computed创建一个computed watcher 注意{ lazy: true }    // 然后挂载到vm._computedWatchers对象上    watchers[key]  new Watcher(vm, getter, ()  {}, { lazy: true })    if (!(key in vm)) {      defineComputed(vm, key, userDef)    }  }}大家都知道computed是有缓存的所以创建watcher的时候会传一个配置{ lazy: true }同时也可以区分这是computed watcher然后到watcer里面接收到这个对象class Watcher {  constructor(vm, exprOrFn, cb, options) {    this.vm  vm    if (typeof exprOrFn  function) {      this.getter  exprOrFn    }    if (options) {      this.lazy  !!options.lazy // 为computed 设计的    } else {      this.lazy  false    }    this.dirty  this.lazy    this.cb  cb    this.options  options    this.id  wId    this.deps  []    this.depsId  new Set()    this.value  this.lazy ? undefined : this.get()  }  // 省略很多代码}从上面这句this.value this.lazy ? undefined : this.get()代码可以看到computed创建watcher的时候是不会指向this.get的。只有在render函数里面有才执行。现在在render函数通过this.info还不能读取到值因为我们还没有挂载到vm上面上面defineComputed(vm, key, userDef)这个函数功能就是让computed挂载到vm上面。下面我们实现一下。set个上面代码有看到在watcher中调用了watcher.evaluate()和watcher.depend()然后去watcher里面实现这两个方法下面直接看watcher的完整代码。class Watcher {  constructor(vm, exprOrFn, cb, options) {    this.vm  vm    if (typeof exprOrFn  function) {      this.getter  exprOrFn    }    if (options) {      this.lazy  !!options.lazy // 为computed 设计的    } else {      this.lazy  false    }    this.dirty  this.lazy    this.cb  cb    this.options  options    this.id  wId    this.deps  []    this.depsId  new Set() // dep 已经收集过相同的watcher 就不要重复收集了    this.value  this.lazy ? undefined : this.get()  }  get() {    const vm  this.vm    pushTarget(this)    // 执行函数    let value  this.getter.call(vm, vm)    popTarget()    return value  }  addDep(dep) {    let id  dep.id    if (!this.depsId.has(id)) {      this.depsId.add(id)      this.deps.push(dep)      dep.addSub(this);    }  }  update(){    if (this.lazy) {      this.dirty  true    } else {      this.get()    }  }  // 执行get并且 this.dirty  false  evaluate() {    this.value  this.get()    this.dirty  false  }  // 所有的属性收集当前的watcer  depend() {    let i  this.deps.length    while(i--) {      this.deps[i].depend()    }  }}代码都实现王完成之后我们说下流程1、首先在render函数里面会读取this.info这个会触发createComputedGetter(key)中的computedGetter(key)2、然后会判断watcher.dirty执行watcher.evaluate()3、进到watcher.evaluate()才真想执行this.get方法这时候会执行pushTarget(this)把当前的computed watcher push到stack里面去并且把Dep.target 设置成当前的computed watcher4、然后运行this.getter.call(vm, vm) 相当于运行computed的info: function() { return this.name this.age }这个方法5、info函数里面会读取到this.name这时候就会触发数据响应式Object.defineProperty.get的方法这里name会进行依赖收集把watcer收集到对应的dep上面并且返回name 张三的值age收集同理6、依赖收集完毕之后执行popTarget()把当前的computed watcher从栈清除返回计算后的值(张三10)并且this.dirty false7、watcher.evaluate()执行完毕之后就会判断Dep.target 是不是true如果有就代表还有渲染watcher就执行watcher.depend()然后让watcher里面的deps都收集渲染watcher这就是双向保存的优势。8、此时name都收集了computed watcher 和 渲染watcher。那么设置name的时候都会去更新执行watcher.update()9、如果是computed watcher的话不会重新执行一遍只会把this.dirty 设置成 true如果数据变化的时候再执行watcher.evaluate()进行info更新没有变化的的话this.dirty 就是false不会执行info方法。这就是computed缓存机制。实现了之后我们看看实现效果这里conputed的对象set配置没有实现大家可以自己看看源码watch实现先在script标签配置watch配置如下代码#root)知道了computed实现之后自定义watch实现很简单下面直接实现initWatchfunction initWatch(vm) {然后修改一下Watcher,直接看Wacher的完整代码。let wId  0最后看看效果当然很多配置没有实现比如说options.immediate 或者options.deep等配置都没有实现。篇幅太长了。自己也懒 完结撒花详细代码https://github.com/naihe138/write-vue感谢 · 转发欢迎大家留言好文章我在看❤️
http://www.ihoyoo.com/news/63936.html

相关文章:

  • 环保网站开发定制网站制作服务商
  • 孝感市门户网站管理中心直接买个域名就能自己做网站
  • 网站建设方案总结语wordpress elegant
  • 宝塔搭建网站中国建设银行郑州分行网站
  • 没营业执照怎么做网站注册公司找黄牛一般多少钱
  • 网站图片像素购物网站排版设计
  • 昭平县建设局网站简单网站开发实例教程
  • 媒体网站怎么申请鞍山微信小程序定制开发
  • 建设银行河北招聘网站境外电商是做什么的
  • 东莞高端网站设计陕西省建设网一体化平台
  • 网站 百度认证河南浪博网站开发
  • 个人网站备案转公司备案二级域名对于英文网站推广有什么影响
  • 江门模板建站源码成都网站建设scjsc888
  • 网站建设的注意事项计算机网页设计专业学什么
  • 免费外贸接单网站汕头中企动力
  • 电子商务模拟实训报告企业网站建设wordpress 实时更新
  • 网站数据库管理系统免费推广软件有哪些
  • 建设银行小微企业网站进不了网页制作平台有什么
  • 餐饮公司 网站建设乐装网
  • 自己做的一个网站怎么赚钱中企动力待遇怎么样
  • 景山网站建设网上书城网站开发环境
  • 网页制作软件dw还需要什么seo搜索引擎优化求职简历
  • 企业网站推广排名网站建设 苏州
  • 门店到什么地步可以做网站域名三天更换一次
  • seo教程网站长春网站制作的公司哪家好
  • 银川做网站建设北京专业做网站怎么样
  • 网站建设与管理工资wordpress3.8.1中文版
  • 响应式 网站建设上海注册公司费用
  • 建设快照网站广州商城型网站
  • 网站规划教学设计天津地铁建设网站