手撕Vue-编译指令数据
经过上一篇的分析,完成了查找指令和模板的功能,接下来就是编译指令的数据了。
所以本章节主要处理的方法则是 buildElement 方法,我们先分析一下我们所拿到的数据在进行编码,这样会更加清晰一些。
我将 name, value 打印出来,分别对应的值是 name: v-model, value: name,在今后我们的命令中可不止只有 v-model,还有 v-text、v-html、v-on 等等,所以我们需要对这些指令进行分类,然后再进行编译。
所以我这里特意定义了一个工具类叫 CompilerUtil,用来处理指令的分类,代码如下:
let CompilerUtil = {
/**
* 处理 v-model 指令
* @param node 当前元素
* @param value 指令的值
* @param vm Nue 的实例对象
*/
model: function (node, value, vm) {
},
html: function (node, value, vm) {
},
text: function (node, value, vm) {
}
}
然后我们在 buildElement 方法中调用这个方法,代码如下:
// 解构 name
let [, directive] = name.split('-');
// v-model -> [v, model]
// 2.根据指令名称, 调用不同的处理函数
CompilerUtil[directive](node, value, this.vm);
这样我们就可以根据指令的名称,调用不同的处理函数了。
接下来我们就来处理 v-model 指令,代码如下:
/**
* 处理 model 指令
* @param node 当前元素
* @param value 指令的值
* @param vm Nue 的实例对象
*/
model: function (node, value, vm) {
node.value = vm.$data[value];
},
这样我们就可以将数据渲染到页面上了,打开浏览器,可以看到效果如下:

v-model 指令已经可以正常使用了,但是还有问题,就是我们的数据结构目前是比较简单的,那么如果我们的数据是一个对象呢,例如:

time: {
h: 10,
m: 10,
s: 10
}
在用 input 绑定 v-model 进行渲染发现,只有第一个 input 能够正常渲染,其他的 input 都是 undefined,这是为什么呢?
<input type="text" v-model="time.h">
<input type="text" v-model="time.m">
<input type="text" v-model="time.s">
那么这里就要去看一下我们 model 方法的实现了,如果是 time.h,value 等于的值为 time.h, 然后我们在执行 vm.$data[value] 就变为了 vm.$data[time.h], 正常的获取这种数据结构的方式应该是先 vm.$data[time] 拿到 time 对象,然后再 time[h] 拿到 h 的值,所以我们需要对这种数据结构进行处理,为了已维护,我这里单独抽离了一个方法出来进行处理获取 value,方法名字叫做 getValue,代码如下:
getValue(vm, value) {
// time.h --> [time, h]
return value.split('.').reduce((data, currentKey) => {
// 第一次执行: data=$data, currentKey=time
// 第二次执行: data=time, currentKey=h
return data[currentKey];
}, vm.$data);
},
reduce 方法被用于迭代这个字符串数组。它接受一个回调函数,这个回调函数在每次迭代中被调用。在这个回调函数中,data 是上一次迭代的结果,而 currentKey 是当前迭代的数组元素(键路径中的一个部分)在每次迭代中,回调函数通过 data[currentKey] 的方式访问嵌套对象的属性,然后将这个属性的值作为下一次迭代的 data, 最终,reduce 方法将遍历整个键路径,直到达到最深层的属性,然后返回该属性的值。这样我们就可以正常的获取到数据了,最后在改造一下之前 model 方法获取值的地方,调用下刚刚编写的 getValue 方法即可:
model: function (node, value, vm) {
node.value = this.getValue(vm, value);
},
再次打开浏览器,可以看到效果如下:

这个搞定之后,我们紧接着把 v-html 和 v-text 也搞定,代码基本上都是一样的,只是渲染的方式不一样,代码如下:
/**
* 处理 html 指令
* @param node 当前元素
* @param value 指令的值
* @param vm Nue 的实例对象
*/
html: function (node, value, vm) {
node.innerHTML = this.getValue(vm, value);
},
/**
* 处理 text 指令
* @param node 当前元素
* @param value 指令的值
* @param vm Nue 的实例对象
*/
text: function (node, value, vm) {
node.innerText = this.getValue(vm, value);
}
编写测试代码:

html: `<div>我是div</div>`,
text: `<div>我是div</div>`
编写HTML代码:
<div v-html="html">abc</div>
<div v-text="text">123</div>
打开浏览器,可以看到效果如下:

