Vue笨蛋学原理:数据(data)是如何出现在页面上的?

本篇只是为了让大家看懂原理,写出来的代码并不是Vue源码

<div id="app">
	<h1> {
    
    {
    
     name }} </h1>
	<p> {
    
    {
    
     mes }} </p>
</div>
console.log(app) // 打印出来看一下

new Vue({
    
    
	el:'#app',
	data:{
    
    
		name:'刘亦菲',
		mes:'我爱你'
	}
})
console.log(app) // 在这里打印出来看一下

在这里插入图片描述

  • 可以看出来,虽然两个都是app,但是在两个不同的div里出现的内容是不同的,而且后者是渲染在页面上的,鼠标放上去,页面有高亮反应
  • 那么,Vue是怎么把实例中的data里的name和mes渲染到页面上的呢

四个步骤

  • 找到标签
  • 拿到数据
  • 找到双大括号,进行替换
  • 渲染上去

找到标签

重新创建一个新的页面,把引入的Vue文件删除

let tempNode = document.querySelector('#app')

拿到数据

let data = {
    
    
	name:'刘亦菲',
	mes:'我爱你'
}

找到双大括号,将数据与模板结合

  • 先找到模板的所有子元素
  • 一般都是使用递归
  • 在真正的Vue源码中是 DOM–>字符串模板–>VNode–>真正的DOM
function compiler(template,data) {
    
    
  let chileNodes = template.childeNode  // 拿到所有子节点
}
  • 我们知道,DOM节点对应不同的数值,代表着不同的节点
  • 我们来遍历所有的子节点,当这个节点是元素节点的时候,我们就需要进行递归,因为他可能是个嵌套标签
  • 考虑它有没有子元素,是否需要将其子元素进行判断是否要插值
function compiler(template,data) {
    
    
  let chileNodes = template.childNodes
  for(let i = 0; i < childNodes.length; i++) {
    
    
    let type = childNodes[i].nodeType
    if(type === 3){
    
     // 文本节点
    
    } else if(type === 1) {
    
     // 元素节点
      compiler(childNodes[i],data)
    }
  }
}
  • 当这个节点是文本节点的时候,就说明这里面可能有咱们需要的双大括号
// 使用正则来选择
let reg = /\{\{(.+?)\}\}/g;
if(type === 3){
    
    
  	let txt = childNodes[i].nodeValue // 该属性只有文本节点才有意义
	txt =	txt.replace(reg,function(_,g) {
    
    
		let key = g.trim(); // 剔除掉不必要的东西
		let value = data[key] // 把保存在data里的对应的数据赋值给选出来的值
		return value // 返回被data赋值后的新的值
	})
	childNodes[i].nodeValue = txt 
}
  • 可能对replace的用法不太熟悉,我们来看一下

在这里插入图片描述

  • 所匹配到的东西是函数的第一个参数
  • 函数的返回值用来替换被匹配到的东西
  • 函数的第个参数以及以后的参数是正则表达式里的对应的第几组
    在这里插入图片描述
    在这里插入图片描述

把数据渲染到页面上

  • 此时是没有生成新的template, 所以这里看到的是直接在页面中就更新的数据,因为DOM是引用类型

  • 这样做模板就没有了

  • 我们不会去直接改变模板,所以clone一下

let generateNode = tempNode.cloneNode(true)
console.log(tempNode)
// compiler(tempNode,data)
compiler(generateNode,data)
console.log(tempNode)

app.parentNode.replaceChild(generateNode,app)
  • 看一下打印到页面的效果

在这里插入图片描述

看一下完整的代码

<body>
	<div id="app">
		<h1> {
    
    {
    
     name }} </h1>
		<p> {
    
    {
    
     mes }} </p>
	</div>
	// js部分
	<script>
		let tempNode = document.querySelector('#app')
		
		let data = {
    
    
			name:'刘亦菲',
			mes:'我爱你'
		}
		
		let reg = /\{\{(.+?)\}\}/g;
		
		function compiler(template,data) {
    
    
			let childNodes = template.childNodes
			for(let i = 0; i < childNodes.length; i++) {
    
    
				let type = childNodes[i].nodeType
				if(type === 3) {
    
    
					let txt = childNodes[i].nodeValue
					txt =	txt.replace(reg,function(_,g) {
    
    
						let key = g.trim();
						let value = data[key]
						return value
					})
					childNodes[i].nodeValue = txt
				} else if(type === 1) {
    
    
					compiler(childNodes[i],data)
				}
			}
		}
		
		let generateNode = tempNode.cloneNode(true)
		console.log(tempNode)
		// compiler(tempNode,data)
		compiler(generateNode,data)
		console.log(tempNode)
		
		app.parentNode.replaceChild(generateNode,app)
	</script>
</body>

猜你喜欢

转载自blog.csdn.net/m0_47883103/article/details/108635271