1. 程式人生 > >JavaScript 之實現一個簡單的 Vue

JavaScript 之實現一個簡單的 Vue

vue的使用相信大家都很熟練了,使用起來簡單。但是大部分人不知道其內部的原理是怎麼樣的,今天我們就來一起實現一個簡單的vue

Object.defineProperty()

實現之前我們得先看一下Object.defineProperty的實現,因為vue主要是通過資料劫持來實現的,通過 get、 set來完成資料的讀取和更新。

  1. var obj = {name:'wclimb'}

  2. var age = 24

  3. Object.defineProperty(obj,'age',{

  4.    enumerable: true, // 可列舉

  5.    configurable: false, // 不能再define

  6.    get () {

  7.        return age

  8.    },

  9.    set (newVal) {

  10.        console.log('我改變了',age +' -> '+newVal);

  11.        age = newVal

  12.    }

  13. })

  14. > obj.age

  15. > 24

  16. > obj.age = 25;

  17. > 我改變了 24 -> 25

  18. > 25

從上面可以看到通過 get獲取資料,通過 set監聽到資料變化執行相應操作,還是不明白的話可以去看看Object.defineProperty文件。

流程圖

html程式碼結構

  1. <div id="wrap">

  2.    <p v-html="test"></p>

  3.    <input type="text" v-model="form">

  4.    <input type="text" v-model="form">

  5.    <button @click="changeValue">改變值</button>

  6.    {{form}}

  7. </div>

js呼叫

  1.    new Vue({

  2.        el: '#wrap',

  3.        data:{

  4.            form: '這是form的值',

  5.            test: '<strong>我是粗體</strong>',

  6.        },

  7.        methods:{

  8.            changeValue(){

  9.                console.log(this.form)

  10.                this.form = '值被我改變了,氣不氣?'

  11.            }

  12.        }

  13.    })

Vue結構

  1.    class Vue{

  2.        constructor(){}

  3.        proxyData(){}

  4.        observer(){}

  5.        compile(){}

  6.        compileText(){}

  7.    }

  8.    class Watcher{

  9.        constructor(){}

  10.        update(){}

  11.    }

  • Vue constructor 建構函式主要是資料的初始化

  • proxyData 資料代理

  • observer 劫持監聽所有資料

  • compile 解析dom

  • compileText 解析 dom裡處理純雙花括號的操作

  • Watcher 更新檢視操作

Vue constructor 初始化

  1.    class Vue{

  2.        constructor(options = {}){

  3.            this.$el = document.querySelector(options.el);

  4.            let data = this.data = options.data;

  5.            // 代理data,使其能直接this.xxx的方式訪問data,正常的話需要this.data.xxx

  6.            Object.keys(data).forEach((key)=> {

  7.                this.proxyData(key);

  8.            });

  9.            this.methods = obj.methods // 事件方法

  10.            this.watcherTask = {}; // 需要監聽的任務列表

  11.            this.observer(data); // 初始化劫持監聽所有資料

  12.            this.compile(this.$el); // 解析dom

  13.        }

  14.    }

上面主要是初始化操作,針對傳過來的資料進行處理

proxyData 代理data

  1. class Vue{

  2.        constructor(options = {}){

  3.            ......

  4.        }

  5.        proxyData(key){

  6.            let that = this;

  7.            Object.defineProperty(that, key, {

  8.                configurable: false,

  9.                enumerable: true,

  10.                get () {

  11.                    return that.data[key];

  12.                },

  13.                set (newVal) {

  14.                    that.data[key] = newVal;

  15.                }

  16.            });

  17.        }

  18.    }

上面主要是代理 data到最上層, this.xxx的方式直接訪問 data

observer 劫持監聽

  1. class Vue{

  2.        constructor(options = {}){

  3.            ......

  4.        }

  5.        proxyData(key){

  6.            ......

  7.        }

  8.        observer(data){

  9.            let that = this

  10.            Object.keys(data).forEach(key=>{

  11.                let value = data[key]

  12.                this.watcherTask[key] = []

  13.                Object.defineProperty(data,key,{

  14.                    configurable: false,

  15.                    enumerable: true,

  16.                    get(){

  17.                        return value

  18.                    },

  19.                    set(newValue){

  20.                        if(newValue !== value){

  21.                            value = newValue

  22.                            that.watcherTask[key].forEach(task => {

  23.                                task.update()

  24.                            })

  25.                        }

  26.                    }

  27.                })

  28.            })

  29.        }

  30.    }

同樣是使用 Object.defineProperty來監聽資料,初始化需要訂閱的資料。
把需要訂閱的資料到 push到 watcherTask裡,等到時候需要更新的時候就可以批量更新資料了。