第三節(jié): Vue選項: data數(shù)據(jù)以及數(shù)據(jù)響應式

Vue data 數(shù)據(jù)屬性

1.數(shù)據(jù)屬性 Data的了解

通過前面的學習,我們知道vue的數(shù)據(jù)是寫在vue選項對象(也可以理解為配置對象)的data屬性中的,我們可以通過Mustache(雙大括號語法)就數(shù)據(jù)插入到頁面上

<div id="app">
    <p>第二條狗狗的名字是:{{dogs[2]}}</p>
    <p>所有狗狗名字是:{{dogs}}</p>
</div>

<script>   
    const vm = new Vue({
        el:"#app",
        data:{
            dogs: ["哈士奇","中華田園犬","藏獒"]
        }
    })
</script>

示例的感悟:

  1. 會發(fā)現(xiàn),如果將這個數(shù)組或?qū)ο筝敵龅巾撁嫔?并不會像JS一樣輸出[Object object]
  2. Vue會輸出JSON編碼后的值,這樣在調(diào)試的時候超級有用
  3. 調(diào)試時將內(nèi)容渲染到頁面比將數(shù)據(jù)輸出到控制臺更加有效果,
  4. 在頁面上顯示會隨著值的變化而變化(響應式),,這樣更加直觀的看到數(shù)據(jù)的變化


2.數(shù)據(jù)響應變化

當一個 Vue 實例被創(chuàng)建時,通過插值語法將數(shù)據(jù)顯示在頁面上,當我們修改數(shù)據(jù)時,頁面也會發(fā)生變化

// 我們的數(shù)據(jù)對象
var data = { a: 1 }

// 該對象被加入到一個 Vue 實例中
var vm = new Vue({
  el:"#app",
  data: data
})

// 獲得這個實例上的屬性
// 返回源數(shù)據(jù)中對應的字段
vm.a == data.a // => true

// 設(shè)置屬性也會影響到原始數(shù)據(jù)
vm.a = 2
data.a // => 2

// ……反之亦然
data.a = 3
vm.a // => 3

為什么頁面會自動發(fā)生變化呢?

  1. 這就是因為在Vue實例化時,就會向Vue的響應式系統(tǒng)中加入data對象中能夠找到的所有屬性然爆。
  2. 其實是Vue通過監(jiān)聽的方式一直在偵查值是否發(fā)生變化,我們可以在控制臺上打印實例:

圖如下:


監(jiān)聽.png

通過這張圖,我們就會發(fā)現(xiàn):

  1. 示例中data數(shù)據(jù)屬性中的數(shù)據(jù)aVue實例通過get,和set一直在檢測著,
  2. 也就是說vue的響應系統(tǒng)一直在觀察數(shù)據(jù)a的變化,一旦發(fā)生變化,響應系統(tǒng)做出反應,改變視圖.

所以當數(shù)據(jù)值發(fā)生改變扁达,視圖也會產(chǎn)生響應。


2.1 認識數(shù)據(jù)響應式的變化

通過剛才例子了解當數(shù)據(jù)發(fā)生變化時筹我,頁面視圖也會進行重新渲染,值得注意的時,只有data中存在的屬性才是響應的玩徊。

也就是說如果你添加一個新的屬性,比如:

vm.b = 'hi'

那么對b的改動不會出發(fā)任何視圖的更改谨究。因為vue并沒有將b加入到響應系統(tǒng)中, 說白了就是沒有檢測b的變化



那如何解決此類問題呢?

如果你知道你會晚些時候需要一個屬性恩袱,那么你可以在開始時設(shè)置一些初始值。如:

data: {
  a: "hello",
  b: ''
}



這里要注意一個特例:

這個例外是使用 Object.freeze()胶哲,這個方法是凍結(jié)方法,意思是不允許修改對象的屬性值,
這就會阻止修改現(xiàn)有的屬性畔塔, 數(shù)據(jù)沒發(fā)改變,也就不會觸發(fā)Vue的響應系統(tǒng)

var obj = {
  foo: 'bar'
}

Object.freeze(obj)

new Vue({
  el: '#app',
  data: obj
})

這個示例中我們利用了Object.freeze()凍結(jié)方法,讓Vue實例的所有data屬性中的數(shù)據(jù)都失去了響應式, 這樣做沒什么意義, 做了時候,Vue也就失去了數(shù)據(jù)驅(qū)動的功能

