1. 程式人生 > >模擬Vue雙向資料繫結

模擬Vue雙向資料繫結

事件物件

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>