手撕Vue-查找指令和模板
接着上一篇文章,我们已经实现了提取元素到内存的过程,接下来我们要实现的是查找指令和模板。
大致的思路是这样的:
- 遍历所有的节点
- 需要判断当前遍历到的节点是一个元素还是一个文本
- 如果是一个元素, 我们需要判断有没有v-model属性
- 如果是一个文本, 我们需要判断有没有{{}}的内容
那么随着思路的展开,接下来我们就来实现这个功能。
首先我们编写一个 buildTemplate 方法,主要功能是利用指定的数据编译内存中的元素:
buildTemplate(fragment) {
let nodeList = [...fragment.childNodes];
// 1.遍历所有的节点
nodeList.forEach(node => {
});
}
buildTemplate 方法定义在 Compiler 类中,我们需要在 compile 方法中调用它:

// 2.利用指定的数据编译内存中的元素
this.buildTemplate(fragment);
然后我们在 buildTemplate 方法中完善我们的代码,这里我就先直接上完整的实现代码:
buildTemplate(fragment) {
let nodeList = [...fragment.childNodes];
// 1.遍历所有的节点
nodeList.forEach(node => {
// 2.需要判断当前遍历到的节点是一个元素还是一个文本
if (this.vm.isElement(node)) {
// 是一个元素
this.buildElement(node);
} else {
// 不是一个元素
this.buildText(node);
}
});
}
buildElement(node) {
// 可以通过 node.attributes 获取到当前元素上所有的属性
let attrs = [...node.attributes];
// 1.遍历所有的属性
attrs.forEach(attr => {
let {name, value} = attr;
if (name.startsWith('v-')) {
console.log('是Vue的指令, 需要我们处理', name);
}
});
}
buildText(node) {
// 可以通过 node.textContent 获取到当前文本节点的内容
let content = node.textContent;
// 编写一个正则表达式, 用来匹配 {{}}
// 如下正则表达式的含义是: 匹配 {{}} 中间的内容
// /: 正则表达式通常以斜杠 / 开始和结束,表示正则表达式的开始和结束。
// \{ 和 \}: 这些是转义字符,用于匹配实际的花括号 { 和 }。花括号在正则表达式中具有特殊意义,因此需要使用反斜杠进行转义。
// \{\{ 和 \}\}: 这是正则表达式的起始和结束部分,用于匹配双花括号 {{ 和 }}。
// .+?: 这部分用于匹配双花括号内的任意字符,. 表示匹配任意字符,+ 表示匹配一个或多个前面的字符,? 表示非贪婪匹配,即尽可能匹配最短的内容。这样确保匹配到最近的结束双花括号 }}。
// /g: g 是正则表达式的标志,表示全局匹配,即匹配字符串中的所有符合条件的部分。
// /i: i 也是正则表达式的标志,表示不区分大小写匹配,这意味着 {{...}} 和 {{...}} 都会被匹配到。
// 因此,这个正则表达式可以用于在字符串中找到并提取所有的 {{...}} 结构,不区分大小写,不贪婪匹配,且匹配所有出现的情况。
let reg = /\{\{.+?\}\}/gi;
if (reg.test(content)) {
console.log('是一个文本节点, 需要我们处理', content);
}
}
好了,我们来看一下效果,我们在浏览器中打开,然后打开控制台,可以看到如下的效果:

发现,只有 v-model 指令被处理, {{}} 没有被处理,如下图我框出了 <p>:

也就是说我们循环节点的时候,只循环了一层,没有循环到 <p> 标签中的文本节点,所以我们需要修改一下 buildTemplate 方法, 让它支持递归,处理子元素(处理后代):

// 处理子元素(处理后代)
this.buildTemplate(node);
改造后,我们再来看一下效果,可以看到 {{}} 也被处理了:

好了,到这里我们就实现了查找指令和模板的功能,下一篇我们来继续完善一下我们的不完整的代码,一步一步来慢慢撕。
手撕Vue-查找指令和模板的更多相关文章
- Vue自定义指令使用场景
当你第一次接触vue的时候,一定会使用到其中的几个指令,比如:v-if.v-for.v-bind...这些都是vue为我们写好的,用起来相当的爽.如果有些场景不满足,需要我们自己去自定义,那要怎么办呢 ...
- 编译原理--05 用C++手撕PL/0
前言 目录 01 文法和语言.词法分析复习 02 自顶向下.自底向上的LR分析复习 03 语法制导翻译和中间代码生成复习 04 符号表.运行时存储组织和代码优化复习 05 用C++手撕PL/0 在之前 ...
- 剖析手写Vue,你也可以手写一个MVVM框架
剖析手写Vue,你也可以手写一个MVVM框架# 邮箱:563995050@qq.com github: https://github.com/xiaoqiuxiong 作者:肖秋雄(eddy) 温馨提 ...
- vue的指令
我之前学了学angular 发现angular和vue的指令有点类似 先说一下 new Vue({ el: "#box", // element(元素) 当前作 ...
- vue自定义指令用法总结及案例
1.vue中的指令有哪些?
- 第3章-Vue.js 指令扩展 和 todoList练习
一.学习目标 了解Vue.js指令的实现原理 理解v-model指令的高级用法 能够使用Vue.js 指令完成 todoList 练习(重点+难点) 二.todoList练习效果展示 2.1.效果图展 ...
- vue自定义指令clickoutside使用以及扩展用法
vue自定义指令clickoutside使用以及扩展用法 产品使用vue+element作为前端框架.在功能开发过程中,难免遇到使用element的组件没办法满足特殊的业务需要,需要对其进行定制,例如 ...
- vue自定义指令clickoutside扩展--多个元素的并集作为inside
都是个人理解,如果发现错误,恳请大家批评指正,谢谢.还有我说的会比较啰嗦,因为是以自身菜鸡水平的视角来记录学习理解的过程,见谅. 1.前言 产品使用vue+element作为前端框架.在功能开发过程中 ...
- 每个人都能实现的vue自定义指令
前文 先来bb一堆废话哈哈.. 用vue做项目也有一年多了.除了用别人的插件之外.自己也没尝试去封装指令插件之类的东西来用. 刚好最近在项目中遇到一个问题.(快速点击按钮多次触发多次绑定的方法),于是 ...
- Vue的指令以及组件化开发
一. 自定义指令 如何: 1. 创建指令 Vue.directive("指令名",{ inserted(elem){//指令所在的元素被加载到DOM树上后自动执行指令 //elem ...
随机推荐
- 【SpringCloud】 Eureka
Eureka 父工程 核心依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns=& ...
- ISP-AF相关-聚焦区域选择-清晰度评价
1.镜头相关 镜头类型 变焦类型: 定焦.手动变焦.自动变焦 光圈: 固定光圈.手动光圈.自动光圈 视场角: 鱼眼镜头.超广角镜头.广角镜头.标准镜头.长焦镜头.超长焦镜头(由大至小) 光圈: 超星光 ...
- 通过Jmeter压测存储过程
通过Jmeter压测存储过程 一.存储过程准备: 1.建立一个空表: CREATE TABLE test_data ( id NUMBER, name VARCHAR2(50), age NUMBER ...
- [Spring+SpringMVC+Mybatis]框架学习笔记:前言_目录
下一章:[Spring+SpringMVC+Mybatis]框架学习笔记(一):SpringIOC概述 前言 本笔记用于记录本人(Steven)的SSM框架学习历程,仅用作学习.交流,不用于商业用途, ...
- mysql基础_约束
介绍 约束对应的英语单词:constraint,在创建表的时候,我们可以给表中的字段加上一些约束,来保证这个表中数据的完整性.有效性. 约束的作用就是为了保证:表中的数据有效. 类型 非空约束:not ...
- 国产化之x64平台安装银河麒麟操作系统
背景 某个项目需要实现基础软件全部国产化,其中操作系统指定银河麒麟v4,CPU使用飞腾处理器.飞腾处理器是ARMv8架构的,在之前的文章中介绍了使用QEMU模拟ARMv8架构安装银河麒麟操作系统的方式 ...
- 反汇编分析C语言
环境 VC6.0环境 空函数反汇编 #include "stdafx.h" void function(){ } int main(int argc, char* argv[]) ...
- 你一定要知道的iterator和generator
generator是一种特殊的iterator,generator可以替代iterator实现,使代码更为简洁 什么是iterator iterator叫做迭代器,是用来帮助某个数据结构进行遍历的对象 ...
- 如何将 dubbo filter 拦截器原理运用到日志拦截器中?
业务背景 我们希望可以在使用日志拦截器时,定义属于自己的拦截器方法. 实现的方式有很多种,我们分别来看一下. 拓展阅读 java 注解结合 spring aop 实现自动输出日志 java 注解结合 ...
- 安装部署RabbitMQ
前言 RabbitMQ是一款使用Erlang语言开发,实现AMQP(高级消息队列协议)的开源消息中间件.RabbitMQ的特点: 可靠性.支持持久化,传输确认,发布确认等保证了MQ的可靠性. 灵活的分 ...