但是Object.freeze()方法在某些時候還是非常有用的, 當然不是凍結(jié)整個data,我們可以凍結(jié)data屬性中的一些對象數(shù)據(jù),
想了解,接著往下看

2.2 對象數(shù)據(jù)的響應變化
2.2.1 了解對象數(shù)據(jù)的響應變化

剛看到的是data屬性只是是基本類型的問題, 接下來看看數(shù)據(jù)屬性值是對象的狀況

vue在初始化的時候會循環(huán)data中的數(shù)據(jù),(數(shù)據(jù)劫持),以此增加getter和setter來監(jiān)聽數(shù)據(jù)

示例:

<div id="app">
    {{student.name}}
</div>
<script src="../vue.js/vue.js"></script>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            student: {
                name:"xiaoming"
            }
        }
    })
</script>

頁面顯示結(jié)果


示例結(jié)果.png

此時頁面正常顯示結(jié)果, 如果我們在控制臺改變對象數(shù)據(jù),會有如下結(jié)果:


測試示例結(jié)果.png

通過示例了解到,Vue數(shù)據(jù)如果是對象student,student中的屬性name在發(fā)生改變的時候,頁面也會發(fā)生改變,說明對象中的name屬性是被vue關(guān)注著的

那么問題來了, Vue會檢測到student數(shù)據(jù)的變化, 那么如果student對象中的新鎮(zhèn)一些屬性,會不會被檢測到呢.

我們可以通過如下的示例進行測試:

<div id="app"><!---view--->
    {{student.name}}
    {{student.age}}
</div>
<script src="../vue.js/vue.js"></script>
<script>
    const vm = new Vue({
        el: "#app",
        data: {
            student: {
                name:"xiaoming"
            }
        }
    })

    // 會發(fā)現(xiàn)初始化存在的name屬性會觸發(fā)頁面的更新
    //setTimeout(() => {
    //    vm.student.name = "小明";
    //}, 2000)
    
    // 對象age的改變不會觸發(fā)頁面的更新
    //setTimeout(() => {
    //    vm.student.age = 18;
    //}, 2000)
    
    // 但是我們會發(fā)現(xiàn),如果頁面一旦更新,age的值也會渲染在頁面上,
   //原因在于Vue get和set方法監(jiān)聽的是對象,不是對象的每一個屬性
    setTimeout(() => {
        vm.student.name = "小明";
        vm.student.age = 18;
    }, 2000)

</script>

通過上面三個定時器的不同測試結(jié)果, 我們了解到了:

  1. Vue初始化時定義的數(shù)據(jù)student的改變,
  2. 以及student數(shù)據(jù)的name屬性發(fā)生變化都會觸發(fā)響應系統(tǒng), 進而改變視圖,
  3. 但是如果student數(shù)據(jù)新增一個屬性, 卻沒有觸發(fā)響應式系統(tǒng), 頁面也沒有重新渲染,

為什么會這樣呢?

我們可以在控制臺打印Vue實例對象

示例結(jié)果.png

Vue會檢測student就不多講了

在看另外一張圖

示例結(jié)果2.png

通過這張圖我們就會發(fā)現(xiàn),Vue不但會監(jiān)聽student數(shù)據(jù),還會監(jiān)聽在Vue實例化時,student就已經(jīng)存在的屬性name,所以name的改變也會觸發(fā)響應系統(tǒng),

但是我們后添加的對象的數(shù)據(jù)不是響應式, Vue不會根據(jù)這些數(shù)據(jù)的變化來改變對應的視圖,所以當你單獨新增一個屬性是不會觸發(fā)響應系統(tǒng),

通過示例,我們有發(fā)現(xiàn)不會觸發(fā)響應系統(tǒng)的數(shù)據(jù)屬性跟具有響應系統(tǒng)的屬性一起改變,也會到處頁面的重新渲染, 因為有人觸發(fā)了響應系統(tǒng),如果你稍后還是單獨改變age數(shù)據(jù)值,頁面依然不會變化

總結(jié):

  1. 在實例化Vue之前,就已經(jīng)定義好的對象,已經(jīng)對象中的數(shù)據(jù)會被Vue響應式檢測
  2. 數(shù)據(jù)對象新增的屬性因為沒有被檢測,所以單獨改變不會觸發(fā)Vue響應式
  3. 但是只要Vue響應式被觸發(fā)了,新增的屬性值也會觸發(fā)頁面的改變


2.2.2 將不是響應系統(tǒng)檢測的數(shù)據(jù)添加到響應系統(tǒng)

