最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue監(jiān)聽數(shù)據(jù)的原理詳解

 更新時間:2021年10月09日 16:06:40   作者:黑貓幾絳  
本篇文章主要介紹了Vue監(jiān)測數(shù)據(jù)的原理,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看

一、引入

首先畫一個簡單的圖。

我們在寫Vue的時候總會和數(shù)據(jù)打交道,將我們的目標(biāo)數(shù)據(jù)寫在data中,然后在template的差值表達式中通過{{xxx}}的格式可以響應(yīng)式的渲染數(shù)據(jù)。當(dāng)data中的數(shù)據(jù)改變時,這里橙色的線就會引起差值表達式的變化。那么問題來了,我們?nèi)绾伪O(jiān)測到data中數(shù)據(jù)的改變呢?這里就涉及到了Vue監(jiān)測數(shù)據(jù)的問題。

二、監(jiān)測對象  

2.1 為什么需要監(jiān)測對象

 首先寫出需要用到的靜態(tài)頁面。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>更新數(shù)據(jù)</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>

現(xiàn)在我們假設(shè)有一個需求,在頁面上添加一個按鈕,通過這個按鈕可以修改id為002的數(shù)據(jù)。

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

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

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

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

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

 2.2數(shù)據(jù)代理

要想理解數(shù)據(jù)監(jiān)測,還需要理解一個前置概念:數(shù)據(jù)代理。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>監(jiān)測對象</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>

在以前的時候我們?nèi)绻朐L問data里的數(shù)據(jù),可以直接通過實例對象,如vm.name,vm.age拿到具體的數(shù)值。其實這是做了數(shù)據(jù)代理后的簡化寫法。

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

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

vm._data = data = new Observer(data)

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

2.3 對象監(jiān)測相關(guān)API之Vue.set

還是先上靜態(tài)頁面。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>更新數(shù)據(jù)</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <div id="root">
       <h2>學(xué)校名稱:{{name}}</h2>
       <h2>學(xué)校地址:{{address}}</h2>
       <hr/>
       <h2>學(xué)生姓名:{{student.name}}</h2>
       <h2>學(xué)生性別:{{student.sex}}</h2>
       <h2>學(xué)生年齡:{{student.age}}</h2>
       <h1>朋友</h1>
       <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中出現(xiàn)的sex其實并不存在于data中。當(dāng)輸出一個對象中不存在的屬性值時,會輸出undefined,但是Vue經(jīng)過處理后不會顯示undefined值,也就是說此時頁面上學(xué)生性別后面是空值,控制臺也不會出現(xiàn)報錯?,F(xiàn)在提出一個需求,我們?nèi)绻枰獮閷W(xué)生添加一個新的性別屬性。要求是不能改變data中的現(xiàn)有數(shù)據(jù),即sex不能直接放入data中。

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

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

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

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

 

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

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>更新數(shù)據(jù)</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <div id="root">
       <button @click="addSex">點擊按鈕新增性別</button>
       <h2>學(xué)校名稱:{{name}}</h2>
       <h2>學(xué)校地址:{{address}}</h2>
       <hr/>
       <h2>學(xué)生姓名:{{student.name}}</h2>
       <h2>學(xué)生性別:{{student.sex}}</h2>
       <h2>學(xué)生年齡:{{student.age}}</h2>
       <h1>朋友</h1>
       <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>

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

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

2.4 為對象賦多個新值

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

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

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

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

三、監(jiān)測數(shù)組

依舊是先上靜態(tài)頁面。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>更新數(shù)據(jù)</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <div id="root">
       <button @click="addSex">點擊按鈕新增性別</button>
       <h2>學(xué)校名稱:{{name}}</h2>
       <h2>學(xué)校地址:{{address}}</h2>
       <hr/>
       <h2>學(xué)生姓名:{{student.name}}</h2>
       <h2>學(xué)生性別:{{student.sex}}</h2>
       <h2>學(xué)生年齡:{{student.age}}</h2>
       <h1>朋友</h1>
       <ul>
           <li v-for="(f,index) in student.friends" :key="index">
               {{f.name}} - {{f.age}}
           </li>
       </ul>
       <h1>愛好</h1>
       <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數(shù)組,數(shù)組整體來說有g(shù)et和set,是響應(yīng)式的。但是數(shù)組里面的元素并非響應(yīng)式,而是簡單的掛在了數(shù)組中,這也就是為什么在2.1中,當(dāng)我們嘗試對數(shù)組索引下標(biāo)進行重新賦值時,頁面上并沒有響應(yīng)。如果將hobby數(shù)組改為對象,再打印一下,就會發(fā)現(xiàn)對象中的屬性是響應(yīng)式的。由此我們可以粗略猜測,在Vue中,如果想要通過索引修改數(shù)組中的數(shù)值,就需要使用某些特殊方法。

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

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

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

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

比如在這里,我們?nèi)绻胍薷膆obby當(dāng)中的打豆豆為學(xué)習(xí),應(yīng)該怎么做?

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

 this.student.hobby[2] = '學(xué)習(xí)'

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

this.student.hobby.splice(2,3,'學(xué)習(xí)')

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

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

this.$set(this.student.hobby,2,'學(xué)習(xí)')

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

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

總結(jié)

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • Vue如何使用patch-package優(yōu)雅地修改第三方依賴庫

    Vue如何使用patch-package優(yōu)雅地修改第三方依賴庫

    在前端開發(fā)中,有時我們需要對第三方依賴庫進行修改以滿足項目需求,patch-package 是一個優(yōu)秀的工具,可以幫助我們優(yōu)雅地管理這些修改,下面我們來看看具體操作吧
    2025-03-03
  • vue項目啟動后沒有局域網(wǎng)地址問題

    vue項目啟動后沒有局域網(wǎng)地址問題

    這篇文章主要介紹了vue項目啟動后沒有局域網(wǎng)地址問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • vue cli4.0 如何配置環(huán)境變量

    vue cli4.0 如何配置環(huán)境變量

    這篇文章主要介紹了vue cli4.0 如何配置環(huán)境變量,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • el-upload多選文件上傳報錯解決方案

    el-upload多選文件上傳報錯解決方案

    本文主要介紹了el-upload多選文件上傳報錯解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • vue3如何定義變量及ref、reactive、toRefs特性說明

    vue3如何定義變量及ref、reactive、toRefs特性說明

    這篇文章主要介紹了vue3如何定義變量及ref、reactive、toRefs特性說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • vue的常用組件操作方法應(yīng)用分析

    vue的常用組件操作方法應(yīng)用分析

    這篇文章主要介紹了vue的常用組件操作方法應(yīng)用分析,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2018-04-04
  • vue3模塊創(chuàng)建runtime-dom源碼解析

    vue3模塊創(chuàng)建runtime-dom源碼解析

    這篇文章主要為大家介紹了vue3模塊創(chuàng)建runtime-dom源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-01-01
  • vue.js實現(xiàn)簡單購物車功能

    vue.js實現(xiàn)簡單購物車功能

    這篇文章主要為大家詳細(xì)介紹了vue.js實現(xiàn)簡單購物車功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • vue中pinia數(shù)據(jù)一直重復(fù)獲取之前的值的解決方法

    vue中pinia數(shù)據(jù)一直重復(fù)獲取之前的值的解決方法

    這篇文章主要介紹了vue中pinia數(shù)據(jù)一直重復(fù)獲取之前的值的解決方法,如果想讓pinia數(shù)據(jù)不會重復(fù)獲取之前的值需要手動強制觸發(fā) Pinia store 的狀態(tài)更新,文中有詳細(xì)的解決方法,需要的朋友可以參考下
    2024-04-04
  • 一篇文章帶你吃透Vuex3的狀態(tài)管理

    一篇文章帶你吃透Vuex3的狀態(tài)管理

    Vuex是一個專為Vue.js應(yīng)用程序開發(fā)的狀態(tài)管理模式,它采用集中式存儲管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化,下面這篇文章主要給大家介紹了關(guān)于如何通過一篇文章帶你吃透Vuex3的狀態(tài)管理,需要的朋友可以參考下
    2022-07-07

最新評論

内黄县| 莒南县| 化州市| 深圳市| 黎平县| 新昌县| 开原市| 隆回县| 南投县| 德清县| 蒙山县| 叶城县| 阿拉善右旗| 莆田市| 杂多县| 七台河市| 陆川县| 班戈县| 永清县| 筠连县| 友谊县| 博兴县| 陕西省| 泗阳县| 赣州市| 扶绥县| 汉沽区| 望都县| 安远县| 大连市| 柳河县| 竹溪县| 蓬莱市| 湖南省| 鹤庆县| 花垣县| 芒康县| 盐亭县| 邵东县| 高邮市| 清原|