概述

前面两篇文章已经实现了对数据的变化的监听以及模板语法编译初始化,但是当数据变化时,视图还不能够跟随数据实时更新。本文就在之前的基础上介绍下视图响应式更新部分。

思路

统一封装更新函数

待数据发生改变时调用对应的更新函数

这里思考个问题:

在何时注册这个更新函数?

如何找到对应的更新函数?

第一步统一封装更新函数

基于上篇文章compile的部分,将数据初始化的部分统一封装起来。

compileText (n) {
    // 获取表达式
    // n.textContent = this.$vm[RegExp.$1]
    // n.textContent = this.$vm[RegExp.$1.trim()]
    this.update(n, RegExp.$1.trim(), 'text')
  }
  text (node, exp) {
    this.update(node, exp, 'text')
    // node.textContent = this.$vm[exp] || exp
  }
  html (node, exp) {
    this.update(node, exp, 'html')
    // node.innerHTML = this.$vm[exp]
  }

很容易写出update方法:

每个指令都有对应的[dir]Updater管理器,用于在公共的update函数里调用去在相应视图渲染数据。

  update (node, exp, dir) {
    // 第一步: 初始化值
    const fn = this[dir   'Updater']
    fn && fn(node, this.$vm[exp])
  }
  textUpdater (node, val) {
    node.textContent = val
  }
  htmlUpdater (node, val) {
    node.innerHTML = val
  }

第二步监听并触发视图更新

分析可知,每个模板渲染初始化的过程都需要对数据进行监听,并注册监听函数,因此在上述的update函数中添加更新逻辑。

  update (node, exp, dir) {
    // 第一步: 初始化值
    const fn = this[dir   'Updater']
    fn && fn(node, this.$vm[exp])
    // 第二步: 更新
    new Watcher(this.$vm, exp, val => {
      fn && fn(node, val)
    })
  }

创建Watcher类:

// 监听器:负责依赖更新
class Watcher {
  constructor (vm, key, updateFn) {
    this.vm = vm
    this.key = key
    this.updateFn = updateFn
  }
  update () {
    // 绑定作用域为this.vm,并且将this.vm[this.key]作为值传进去
    this.updateFn.call(this.vm, this.vm[this.key])
  }
}

此时我们已经完成了更新函数的功能,需要做的就是在数据发生改变的时候,主动调用下对应的update函数。

简单测试下:声明一个全局的watchers数组。在每次Watcher的构造函数中都往watchers中push一下,那么我们就可以再Object.defineProperty()的set方法中去遍历所有的watchers,调用update方法。

浅试一下:

const watchers = []
class Watcher {
  constructor (vm, key, updateFn) {
    this.vm = vm
    this.key = key
    this.updateFn = updateFn
    watchers.push(this)
  }
  update () {
    this.updateFn.call(this.vm, this.vm[this.key])
  }
}
function defineReactive (obj, key, val) {
  // 递归
  // val如果是个对象,就需要递归处理
  observe(val)
  const dep = new Dep()
  Object.defineProperty(obj, key, {
    get () {
      Dep.target && dep.addDep(Dep.target)
      return val
    },
    set (newVal) {
      if (newVal !== val) {
        val = newVal
        // 新值如果是对象,仍然需要递归遍历处理
        observe(newVal)
        //暴力的写法,让一个人干事指挥所有人动起来(不管你需不需要更新,全给我更新一遍)
        watchers.forEach(watch => {
           watch.update()
        })
      }
    }
  })
}

此时页面视图已经可以根据数据的变而发生相应的更新了。

引入Dep管家

只触发需要更新的函数

上述的写法过于暴力,数据量一旦稍微大点就会严重影响性能。vue内部引入了Dep这个大管家的概念来进行依赖收集,统一管理所有的watcher。只让需要干活的watcher去update。

class Dep {
  constructor () {
    this.deps = []
  }
  addDep (dep) {
    this.deps.push(dep)
  }
  notify () {
    this.deps.forEach(dep => dep.update())
  }
}

每个data中的key对应一个dep就行,所以选择在Object.defineProperty的getter函数中进行依赖收集。在watcher中触发依赖收集

class Watcher {
  constructor (vm, key, updateFn) {
    this.vm = vm
    this.key = key
    this.updateFn = updateFn
    // 触发依赖收集,使用一个静态变量target去保存对应的Watcher
    Dep.target = this
    // 主动访问vm[key],触发一下getter
    this.vm[this.key]
    Dep.target = null
  }
  update () {
    // 绑定作用域为this.vm,并且将this.vm[this.key]作为值传进去
    this.updateFn.call(this.vm, this.vm[this.key])
  }
}

收集依赖,创建Dep实例

function defineReactive (obj, key, val) {
  observe(val)
  const dep = new Dep()
  Object.defineProperty(obj, key, {
    get () {
      Dep.target && dep.addDep(Dep.target)
      return val
    },
    set (newVal) {
      if (newVal !== val) {
        val = newVal
        observe(newVal)
        dep.notify()
      }
    }
  })
}

至此,我们一个简版的Vue就实现了。这里还没有涉及到虚拟dom得概念,以后介绍。

实现下语法糖v-model

v-model虽然很像使用了双向数据绑定的 Angular 的 ng-model,但是 Vue 是单项数据流,v-model 只是语法糖而已。

// 最简形式,省略了value的显式绑定,省略了oninput的显式事件监听,是第二句代码的语法糖形式
<input v-model="sth" />
<input v-bind:value="sth" v-on:input="sth = $event.target.value" />
//第二句代码的简写形式
<input :value="sth" @input="sth = $event.target.value" />

分析一下其就是在内部实现了v-bind:value=“” 和@input。

 model (node, exp) {
   node.value = this.$vm[exp]
   node.addEventListener('input', (e) => {
     this.$vm[exp] = e.target.value
   })
 }

到此这篇关于vue视图响应式更新详细介绍的文章就介绍到这了,更多相关vue响应式更新内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

vue视图响应式更新详细介绍的更多相关文章

  1. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  2. vue自定义加载指令v-loading占位图指令v-showimg

    这篇文章主要为大家介绍了vue自定义加载指令和v-loading占位图指令v-showimg的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  3. Thinkphp5框架实现获取数据库数据到视图的方法

    这篇文章主要介绍了Thinkphp5框架实现获取数据库数据到视图的方法,涉及thinkPHP5数据库配置、读取、模型操作及视图调用相关操作技巧,需要的朋友可以参考下

  4. vue使用动画实现滚动表格效果

    这篇文章主要为大家详细介绍了vue使用动画实现滚动表格效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. 关于Vue 监控数组的问题

    这篇文章主要介绍了Vue 监控数组的示例,主要包括Vue 是如何追踪数据发生变化,Vue 如何更新数组以及为什么有些数组的数据变更不能被 Vue 监测到,对vue监控数组知识是面试比较常见的问题,感兴趣的朋友一起看看吧

  6. Vue子组件props从父组件接收数据并存入data

    这篇文章主要介绍了Vue子组件props从父组件接收数据并存入data的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  7. Vue h函数的使用详解

    本文主要介绍了Vue h函数的使用详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  8. VUE响应式原理的实现详解

    这篇文章主要为大家详细介绍了VUE响应式原理的实现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

  9. vue+Element ui实现照片墙效果

    这篇文章主要为大家详细介绍了vue+Element ui实现照片墙效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. vue+elemet实现表格手动合并行列

    这篇文章主要为大家详细介绍了vue+elemet实现表格手动合并行列,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部