资讯专栏INFORMATION COLUMN

理解数据驱动视图原理

Lyux / 353人阅读

摘要:源代码响应式原理数据观察数据递归无反应无反应无反应包括无反应讲解只所以能实现双向绑定,是利用里面的这就是为什么只支持及以上从以上代码可以看出,对象属性的删除和添加新属性,不会触发对应的方法对于初始化没有定义的属性,设置值不能触发视图层渲染在

源代码1
// 响应式原理 defineProperty
 
//数据
const data = {
  obj: {
    a: 4,
    b: 6
  },
  arr: [1, 5, 9]
}
 
// 观察数据
function observe(data) {
  Object.keys(data).forEach(function(key) {
    let value = data[key]
    if (value && typeof value === "object") observe(value) // 递归
    Object.defineProperty(data, key, {
      get() {
        console.log(`get ${key}`)
        return value
      },
      set(newVal) {
        console.log(`set ${key} = ${newVal}`)
        if (newVal && typeof newVal === "object") observe(newVal)
        value = newVal
      }
    })
  })
 
}
 
observe(data)
 
let obj = data.obj
// get obj
let arr = data.arr
// get arr
 
 
obj.a = 8
// set a = 8
obj.a
// get a
delete obj.b
// 无反应
obj.c = 9
// 无反应
obj.c
// 无反应
 
data.obj = {...obj, c: 7}
// set obj = [object Object]
obj = data.obj
// get obj
 
obj.c = 9
// set c = 9
obj.c
// get c
 
arr.push(9) // 包括pop,shift,unshift,splice,sort,reverse
// 无反应
data.arr = [...arr,9]
// set arr = 1,5,9,9,9
讲解

vue只所以能实现双向绑定,是利用es5里面的Object.defineProperty(这就是为什么vue只支持es9及以上)

从以上代码可以看出,对象属性的删除(delete obj.b)和添加新属性(obj.c = 9),不会触发对应的set方法(vue对于初始化没有定义的属性,设置值不能触发视图层渲染)

在项目开发中肯定会遇到有些属性,初始化时没有定义,通过改变其父元素的值去实现(data.obj = {...obj, c: 7}),父元素的值改变后,会触发其set方法,会对其子元素重新进行双向绑定

对于数组的处理,push,pop,shift,unshift,splice,sort,reverse都不会触发set,但我们看到的vue,这些方法是会触发视图层的变化,这是因为vue针对这些方法做了特殊的处理,原理如

const arr = [5, 9, 8]
const push = Array.prototype.push
Array.prototype.push = function () {
  const result = push.apply(this, arguments)
  console.log("做自己喜欢的事情")
  return result
}
arr.push(7)
console.log(arr)

vue代码片段

/*
 * not type checking this file because flow doesn"t play well with
 * dynamically accessing methods on Array prototype
 */
 
var arrayProto = Array.prototype;
var arrayMethods = Object.create(arrayProto);[
  "push",
  "pop",
  "shift",
  "unshift",
  "splice",
  "sort",
  "reverse"
]
.forEach(function (method) {
  // cache original method
  var original = arrayProto[method];
  def(arrayMethods, method, function mutator () {
    var args = [], len = arguments.length;
    while ( len-- ) args[ len ] = arguments[ len ];
 
    var result = original.apply(this, args);
    var ob = this.__ob__;
    var inserted;
    switch (method) {
      case "push":
      case "unshift":
        inserted = args;
        break
      case "splice":
        inserted = args.slice(2);
        break
    }
    if (inserted) { ob.observeArray(inserted); }
    // notify change
    ob.dep.notify();
    return result
  });
});
 
/*  */
源代码2
// 响应式原理 defineProperty
 
//数据
const data = {
  obj: {
    a: 4,
    b: 6
  },
  arr: [1, 5, 9]
}
function Dep() {}
Dep.target = null // 当前函数
function watcher(fn) { // 函数
  Dep.target = fn
  fn()
}
 
// 初始化
function init() {
  const a = () => {
    console.log(data.obj.a)
  }
  const mix = () => {
    const c = data.obj.a + data.obj.b
    console.log(c)
  }
  watcher(a)
  watcher(mix)
}
 
