模擬Vue雙向資料繫結
阿新 • • 發佈:2018-12-11
事件物件
function EventEmit(){
// {
// "message":['事件1','事件2']
// }
this.callbacks={}
}
EventEmit.prototype.on=function(eventName,fn){
if(!this.callbacks[eventName]){
this.callbacks[eventName]=[]
}
this.callbacks[eventName].push(fn)
}
EventEmit.prototype.emit=function (eventName,fn){
if(!this.callbacks[eventName]){
return
}
this.callbacks[eventName].forEach(fn=>{
fn()
})
}
// 事件物件
// var e1=new EventEmit();
// // on訂閱事件
// e1.on('message',function(){
// console.log('操作h1')
// })
// e1.on('message',function(){
// console.log('操作h2')
// })
// e1.on('message',function(){
// console.log('操作p')
// })
vue.js
;(function(){
function Vue(options){
var {el,data}=options
//根節點
var rootEl=document.querySelector(el);
var _data={}
var _events=new EventEmit();
// 資料觀測
// 當data中的資料發生變化,發出事件通知,所以訂閱了該事件的DOM都會得到更新
for (let key in data){
_data[key]=data[key]
Object.defineProperty(this,key,{
get(){
return _data[key]
},
set(val){
_data[key]=val
_events.emit(key)
}
})
}
// 遞迴解析模板,註冊資料繫結事件
function compile(childNodes){
childNodes.forEach((node,index)=>{
switch(node.nodeType){
case 1:
// 處理input標籤
if(node.nodeName==='INPUT'){
const vModel=node.attributes['v-model']
if(!vModel){
return
}
var dataKey=vModel.value.trim();
node.oninput=()=>{
this[dataKey]=node.value
}
}
// 標籤節點繼續遞迴呼叫
compile.call(this,node.childNodes)
break;
case 3:
var matches=/{{(.+)}}/.exec(node.textContent)
if(matches){
var dataKey=matches[1].trim()
node.textContent=_data[dataKey]
_events.on(dataKey,()=>{
node.textContent=_data[dataKey]
})
}
break;
}
})
}
compile.call(this,rootEl.childNodes)
}
window.Vue=Vue;
})()
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
{{message}}
<p>{{message}}</p>
<div><p>{{message}}</p></div>
<input type="text" v-model="message">
</div>
<script src="js/eventemit.js"></script>
<script src="js/vue.js"></script>
<script>
// 模擬實現{{}} v-model
var app=new Vue({
el:'#app',
data:{
message:'hello vue'
}
})
</script>
</body>
</html>