目录
1.搭建html页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue原理及虚拟DOM</title>
</head>
<body>
<div id="app">
<p>{{msg}}</p>
<p>{{age}}</p>
<p>{{obj.firstName}}</p>
<p>{{obj.second.username}}</p>
</div>
</body>
</html>
2.创建Myvue构造函数(js部分)
<script>
// 创建Myvue构造函数
function Myvue(options) {
this._data = options.data;
this._el = options.el;
this.$el = this._templateDOM = document.querySelector(this._el);
this._parent = this._templateDOM.parentNode;
this.render()
}
Myvue.prototype.render = function () {
this.compiler()
}
Myvue.prototype.compiler = function () {
// 拷贝原来的DOM元素赋值给新元素
let realDOM = this._templateDOM.cloneNode(true);
// 调用模拟插值表达式
compiler(realDOM, this._data);
this.update(realDOM)
}
Myvue.prototype.update = function (real) {
//用新的元素替换原来的DOM元素
this._parent.replaceChild(real, document.querySelector("#app"))
}
// Myvue构造函数实例化
var vm = new Myvue({
el: "#app",
data: {
msg: "yxx",
age: 18,
obj: {
firstName: "zs",
second: {
username: "lisi"
}
}
}
})
// 模拟插值表达式:把{{ }}内的字符串替换为Myvue中data对象中的数据
function compiler(ele, data) {
//正则表达式 .+匹配{{}}所有字符 ?取消贪婪 g全局
let regulation = /\{\{(.+?)\}\}/g;
let childEle = ele.childNodes;
for (var i = 0; i < childEle.length; i++) {
let type = childEle[i].nodeType;
//节点nodeType==1 为标签元素
//节点nodeType==3 为文本元素
if (type === 3) {
let txt = childEle[i].nodeValue;
txt = txt.replace(regulation, function (_, val) {
console.log(val);
let key = val.trim();
//调用 对象嵌套函数
let value = getValueByPath(data, key)
return value;
})
childEle[i].nodeValue = txt;
} else if (type === 1) {
compiler(childEle[i], data)
}
}
}
// 解决 对象多层嵌套 得不到值的问题
/* 例如这样的对象
var obj={
a:{
b:{
c:{
d:"hello vue"
}
}
}
}
getValueByPath(obj,'a.b.c.d') 结果为 hello vue
*/
function getValueByPath(obj, str) {
let paths = str.split('.');
// 定义变量把对象的值赋给它
let res = obj;
//定义变量 让他等于删除数组中第一个元素
let prop;
// shift() 删除数组中第一个元素,返回值为删除的元素
while (prop = paths.shift()) {
//循环获取 下一层获取对象元素 的值 a.b.c.d
res = res[prop]
}
return res
}
</script>
这里为上方的函数解释:⬇⬇⬇⬇
3.模拟插值表达式函数
// 模拟插值表达式:把{{ }}内的字符串替换为Myvue中data对象中的数据
function compiler(ele, data) {
//正则表达式 .+匹配{{}}所有字符 ?取消贪婪 g全局
let regulation = /\{\{(.+?)\}\}/g;
let childEle = ele.childNodes;
for (var i = 0; i < childEle.length; i++) {
let type = childEle[i].nodeType;
//节点nodeType==1 为标签元素
//节点nodeType==3 为文本元素
if (type === 3) {
let txt = childEle[i].nodeValue;
txt = txt.replace(regulation, function (_, val) {
console.log(val);
let key = val.trim();
//调用 对象嵌套函数
let value = getValueByPath(data, key)
return value;
})
childEle[i].nodeValue = txt;
} else if (type === 1) {
compiler(childEle[i], data)
}
}
}
4. 解决对象多层嵌套得不到值的问题
/* 例如这样的对象
var obj={
a:{
b:{
c:{
d:"hello vue"
}
}
}
}
getValueByPath(obj,'a.b.c.d') 结果为 hello vue
*/
function getValueByPath(obj, str) {
let paths = str.split('.');
// 定义变量把对象的值赋给它
let res = obj;
//定义变量 让他等于删除数组中第一个元素
let prop;
// shift() 删除数组中第一个元素,返回值为删除的元素
while (prop = paths.shift()) {
//循环获取 下一层获取对象元素 的值 a.b.c.d
res = res[prop]
}
return res
}
5.运行结果
在标签中写入插值表达式
运行结果