【前端控】html上的DOM元素发生相应的改变

那么,今天我们来看看,基于库,如何实现动态数据绑定?思路:因为数据所有属性的变化都会冒泡到顶层,所以我只需要在数据顶层注册一个事件。这样我们就实现了只更新数据变动对应的那一个部分DOM。这就是vue实现动态数据绑定的三大核心概念。但是没有办法,因为这个是实现动态数据绑定功能最早的了,我只能从这儿开始看起。另外,上面通过、、构建起来的动态数据绑定体系还有一个重大的缺陷,我们把它留到下一篇来专门阐述。

本系列更多文章请移步我的博客:-/blog:梁少峰个人博客或扫描下方二维码,关注我的公众号“前控”,欢迎交流讨论!PS:知乎不能直接显示gif,请点击放大图片查看,或者直接去我的原读。

【前端控】html上的DOM元素发生相应的改变

前言

在上一篇文章 #86 中,我们学习了如何监听数据的变化,并使用观察者模式和事件传递来响应变化事件。那么,今天我们来看看,基于库,如何实现动态数据绑定?

问题表示

我们可以将问题可视化为以下示例

// html<div id="app">    <p>姓名:{{user.name}}p>    <p>年龄:{{user.age}}p>div>

// jsconst app = new Bue({    el: '#app',    data: {        user: {            name: 'youngwind',            age: 24        }    }});

问题是:当 user.name 或 user.age 发生变化时,如何使 html 上的 DOM 元素发生相应的变化?

笨拙的方法

让我们看一下我最初采用的方法。

思路:因为对数据所有属性的更改都会冒泡到顶层,所以我只需要在数据的顶层注册一个事件即可。当任何属性发生变化时,我再次遍历 DOM 模板,将 {{user.name}} 转换为实际值,在内存中将它们拼接在一起,最后将原来的 DOM 结构替换为新生成的块。.

这里比较简单,我就不多说了,大家可以直接看这个版本的源码。

实现效果如下图所示。

【前端控】html上的DOM元素发生相应的改变

但是,这种方法非常粗糙,存在很多问题。

当我修改非 DOM 相关的数据时,也会触发 DOM 重新渲染!(如图,city 根本没有在 DOM 中渲染,所以修改它应该不会触发 DOM 的更新)当我修改任何与 DOM 相关的属性时,它会渲染和更新整个 DOM,而不是在哪里我改变它。.

基于以上两个缺陷,这种做法是绝对不能容忍的。那么,让我们看看如何修复它们。

操作说明

如果你想做:只更新与数据变化相关的DOM,你必须有这样一个对象来一一映射DOM节点和对应的数据。这里介绍(指令)的概念。它的构造函数和原型方法如下。

/** * 指令构造函数 * @param name {string} 值为"text", 代表是文本节点 * @param el {Element} 对应的DOM元素 * @param vm {Bue} bue实例 * @param expression {String} 指令表达式,例如 "name"*  @param attr {String} 值为'nodeValue', 代表数据值对应的书节点的值 * @constructor */function Directive(name, el, vm, expression) {    this.name = name;  // 指令的名称, 对于普通的文本节点来说,值为"text"    this.el = el;              // 指令对应的DOM元素    this.vm = vm;          // 指令所属bue实例    this.expression = expression;       // 指令表达式,例如 "name"    this.attr = 'nodeValue';            this.update();}// 这是指令的更新方法。当对应的数据发生改变了,就会执行这个方法// 可以看出来,这个方法就是用来更新nodeValue的Directive.prototype.update = function () {    this.el[this.attr] = this.vm.$data[this.expression];    console.log(`更新了DOM-${this.expression}`);};

关键实现思路:

在遍历DOM模板的过程中,当遍历文本节点:“{{name}}”时,会先匹配其中的表达式“name”,然后创建一个空的,也就是上面的this .el ,将其插入文本节点之前,最后删除文本节点。这样就实现了用生成的程序代替原来的,使每一个都与它的表达式一一对应。

可以直接去这个版本的源码

具体效果如下图所示。

【前端控】html上的DOM元素发生相应的改变

从图中我们可以看出,bue的实例app中的属性比较多,是一个数组,里面存放了遍历DOM模板时解析出来的几条指令。当数据发生变化时,会找到对应的指令,然后执行对应指令上面的方法。

这样,我们就意识到只有数据变化对应的部分DOM被更新了。

但是,这还存在其他问题。

每次数据变化时,我都需要循环遍历数组,找到对应值匹配的指令。这显然是低效的。最好使用能索引对象键值的那种。如果我想实现一个像 vue 的 $ 这样的 API 怎么办?显然不是一个人。因为 $ 只是一个回调函数,和 DOM 完全没有关系,所以不会有 el 和 attr 之类的东西。,

为了解决以上两个问题,我们引入了这两个“类”(解决键值索引,解决$)。那么,这三者之间是什么关系呢?让我们看一下下面的图片。(这是本文最重要的一张图)

【前端控】html上的DOM元素发生相应的改变

从图中我们可以看出。有一个对象,其属性是根据 DOM 模板中使用的数据逐层排列的。(由于我们在模板中只用到了 user.name 和 user.age,所以这里只有这两个属性)。此外,每个属性都有一个数组。这个数组其实就是订阅的意思,里面存储了一个系列。这些表示当属性数据发生变化时,会在里面循环,执行里面的方法。

那么,它与我们上面所取得的成就有什么关系呢?是一种包容的关系。也就是说,它是一个观察容器,可以装载。此时cb是更新DOM的功能,以便在数据变化时更新DOM;它也可以用 $ 加载。此时cb是自定义回调函数,实现数据变化时执行自定义回调函数。

以上就是 Vue 实现动态数据绑定的三个核心概念。

效果如下:

【前端控】html上的DOM元素发生相应的改变

话不多说,直接上代码。

参考6174..io//-in-vue-two..js源码学习笔记vue.js源码分析后面的MVVM竞赛

这次学习vue,就来到了这个版本的vue。不过和我学写库的时候相比,这个版本的代码量急剧增加,从原来的七八百行增加到将近五千行,显得非常吃力。但是没办法,因为这是最早实现动态数据绑定功能的,我只能从这里开始。尤其是,还有这些核心概念,一开始让人头晕目眩,不知道为什么会有这些东西。经过多日的思考和不断的思考,我慢慢想通了。

经过这段时间,我发现学习别人的源代码的一个很大的困难不是看懂作者写的什么(因为经常有评论),而是理解为什么作者一定要这样写,理解作者的设计思想, 但是评论通常不会提及这些。这只能靠大胆的想象和不断的尝试。

另外,上面通过 , , 和 , 构建的动态数据绑定系统有一个很大的缺陷,留待下一篇文章来详述。

免责声明:本文来自网络用户投稿,不代表本站观点和立场。如有侵权请发送邮件至tzanseo@163.com告知本站删除,本站不负任何责任及承诺。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

发表评论

登录后才能评论