松鼠乐园 松鼠乐园
  • 注册
  • 登录
  • 首页
  • 快捷入口
    • Vue
    • Tensorflow
    • Springboot
    • 语言类
      • CSS
      • ES5
      • ES6
      • Go
      • Java
      • Javascript
    • 工具类
      • Git
      • 工具推荐
    • 服务器&运维
      • Centos
      • Docker
      • Linux
      • Mac
      • MySQL
      • Nginx
      • Redis
      • Windows
    • 资源类
      • 论文
      • 书籍推荐
      • 后端资源
      • 前端资源
      • html网页模板
      • 代码
    • 性能优化
    • 测试
  • 重大新闻
  • 人工智能
  • 开源项目
  • Vue2.0从零开始
  • 广场
首页 › Vue › 一个简化版Vue助你理解Vue原理

一个简化版Vue助你理解Vue原理

迦娜王
10月前Vue
246 0 0

好多人看完我的这个文章对它的理解还是只是知道了大概原理,但是对具体的Vue双向绑定的实现很模糊,因此就出了这篇文章,供大家参考希望可以得到收获,以下是主要代码逻辑,先陈述一下这一过程都需要什么:

需要有一个接收Vue实例配置项的构造函数SimpleVue,给他加两个原型方法分别是observe()和compile(),再构造出一个订阅器watcher,给他加一个更新视图方法

  • observe():用来劫持并监听数据变化的数据监听器,有变化就会通知下文中的订阅器watcher
  • compile():节点DOM解析器,用来获取和解析每一个节点及其指令,根据初始化的模板数据来创建订阅器watcher
  • watcher():订阅器watcher,用来接收属性值的相关数据的变化通知,调用自身原型方法update从而更新视图

由于Vue就是一个MVVM的框架理念,所以就要通过Object.defineProperty()方法来劫持并监听所有属性值相关的数据,看看它是否变化,如有变化则通知订阅器watcher看是否需要视图更新,这一过程就是我们的数据监听器observe的工作任务,由于数据和订阅器是一对多的关系,所以通知订阅器的时候需要把数据对应的订阅器的集合都放在一个oWatcherObj对象中,接下来需要一个节点DOM解析器compile,主要用来迭代递归获取和解析每一个节点及其指令,根据初始化的模板数据来创建订阅器watcher,实例化watcher就会接到数据变化的通知,进而实现VM更新视图

template:

<div id=”simpleVue”>

<button yf-on:click=”copy”>戳我</button>

<div>

<textarea yf-model=”name”></textarea>

<div yf-text=”name”></div>

</div>

<hr>

<button yf-on:click=”show”>显示/隐藏</button>

<div yf-if=”isShow”>

<input type=”text” yf-model=”webSite”>

<div yf-text=”webSite”></div>

</div>

</div>

SimpleVue构造:

class SimpleVue { // 简化版Vue实例的构造 用来接收实例的配置项

constructor(options) {

this.$el = document.querySelector(options.el);

this.$data = options.data;

this.$methods = options.methods;

this.oWatcherObj = {}; // 所有属性值相关的数据对应的订阅器的集合都放在该对象中

this.observe(); // 调用数据监听器对属性值相关的数据进行劫持并监听

this.compile(this.$el); // 对该DOM节点进行解析

}

observe() { // 数据监听器 用来劫持并监听属性值相关数据的变化 如有变化则通知订阅器watcher

for (let key in this.$data) {

let value = this.$data[key];

this.oWatcherObj[key] = []; // 初始化该数据的订阅器 数据和订阅器的关系是一对多

let oWatcherObj = this.oWatcherObj[key];

Object.defineProperty(this.$data, key, { // 关键方法 可以修改对象身上的默认属性值的ES5方法 下面用到的是ES中两大属性中的访问器属性,有以下四种描述符对象

configurable: false, // 该状态下的属性描述符不能被修改和删除

enumerable: false, // 该状态下的属性描述符中的属性不可被枚举

get() { // 属性值相关的数据读取函数

return value;

},

set(newVal) { // 属性值相关的数据写入函数

if (newVal !== value) {

value = newVal;

oWatcherObj.forEach((obj) => {

obj.update(); // 通知和该数据相关的所有订阅器

});

}

}

});

}

}

compile(el) { // 节点DOM解析器 用来获取和解析每一个节点及其指令 根据初始化的模板数据来创建订阅器watcher

let nodes = el.children;

for (let i = 0; i < nodes.length; i++) { // 迭代同级所有节点

let node = nodes[i];

if (node.children.length > 0) {

this.compile(node); // 递归所有子节点

}

if (node.hasAttribute(‘yf-on:click’)) { // 节点中如存在该指令则执行以下操作

let eventAttrVal = node.getAttribute(‘yf-on:click’);

node.addEventListener(‘click’, this.$methods[eventAttrVal].bind(this.$data)); // 绑定获取到的指令对应的数据所触发的方法

}

if (node.hasAttribute(‘yf-if’)) {

let ifAttrVal = node.getAttribute(‘yf-if’);

this.oWatcherObj[ifAttrVal].push(new Watcher(this, node, “”, ifAttrVal)); // 给该指令对应的数据创建订阅器放在该数据对应的订阅器数组里

}

if (node.hasAttribute(‘yf-model’)) {

let modelAttrVal = node.getAttribute(‘yf-model’);

node.addEventListener(‘input’, ((i) => { // 前方高能:此处有闭包请绕行!!! i的问题

this.oWatcherObj[modelAttrVal].push(new Watcher(this, node, “value”, modelAttrVal));

return () => {

this.$data[modelAttrVal] = nodes[i].value; // 将该指令所在节点的值扔给该指令的数据

}

})(i));

}

if (node.hasAttribute(‘yf-text’)) {

let textAttrVal = node.getAttribute(‘yf-text’);

this.oWatcherObj[textAttrVal].push(new Watcher(this, node, “innerText”, textAttrVal));

}

}

}

}

