实现一个简易的 MVVM 分为这么几步来

1.类 Vue:这个类接收的是一个 options。

el属性:根元素的id

data属性:双向绑定的数据。

2.Dep 类:

subNode数组:存放所依赖这个属性 的依赖,

addSub方法:添加依赖的

removeSub方法:删除,

updata方法:遍历更新它subs中的所有依赖

target静态属性:用来表示 '当前的观察者' ,依赖收集的时候可以将它添加到dep. subNode中

静态的是指向类自身,而不是指向实例对象,主要是归属不同,这是静态属性的核心

3.observe 方法:监听数据变化(参数:data,也就是 options.data)

遍历data:使用Object.defineProperty()来重写它的get和set,

使用new Dep():实例化一个dep对象,

get时:addSub 添加 '当前的观察者Dep.target' 完成依赖收集,

set时:dep.updata 通知每一个依赖它的观察者进行更新

4.compile 方法:来将 HTML 模版和数据结合起来(参数:node 节点)。

遍历它的所有子级,判断是否有firstElmentChild

有:进行递归调用compile方法,

没有:child.innderHTML用判断是否有(/{{(.)}}/)需要双向绑定的数据,

有:new Reg('\{\{\s
' + key + '\s*\}\}', 'gm')替换msg变量。

5.将 Dep.target 指向当前的这个 child,

调用this.opt.data[key]:触发这个数据的get来对当前的child进行依赖收集,

目的:下次数据变化通知child进行视图更新,

将Dep.target指为null(其实在Vue中是有一个targetStack栈用来存放target的指向的)

6.监听 document 的 DOMContentLoaded

回调函数中实例化这个Vue对象就可以了

需要注意的点:

childNodes 会获取到所有的子节点以及文本节点(包括元素标签中的空白节点)

firstElementChild 表示获取元素的第一个字元素节点,以此来区分是不是元素节点,如果是的话则调用 compile 进行递归调用,否则用正则匹配

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>MVVM</title>
</head>
<body>
<div id="app">
<h3>姓名</h3>
<p>{{name}}</p>
<h3>年龄</h3>
<p>{{age}}</p>
</div>
</body>
</html>
<script>
document.addEventListener(
"DOMContentLoaded",
function () {
let opt = { el: "#app", data: { name: "等待修改...", age: 20 } };
let vm = new Vue(opt);
setTimeout(() => {
opt.data.name = "jing";
}, 2000);
},
false
);
class Vue {
constructor(opt) {
this.opt = opt;
this.observer(opt.data);
let root = document.querySelector(opt.el);
this.compile(root);
}
observer(data) {
Object.keys(data).forEach((key) => {
let obv = new Dep();
data["_" + key] = data[key]; Object.defineProperty(data, key, {
get() {
Dep.target && obv.addSubNode(Dep.target);
return data["_" + key];
},
set(newVal) {
obv.update(newVal);
data["_" + key] = newVal;
},
});
});
}
compile(node) {
[].forEach.call(node.childNodes, (child) => {
if (!child.firstElementChild && /\{\{(.*)\}\}/.test(child.innerHTML)) {
let key = RegExp.$1.trim();
child.innerHTML = child.innerHTML.replace(
new RegExp("\\{\\{\\s*" + key + "\\s*\\}\\}", "gm"),
this.opt.data[key]
);
Dep.target = child;
this.opt.data[key];
Dep.target = null;
} else if (child.firstElementChild) this.compile(child);
});
}
} class Dep {
constructor() {
this.subNode = [];
}
addSubNode(node) {
this.subNode.push(node);
}
update(newVal) {
this.subNode.forEach((node) => {
node.innerHTML = newVal;
});
}
}
</script>

