第十三節(jié):Vue選項(xiàng):watch偵聽器

官方解釋:

觀察 Vue 實(shí)例變化的一個(gè)表達(dá)式或計(jì)算屬性函數(shù)涛舍⊥醮眨回調(diào)函數(shù)得到的參數(shù)為新值和舊值浴栽。表達(dá)式只接受監(jiān)督的鍵路徑。對于更復(fù)雜的表達(dá)式涎劈,用一個(gè)函數(shù)取代


1. 偵聽器的基本使用

偵聽器可以監(jiān)聽data對象屬性或者計(jì)算屬性的變化

watch是觀察屬性的變化

所以watch的屬性名必須要與觀察人的名字保持一致;

只要觀察的值發(fā)生了變化才會(huì)觸發(fā),

<div id="app">
    <!-- 監(jiān)聽器 -->
    <input type="text" v-model="msg">
</div>

<script>   
    const vm = new Vue({
        el: "#app",
        data: {
            msg:""
        },
        watch:{
            msg(){
                console.log("數(shù)據(jù)發(fā)生了變化")
                console.log(arguments)
            }
        }
    })
</script>

通過這個(gè)理解,我們就會(huì)發(fā)現(xiàn), 只要數(shù)據(jù)一但發(fā)生變化,那么監(jiān)聽函數(shù)msg就會(huì)被觸發(fā), 監(jiān)聽函數(shù)中接受兩個(gè)參數(shù),第一個(gè)參數(shù)是數(shù)據(jù)變化后的新值, 第二個(gè)參數(shù)是數(shù)據(jù)變化后的舊值


盡管大部分時(shí)間我們用不到偵聽器, 但偵聽器對于處理異步操作非常適合,

例如我們需要將用戶輸入的內(nèi)容延遲5秒后現(xiàn)在在頁面上

<div id="app">
    <!-- 監(jiān)聽器 -->
    <input type="text" v-model="msg">
    {{showMsg}}
</div>

<script>   

    const vm = new Vue({
        el: "#app",
        data: {
            msg:"",
            showMsg: ""
        },
        watch:{
            msg(){
                let newValue = this.msg
                setTimeout(() => {
                    this.showMsg = newValue
                },5000)
            }
        }


    })
</script>


2. 獲取舊值

偵聽器在數(shù)據(jù)發(fā)生變化的時(shí)候就會(huì)觸發(fā),觸發(fā)時(shí),數(shù)據(jù)已經(jīng)更新,我們那到就是新值,那么我們?nèi)绾潍@取之前的舊值呢

其實(shí)當(dāng)監(jiān)聽的屬性發(fā)生變化時(shí),偵聽器會(huì)被傳入兩個(gè)參數(shù)

第一個(gè)參數(shù):偵聽器所監(jiān)聽屬性的當(dāng)前值,即更新后的值

第二個(gè)參數(shù): 原來舊值

<div id="app">
    <!-- 監(jiān)聽器 -->
    <input type="text" v-model="msg">
</div>

<script>   
    const vm = new Vue({
        el: "#app",
        data: {
            msg:"",
        },
        watch:{
            msg(val, oldval){
                console.log(val);
                console.log(oldval);            
            }
        }
    })
</script>


3. 監(jiān)聽data對象中某個(gè)對象的屬性

data屬性中的數(shù)據(jù)值除了是基本數(shù)據(jù)類型的數(shù)據(jù)為,還有可能是對象類型,那么我們?nèi)绾伪O(jiān)聽對象數(shù)據(jù)的屬性的

<div id="app">
    <!-- 監(jiān)聽器 -->
    <input type="text" v-model.number="fruit.price">

</div>

<script>   

    const vm = new Vue({
        el: "#app",
        data: {
            fruit:{
                name:"蘋果",
                price: 20
            },
        },
        watch:{
            fruit(val, oldval){
                console.log(val);
                console.log(oldval);            
            }
        }
    })
</script>

如果我們按照之前的監(jiān)聽方式, 那么我們就會(huì)發(fā)現(xiàn),當(dāng)我們修改fruit屬性值的時(shí)候,偵聽器不會(huì)被觸發(fā), 偵聽器會(huì)在fruit對象整體被修改時(shí)觸發(fā).


為了監(jiān)聽對象里某個(gè)特定屬性的變化,可以在偵聽器的名稱中使用.操作符, 就像訪問這個(gè)對象的屬性

<div id="app">
    <!-- 監(jiān)聽器 -->
    <input type="text" v-model.number="fruit.price">

</div>

