手写一个简单的vue数据驱动原理
Vue与模板
- 编写一个模板
如何去编写一个模板,
1、直接在html标签中写标签
2、使用 template
3、在单文件中使用template - 创建一个Vue实例
- 将Vue 挂载到页面上
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../js/vue.js"></script>
</head>
<body>
<!-- 写模板 -->
<div id="root">
<p>{{ name }}</p>
<p>{{ message }}</p>
</div>
<script>
console.log(root); //没有替换之前的模板
// 第二步 创建vue实例
let app = new Vue({
el: "#app",
data: {
name: '张三',
message: "是一个男人"
}
})
// 第三步 是挂载 这种写法 在 vue js中已经帮我们实现了挂载
console.log(root);// 替换之后的模板
</script>
</body>
</html>
那么我们自己如何去实现这样一个过程呢,在当前案列中,模板其实就是一个html元素,在vue源码中模板其实是一个字符串,Vue所做的就是,DOM => 字符串模板 => 虚拟DOM => 真实DOM ,首先我们先来做一下步骤拆解
- 拿到模板DOM元素
- 获取数据
- 数据与模板结合,得到的就是DOM
- 放在页面中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>实现简单的vue数据驱动</title>
</head>
<body>
<!-- 写模板 -->
<div id="root">
<div>
<div>
<p>{{name}}{{message}}</p>
</div>
</div>
<p>{{ name }}</p>
<p>{{ message }}</p>
</div>
<script>
// 获取当前的模板
let temNode = document.getElementById("root");
// 复制一个模板出来 因为是DOM元素可以这么做
let clonetemNode = temNode.cloneNode(true);
// 定义一个数据
let data = {
name: '一个新的name',
message: '一个新的message'
};
// 如何将数据放入模板中
// 一般使用递归
let rkuohao = /\{\{(.+?)\}\}/g;
function compiler(template, data) {
// 遍历他下面的子节点
let childrenNodes = template.childNodes;
for (let i = 0; i < childrenNodes.length; i++) {
//循环 判断是否是元素节点 还是文本节点 1是元素节点 3是文本节点 元素节点的nodeValue是没有意义的 文本节点的nodeName是没有意义的
let type = childrenNodes[i].nodeType;
if (type === 3) {
// 文本节点就去判断里面有没有 {{}}
let txt = childrenNodes[i].nodeValue;// 获取文本节点里面的值
// 有没有 {{}}
txt = txt.replace(rkuohao, function (_, g) {
let key = g.trim();
let value = data[key];
return value;
})
// 注意现在txt与DOM没有关系 需要重新加回去
childrenNodes[i].nodeValue = txt;
} else if (type === 1) {
// 元素节点的话就去判断他有没有有子元素 查看子元素是否有插值语法 用到了递归
compiler(childrenNodes[i], data)
}
}
}
console.log(temNode)
compiler(clonetemNode, data)
console.log(clonetemNode)
// 复制好的模板替换原来的DOM
root.parentNode.replaceChild(clonetemNode, root)
// 存在的问题
// vue使用的是虚拟DOM
// 只考虑了单属性{{ name }},但是在Vue中使用了大量的层级 {{ xx.xx.xx}}
// 代码没有整合 ,Vue中使用了构造函数
</script>
</body>
</html>
如果有不对的地方,还请各位大佬指正。