持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情
前言
学习框架,仅仅会使用是不够的,想要更熟悉框架,需要对源码有一定的了解。本篇文章通过vue源码解析,实现vue的模板解析。
介绍
我们先来看看vue的模板语法
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统
<div id="app">
{{ message }}
</div>
var app = new Vue({
el: '#app',
data: {
message: 'HelloWorld!'
}
})
通过模板字符串的形式,将data中的数据,渲染到DOM节点中
接下来,我们就来实现一下模板解析!
实现
首先将vue的结构搭建好,通过引入vue.js的形式实现,模板字符串的解析
<!DOCTYPE html>
<head>
<title></title>
</head>
<body>
<div id="app">
{{message}}
</div>
<script src="vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
message: 'helloWorld'
}
})
</script>
</body>
</html>
接下来,我们通过自己写vue.js实现模板字符串解析
-
首先,我们需要了解几点:
-
this.$data:是vue中的 data
-
this.$el:是DOM结构中的根节点
-
让我们打印看看
-
分析vue结构
- vue是一个构造函数,并且接收一个参数,参数为一个对象
- 我们可以通过对象来获取对象内部的值
-
实现vue.js
-
定义一个Vue类
-
构造函数中接收一个对象options,可以通过options获取对象
vue.js
class Vue { constructor(options) { console.log(options) } }
-
获取data。通过
对象.el
节点,获取到el节点;通过对象.data
获取到data;vue.js
class Vue { constructor(options) { this.$el = document.querySelector(options.el) this.$data = options.data console.log(this.$el, this.$data); } }
-
实现模板解析。
- 定义一个模板解析方法Parser
- 在构造函数中,调用Parser,并传入this.$el
- 在Parser方法中,通过传入的父节点,可以找到所有的子节点
vue.js
class Vue { constructor(options) { this.$el = document.querySelector(options.el) this.$data = options.data this.Parser(this.$el) } Parser(node) { console.log(node.childNodes) } }
当前子节点只有一个,我们多加几个查看效果
<div id="app"> {{message}} <h1>{{message}</h1> <h2>{{message}</h2> <div>{{message}}</div> </div>
text代表文本,h1、h2、div代表标签,我们只需要将文本替换即可
-
通过循环,获取所有节点
node.childNodes.forEach(item => console.log(item))
-
通过nodeType,查看节点对应的数字类型
node.childNodes.forEach(item => console.log(item.nodeType))
可以看出,文本节点对应的是3,标签对应的是1
-
根据对应的数字类型,处理对应数据
-
元素节点。通过递归,调用Parser继续解析
-
文本节点。通过正则匹配,替换{{}}括号内的数据,并去除空格
// 文本 if (item.nodeType == 1) { this.Parser(item) } // 标签 if (item.nodeType == 3) { let reg = /\{\{(.*?)\}\}/g let text = item.textContent item.textContent = text.replace(reg, value => this.$data[value.trim()]) }
-
-
完整代码
index.html
<!DOCTYPE html>
<head>
<title></title>
</head>
<body>
<div id="app">
{{message}}
<h1>{{name}}</h1>
<h2>{{age}}</h2>
</div>
<script src="vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
message: 'helloWorld',
name: '张三',
age: '20'
},
mounted() {
console.log(this.$data, this.$el)
}
})
</script>
</body>
</html>
vue.js
class Vue {
constructor(options) {
this.$el = document.querySelector(options.el)
this.$data = options.data
this.Parser(this.$el)
}
// 解析模板函数
Parser(node) {
node.childNodes.forEach(item => {
// 文本
if (item.nodeType == 1) {
this.Parser(item)
}
// 标签
if (item.nodeType == 3) {
let reg = /\{\{(.*?)\}\}/g
let text = item.textContent
item.textContent = text.replace(reg, (match,value) => this.$data[value.trim()])
}
})
}
}
补充
正则规则
总结
通过修改DOM节点,然后进行判断是否为标签,再通过正则替换{{}}里面的内容,从而实现模板字符串替换。