Vue響應式原理以及注意事項


響應基於 set 和 get(Object.defineProperty)

類型:

    單向綁定
    雙向綁定

簡單例子(基於Object.defineProperty)
<!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>
        <form action="" class="form">
            <div>
                <label for="name">name</label>
                <input type="text" name="name" id="name">
            </div>
            <div>
                <label for="age">age</label>
                <input type="text" name="age" id="age">
            </div>
        </form>
    </div>

</body>
<script>
    // 實現Model到View的單向綁定
    //Model
    let person = {
        data: {
            name: '',
            age: '',
        }
    };
    //ViewModel
    function binding(obj) {
        for (let key in obj.data) {
            Object.defineProperty(obj, key, {
                get() {
                    console.log("getter");
                    return obj.data.key;
                },
                set(value) {
                    console.log("setter: " + value);
                    let dom = document.querySelector(`#${key}`);
                    dom.value = value;
                    console.log("dom.value: " + dom.value);
                    obj.data.key = value;
                    console.log("obj.data.key: " + obj.data.key);
                },
            });
        }
    }

    binding(person);

    // 實現view到model的單向綁定
    //View
    //獲取表單對象
    // let form = document.querySelector(".form");

    // //監聽form的input事件
    // form.addEventListener('input', (e) => {
    //     let value = e.target.value;
    //     let name = e.target.getAttribute('name');
    //     person[name] = value;
    // });

</script>

</html>
分析:
    1.js部分划分為數據(model)、關聯視圖方法viewModel

    2.只需要使用binding方法,此方法就會遍歷觀測對象的所有key,並為key定義屬性攔截器(Object.defineProperty),在數據set、get時定義額外的處理

    3.特別地,在set的時候,不僅僅更新的觀測對象的的值,還更新了DOM元素的值,當然這里是做了簡單處理,用以了解響應設計基礎部分,詳細部分的話,有興趣可以去看看官方源碼設計

    4.大家可能注意到有一個部分被我注釋了,那個就是那個addEventListener這部分,這里實現了view到model的單向更新

總結: vue的響應式核心是基於ES5特性Object.defineProperty生成的set、get

Vue對數組和對象的觀測處理:

    非根級變量響應方法:

        1.數組(vue對這些數組方法進行了代理,調用時做了更新視圖的處理),至於為什么,下面馬上解釋
        
        檢測邊界:
            1.增加或者修改

            新增:vm.items[indexOfItem]=newValue
            這種情況其實就是在為對象添加一個新key,數組本身也是Array類的一個實例

            修改:vm.items[indexOfItem]=newValue按照數組本身是一個對象應該會觸發更新,但是vue設計源碼沒有把數組對象的key進行set和get轉換

            2.修改長度

            vm.items.length = newLength
            同樣這樣沒有set和get沒法觸發視圖更新

        另辟蹊徑:

            通過對原生方法進行改寫來觸發視圖更新
        
            1.變異方法(改變原數組)

                push()
                pop()
                shift()
                unshift()
                splice()
                sort()
                reverse()

            2.非變異方法(返回新數組),vue在更新視圖對這種覆蓋原數組的情況作了優化處理,無需擔心渲染效率

                filter()
                contact()
                slice()


        檢測邊界的新處理方法:

            1.增加元素

                1.1 按順序插入

                    push(value)
                    unshift(value)

                1.2 按指定key插入

                    Vue.$set(arr,index,value)


            2.刪除元素

                splice(index,count)    

            3.修改元素

                splice(index,1,value)


        2.對象(遍歷data賦予set和get)
            
             Vue.$set(target, key, value) 
             
             注意事項:被設置變量不能存在(源碼發現key存在就會跳過此key的set和get轉換)

            增加單個屬性

            Vue.$set(target, key , value)
            
            增加多個屬性
            
            Object.assign({},target,source)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM