20_Vue如何監測數組類型數據發生改變的?

通過上一節,我們知道了vue檢測對象數據發生改變的原理

但是還有個api我們沒有講解,Vue.set();

這個API比較適合在理解了對象檢測的原理後進行講解

案例準備

html

<!-- 創建一個容器 -->
    <div class="app">
        <h1>姓名:{{student.name}}</h1>
        <h1>年齡:{{student.age}}</h1><br>
        <h2>朋友們</h2>
        <ul>
            <!-- 列表渲染 == friends -->
            <li v-for="(item,index) in friends">
                {{item.name}}-{{item.rage}}-{{item.mage}}
            </li>
        </ul>
    </div>

data配置項

<script>
    const vm = new Vue({
        el: '.app',
        data: {
            student: {
                name: 'wavesbright',
                age: 21,
            },
            friends: [ // 真實年齡,內心年齡
                {name: "Jack",rage: 32,mage: 40},
                {name: "Jony",rage: 24,mage: 45},
                {name: "Jone",rage: 28,mage: 50},
            ]
        },
        methods: {

        },
    });
</script>

頁面效果

image-20221102141955076

需求

  • 我的數據都是寫在data當中的,通過vue的數據代理
  • 在頁面當中實現了響應式開發
  • 那麼現在有一個問題
  • 我想給,student 添加一個屬性,這個屬性是後來添加的,不是之前就添加的
  • 想讓 這個屬性能夠實現響應式,應該如何實現?

錯誤示範

  1. 直接在vm後面加個屬性不就完了?
    • image-20221102142752146
  2. 修改 _data,然後給它添加一個屬性?
    • image-20221102142917697
  • 上述兩個操作的問題,添加的屬性沒有進行數據代理
  • 無法完成響應式
  • 仔細看的話,在student這個對象當中,sex這個屬性是沒有get和set函數的
    • image-20221102143518688

添加測試

image-20221102143106349

我們在這裡添加一個渲染項,然後我們添加屬性試試,現在我data當中是沒有這個屬性的

11-2-2

並不能被vue所識別到

那麼我們後面想要自己添加屬性就沒有辦法完成響應式了嗎,誒,這就是我們接下來要引入的API

Vue.set()

  • 該API需要三個參數image-20221102143813121
    1. target: 目標
    2. key: 添加的屬性名
    3. val: 添加的屬性值

11-2-3

我現在算是明白了,小程序的 this.setData() 就是從這裡變來的

這裡其實應該是 .student的;因為操作的都是同一個對象的地址

set的局限性

image-20221102145233850

我現在要在data當中,添加一個屬性,這個屬性是leader == 校長

我們使用.set添加試試

image-20221102145407017

  • 這裡報錯的意思就是,不允許直接在vue實例身上添加一個屬性
  • 解讀一下這段話哈
    • 我現在是在_data當中添加屬性
    • 但是這個添加的屬性,最後會掛載在vue實例身上
    • 所以,這裡使用.set是不允許的,不能直接添加
  • .set()不能在data當中直接添加屬性
  • 只能給data當中的某個對象(student)添加屬性

vm是不能作為target的,vm當中的data,也不能作為target

image-20221102145940047

監測數組

準備工作

image-20221102155518981

  • 新建一個demo,重新配置了數據項data
  • 在data當中有兩個屬性,一個numbers的數組,一個student的對象
  • 我們查看vue實例對象,在查看之前可以很明確的說,numbers 和 student 都掛載在了vue實例身上,並且,有專門為他倆服務的get和set

image-20221102155656363

數據代理

image-20221102155712983

現在我們點擊去看看二者有什麼不同,或者說,vue當中對數組和對象類型的數據是如何代理的

數組和對象的不同

數組

image-20221102155800634

對象

image-20221102155900547

區別,目前而言

  1. 數組當中的數據,是沒有進行數據代理的,沒有專門為 元素 服務 的 get和set
  2. 而對象當中,每個屬性都是有get和set的,哪怕這個屬性是對象也有
  3. 也就是說,如果我們直接在vue當中直接修改numbers對應索引的值,vue是觀測不到的

直接修改numbers

我們寫一串DOM元素進行測試

<div class="app">
    <ul>
    	<li v-for="item in numbers">{{item}}</li>	
    </ul>
</div>

image-20221102160319751

現在,我直接在控制台中對數組當中的元素進行修改

我們將最後一項 從5改為6

11-2-4

數據的確修改成功了,但是vue檢測不到,頁面無法響應

之前的錯誤解釋

現在,我們來回顧一下之前遇到的bug,我們添加一個persons對象數組

image-20221102160649390

從控制台我們來觀察一下這個persons

image-20221102160755419

  1. 這是一個對象數組,這個數組當中的每一項數據,都沒有被進行數據代理
  2. 但是因為每一項 數據 都是對象類型,所以 在對象類型當中 數據是進行了代理(get和set)的
    • image-20221102160940508
  3. 這裡很重要,請仔細看

image-20221102161141470

所以為什麼下面的修改不起作用,因為根本沒代理,沒有代理無法完成響應式數據

這個問題解決了順勢拋出下一個問題,vue怎麼就知道數組內部的屬性發生改變了呢,它是如何監測到的?

vue如何監測?

image-20221102150731267

  • 藍色框當中的都是可以對數組進行修改的,會改變原有數組結構
  • 但是filter不會,他會返回一個新數組,不修改原數組
  • arr 調用了藍色框框當中的數組API,自身才會發生改變
  • vue當中規定,你只有使用了上述的7個方法,我才承認你修改數組了

那它咋知道我調用了上面的7個API呢?

包裝技術

原形

使用 Array這個原形對象身上的 push 舉例子

這個push,是給數組調用的

image-20221102163219750

我們在控制台上來個數組

image-20221102163709960

這個push是哪裡來的?==> 其實是一層一層嵌套的,從原形對象身上來的

image-20221102163823820

二者身上的push是相等的

image-20221102163930949

vue

vue身上的數組,使用的並不是 原形數組Array身上的 API函數

如何測試?

很簡單,回到我們剛剛的案例

image-20221102164255786

這下您能明白了嗎

流程

當你對一個被vue所管理的數組進行了api的調用(push,shift,unshift…..)

image-20221102165531528

你調用的這個API,就不是原型對象Array身上的API了;而是vue的api

在這個api當中,會做兩個步驟

  1. 調用原形身上的API(push…..)
  2. 重新解析模板,生成虛擬dom…….那一套流程
    • image-20221102165723073

是這麼一回事嗎,我們看下官網是如何解答的

官網尋找答案

點我跳轉

  1. 點擊 列表渲染
  2. 點擊 數組更新檢測

image-20221102170123421

我們來看這句話

image-20221102170337738

enmmmm,後面沒講了,基本其實到這裡就差不多了,後面的都需要在實際開發當中去慢慢琢磨了

尚硅谷yyds,黑馬也是

你們都是我的天使