手撕Vue-数据驱动界面改变下
经过上一篇的介绍,数据驱动界面改变 v-model 的双向绑定已告一段落, 剩余的就以这篇文章来完成。
首先完成我们的 v-html,v-text, 其实很简单,就是将我们之前的 v-model 创建观察者的方法,在 v-html 和 v-text 中再写一次即可,创建属于 v-html 和 v-text 的观察者。
v-html:
html: function (node, value, vm) {
new Watcher(vm, value, (newValue, oldValue) => {
node.innerHTML = newValue;
});
node.innerHTML = this.getValue(vm, value);
},
v-text:
text: function (node, value, vm) {
new Watcher(vm, value, (newValue, oldValue) => {
node.innerText = newValue;
});
node.innerText = this.getValue(vm, value);
},
测试一下 v-html,打开浏览器控制台,输入 vue.$data.html = '<p>我是测试v-html<p/>',可以看到界面上的内容已经改变了。

测试一下 v-text,打开浏览器控制台,输入 vue.$data.text = '<p>我是测试v-text<p/>',可以看到界面上的内容已经改变了。

好了到此为止,指令的数据驱动界面改变已经完成了,接下来我们来完成模板语法的数据驱动界面改变。
这个就与之前的指令的数据驱动界面改变不同了,好了先不说问题,我们先直接来看代码一步一步分析。
我看了下之前处理 content 的代码发现,获取不到对应的属性名称叫什么,因为是直接调用 this.getContent(vm, value); 获取的,所以会出现一个问题就是给 content 创建观察者对象的时候不能直接告诉他我要监听的是哪个属性,所以我就想到了一个办法。
首先将之前的代码注释掉,再然后我编写一个正则表达式,关于这个正则表达式在之前的文章中有讲到,大概意思就是匹配 {{}} 中的内容,这里就不再赘述了。
let reg = /\{\{(.+?)\}\}/gi;
继续往下看,我利用 value 调用了 replace 方法,传递了两个参数,第一个参数是刚刚编写的正则表达式,第二个参数是一个函数,这个函数的作用就是将匹配到的内容替换成对应的值,我先将其返回值打印出来,看看是什么,我们的代码就可以写成这样。
content: function (node, value, vm) {
// console.log(value); // {{ name }} -> name -> $data[name]
// node.textContent = this.getContent(vm, value);
let reg = /\{\{(.+?)\}\}/gi;
value.replace(reg, (...args) => {
console.log(args[1].trim());
});
}

是的,我们的确获取到了对应的属性名称,接下来我们就可以利用这个属性名称来创建观察者对象了,我们的代码就可以写成这样。
content: function (node, value, vm) {
// console.log(value); // {{ name }} -> name -> $data[name]
// node.textContent = this.getContent(vm, value);
let reg = /\{\{(.+?)\}\}/gi;
node.textContent = value.replace(reg, (...args) => {
const attr = args[1].trim();
new Watcher(vm, attr, (newValue, oldValue) => {
node.textContent = this.getContent(vm, value);
});
return this.getValue(vm, args[1]);
});
}
好了,我们来测试一下,打开浏览器控制台,输入 vue.$data.name = '我是测试 {{ name }}',可以看到界面上的内容已经改变了。

一切看起来都很完美,最终版代码其实是我没有将坑点说出来,现在我们来看看这个坑点是什么,再看之前,我来讲述一下为什么是又调用了 this.getContent 方法而不是直接将 newValue 赋值给 node.textContent。
假如我们的数据结构是这样的 {{ name }} - {{ age }} 如果是通过直接将 newValue 赋值给 node.textContent 的话,这个时候呢,我假设 name 的值是 BNTang, age 的值是 33,那么界面上第一次加载的内容会是 BNTang - 33,但是如果我将 name 的值改成了 xhh,那么界面上的内容就会变成 xhh,这个时候 age 的值就丢掉了,如下图是我的测试结果。

