web技术支持| 简单实现Vue第一章:模板编译
创建vue构造函数
function Vue(option) {
this.$option = option;
}
挂载方法
Vue.prototype.$mount = function(element) {
const rootNode = document.getElementById(element);
if (rootNode) {
this.$rootNode = rootNode;
} else {
throw new Error('$mount Receives an ID node');
}
if (this.$option.template) {
this.$render();
} else {
throw new Error('The lack of the template');
}
return this;
}
Vue.prototype.$render = function render() {
this.$AST = this.$templateCompilation(this.$option.template);
}
Vue.prototype.$templateCompilation = function templateCompilation(html) {
const AST = {
attrs: [],
children: []
};
function start(AST) {
let result = html.match(startReg.startTag);
AST.tagName = result[0];
cuttingHTML(result);
while (html.match(startReg.endTag).index) {
result = html.match(startReg.startAttrs);
AST.attrs.push({
key: result[0].split('=')[0],
value: result[1]
});
cuttingHTML(result);
}
cuttingHTML(html.match(startReg.endTag));
text(AST);
return AST;
}
function text(parent) {
while (html && html.match(textReg.endTag).index) {
let result = html.match(textReg.startTag);
if (result && !result.index) {
parent.children.push(start(JSON.parse(JSON.stringify(AST))));
} else {
result = html.match(textReg.text);
parent.children.push(result[0]);
cuttingHTML(result);
}
}
cuttingHTML(html.match(textReg.endTag));
}
function cuttingHTML(result) {
html = html.substr(result.index + result[0].length);
}
return start(JSON.parse(JSON.stringify(AST)));
}
创建reg.js
const startReg = {
startTag: /[\w\d]+/,
startAttrs: /[^\s=]+\s*=\s*('[^'>]*'|"[^">]*")/,
endTag: /\s*>/
};
const textReg = {
startTag: /\s*<[\w\d]+/,
text: /[^<]+/,
endTag: /\s*<\/[a-z0-9]+>/i
};
使用
<!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>
<script src="./reg.js"></script>
<script src="./vue.js"></script>
<style>
.box {
display: flex;
}
img {
width: 200px;
height: 100%;
margin-right: 20px;
}
.content {
line-height: 27px;
font-size: 14px;
}
.content span {
color: #000;
font-weight: 600;
}
</style>
</head>
<body>
<div id="app"></div>
<script>
const template = `<div class='box' style='
width: 900px;
height: 300px;
border: 1px solid green;
margin: 150px auto;
padding: 20px;
box-sizing: border-box'>
<img src='./touxiang.webp'></img>
<div class='content'>
您好,我是 <span>{{ name }}</span>,毕业于 <span>{{ university.name }}</span> 大学 <span>{{ university.professional }}</span> 专业。
今天应聘的是贵公司的xxxx岗位。在校期间,我在学校的学生会/团总支/社团/班级/寝室担任xxxx职务。
期间,我参加xxx活动。课余,我还参加了xxxx的实践活动。我的兴趣爱好是xxxx,擅长xxxx。
我对贵公司和xxxx这个岗位十分感兴趣,希望您能给我一个机会。
<br></br>
<br></br>
您好,我是 <span>{{ name }}</span>,毕业于 <span>{{ university.name }}</span> 大学 <span>{{ university.professional }}</span> 专业。
今天应聘的是贵公司的xxxx岗位。在校期间,我在学校的学生会/团总支/社团/班级/寝室担任xxxx职务。
期间,我参加xxx活动。课余,我还参加了xxxx的实践活动。我的兴趣爱好是xxxx,擅长xxxx。
我对贵公司和xxxx这个岗位十分感兴趣,希望您能给我一个机会。
</div>
</div>`;
const vn = new Vue({
template,
data() {
return {
name: 'Jack',
age: 23,
university: {
name: 'Shanghai Jiao Tong',
professional: 'Computer information'
}
}
}
}).$mount('app');
console.log(vn);
</script>
</body>
</html>
效果截图
注意:上述代码无法实现以下效果,本章代码只进行了模板编译,还没有渲染真实DOM;