<script>   

    const vm = new Vue({
        el: "#app",
        data: {
            fruit:{
                name:"蘋果",
                price: 20
            },
        },
        watch:{
            "fruit.price"(val, oldval){
                console.log(val);
                console.log(oldval);            
            }
        }
    })
</script>


4. 深度監(jiān)聽

通過上面的例子,我們知道,我們可以監(jiān)聽對象的特定屬性的變化,,可以我們想監(jiān)聽整個(gè)對象的所有屬性的變化就需要給對象所有的屬性添加監(jiān)聽就不是特別的好,如果我們只是單純的監(jiān)聽對象,那么屬性的變化并不會(huì)觸發(fā)監(jiān)聽器,只有整個(gè)對象被替換式才會(huì)觸發(fā)

所以我們可以通過deep屬性來開啟對象的深度監(jiān)聽,

4.1 deep 選項(xiàng)

為了發(fā)現(xiàn)對象內(nèi)部值的變化,可以在選項(xiàng)參數(shù)中指定 deep: true阅茶。注意監(jiān)聽數(shù)組的變更不需要這么做蛛枚。

如果需要開啟深度監(jiān)聽,那么監(jiān)聽器將不再是一個(gè)函數(shù),而需要寫成一個(gè)對象,對象中配置deep屬性

<div id="app">
    <!-- 監(jiān)聽器 -->
    <input type="text" v-model.number="fruit.price">

</div>

<script>   
    const vm = new Vue({
        el: "#app",
        data: {
            fruit:{
                name:"蘋果",
                price: 20
            },
        },
        watch:{
            fruit:{// 此時(shí)fruite 就是一個(gè)配置對象,里面的屬性都是配置選項(xiàng)
                // handler 就是原來的監(jiān)聽函數(shù), 當(dāng)數(shù)據(jù)變化是執(zhí)行的函數(shù)
                handler(val,oldval){
                    console.log(val);
                    console.log(oldval);            

                },
                // 深度監(jiān)聽選項(xiàng)
                deep:true
            }
        }
    })
</script>

此時(shí)我們就做到了即監(jiān)聽這整個(gè)對象的變化, 也簡體對象里面所有的屬性的變化,


4.2 immediate選項(xiàng)

監(jiān)聽除了deep選項(xiàng)外,還有immediate選項(xiàng)

指定 immediate: true 將立即以表達(dá)式的當(dāng)前值觸發(fā)回調(diào),

watch:{
    fruit:{// 此時(shí)fruite 就是一個(gè)配置對象,里面的屬性都是配置選項(xiàng)
        // handler 就是原來的監(jiān)聽函數(shù), 當(dāng)數(shù)據(jù)變化是執(zhí)行的函數(shù)
        handler(val,oldval){
            console.log(val);
            console.log(oldval);            

        },
            // 深度監(jiān)聽選項(xiàng)
        deep:true,
        immediate: true  // 理解執(zhí)行監(jiān)聽函數(shù)handler
    }
}


5. 引用類型深度監(jiān)聽后,屬性變化,獲取新舊值問題

但是細(xì)心的朋友就會(huì)發(fā)現(xiàn)我們在改變對象屬性的時(shí)候,雖然觸發(fā)了偵聽器,但是我沒發(fā)獲取舊值了,我們拿到的兩個(gè)形參的值都是對象更改后的新值.

出于某種原因沒有深入過濾對象的每個(gè)屬性,那么只能監(jiān)聽到對象的變化脸哀,而JavaScript里對象的賦值是引用賦值蹦浦,雖然屬性變化了,但是它引用的地址卻一直沒有變化撞蜂,這樣的話盲镶,當(dāng)對象的屬性值改變了侥袜,Vue雖然知道它改變了,但也只能循著引用地址去獲得對象溉贿,可此時(shí)對象的屬性的值已經(jīng)改變了枫吧,因此Vue并不能得到變異之前的值。

示例:

<div id="app">
    <!-- 監(jiān)聽器 -->
    <input type="text" v-model.number="fruit.price">

</div>

<script>   

    const vm = new Vue({
        el: "#app",
        data: {
            fruit:{
                name:"蘋果",
                price: 20
            },

        },
        watch:{
            fruit:{
                handler(val,oldval){
                    console.log(11)
                    console.log(val);
                    console.log(oldval);            

                },
                deep:true
            }
        },

    })
</script>

此時(shí)當(dāng)數(shù)據(jù)發(fā)生變化是, 查看handler 兩個(gè)參數(shù)值

監(jiān)聽屬性.png


