計(jì)算屬性
基礎(chǔ)例子
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 計(jì)算屬性的 getter
reversedMessage: function () {
// `this` 指向 vm 實(shí)例
return this.message.split('').reverse().join('')
}
}
})
console.log(vm.reversedMessage) // => 'olleH'
vm.message = 'Goodbye'
console.log(vm.reversedMessage) // => 'eybdooG'
可以像綁定普通屬性一樣在模板中綁定計(jì)算屬性。Vue
知道vm.reversedMessage
依賴于vm.message
,因此當(dāng)vm.message
發(fā)生改變時(shí)粗截,所有依賴vm.reversedMessage
的綁定也會(huì)更新。
計(jì)算屬性緩存vs方法
我們可以通過(guò)在表達(dá)式中調(diào)用方法來(lái)達(dá)到同樣的效果泛鸟。
<p>Reversed message: "{{ reversedMessage() }}"</p>
// 在組件中
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
我們可以將同一函數(shù)定義為一個(gè)方法而不是一個(gè)計(jì)算屬性奄容。兩種方式的最終結(jié)果確實(shí)是完全相同的。然而暂刘,不同的是計(jì)算屬性是基于它們的依賴進(jìn)行緩存的饺谬。計(jì)算屬性只有在它的相關(guān)依賴發(fā)生改變時(shí)才會(huì)重新求值。這就意味著只要message
還沒(méi)有發(fā)生改變,多次訪問(wèn)reversedMessage
計(jì)算屬性會(huì)立即返回之前的計(jì)算結(jié)果募寨,而不必再次執(zhí)行函數(shù)族展。
這也同樣意味著下面的計(jì)算屬性將不再更新,因?yàn)?code>Date.now()不是響應(yīng)式依賴拔鹰。
computed: {
now: function () {
return Date.now()
}
}
相比之下仪缸,每當(dāng)觸發(fā)重新渲染時(shí),調(diào)用方法將總會(huì)再次執(zhí)行函數(shù)列肢。
計(jì)算屬性vs偵聽(tīng)屬性
Vue
提供了一種更通用的方式來(lái)觀察和響應(yīng)Vue
實(shí)例上的數(shù)據(jù)變動(dòng):偵聽(tīng)屬性恰画。
當(dāng)有一些數(shù)據(jù)需要隨著其它數(shù)據(jù)變動(dòng)而變動(dòng)時(shí),更好的做法是使用計(jì)算屬性而不是命令式的watch
回調(diào)瓷马。
計(jì)算屬性的setter
計(jì)算屬性默認(rèn)只有getter
拴还,不過(guò)在需要時(shí)也可以提供一個(gè)setter
。
// ...
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
// ...
現(xiàn)在再運(yùn)行vm.fullName='John Doe'
時(shí)欧聘,setter
會(huì)被調(diào)用片林,vm.firstName
和vm.lastName
也會(huì)相應(yīng)地被更新。
偵聽(tīng)器
雖然計(jì)算屬性在大多數(shù)情況下更合適怀骤,但有時(shí)也需要一個(gè)自定義的偵聽(tīng)器费封。這就是為什么Vue
通過(guò)watch
選項(xiàng)提供了一個(gè)更通用的方法,來(lái)響應(yīng)數(shù)據(jù)的變化蒋伦。當(dāng)需要在數(shù)據(jù)變化時(shí)執(zhí)行異步或開(kāi)銷較大的操作時(shí)弓摘,這個(gè)方式是最有用的。
<div id="watch-example">
<p>
Ask a yes/no question:
<input v-model="question">
</p>
<p>{{ answer }}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
el: '#watch-example',
data: {
question: '',
answer:'I cannot give you an answer until you ask a question!'
},
watch: {
// 如果 `question` 發(fā)生改變痕届,這個(gè)函數(shù)就會(huì)運(yùn)行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.getAnswer()
}
},
methods: {
// `_.debounce` 是一個(gè)通 Lodash限制操作頻率的函數(shù)韧献。
// 在這個(gè)例子中,我們希望限制訪問(wèn)yesno.wtf/api的頻率
// AJAX 請(qǐng)求直到用戶輸入完畢才會(huì)發(fā)出研叫。
getAnswer: _.debounce(
function () {
if (this.question.indexOf('?') === -1) {
this.answer = 'Questions usually contain a question mark. ;-)'
return
}
this.answer = 'Thinking...'
var vm = this
axios.get('https://yesno.wtf/api')
.then(function (response) {
vm.answer = _.capitalize(response.data.answer)
})
.catch(function (error) {
vm.answer = 'Error! Could not reach the API. ' + error
})
},
// 這是我們?yōu)榕卸ㄓ脩敉V馆斎氲却暮撩霐?shù)
500
)
}
})
</script>
在這個(gè)示例中势决,使用watch
選項(xiàng)允許我們執(zhí)行異步操作 (訪問(wèn)一個(gè)API),限制我們執(zhí)行該操作的頻率蓝撇,并在我們得到最終結(jié)果前果复,設(shè)置中間狀態(tài)。這些都是計(jì)算屬性無(wú)法做到的渤昌。
除了watch
選項(xiàng)之外虽抄,還可以使用命令式的vm.$watch API
。
Class 與 Style 綁定
因?yàn)樗鼈兌际菍傩远栏蹋晕覀兛梢杂?code>v-bind處理它們:只需要通過(guò)表達(dá)式計(jì)算出字符串結(jié)果即可迈窟。表達(dá)式結(jié)果的類型除了字符串之外,還可以是對(duì)象或數(shù)組忌栅。
綁定HTML Class
對(duì)象語(yǔ)法
我們可以傳給v-bind:class
一個(gè)對(duì)象车酣,以動(dòng)態(tài)地切換class
曲稼。
<div v-bind:class="{ active:isActive }"></div>
上面的語(yǔ)法表示active
這個(gè)class
存在與否將取決于數(shù)據(jù)屬性isActive
的值。
可以在對(duì)象中傳入更多屬性來(lái)動(dòng)態(tài)切換多個(gè)class
湖员。此外贫悄,v-bind:class
指令也可以與普通的class
屬性共存。
<div class="static" v-bind:class="{active:isActive,'text-danger':hasError}"></div>
data: {
isActive: true,
hasError: false
}
//結(jié)果渲染為:
<div class="static active"></div>
當(dāng)isActive
或者hasError
變化時(shí)娘摔,class
列表將相應(yīng)地更新窄坦。
綁定的數(shù)據(jù)對(duì)象不必內(nèi)聯(lián)定義在模板里。
<div v-bind:class="classObject"></div>
data: {
classObject: {
active: true,
'text-danger': false
}
}
渲染的結(jié)果和上面一樣凳寺。我們也可以在這里綁定一個(gè)返回對(duì)象的計(jì)算屬性鸭津。
<div v-bind:class="classObject"></div>
data: {
isActive: true,
error: null
},
computed: {
classObject: function () {
return {
active: this.isActive && !this.error,
'text-danger': this.error && this.error.type === 'fatal'
}
}
}
數(shù)組語(yǔ)法
我們可以把一個(gè)數(shù)組傳給v-bind:class
,以應(yīng)用一個(gè)class
列表肠缨。
<div v-bind:class="[activeClass, errorClass]"></div>
data: {
activeClass: 'active',
errorClass: 'text-danger'
}
渲染為:
<div class="active text-danger"></div>
如果你也想根據(jù)條件切換列表中的class
逆趋,可以用三元表達(dá)式。
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
這樣寫將始終添加errorClass
晒奕,但是只有在isActive
是true
時(shí)才添加activeClass
父泳。
不過(guò),當(dāng)有多個(gè)條件class
時(shí)這樣寫有些繁瑣吴汪。所以在數(shù)組語(yǔ)法中也可以使用對(duì)象語(yǔ)法。
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
用在組件上
當(dāng)在一個(gè)自定義組件上使用class
屬性時(shí)蒸眠,這些類將被添加到該組件的根元素上面漾橙。這個(gè)元素上已經(jīng)存在的類不會(huì)被覆蓋。
Vue.component('my-component', {
template: '<p class="foo bar">Hi</p>'
})
//在使用它的時(shí)候添加一些class楞卡。
<my-component class="baz boo"></my-component>
//HTML將被渲染為:
<p class="foo bar baz boo">Hi</p>
對(duì)于帶數(shù)據(jù)綁定class
也同樣適用霜运。
<my-component v-bind:class="{ active:isActive }"></my-component>
// 當(dāng)isActive為true時(shí),HTML將被渲染成為:
<p class="foo bar active">Hi</p>
綁定內(nèi)聯(lián)樣式
對(duì)象語(yǔ)法
v-bind:style
的對(duì)象語(yǔ)法看著非常像CSS蒋腮,但其實(shí)是一個(gè)JavaScript對(duì)象淘捡。CSS屬性名可以用駝峰式或短橫線分隔來(lái)命名。
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data: {
activeColor: 'red',
fontSize: 30
}
直接綁定到一個(gè)樣式對(duì)象通常更好池摧,這會(huì)讓模板更清晰焦除。
<div v-bind:style="styleObject"></div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
同樣的,對(duì)象語(yǔ)法常常結(jié)合返回對(duì)象的計(jì)算屬性使用作彤。
數(shù)組語(yǔ)法
v-bind:style
的數(shù)組語(yǔ)法可以將多個(gè)樣式對(duì)象應(yīng)用到同一個(gè)元素上膘魄。
<div v-bind:style="[baseStyles, overridingStyles]"></div>
自動(dòng)添加前綴
當(dāng)v-bind:style
使用需要添加瀏覽器引擎前綴的CSS屬性時(shí),如transform
竭讳,Vue.js
會(huì)自動(dòng)偵測(cè)并添加相應(yīng)的前綴创葡。
多重值
可以為style
綁定中的屬性提供一個(gè)包含多個(gè)值的數(shù)組,常用于提供多個(gè)帶前綴的值绢慢。
<div :style="{ display:['-webkit-box','-ms-flexbox','flex'] }"></div>
這樣寫只會(huì)渲染數(shù)組中最后一個(gè)被瀏覽器支持的值灿渴。在本例中,如果瀏覽器支持不帶瀏覽器前綴的flexbox
,那么就只會(huì)渲染display:flex
骚露。