那么如何才能在給對象添加新的屬性觸發(fā)vue的響應系統(tǒng),讓頁面發(fā)生更新呢?

可以通過 vm.$set()方法可以給對象添加響應式的數(shù)據(jù)變化

<div id="app"><!---view--->
    {{student.name}}
    {{student.age}}
</div>
<script src="../vue.js/vue.js"></script>
<script>

    const vm = new Vue({
        el: "#app",
        data: {
            student: {
                name:"xiaoming"
            }
        }
    })

    // 通過$set 方法改變對象的屬性會觸發(fā)響應式
    // 讓頁面視圖發(fā)生更新
    setTimeout(() => {
        vm.$set(vm.student,"age",18)
    }, 2000)

</script>

為什么$set()會觸發(fā)頁面的 改變呢? 我們可以在控制臺上打印Vue實例對象


示例結(jié)果.png

我們會發(fā)現(xiàn)通過$set方法處理后,Vue會將age屬性添加到響應系統(tǒng)上,所以就觸發(fā)了響應系統(tǒng), 進而改變視圖


2.2.3 修改多個不是響應系統(tǒng)檢測的數(shù)據(jù)

但是$set方法并不好,如果我要設(shè)置100個屬性那不得累死,怎么辦呢?

所以我們可以采用直接替換屬性對象內(nèi)容的方法,因為響應系統(tǒng)會測試student數(shù)據(jù)整體的變化

<div id="app"><!---view--->
    {{student.name}}
    {{student.age}}
</div>
<script src="../vue.js/vue.js"></script>
<script>

    const vm = new Vue({
        el: "#app",
        data: {
            student: {
                name:"xiaoming"
            }
        }
    })

    // 因為vue實時監(jiān)聽對象student的變化
    // 所以我們可以采用替換對象值的方法來觸發(fā)響應式
    setTimeout(() => {
        vm.student = {
            name: "xiaoming",
            age: 18
        }
    }, 2000)

</script>

通過上面的例子

我們會發(fā)現(xiàn)$set每次只能新增一個屬性,如果我要新增多個屬性就不是那么友好了,


2.2.4 解決直接替換對象數(shù)據(jù)的缺點

同樣的如果采用替換原對象,通過字面量的方式替換,會發(fā)現(xiàn)如果我原對象已有多個屬性,在通過替換原對象的方式觸發(fā)響應式的時候,需要不斷重寫原對象的屬性, 就很繁瑣.

所以關(guān)于替換原對象,我們可以采用Object.assign 來給原對象擴展屬性,然后在賦值給原對象,比如

//不要這樣,這樣并沒有新的對象,還是在原有對象上新增屬性
// 這種寫法跟vm.student.age = 18 完全等價 不會觸發(fā)響應式
Object.assign(vm.student,{
    age:18
})

//你應該這樣做, 在合并后形成新的對象, 在把新對象賦值給vue的數(shù)據(jù)對象
// 這樣多就會觸發(fā)響應式
vm.student = Object.assign({},vm.student,{
    age:18
})


2.3 數(shù)組數(shù)據(jù)的響應變化

在操作數(shù)組是不能使用下標的方式去改變數(shù)據(jù)

因為這種方式改變數(shù)據(jù)的值并不會觸發(fā)頁面的重新渲染

因為通過下標,去改變數(shù)組中的某一項是監(jiān)控不到的

<div id="app">
    {{arr}}
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            arr: [1, 2, 3, 4, 5, 6]
        }
    })
    // 通過下標改變內(nèi)容,不會觸發(fā)響應式,頁面不會重新渲染
    // 但是數(shù)組的值會發(fā)生改變
    setTimeout(() => {
        vm.arr[0] = 5;
        vm.arr.length = 2;
    }, 5000)
</script>

以上的寫法雖然改變了數(shù)組,但是不會同步渲染到頁面中去,因為vm沒有g(shù)et,set 檢測數(shù)組的每一項;
我們可以在控制臺上打印實例對象查看Vue是否在監(jiān)聽數(shù)據(jù)的每一項


示例結(jié)果.png

通過Vue實例對象,我們就了解到Vue并沒有檢測數(shù)據(jù)的每一項.

那么我們?nèi)绾巫寯?shù)組變成響應式的呢?

我們會發(fā)現(xiàn)Vue的響應系統(tǒng)是監(jiān)聽著數(shù)組本身的,所以我們只能采用直接替換原數(shù)組的方案

<div id="app"><!---view--->
    {{arr}}