5.1 解決方案: 利用計(jì)算屬性

官方方案: 觀察 Vue 實(shí)例變化的一個(gè)表達(dá)式或計(jì)算屬性函數(shù)宇色【旁樱回調(diào)函數(shù)得到的參數(shù)為新值和舊值。表達(dá)式只接受監(jiān)督的鍵路徑宣蠕。對于更復(fù)雜的表達(dá)式例隆,用一個(gè)函數(shù)取代


既然 watch無法在變異對象或數(shù)組時(shí)監(jiān)聽新舊值,那么我們可以先使用JSON.parse()來淺復(fù)制一遍data對象抢蚀,然后在復(fù)制的對象上修改镀层,完了重新賦值給該data對象,這樣變化前后兩個(gè)對象是完全不一樣的,因?yàn)樗鼈兊囊玫刂吠耆灰粯用笄琕ue可以循著兩個(gè)引用地址獲得新舊兩個(gè)

<div id="app">
    <!-- 監(jiān)聽器 -->
    <input type="text" v-model.number="fruit.price">

</div>

<script>   

    const vm = new Vue({
        el: "#app",
        data: {
            fruit:{
                name:"蘋果",
                price: 20
            },

        },
        watch:{
            fruitNew:{
                handler(val,oldval){
                    console.log(11)
                    console.log(val);
                    console.log(oldval);            

                },
                deep:true
            }
        },
        computed:{
            fruitNew(){
                return JSON.parse(JSON.stringify(this.fruit));
            }
        },
    })
</script>


6. 可以通過Vue是實(shí)例對象的$watch屬性來監(jiān)聽

除了 watch 選項(xiàng)之外唱逢,您還可以使用命令式的 vm.$watch ,通過Vue實(shí)例對象來監(jiān)聽數(shù)據(jù)


6.1 普通監(jiān)聽

可以通過實(shí)例對象調(diào)用$watch設(shè)置監(jiān)聽

<!-- 監(jiān)聽字符變化-->
<div id="app">
    <!-- 監(jiān)聽器 -->
    <input type="text" v-model="msg">

</div>

<script>   
    const vm = new Vue({
        el: "#app",
        data: {
            msg:'你好'
        }
    })
    
    // $watch 是一個(gè)實(shí)例方法
    vm.$watch("msg",(val,newVal) => {
        console.log(val)
        console.log(newVal);       
    })
</script>


6.2 監(jiān)聽配置
<div id="app">
    <!-- 監(jiān)聽器 -->
    <input type="text" v-model.number="fruit.price">
</div>

<script>   
    const vm = new Vue({
        el: "#app",
        data: {
            fruit:{
                name:"蘋果",
                price: 20
            },
        }
    })
    
    // $watch 是一個(gè)實(shí)例方法
    vm.$watch("fruit",(val,newVal) => {
        console.log(val)
        console.log(newVal);       
    },{
        deep: true
    })
</script>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市谷饿,隨后出現(xiàn)的幾起案子惶我,更是在濱河造成了極大的恐慌,老刑警劉巖博投,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绸贡,死亡現(xiàn)場離奇詭異,居然都是意外死亡毅哗,警方通過查閱死者的電腦和手機(jī)听怕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來虑绵,“玉大人尿瞭,你說我怎么就攤上這事〕峋Γ” “怎么了声搁?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長捕发。 經(jīng)常有香客問我疏旨,道長,這世上最難降的妖魔是什么扎酷? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任檐涝,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘谁榜。我一直安慰自己幅聘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布窃植。 她就那樣靜靜地躺著帝蒿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪撕瞧。 梳的紋絲不亂的頭發(fā)上陵叽,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天,我揣著相機(jī)與錄音丛版,去河邊找鬼巩掺。 笑死,一個(gè)胖子當(dāng)著我的面吹牛页畦,可吹牛的內(nèi)容都是我干的胖替。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼豫缨,長吁一口氣:“原來是場噩夢啊……” “哼独令!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起好芭,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤燃箭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后舍败,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體招狸,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年邻薯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了裙戏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,133評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡厕诡,死狀恐怖累榜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情灵嫌,我是刑警寧澤壹罚,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站寿羞,受9級特大地震影響猖凛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜稠曼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一形病、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧霞幅,春花似錦漠吻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至扔傅,卻和暖如春耍共,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背猎塞。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工试读, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人荠耽。 一個(gè)月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓钩骇,卻偏偏與公主長得像,于是被迫代替她去往敵國和親铝量。 傳聞我的和親對象是個(gè)殘疾皇子倘屹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評論 2 355