// 观察数据
function observe(data) {
  Object.keys(data).forEach(function(key) {
    let value = data[key]
    const dep = [] // 存放函数的容器
    if (value && typeof value === "object") observe(value) // 递归
    Object.defineProperty(data, key, {
      get() {
        dep.push(Dep.target)
        return value
      },
      set(newVal) {
        if (newVal && typeof newVal === "object") observe(newVal)
        value = newVal
        dep.forEach(fn => fn())
      }
    })
  })
 
}
 
observe(data)
init()
 
setTimeout(() => {
  data.obj.a = 10
}, 2000)
讲解

以上代码可以看出,当obj.a值变化的时候,会触发a函数和mix函数,具体执行步骤如下

先将属性a绑定了对应的set和get方法

初始化init()时,会调用watcher(a),此时 Dep.target等于a函数

执行a()函数时,会执行里面的console.log(data.obj.a)

data.obj.a会调用a的get方法,此时dep.push(Dep.target)就相当于dep.push(a函数),mix函数同理

当属性a的值改变时(data.obj.a = 10),会触发其set方法,dep.forEach(fn => fn())将a函数和mix函数循环执行一遍,从而实现了数据驱动视图

注意点

在驱动视图之前都要先赋值,比如源代码2的(value = newVal)和(dep.forEach(fn => fn()))不能互换位置

以上代码不是vue的源代码,但原理是一致的,帮助开发者更好的理解自己写的代码

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/107178.html

相关文章

  • vue总结系列--数据驱动和响应式

    摘要:由于是需要兼容的后台系统,该项目并不能使用到等技术,因此我在上的经验大都是使用原生的编写的,可以看见一个组件分为两部分视图部分,和数据部分。 在公司里帮项目组里开发后台系统的前端项目也有一段时间了。 vue这种数据驱动,组件化的框架和react很像,从一开始的快速上手基本的开发,到后来开始自定义组件,对element UI的组件二次封装以满足项目需求,期间也是踩了不少坑。由于将来很长一...

    AbnerMing 评论0 收藏0
  • vue的数据驱动原理及简单实现

    摘要:监听器构造函数被监听数据属性遍历监听函数属性被监听了,现在值为监听器被监听对象构造函数所有入参监听数据更新视图实现在流程介绍中,我们需要创建一个可以订阅者的订阅器,主要负责手机订阅者,属性变化的时候执行相应的订阅者,更新函数。 1、目标实现 理解双向数据绑定原理; 实现{{}}、v-model和基本事件指令v-bind(:)、v-on(@); 新增属性的双向绑定处理; PS:实例源...

    caoym 评论0 收藏0
  • 开源中国专访:Chameleon原理首发,其它跨多端统一框架都是假的?

    摘要:中国互联网络信息中心发布的中国互联网络发展状况统计报告显示,截至年月,我国网民规模达亿人,微信月活亿支付宝月活亿百度月活亿另一方面,中国手机占智能手机整体的比例超过,月活约亿。在年末正式发布了面向未来的跨端的。 开源中国专访:Chameleon原理首发,其它跨多端统一框架都是假的? 原创: 嘉宾-张楠 开源中国 以往我们说某一功能跨多端,往往是指在诸如 PC、移动等不同类型的设备之...

    GraphQuery 评论0 收藏0
  • MVVM框架理解及其原理实现

    摘要:小白一枚,一直使用的是,想要多了解一些其它的框架,正好最近越来越火热,上的数已经超过了。框架理解说起这个模型,就不得不说框架。函数表示创建一个文本节点,函数表示创建一个数组。 小白一枚,一直使用的是React,想要多了解一些其它的框架,正好最近Vue越来越火热,Github上的Star数已经超过了React。而其背后蕴含的MVVM框架思想也一直跟React的组件化开发思想并驾齐驱,在这...

    DevWiki 评论0 收藏0
  • 给研发工程师的代码质量利器 | SOFAChannel#5 直播整理

    摘要:接入分为两部分,其一是可视化编辑器,在官网上我们可以获取该编辑器的安装包,并通过的插件管理进行安装。借助可视化编辑器,在整个过程中我们可以替换大部分手工编写代码的工作,进行一站式操作。,有趣实用的分布式架构频道。本文根据 SOFAChannel#5 直播分享整理,主题:给研发工程师的代码质量利器 —— 自动化测试框架 SOFAActs。回顾视频以及 PPT 查看地址见文末。欢迎加入直播互动钉...

    ivan_qhz 评论0 收藏0

发表评论

0条评论

Lyux

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<