10分钟搞定简易MVVM的更多相关文章

  1. 【转】让你10分钟搞定Mac--最简单快速的虚拟安装

    文章出处:让你10分钟搞定Mac--最简单快速的虚拟安装http://bbs.itheima.com/thread-106643-1-1.html (出处: 黑马程序员训练营论坛) 首先说明一下. 第 ...

  2. OpenCV3.4.1快速集成到Android studio中,10分钟搞定

    OpenCV3.4.1快速集成到Android studio中,10分钟搞定     转载 https://blog.csdn.net/yu540135101/article/details/8259 ...

  3. 10分钟搞定让你困惑的 Jenkins 环境变量

    前言 Jenkins, DevOps 技术栈的核心之一,CI/CD 离不开编写 Pipeline 脚本,上手 Jenkins ,简单查一下文档,你就应该不会被 agent,stages,step 这类 ...

  4. Python基于VS2013 开发环境搭建 Hello World 10分钟搞定

    1.先下载Python 安装 Next ->安装完成 2.以前安装过VS2013 打开VS2013 文件->新建项目 (此时如果没有Python Application,请点击里面的安装插 ...

  5. 10分钟搞定 Java 并发队列好吗?好的

    | 好看请赞,养成习惯 你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it ...

  6. 【前端知识体系-JS相关】10分钟搞定JavaScript正则表达式高频考点

    1.正则表达式基础 1.1 创建正则表达式 1.1.1 使用一个正则表达式字面量 const regex = /^[a-zA-Z]+[0-9]*\W?_$/gi; 1.1.2 调用RegExp对象的构 ...

  7. 10分钟搞定nginx实现负载均衡

    10.1 负载均衡的概念 对用户请求的数据进行调度的作用 对用户访问的请求网站可以进行压力的分担 10.2 常见的代理方式 10.2.1 正向代理 10.2.2 反向代理 10.3 负载均衡的部署环节 ...

  8. 10分钟搞定react-router

    1.路由的安装: $ npm install -S react-router 2.引入路由文件 import {Router, Route, browserHistory} from 'react-r ...

  9. 10分钟搞定webpack打包

    入门前端这个职位近三年的时间了,但是脑子里的东西不多也不少,今天就从脑袋里把新版本的webpack打包过程拔出来给大家鲁一遍,就算帮助那些小白了,废话不多说,开始鲁起来,大家跟着我一起撸... 首先, ...

  10. JS组件系列——又一款MVVM组件:Vue(一:30分钟搞定前端增删改查)

    前言:关于Vue框架,好几个月之前就听说过,了解一项新技术之后,总是处于观望状态,一直在犹豫要不要系统学习下.正好最近有点空,就去官网了解了下,看上去还不错的一个组件,就抽空研究了下.最近园子里vue ...

随机推荐

  1. 在业务逻辑中,经常会有父组件调用子组件方法的情况,vue2.0 和 vue3.0 的使用中有些不一样,在这里总结下。

    在业务逻辑中,经常会有父组件调用子组件方法的情况,vue2.0 和 vue3.0 的使用中有些不一样,在这里总结下. vue2.0 中的使用方法 父组件: <template> <d ...

  2. MISC中的图片修改宽高问题

    在做CTF中MISC分类题目时,很常见的一个问题就是修改图片正确的宽与高 (此篇笔记中的内容以ctfshow中MISC入门分类为切入点,感兴趣的同学可以一边做一边有不会的看看,仅供参考,我是菜鸡) 曾 ...

  3. 【Spark】Day05-内核解析:组件、流程、部署、运行模式、通讯架构、任务调度(Stage、task级)、两种Shuffle机制、内存管理、核心组件

    一.内核概述 内核:核心组件的运行机制.任务调度.内存管理.运行原理 1.核心组件 (1)Driver驱动器节点:执行main方法,将程序转化为作业job,在executor中调度任务task,跟踪并 ...

  4. Selenium4+Python3系列(十一) - Page Factory设计模式

    写在前面: Page Object模式,目的是将元素定位和元素操作分层,只接触测试内容,不写基础内容,便于后续对自动化测试用例体系的维护,这是中心思想,也是核心. 那么我们继续将简洁延续,这里沿用Ja ...

  5. Spring中11个最常用的扩展点,你知道几个?

    前言 在使用spring的过程中,我们有没有发现它的扩展能力很强呢? 由于这个优势的存在,使得spring具有很强的包容性,所以很多第三方应用或者框架可以很容易的投入到spring的怀抱中.今天我们主 ...

  6. JavaScript:控制跳转:break、continue与标签

    在循环结构中,经常需要使用关键字break和continue来控制跳转: 遇到break,就会跳出循环结构,执行循环体后面的代码: 遇到continue,就会跳出本次循环,进入下一次循环: 那么,假如 ...

  7. windows装机小经验

    小白的装机之路 大学时有试过自己用硬盘装,但只知其然,不知其所以然,真出现什么问题也不知道怎么解决,作为一名码农还是好好补补知识,免得以后被人笑话. 经过自己的看各路大神文章,试验并总结以下粗浅见解. ...

  8. ESXI 7.0封装网卡驱动

    前段时间配置的All In One 主机,由于华擎H410M-ITX/AC主板的板载网卡为intel I219-V,在安装ESXI后网卡无法驱动.查询之后发现原来ESXI7.0.2的版本不含该网卡驱动 ...

  9. C#应用程序配置文件(XML序列化) - 开源研究系列文章

    上次写了一个C#线程池及管理器的博文( C#开发的线程池和管理器 - 开源研究系列文章 ),收到了不小的浏览量,在此感谢各位网友的支持.这次将另一个功能放出来单独讲解:C#应用程序的配置文件,使用的是 ...

  10. [WPF]程序随系统自启动

    代码 Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE\ ...