订阅器构造:

class Watcher { // 订阅器构造 用来接收属性值的相关数据的变化通知 从而更新视图

constructor(…arg) {

this.vm = arg[0];

this.el = arg[1];

this.attr = arg[2];

this.val = arg[3];

this.update(); // 初始化订阅器时更新一下视图

}

update() { // 将收到的新的数据更新在视图中从而实现真正的VM

if (this.vm.$data[this.val] === true) {

this.el.style.display = ‘block’;

} else if (this.vm.$data[this.val] === false) {

this.el.style.display = ‘none’;

} else {

this.el[this.attr] = this.vm.$data[this.val];

}

}

}

vue vue原理 简化版vue
0
Vue 学习路线图
上一篇
Vue 3.0 对 Web 开发意味着什么?
下一篇
评论 (0)

请登录以参与评论。

现在登录
聚合文章
在Gitee收获近 5k Star,更新后的Vue版RuoYi有哪些新变化?
2月前
vue3.x reactive、effect、computed、watch依赖关系及实现原理
2月前
Vue 3 新特性:在 Composition API 中使用 CSS Modules
2月前
新手必看的前端项目去中心化和模块化思想
2月前
标签
AI AI项目 css docker Drone Elaticsearch es5 es6 Geometry Go gru java Javascript jenkins lstm mysql mysql优化 mysql地理位置索引 mysql索引 mysql规范 mysql设计 mysql配置文件 mysql面试题 mysql高可用 nginx Redis redis性能 rnn SpringBoot Tensorflow tensorflow2.0 UI设计 vue vue3.0 vue原理 whistle ZooKeeper 开源项目 抓包工具 日志输出 机器学习 深度学习 神经网络 论文 面试题
相关文章
在Gitee收获近 5k Star,更新后的Vue版RuoYi有哪些新变化?
vue3.x reactive、effect、computed、watch依赖关系及实现原理
Vue 3 新特性:在 Composition API 中使用 CSS Modules
新手必看的前端项目去中心化和模块化思想
松鼠乐园

资源整合,创造价值

小伙伴
墨魇博客 无同创意
目录
重大新闻 Centos CSS Docker ES5 ES6 Go Java Javascript Linux Mac MySQL Nginx Redis Springboot Tensorflow Vue Vue2.x从零开始 Windows 书籍推荐 人工智能 前端资源 后端资源 壁纸 开源项目 测试 论文
Copyright © 2018-2021 松鼠乐园. Designed by nicetheme. 浙ICP备15039601号-4
  • 重大新闻
  • Centos
  • CSS
  • Docker
  • ES5
  • ES6
  • Go
  • Java
  • Javascript
  • Linux
  • Mac
  • MySQL
  • Nginx
  • Redis
  • Springboot
  • Tensorflow
  • Vue
  • Vue2.x从零开始
  • Windows
  • 书籍推荐
  • 人工智能
  • 前端资源
  • 后端资源
  • 壁纸
  • 开源项目
  • 测试
  • 论文
热门搜索
  • jetson nano
  • vue
  • java
  • mysql
  • 人工智能
  • 人脸识别
迦娜王
坚持才有希望
1224 文章
33 评论
231 喜欢
  • 0
  • 0
  • Top