</div>
<script src="../vue.js/vue.js"></script>
<script>

    const vm = new Vue({
        el: "#app",
        data: {
            arr:[1,2,3,4,5]
        }
    })

    // 采用替換原數(shù)組的方案,觸發(fā)響應式,重新渲染頁面
    setTimeout(() => {
        vm.arr = [5,2]
    }, 2000)

</script>

也可以通過數(shù)組的改變原數(shù)組的方法來觸發(fā)響應系統(tǒng)

變異方法;

pop push shift unshift sort reserve splice()

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

變異方法 (mutation method),顧名思義,會改變被這些方法調(diào)用的原始數(shù)組澈吨。

非變異 (non-mutating method) 方法把敢,例如:filter(), concat()slice() 。這些不會改變原始數(shù)組棚辽,但總是返回一個新數(shù)組。

變異方法觸發(fā)響應系統(tǒng)的示例

<div id="app"><!---view--->
    {{arr}}
</div>
<script src="../vue.js/vue.js"></script>
<script>

    const vm = new Vue({
        el: "#app",
        data: {
            arr:[1,2,3,4,5]
        }
    })

    // 采用會改變原數(shù)組的一些方法來觸發(fā)響應系統(tǒng)
    setTimeout(() => {
        // vm.arr.push(6)
        // vm.arr.pop()
        // vm.arr.unshift(6)
        // vm.arr.shift()
        // vm.arr.splice(1,2,9,8,7)
        // vm.arr.sort(() => {
        //     return -1
        // })
        // vm.arr.reverse();
    }, 2000)

</script>

其實并不是這些方法本身會觸發(fā)響應系統(tǒng),而是Vue 包含觀察數(shù)組的變異方法的功能冰肴,所以它會觸發(fā)響應系統(tǒng), 然后更新視圖

當使用非變異方法時屈藐,可以采用新數(shù)組替換舊數(shù)組:

<div id="app"><!---view--->
    {{arr}}
</div>
<script src="../vue.js/vue.js"></script>
<script>

    const vm = new Vue({
        el: "#app",
        data: {
            arr:[1,2,3,4,5]
        }
    })

    // 用修改后返回的數(shù)組直接覆蓋原數(shù)組來觸發(fā)響應系統(tǒng)
    setTimeout(() => {
        vm.arr = vm.arr.map(item => item*2)
    }, 2000)

</script>

雖然我們對響應式系統(tǒng)的底層原理不是那么的明白,
但至少現(xiàn)在我們就能知道怎樣改變數(shù)據(jù)會觸發(fā)響應系統(tǒng),從而更新頁面渲染,知道什么樣的方法不會觸發(fā)頁面渲染

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市熙尉,隨后出現(xiàn)的幾起案子联逻,更是在濱河造成了極大的恐慌,老刑警劉巖检痰,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件包归,死亡現(xiàn)場離奇詭異,居然都是意外死亡铅歼,警方通過查閱死者的電腦和手機公壤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來椎椰,“玉大人厦幅,你說我怎么就攤上這事】” “怎么了确憨?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長瓤的。 經(jīng)常有香客問我休弃,道長,這世上最難降的妖魔是什么圈膏? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任塔猾,我火速辦了婚禮,結(jié)果婚禮上稽坤,老公的妹妹穿的比我還像新娘桥帆。我一直安慰自己,他們只是感情好慎皱,可當我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布老虫。 她就那樣靜靜地躺著,像睡著了一般茫多。 火紅的嫁衣襯著肌膚如雪祈匙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天,我揣著相機與錄音夺欲,去河邊找鬼跪帝。 笑死,一個胖子當著我的面吹牛些阅,可吹牛的內(nèi)容都是我干的伞剑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼市埋,長吁一口氣:“原來是場噩夢啊……” “哼黎泣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起缤谎,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤抒倚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后坷澡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體托呕,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年频敛,在試婚紗的時候發(fā)現(xiàn)自己被綠了项郊。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡斟赚,死狀恐怖呆抑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情汁展,我是刑警寧澤鹊碍,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站食绿,受9級特大地震影響侈咕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜器紧,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一耀销、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧铲汪,春花似錦熊尉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至齿梁,卻和暖如春催植,著一層夾襖步出監(jiān)牢的瞬間肮蛹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工创南, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留伦忠,地道東北人。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓稿辙,卻偏偏與公主長得像昆码,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子邻储,可洞房花燭夜當晚...
    茶點故事閱讀 45,107評論 2 356