1 .拿到模板
let tmpNode= document.querySelector('#root')
2.拿到数据
let data = {
name: '一个新name',
message: '一个消息'
};
3.将数据放入模板中
一般都是使用递归,在真正的 Vue 源码中是 DOM -> 字符串模板 -> VNode -> 真正的 DOM
// template DOM元素
let rkuohao = /\{\{(.+?)\}\}/g
function complier( template ,data){
let childNodes = template.childNodes
for( let i = 0; i<childNodes.length; i++){
let type = childNodes[ i ].nodeType; // 1 元素, 3 文本节点
if(type==3){
let txt = childNodes[i].nodeValue;
txt = txt.replace(rkouhao,function( - ,g){ // replace 使用正则匹配一次 函数就会被调用一次
// 函数的 第 0 个参数 表示匹配到的内容
// 函数的 第 n 个参数 表示正则中的 第 n 组
let key=g.trim() // 写在双花括号里面的 东西(相当于key)
let value = data[key]
return value
})
// 注意: txt 现在和 DOM 元素是没有关系
childNodes[ i ].nodeValue = txt;
}else if ( type === 1 ) {
// 元素, 考虑它有没有子元素, 是否需要将其子元素进行 判断是否要插值
compiler( childNodes[ i ], data );
}
}
}
// 利用 模板生成一个 需要被渲染的 HTML 标签 ( 准 真正在页面中显示的 标签 )
let generateNode = tmpNode.cloneNode( true ); // 注意这里是 DOM 元素, 可以这么用
compiler( generateNode, data ); // 将{{}} 替换掉
4..将 渲染好的 HTML 加到页面中
root.parentNode.replaceChild( generateNode, root );
5 全部代码
<!--
* @Author: MJC
* @Date: 2020-07-13 16:24:09
* @LastEditTime: 2020-07-13 16:36:44
-->
<!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>Document</title>
</head>
<body>
<!-- 写模板 -->
<div id="root">
<div>
<p>{{name}}-{{message}}</p>
</div>
<p>{{name}}</p>
<p>{{message}}</p>
</div>
<script>
let rkuohao = /\{\{(.+?)\}\}/g;
// 步骤拆解
// 1. 拿到模板
// 2. 拿到数据 ( data )
// 3. 将数据与模板结合, 得到 的是 HTML 元素 ( DOM 元素 )
// 4. 放到页面中
// 1. 拿到模板
let tmpNode = document.querySelector( '#root' ); // 元素拿到了 模板就是他了
// 2 拿到数据 ( data )
let data = {
name: '一个新name'
, message: '一个消息'
};
// 3. 将数据放到模板中( ??? )
// 一般都是使用 递归
// 在现在这个案例中 template 是 DOM 元素,
// 在真正的 Vue 源码中是 DOM -> 字符串模板 -> VNode -> 真正的 DOM
function compiler( template, data ) {
let childNodes = template.childNodes; // 取出子元素
for ( let i = 0; i < childNodes.length; i++ ) {
let type = childNodes[ i ].nodeType; // 1 元素, 3 文本节点
if ( type === 3 ) {
// 文本节点, 可以判断里面是否有 {{}} 插值
let txt = childNodes[ i ].nodeValue; // 该属性只有文本节点才有意义
// 有没有双花括号???
txt = txt.replace( rkuohao, function ( _, g ) { // replace 使用正则匹配一次 函数就会被调用一次
// 函数的 第 0 个参数 表示匹配到的内容
// 函数的 第 n 个参数 表示正则中的 第 n 组
let key = g.trim(); // 写在双花括号里面的 东西
let value = data[ key ];
// 将 {{ xxxx }} 用这个 值替换
return value;
} );
// 注意: txt 现在和 DOM 元素是没有关系
childNodes[ i ].nodeValue = txt;
}
else if ( type === 1 ) {
// 元素, 考虑它有没有子元素, 是否需要将其子元素进行 判断是否要插值
compiler( childNodes[ i ], data );
}
}
}
// 利用 模板生成一个 需要被渲染的 HTML 标签 ( 准 真正在页面中显示的 标签 )
let generateNode = tmpNode.cloneNode( true ); // 注意这里是 DOM 元素, 可以这么用
console.log( tmpNode );
compiler( generateNode, data ); // 将 坑 替换掉
console.log( generateNode );
// 我们此时是没有生成 新的 template, 所以这里看到的 是直接在页面中就更新的数据, 因为 DOM 是引用类型
// 这样做 模板就没有了
// 4. 将 渲染好的 HTML 加到页面中
root.parentNode.replaceChild( generateNode, root );
// 上面的思路有很大的问题:
// 1. Vue 使用的 虚拟 DOM
// 2. 只考虑了 单属性 ( {{ name }} ), 而 Vue 中大量的使用层级 ( {{ child.name.firstName }} )
// 3. 代码没有整合
</script>
</body>
</html>
网友评论