Vue2指令原理手写
文件结构
index.js
/*
* @Author: RealRoad
* @Date: 2024-10-31 17:13:50
* @LastEditors: Do not edit
* @LastEditTime: 2024-10-31 17:15:57
* @Description:
* @FilePath: \project_10_08\vite-project\src\testVue\index.js
*/
import Vue from './Vue.js'
window.Vue=Vue
Vue.js
import Compile from './Compile.js'
import observe from './observe.js'
export default class Vue{
constructor(options){
//把参数options对象存为$options
this.$options = options ||{}
//数据
this._data=options.data || undefined;
Observe(this._data)
//数据要变为响应式的
//模板编译
new Compile(options.el,this)
}
}
Compile.js
/*
* @Author: RealRoad
* @Date: 2024-10-31 16:25:34
* @LastEditors: Do not edit
* @LastEditTime: 2024-10-31 16:28:44
* @Description:
* @FilePath: \project_10_08\vite-project\src\testVue\Compile.js
*/
export default class Compile{
constructor(el,vue){
//vue实例
this.$vue=vue;
//挂载点
this.$el=document.querySelector(el)
if(this.$el){
//调用函数,让节点变为fragment,类似与mustache中的tokens。
//实际上用的是AST,这里就是轻量级的,fragment
let $fragment= this.node2Fragment(this.$el);
//编译
this.compile($fragment);
}
}
node2Fragment(el){
var fragment=document.createDocumentFragment();
var child;
//el为第一个子元素,循环添加到fragment中
//让所有dom节点都添加到fragment中
while(child=el.firstChild){
fragment.appendChild(child);
}
return fragment
}
compile(el){
//获取所有子节点
var childNodes=el.childNodes;
var self=this
//遍历所有子节点
for(let i=0,len=childNodes.length;i<len;i++){
let node=childNodes[i];
//判断是否是元素节点
if(node.nodeType===1){
self.compileElement(node);
}else if(node.nodeType===3){
self.compileText(node);
}}
}
compileElement(node){
//获取所有属性节点
var attributes=node.attributes;
//类数组变为数组
[].slice.call(attributes).forEach(attr=>{
if(attr.name==="v-model"){
//获取属性值
var value=attr.value;
node.addEventListener("input",()=>{
this.$vue[value]=node.value
})
}else if(attr.name==="v-text"){
node.textContent=this.$vue[attr.value]
}
else if(attr.name==="v-html"){
node.innerHTML=this.$vue[attr.value]
}
else if(attr.name==="v-bind"){
node.setAttribute(attr.value,this.$vue[attr.value])
}
else if(attr.name==="v-on"){
node.addEventListener(attr.value,()=>{
})}else if(attr.name==="v-show"){
node.style.display=this.$vue[attr.value]===true?"":"none"
}else if(attr.name==="v-if"){
node.style.display=this.$vue[attr.value]===true?"":"none"}
})
}
compileText(){
}
}