Vue中容易被忽視的知識點

NO IMAGE

前言

Vue的學習成本和難度不高,這除了和框架本身的設計理念有關之外,還和Vue完善的官方文檔有著密不可分的關係,相信有很多的開發者和我一樣,很長時間沒有仔細去看過官方文檔了,最近花時間仔細看了一下官方文檔,將裡面一些容易忽視的點整理出來和大家分享。

容易忽視的點

箭頭函數的使用

ES6的普及使得箭頭函數的使用更加頻繁,但是在Vue中不要在選項屬性或者回調上使用箭頭函數,舉個例子:

new Vue({
el: '#app',
data: {
show: true
},
created: () => {
console.log(this.show)
},
})

將created鉤子寫成箭頭函數,這裡的this將不再指向Vue對象,在瀏覽器中將會指向window對象,這是因為箭頭函數並沒有this,this會作為變量一直向上級詞法作用域查找,直到找到為止

指令動態參數

Vue從2.6.0開始,可以用方括號括起來的JavaScript表達式作為一個指令參數,舉個例子:

<div id="app">
<input v-on:[event] = "doSomething">
<button v-on:click="event = 'focus'">change</button>
</div>
new Vue({
el: '#app',
data() {
return {
event: 'input'
}
},
methods: {
doSomething () {
console.log('sss')
}
},
})

這裡將input的事件監聽設置為一個動態的參數event,默認是監聽點擊事件,當點擊change的時候,改為監聽focus事件,動態參數預期會求出一個字符串,異常情況下值為null,null值可以用於移除綁定,任何其他非字符串類型的值都會觸發一個警告

template中使用方法

methods中提供的方法大多數時候都是用來給其他方法調用的,但是它其實也可以像computed計算屬性一樣直接寫在模版裡,舉個例子:

<div id="app">{{reversedMessage('hello')}}</div>
var app = new Vue({
el: '#app',
methods: {
reversedMessage: function (message) {
return message.split('').reverse().join('')
}
},
})

有了computed計算屬性,為什麼還要用methods呢?計算屬性是基於響應式依賴進行緩存的,只在相關依賴發生改變時才會重新求值,而methods每次調用都會重新計算,調用methods時可以傳參,進行指定計算,但是computed不行,這在遍歷數組時十分有用

用key管理可複用元素

Vue會儘可能高效地渲染元素,通常會複用已有元素而不是從頭開始渲染。這麼做會使 Vue變得非常快,舉個例子:

<div id="app">
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address">
</template>
<button @click="change">change</button>
</div>
var app = new Vue({
el: '#app',
data() {
return {
loginType: 'username'
}
},
methods: {
change () {
this.loginType = this.loginType === 'username' ? 'email' : 'username'
}
}
})

上面代碼中切換loginType將不會清除用戶已經輸入的內容,因為兩個模版使用了相同的元素,如果不想複用也很簡單,只需要添加一個具有唯一值的key屬性即可:

<template v-if="loginType === 'username'">
<label>Username</label>
<input key="username" placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input key="email" placeholder="Enter your email address">
</template>
<button @click="change">change</button>

現在切換,每次都會重新渲染,但是label元素還是會被複用,因為它沒有加唯一key值

v-if與v-for一起使用

Vue的風格指南不推薦同時使用v-if與v-for,當項目中的eslint繼承了@vue/standard時,同時使用就會編譯報錯,但是可以通過在模版上加<!– eslint-disable –>進行忽略,同時當它們處於同一節點,v-for的優先級比v-if更高,這意味著v-if 將分別重複運行於每個v-for循環中

對象變更檢測

在Vue中對於已經創建的實例,不允許動態添加根級別的響應式屬性,但是我們知道可以通過Vue.set(object, propertyName, value)方法向嵌套對象添加響應式屬性,那如果需要為已有對象賦值多個新屬性呢?舉個例子:

<div id="app">{{user.name}}-{{user.age}}-{{user.sex}}</div>
var app = new Vue({
el: '#app',
data() {
return {
user: {
name: 'xxx'
}
}
},
created() {
this.user = Object.assign({}, this.user, {
age: 18,
sex: 'name'
})
},
})

可以用Object.assign為這個對象重新賦值,這樣就能添加多個新的響應式屬性

內聯方法訪問原始DOM事件

有時在模版中調用方法時,我們需要向方法中傳參數,但是同時又要傳遞原始的DOM事件,怎麼處理呢?舉個例子:

<div id="app">
<button @click="share('share info', $event)">share</button>
</div>
var app = new Vue({
el: '#app',
data() {
return {
user: {
name: 'xxx'
}
}
},
methods: {
share (info, event) {
console.log(info, event)
}
},
})

如例子所示,可以用特殊變量$event把它傳入方法

once、passive事件修飾符

Vue中提供了多個事件修飾符, once、passive是後面新增的兩個,once用於限定事件只觸發一次,passive用於修飾的事件發生後立即觸發,用於提升移動端性能

表單輸入修飾符

.lazy

在默認情況下,v-model在每次input事件觸發後將輸入框的值與數據進行同步,可以添加lazy修飾符,從而轉變為使用change事件進行同步,舉個例子:

<input placeholder="lazy" v-model.lazy="msg" @input="input" @change="change">

.number

如果想自動將用戶的輸入值轉為數值類型,可以給v-model添加number修飾符,這通常很有用,因為即使在type=”number”時,HTML輸入元素的值也總會返回字符串。如果這個值無法被 parseFloat()解析,則會返回原始的值,舉個例子:

<input placeholder="number" v-model.number="age" @input="input">

.trim

如果要自動過濾用戶輸入的首尾空白字符,可以給v-model添加trim修飾符,舉個例子:

<input placeholder="trim" v-model.trim="trim" @input="input">

子組件替換/合併已有的特性

在Vue中對於絕大多數特性來說,從外部提供給組件的值會替換掉組件內部設置好的值。所以如果傳入type=”text”就會替換掉 type=”date”並把它破壞!慶幸的是,class和 style特性會稍微智能一些,即兩邊的值會被合併起來,從而得到最終的值,舉個例子:

<div id="app">
<base-input type="text" class="out"></base-input>
</div>
Vue.component('base-input', {
template: `<input type="date" placeholder="replace" class="default">`
})
new Vue({
el: '#app',
})

在上例中input的type值為date,class為deafault,在使用子組件時,向子組件中傳入type=”text” class=”out”,此時input的type值會被替換為text,class值會被合併為”default out”,那麼如果想要禁用屬性繼承怎麼辦呢?可以在組件的選項中設置inheritAttrs:false,舉個例子:

Vue.component('base-input', {
inheritAttrs: false,
template: `<input type="date" placeholder="replace" class="default">`
})

但是inheritAttrs:false選項不會影響style和class的綁定,因此style和class還是會合並

.sync修飾符

在有些情況下,可能需要對一個 prop進行“雙向綁定”。不幸的是,真正的雙向綁定會帶來維護上的問題,因為子組件可以修改父組件,且在父組件和子組件都沒有明顯的改動來源,因此Vue提供了sync修飾符,舉個例子:

<div id="app">
<span>{{title}}</span>
<text-document v-bind:title.sync="title"></text-document>
</div>
Vue.component('text-document', {
props: ['title'],
template: `<button @click="change">change</button>`,
methods: {
change () {
this.$emit('update:title', 'change')
}
},
})
new Vue({
el: '#app',
data() {
return {
title: 'default'
}
}
})

當調用this.$emit(‘update:title’, ‘change’),父組件中的title就會改變

總結

這篇文章對Vue中一些容易忽視的點進行了簡單的總結,希望看完之後能對大家有所幫助。
如果有錯誤或不嚴謹的地方,歡迎批評指正,如果喜歡,歡迎點贊

相關文章

if我是前端Leader,談談前端框架體系建設