手撕Vue-编译指令数据的更多相关文章
- Vue自定义指令 数据传递
在项目开发过程中,难免会遇到各种功能需要使用Vue自定义指令--directive 去实现 .关于directive的使用方式这里就不做过多的介绍了,Vue官方文档中说的还是听明白的.今天讲讲在使用V ...
- 手写vue双向绑定数据
来一张原理图: 实现思路: (1)绑定data 种的数据,为每个数据添加指令.通过Object,defineProperty() 来通知属性是否更改 (2) 找到每个DOM节点的指令.绑定事件.并绑定 ...
- 编译原理--05 用C++手撕PL/0
前言 目录 01 文法和语言.词法分析复习 02 自顶向下.自底向上的LR分析复习 03 语法制导翻译和中间代码生成复习 04 符号表.运行时存储组织和代码优化复习 05 用C++手撕PL/0 在之前 ...
- MySQL通过bin log日志恢复数据|手撕MySQL|对线面试官
关注微信公众号[程序员白泽],进入白泽的知识分享星球 前言 作为<手撕MySQL>系列的第二篇文章,今天介绍一下MySQL的二进制日志(bin log),注意不要和MySQL的InnoDB ...
- 剖析手写Vue,你也可以手写一个MVVM框架
剖析手写Vue,你也可以手写一个MVVM框架# 邮箱:563995050@qq.com github: https://github.com/xiaoqiuxiong 作者:肖秋雄(eddy) 温馨提 ...
- 用C/C++手撕CPlus语言的集成开发环境(1)—— 语言规范 + 词法分析器
序言 之所以叫做CPlus语言,是因为原本是想起名为CMinus的,结果发现GitHub和Gitee上一堆的CMinus的编译器(想必都是开过编译原理课程并且写了个玩具级的语言编译器的大佬们吧).但是 ...
- 手写 Vue 系列 之 Vue1.x
前言 前面我们用 12 篇文章详细讲解了 Vue2 的框架源码.接下来我们就开始手写 Vue 系列,写一个自己的 Vue 框架,用最简单的代码实现 Vue 的核心功能,进一步理解 Vue 核心原理. ...
- Vue之九数据劫持实现MVVM的数据双向绑定
vue是通过数据劫持的方式来做数据绑定的,其中最核心的方法便是通过Object.defineProperty()来实现对属性的劫持,达到监听数据变动的目的. 如果不熟悉defineProperty,猛 ...
- vue的指令
我之前学了学angular 发现angular和vue的指令有点类似 先说一下 new Vue({ el: "#box", // element(元素) 当前作 ...
- 第3章-Vue.js 指令扩展 和 todoList练习
一.学习目标 了解Vue.js指令的实现原理 理解v-model指令的高级用法 能够使用Vue.js 指令完成 todoList 练习(重点+难点) 二.todoList练习效果展示 2.1.效果图展 ...
随机推荐
- Linux下AWK、SED、GREP、FIND命令详解
AWK AWK是一个优良的文本处理工具,Linux和Unix环境中现有的功能最强大的数据处理引擎之一. 语法 awk [选项参数] 'script' var=value file(s) 或 awk [ ...
- 离线安装mysql报错解决方法:/usr/sbin/mysqld: error while loading shared libraries: libaio.so.1: cannot open sha --九五小庞
Linux:centos 7.6 64位 mysql:5.6使用离线方式安装:rpm -ivh --nodeps mysql* ,执行 systemctl start mysqld.service发现 ...
- [ESP] 使用Ayla API Reference配网和连Ayla云
示例用的文档及链接 US Dev Dashboard(查看oem-id和oem-key) https://dashboard-dev.aylanetworks.com/ Ayla API Refere ...
- Atcoder ABC244E - King Bombee 题解
原题: Atcoder ABC244E - King Bombee 题意 给你一张图,从 \(S\) 到 \(T\),经过 \(k\) 条边, 经过 \(X\) 号点偶数次的方案数. 做法 设 \(f ...
- Ubuntu18.04 软件源更新:图形界面
通过图形UI界面更新Ubuntu的软件源,手动修改虽然简单,但是要自己去找源,选一个系统配置好的更简单.但是新版的好像没有该功能,找到个奇葩的路径: 将Ubuntu16.04升级为Ubuntu18.0 ...
- Verilog实现奇分频电路
在FPGA中,计数器电路用途很广,一般计数器电路都可作为分频电路.实现占空比为50的偶分频电路很好实现.但实现占空比为50的奇分频电路有点难度.下面给出一个简单例子,记录学习奇分频电路的过程. 实现占 ...
- 安装.NET Framework4.5以上版本受阻怎么办?
安装和卸载 .NET Framework 受阻疑难解答 - .NET Framework | Microsoft Learn Windows RT 8.1.Windows 8.1 和 Windows ...
- 三个编程思想:面向对象编程、面向接口编程、面向过程编程【概念解析系列_1】【C# 基础】
〇.前言 对于 .Net 中的编程思想还是十分重要的,也是编码出高效的程序的基础! 在使用之前了解其本质,那么用起来就游刃有余.下面来简单对比下三个编程思想,看下它们都是什么,它们之间又有什么关系. ...
- 显示Label标签
1 from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QVBoxLayout 2 from PyQt5.QtCore import ...
- Mysql 统计标签出现次数(一行变多行)
需求背景 需求 一张数据表 其中有sid字段,代表tag,每行数据可能有多个tag字段 统计全量数据中所有tag出现的次数(按tag分组,分别有多少数据) source table demo id s ...