中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Vue監聽數據的原理是什么

發布時間:2021-10-09 18:11:13 來源:億速云 閱讀:156 作者:柒染 欄目:開發技術

Vue監聽數據的原理是什么,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。

    一、引入

    首先畫一個簡單的圖。

    Vue監聽數據的原理是什么

    我們在寫Vue的時候總會和數據打交道,將我們的目標數據寫在data中,然后在template的差值表達式中通過{{xxx}}的格式可以響應式的渲染數據。當data中的數據改變時,這里橙色的線就會引起差值表達式的變化。那么問題來了,我們如何監測到data中數據的改變呢?這里就涉及到了Vue監測數據的問題。

    二、監測對象  

    2.1 為什么需要監測對象

     首先寫出需要用到的靜態頁面。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>更新數據</title>
        <script type="text/javascript" src="../js/vue.js"></script>
    </head>
    <body>
        <div id="root">
            <ul>
                <li v-for="p in persons" :key="p.id">
                    {{p.name}} - {{p.age}} = {{p.sex}}
                </li>
            </ul>
        </div>
     
        <script type="text/javascript">
            Vue.config.productionTip = false
            const vm = new Vue({
                el: '#root',
                data:{
                    persons: [
                        {id:'001',name:'黑貓幾絳',age: 20, sex: '未知'},
                        {id:'002',name:'白貓幾絳',age: 23, sex: '男'},
                        {id:'003',name:'阿貓幾絳',age: 18, sex: '女'}
                    ]
                }
            })
        </script>
    </body>
    </html>

    現在我們假設有一個需求,在頁面上添加一個按鈕,通過這個按鈕可以修改id為002的數據。

    <button @click="change">點擊修改白貓幾絳</button>
     
      methods:{
          change(){
              this.persons[1].name = '白馬'
              this.persons[1].age = 17
              this.persons[1].sex = '未知'
          }
      }

    逐個屬性的修改,可以改變id為002的數據,但是這樣是否有些繁瑣,我們是否可以將這么長的一段修改改為一個對象?

     this.persons[1] = {id:'002',name:'白馬',age: 17, sex: '未知'}

    此時在瀏覽器當中點擊按鈕后,頁面并沒有任何反應。然而出乎意料的是,在vm實例對象中,persons[1]的數據確確實實得到了更改!

    Vue監聽數據的原理是什么

    為了解決這個問題,我們可以先看看另外一個例子,然后通過在瀏覽器里面輸出來查看具體執行過程,在理解如何監測后再回來看這個問題。

     2.2數據代理

    要想理解數據監測,還需要理解一個前置概念:數據代理。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>監測對象</title>
        <script type="text/javascript" src="../js/vue.js"></script>
    </head>
    <body>
        <div id="root"></div>
        <script type="text/javascript">
            Vue.config.productionTip = false
            const vm = new Vue({
                el: '#root',
                data:{
                   name: '黑貓幾絳',
                   age: 20
                }
            })
        </script>
    </body>
    </html>

    在以前的時候我們如果想訪問data里的數據,可以直接通過實例對象,如vm.name,vm.age拿到具體的數值。其實這是做了數據代理后的簡化寫法。

    Vue將data進行了一次加工,將data中的數據放在了_data中,實例對象通過._data的方式可以拿到加工后的數據。只不過屬性的值不再直接給出,而是通過get方法來獲取,有點類似于面向對象語言如JAVA中獲取類內私有變量時使用的getter方法。這里還有一個set方法,當data里面數據值改變的時候,就會調用該set方法,導致重新解析模板,然后生成新的虛擬DOM進行新舊DOM對比,最后更新頁面。

    Vue監聽數據的原理是什么

    在這里其實涉及到了源碼方面的問題,我們在本文中不考慮源碼,不然太復雜了。簡化來說,其實在Vue內部有這樣的一種方法:

    vm._data = data = new Observer(data)

    在Observer函數中先通過Object.keys獲取data的所有屬性形成一個數組,然后通過遍歷該數組,使用Object.defineProperty實現數據劫持,最后將計算的最終結果交給_data。

    2.3 對象監測相關API之Vue.set

    還是先上靜態頁面。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>更新數據</title>
        <script type="text/javascript" src="../js/vue.js"></script>
    </head>
    <body>
        <div id="root">
           <h3>學校名稱:{{name}}</h3>
           <h3>學校地址:{{address}}</h3>
           <hr/>
           <h3>學生姓名:{{student.name}}</h3>
           <h3>學生性別:{{student.sex}}</h3>
           <h3>學生年齡:{{student.age}}</h3>
           <h2>朋友</h2>
           <ul>
               <li v-for="(f,index) in student.friends" :key="index">
                   {{f.name}} - {{f.age}}
               </li>
           </ul>
        </div>
        <script type="text/javascript">
            Vue.config.productionTip = false
            const vm = new Vue({
                el: '#root',
                data:{
                    name:'MIT',
                    address:'UUU',
                    student:{
                        name: 'tom',
                        age: 20,
                        friends: [
                            {name: 'jack', age: 21},
                            {name: 'mary', age: 20}
                        ]
                    },
                }
            })
        </script>
    </body>
    </html>

    也許你會注意到,template中出現的sex其實并不存在于data中。當輸出一個對象中不存在的屬性值時,會輸出undefined,但是Vue經過處理后不會顯示undefined值,也就是說此時頁面上學生性別后面是空值,控制臺也不會出現報錯。現在提出一個需求,我們如果需要為學生添加一個新的性別屬性。要求是不能改變data中的現有數據,即sex不能直接放入data中。

    根據之前介紹的_data,我們可以嘗試通過_data直接綁定上sex屬性。然后發現并沒有渲染到頁面上。其實這里和2.1中的問題有點類似了。下面進行分析。

    Vue監聽數據的原理是什么

    我們先打印一下vm的_data看看。由下圖可以清楚的看到,在student對象中成功的添加上了sex屬性名和名為未知的屬性值。但是繼續往下看,在下面的眾多get與set方法中并沒有出現針對sex的方法,這也就代表著這個后添加的屬性并沒有成為響應式數據。

    Vue監聽數據的原理是什么

    為了解決這個問題,我們可以使用Vue提供的API,即Vue.set()方法,來讓后添加的數據也成為響應式數據。該方法第一個參數target表示要往誰身上添加數據,第二個參數key表示要添加的屬性名是什么,第三個參數表示屬性值。

    Vue監聽數據的原理是什么

    此時我們可以通過Vue.set(vm._data.student,'sex','未知'),不僅可以改變_data中的屬性,還可以受到監測,改變頁面中的數據。還有一個同樣效果的api,即vm.$set,用法和Vue.set()相同,參數也是相同,vm.$set(vm._data.student,'sex','未知'),用這兩個方法添加上去的數據即可成為響應式數據。

    Vue監聽數據的原理是什么

     Vue監聽數據的原理是什么

    在實現功能后我們可以考慮一下優化簡寫,由于數據代理,vm.student === vm._data.student,所以可以簡寫為Vue.set(vm.student,'sex','未知)。

    接下來在實際編碼中來驗證瀏覽器中的想法,假設通過點擊一個按鈕來添加sex屬性,這里就不再過多描述了,直接貼代碼。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>更新數據</title>
        <script type="text/javascript" src="../js/vue.js"></script>
    </head>
    <body>
        <div id="root">
           <button @click="addSex">點擊按鈕新增性別</button>
           <h3>學校名稱:{{name}}</h3>
           <h3>學校地址:{{address}}</h3>
           <hr/>
           <h3>學生姓名:{{student.name}}</h3>
           <h3>學生性別:{{student.sex}}</h3>
           <h3>學生年齡:{{student.age}}</h3>
           <h2>朋友</h2>
           <ul>
               <li v-for="(f,index) in student.friends" :key="index">
                   {{f.name}} - {{f.age}}
               </li>
           </ul>
        </div>
        <script type="text/javascript">
            Vue.config.productionTip = false
            const vm = new Vue({
                el: '#root',
                data:{
                    name:'MIT',
                    address:'UUU',
                    student:{
                        name: 'tom',
                        age: 20,
                        friends: [
                            {name: 'jack', age: 21},
                            {name: 'mary', age: 20}
                        ]
                    },
                },
                methods:{
                    addSex(){
                        // 在methoods中,this的指向就是vm實例對象
                        // 這里還可以寫成this.$set(this.student, 'sex', '男')
                        Vue.set(this.student, 'sex', '男')
                    }
                }
            })
        </script>
    </body>
    </html>

    但是使用這樣的方法有一定的局限性,在添加成功的時候是設置給了data中的student對象,那么假如直接設置給data對象呢?比如假設需要在這里添加一個新的屬性建校日期time,如果仍然采用Vue.set方法的話,就會報錯。

    Vue監聽數據的原理是什么

    由此可見該方法只能用于向響應式對象(如這里的data.student)上添加新property,且觸發視圖更新。因為Vue無法探測普通的新增property。

    2.4 為對象賦多個新值

    有時候有你可能需要為已有對象賦值多個新 property,比如使用Object.assign()或者是_.extend()。但是,這樣添加到對象上的新 property 不會觸發更新。因此在這種情況下,你應該用原對象與要混合進去的對象的 property 一起創建一個新的對象。

    比如我想向student新增以前并不存在的身高和體重屬性,我可以這樣做:

    const add = {'height': 180, "weight": 150}
    this.student = Object.assign({},this.student, add)

    將原來的對象和新增的對象進行合并后賦值給一個空的新對象,然后將該對象賦值給this.student,最終數據可以響應式地添加到student身上。

    三、監測數組

    依舊是先上靜態頁面。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>更新數據</title>
        <script type="text/javascript" src="../js/vue.js"></script>
    </head>
    <body>
        <div id="root">
           <button @click="addSex">點擊按鈕新增性別</button>
           <h3>學校名稱:{{name}}</h3>
           <h3>學校地址:{{address}}</h3>
           <hr/>
           <h3>學生姓名:{{student.name}}</h3>
           <h3>學生性別:{{student.sex}}</h3>
           <h3>學生年齡:{{student.age}}</h3>
           <h2>朋友</h2>
           <ul>
               <li v-for="(f,index) in student.friends" :key="index">
                   {{f.name}} - {{f.age}}
               </li>
           </ul>
           <h2>愛好</h2>
           <ul>
               <li v-for="(h,index) in student.hobby" :key="index">
                   {{h}}
               </li>
           </ul>
        </div>
        <script type="text/javascript">
            Vue.config.productionTip = false
            const vm = new Vue({
                el: '#root',
                data:{
                    name:'MIT',
                    address:'UUU',
                    student:{
                        name: 'tom',
                        age: 20,
                        friends: [
                            {name: 'jack', age: 21},
                            {name: 'mary', age: 20}
                        ],
                        hobby:['吃飯','睡覺','打豆豆']
                    },
                },
                methods:{
                    addSex(){
                        this.$set(this.student, 'sex', '男')
                    }
                }
            })
        </script>
    </body>
    </html>

    在控制臺中打印vm._data后我們可以清晰的看到,對于student中的hobby數組,數組整體來說有get和set,是響應式的。但是數組里面的元素并非響應式,而是簡單的掛在了數組中,這也就是為什么在2.1中,當我們嘗試對數組索引下標進行重新賦值時,頁面上并沒有響應。如果將hobby數組改為對象,再打印一下,就會發現對象中的屬性是響應式的。由此我們可以粗略猜測,在Vue中,如果想要通過索引修改數組中的數值,就需要使用某些特殊方法。

    Vue監聽數據的原理是什么

    方法從何而來?現在我們可以看看Vue文檔里面是怎么說的。在文檔列表渲染->數組更新檢測->變更方法的頁面中有這樣一段話:

            Vue 將被偵聽的數組的變更方法進行了包裹,所以它們也將會觸發視圖更新。這些被包裹過的方法包括:

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

    要想修改數組里面的數據,我們不妨試試以上的七種方法。看到這些方法也許你會想到Array原型鏈上的方法,然而在這里并不完全正確。Vue對這些方法進行了一次包裹封裝,Vue在解析到這些方法的時候,第一步仍然是正常的調用Array原型鏈中的方法,第二步則是重新解析模板,這也就是為什么使用這些方法可以觸發視圖更新,因為重新解析模板后會生成新的虛擬DOM進行新舊DOM對比,最后更新頁面。通過vm._data.student.hobby.push === Array.prototype.push這個判斷為false可以印證這個想法。

    比如在這里,我們如果想要修改hobby當中的打豆豆為學習,應該怎么做?

    在接觸這些知識點之前我會使用下面這段代碼,緊接而來的就是一個錯誤的渲染。在改變數據后頁面中并沒有更新。

     this.student.hobby[2] = '學習'

    Vue監聽數據的原理是什么

    接下來我們試試兩種方法,首先試試剛剛介紹的數組操作方法。

    this.student.hobby.splice(2,3,'學習')

    接下來試試以前介紹過的Vue.set方法。

    這里補充一下,在2.3中我們介紹利用該方法修改對象里面的數值時,方法的第二個參數是屬性名;而在數組中使用該方法的時候,第二個參數應該為數組中元素的下標。

    this.$set(this.student.hobby,2,'學習')

    這兩個方法都可以成功修改hobby中的數據,并且成功更新到頁面中。

    Vue監聽數據的原理是什么

    總的來說,不可以通過數組的索引值進行賦值。但是可以改變數組的本身指向,在之前的圖片中我們已經看到,hobby數組本身是響應式的,是可以通過get和set進行監控的。比如在業務邏輯中使用了filter對數組進行過濾,然后賦值給在data中已經存在的數組。這里我們可以再看看文檔中替換數組這一節的介紹。如filter、concat、slice這些方法并不會變更原始數組,而總是返回一個新數組,當使用變更方法時,可以用新數組替換舊數組。

    看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    vue
    AI

    饶阳县| 莲花县| 江陵县| 富平县| 新竹县| 宁津县| 呼玛县| 江安县| 安庆市| 共和县| 万州区| 沁水县| 陇川县| 河津市| 苍梧县| 海城市| 凯里市| 宁强县| 满洲里市| 汝城县| 历史| 涞水县| 东至县| 缙云县| 长乐市| 梨树县| 新竹市| 三原县| 乐山市| 崇阳县| 新安县| 建湖县| 沙雅县| 武鸣县| 宣城市| 乌审旗| 棋牌| 富裕县| 福海县| 双鸭山市| 西安市|