原因就是直接替换掉了,所以在动态更改 name 属性或者 age 属性其中一个的情况下,还需要将 {{ name }} - {{ age }} 这样的内容替换成 BNTang - 33,这样的话,我们就需要调用 this.getContent 方法,这个方法就会利用正则挨个匹配 {{}} 中的内容,然后再将其替换成对应的值,这样就不会出现上面的问题了。
?> 最后总结一下 content 函数的 value.replace 在外层是为了拿到属性名称,内层是为了保证数据完整性。
手撕Vue-数据驱动界面改变下的更多相关文章
- 手撕公司SSO登陆原理
Single Sign-on SSO是老生常谈的话题了,但部分同学对SSO可能掌握的也是云里雾里,一知半解.本次手撕公司的SSO登陆原理,试图以一种简单,流畅的形式为你提供 有用的SSO登陆原理. 按 ...
- Netty实现高性能IOT服务器(Groza)之手撕MQTT协议篇上
前言 诞生及优势 MQTT由Andy Stanford-Clark(IBM)和Arlen Nipper(Eurotech,现为Cirrus Link)于1999年开发,用于监测穿越沙漠的石油管道.目标 ...
- 模拟源码深入理解Vue数据驱动原理(1)
Vue有一核心就是数据驱动(Data Driven),允许我们采用简洁的模板语法来声明式的将数据渲染进DOM,且数据与DOM是绑定在一起的,这样当我们改变Vue实例的数据时,对应的DOM元素也就会改变 ...
- NN入门,手把手教你用Numpy手撕NN(一)
前言 这是一篇包含极少数学推导的NN入门文章 大概从今年4月份起就想着学一学NN,但是无奈平时时间不多,而且空闲时间都拿去做比赛或是看动漫去了,所以一拖再拖,直到这8月份才正式开始NN的学习. 这篇文 ...
- 理解vue数据驱动
vue是双向数据绑定的框架,数据驱动是他的灵魂,他的实现原理众所周知是Object.defineProperty方法实现的get.set重写,但是这样说太牵强外门了.本文将宏观介绍他的实现 使用vue ...
- 编译原理--05 用C++手撕PL/0
前言 目录 01 文法和语言.词法分析复习 02 自顶向下.自底向上的LR分析复习 03 语法制导翻译和中间代码生成复习 04 符号表.运行时存储组织和代码优化复习 05 用C++手撕PL/0 在之前 ...
- 优雅手撕bind函数(面试官常问)
优雅手撕bind函数 前言: 为什么面试官总爱让实现一个bind函数? 他想从bind中知道些什么? 一个小小的bind里面内有玄机? 今天来刨析一下实现一个bind要懂多少相关知识点,也方便我们将零 ...
- (面试题)面试官为啥总是让我们手撕call、apply、bind?
引言 上一篇关于<面试官为啥总是喜欢问前端路由实现方式>的文章发布后,发现还是挺受欢迎的.这就给我造成了一定的困惑 之前花了很长时间,实现了一个自认为创意还不错的关于前端如何利用node+ ...
- NN入门,手把手教你用Numpy手撕NN(2)
这是一篇包含较少数学推导的NN入门文章 上篇文章中简单介绍了如何手撕一个NN,但其中仍有可以改进的地方,将在这篇文章中进行完善. 误差反向传播 之前的NN计算梯度是利用数值微分法,虽容易实现,但是计算 ...
- NN入门,手把手教你用Numpy手撕NN(三)
NN入门,手把手教你用Numpy手撕NN(3) 这是一篇包含极少数学的CNN入门文章 上篇文章中简单介绍了NN的反向传播,并利用反向传播实现了一个简单的NN,在这篇文章中将介绍一下CNN. CNN C ...
随机推荐
- JVM GC配置指南
本文旨在简明扼要说明各回收器调优参数,如有疏漏欢迎指正. 1.JDK版本 以下所有优化全部基于JDK8版本,强烈建议低版本升级到JDK8,并尽可能使用update_191以后版本. 2.如何选择垃圾回 ...
- 2022-02-08 IValueConverter和StringFormat
主页 后台 stringFormat
- 8 最全的零基础Flask教程
最全的零基础Flask教程 1 Flask介绍 1.1 为什么要使用Flask Django和Flask是Python使用最多的两个框架 1.2 Flask是什么 Flask诞生于2010年,是Arm ...
- [nginx]lua控制请求头
前言 nginx原生提供expires.add_header两个指令控制请求头,在Lua API中也有类似的指令. 添加请求头 指令:ngx.req.set_header 语法:ngx.req.set ...
- [golang]使用gocron编写定时任务
前言 linux自带的crontab默认情况下只能精确到分钟,没法执行秒级任务.当然,也不是不行,比如: * * * * * for i in $(seq 1 11);do echo hello &g ...
- Redis 持久化及集群架构
1 Redis 持久化 1.1 持久化的概念和原因 Redis 持久化是指将 Redis 服务器中的数据保存到磁盘上,以便在服务器重启后可以重新加载数据.持久化是为了解决 Redis 内存数据库的数据 ...
- Three.js中实现碰撞检测
1. 引言 碰撞检测是三维场景中常见的需求,Three.js是常用的前端三维JavaScript库,本文就如何在Three.js中进行碰撞检测进行记述 主要使用到的方法有: 射线法Raycaster ...
- 7、Spring之基于注解管理bean
本质上:所有一切的操作都是Java代码来完成的,XML和注解只是告诉框架中的Java代码如何执行. 7.1.环境搭建 创建名为spring_ioc_annotation的新module,过程参考3.1 ...
- 0×03 Vulnhub 靶机渗透总结之 KIOPTRIX: LEVEL 1.2 (#3) SQL注入+sudo提权
0×03 Vulnhub 靶机渗透总结之 KIOPTRIX: LEVEL 1.2 (#3) 系列专栏:Vulnhub靶机渗透系列 欢迎大佬:点赞️收藏关注 首发时间: 2023年8月22日 如有错误 ...
- AI绘画创意文字全流程揭秘,你的终极文字艺术实操宝典
本教程收集于:AIGC从入门到精通教程汇总 AIGC技术不断更新迭代,国内出现了越来越多的新玩法,比如最近大家都在热议的AI绘画创意文字. 过去的一周,我把这些新玩法都研究了一遍,并总结了一套完整的制 ...