Vue 源码阅读学习(一)

Vue 源码阅读学习

tips:

学习课程地址:http://51hcit.cn/

学习资源分享:

链接:https://pan.baidu.com/s/10ikkZ4QGc3DQZDbyyU-gUg

提取码:41FE


数据驱动模型

Vue与模板

vue的执行流程

​ 1.获得模板,模板里面有“坑”

​ 2.利用 vue 构造函数中所提供的数据来填坑,得到就可以在页面中显示“标签”

​ 3.将标签替换页面中原有“坑”的标签

vue 利用提供的数据和页面中模板生成了一个新的Html标签(node元素)替换到了页面中放置模板的位置

<!-- 模板 -->
<div id="root">
    <p>{{msg}}</p>
    <!-- 浏览器 -->
    <p>Hello</p>
</div>


<script>
    //相当于 document.getElementById("root")
    console.log(root);
    let vm = new Vue({
        el:'#root',
        data:{
            msg:'Hello'
        }
    });
    console.log(root);
</script>

控制台输出:

在这里插入图片描述

第11行console.log(root)输出元素无高亮

第18行console.log(root)输出元素有高亮


本节目标:实现?

<!-- 模板 -->
<div id="root">
    <p>{{msg}}</p>
</div>
<script>
	//步骤拆解
    //1.获取模板 获取元素
    //2.获取数据 (data...)
    //3.将数据与模板结合,得到的是HTML元素 (DON元素)
    //4.放入页面中
</script>

步骤一:获取模板 获取元素

let tmpNode = document.querySelector("#root");

步骤二:获取数据 (data…)

let data = {
    msg:'Hello';
}

步骤三:将数据与模板结合,得到的是HTML元素 (DOM元素)

也就是将数据放入模板 如何放入?

思路:一般使用递归

tips: 大家一定要对原生的api操作要熟悉,不然很难看懂

//template 模板
function complier(template,data){
    //取出子元素
    let childNodes = template.childNodes;
    //遍历子元素
    for(let i = 0; i < childNodes.length; i++){
        //判断template是什么数据类型
        let type = childNodes[i].nodeType;
        // type = 1 为元素节点
        // type = 3 为文本节点...
        if(type === 3){
            //文本节点 判断里面是否有 {{}} 插值
            let txt = childNodes[i].nodeValue; 
            //该属性只有文本节点 才有意义 获取节点值
            
            //判断是否有{{}} 使用正则表达式
            //todo 正则表达式匹配...
        }
    }
}

tips:这一部分内容很重要,需要对正则表达式很熟悉!

let r = /\{\{(.+?)\}\}/g;

//todo 正则表达式匹配...
txt = txt.replace(r, function (_, g) {
    //replace 使用正则匹配一次 函数就会调用一次
    //函数的第 0 个 参数 表示匹配的内容
    //函数的第 n 个 参数 表示正则中第n组
    let key = g.trim();//{{}}里面的的内容
	let value = data[key];
	//将 {{xxxx}} 用这个值替换
	return value;
});

注意: txt 现在与 DOM 元素是没有关系的

type 为 1 的情况

//template 模板
function complier(template,data){
    //取出子元素
    let childNodes = template.childNodes;
    //遍历子元素
    for(let i = 0; i < childNodes.length; i++){
        //判断template是什么数据类型
        let type = childNodes[i].nodeType;
        // type = 1 为元素节点
        // type = 3 为文本节点...
        if(type === 3){
            //文本节点 判断里面是否有 {{}} 插值
            let txt = childNodes[i].nodeValue; 
            //该属性只有文本节点 才有意义 获取节点值
            
            //判断是否有{{}} 使用正则表达式
            //todo 正则表达式匹配...
            txt = txt.replace(r, 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); 
      }
   }
}

注意:我们此时是没有生成新的template 是直接在页面就更新的数据,因为DOM是引用类型

console.log(tmpNode);
compiler(tmpNode, data);
console.log(tmpNode);
//这样处理模板就没有用了
//解决方式:将tmpNode拷贝一份

let generateNode = tmpNode.cloneNode(true);//DOM元素
console.log(tmpNode);
compiler(generateNode, data);
console.log(generateNode);

控制台输出:

在这里插入图片描述


步骤四:更新后的模板放入页面

root.parentNode.replaceChild(generateNode, root);

大功告成!

页面以及控制台输出:

在这里插入图片描述


存在的问题:

1.DOM 使用的是虚拟DOM

2.只考虑了单属性 {{name}} Vue 中大量的使用层级

{{child.name.firstName}}

3.代码没有整合, 而 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>
</head>

<body>
    <div id="root">
        <p>{{msg}}</p>
    </div>

    <script>
        let r = /\{\{(.+?)\}\}/g;
        //步骤拆解
        //1.拿到模板 获取元素
        //2.拿到数据 (data ...)
        //3.将数据与模板结合,得到的是HTML元素 (DON元素)
        //4.放到页面中

        let tmpNode = document.querySelector('#root');//获取元素  获取模板
        let data = {
            msg: 'message'
        }

        //将数据放入模板??
        //思路:一般使用递归    
        function compiler(template, data) {
            //判断template是什么数据类型
            //现在的案例 template 是 DOM 元素
            //在真正的 Vue 源码中 DOM --> 字符串模板 --> 抽象语法树 --> VNode --> 真正的DOM
            let childNodes = template.childNodes;//取出子元素
            for (let i = 0; i < childNodes.length; i++) {
                let type = childNodes[i].nodeType;
                // type 值为 1 元素节点, 3为文本节点
                if (type === 3) {
                    //文本节点 可以判断里面是否有 {{}} 插值
                    let txt = childNodes[i].nodeValue; // 该属性只有文本节点 才有意义
                    //判断是否有双花括号
                    txt = txt.replace(r, 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);
                }
            }
        }
        let generateNode = tmpNode.cloneNode(true);//DOM元素
        console.log(tmpNode);
        compiler(generateNode, data);
        console.log(generateNode);
        //我们此时是没有生成新的template 所以这里看到的是直接在页面总就更新的数据,因为DOM是引用类型
        //这样处理模板就没有了
        //解决方式:将tmpNode拷贝一份


        //第四步 放入页面中
        root.parentNode.replaceChild(generateNode, root);

        //有很大的问题
        //1. DOM 使用的是虚拟DOM
        //2. 只考虑了单属性 {{name}} 而 Vue 中大量的使用层级
        // {{child.name.firstName}}
        //3. 代码没有整合 Vue中使用的是构造函数
    </script>
</body>

</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值