偵聽多個屬性時——計算屬性 comuted。javascript
模板內的表達式很是便利,可是設計它們的初衷是用於簡單運算的。在模板中放入太多的邏輯會讓模板太重且難以維護。例如:css
<body> <div id="computed"> <div> {{msg.split('').reverse().join('')}} </div> </div> <script type="text/javascript" src="./vue.js"></script> <script type="text/javascript"> var com = new Vue({ el: "#computed", data:{ msg:"Hello World" } }) </script> </body>
在這個地方,模板再也不是簡單的聲明式邏輯。你必須看一段時間才能意識到,這裏是想要顯示變量 message
的翻轉字符串。顯示效果以下:vue
當你想要在模板中屢次引用此處的翻轉字符串時,就會更加難以處理。java
因此,對於任何複雜邏輯,都應當使用計算屬性。數組
<body> <div id="computed"> <div> <!--{{msg.split('').reverse().join('')}}--> {{reverseStr}} </div> <button @click="clickHandler">修改</button> </div> <script type="text/javascript" src="./vue.js"></script> <script type="text/javascript"> var com = new Vue({ el: "#computed", data:{ msg:"Hello World" }, methods:{ clickHandler(){ this.msg = 'Hello Luffy' } }, computed:{ // 計算屬性: watch監聽 // 計算屬性默認只有getter方法,所以必須return reverseStr(){ return this.msg.split('').reverse().join(''); } } }) </script> </body>
當我點擊按鈕的時候更改了當前的數據,同時h3和p標籤中數據也隨時改變。緩存
(1)爲何會這樣呢?app
由於Vue知道com.currentMsg依賴與com.msg,所以當com.msg發生改變時,全部依賴com.currentMsg的綁定也會更新。並且最妙的是咱們已經以聲明的方式建立了這種依賴關係。:計算屬性的getter函數是沒有反作用的,這使它更易於測試和理解。異步
(2)一樣的上面操做,咱們不用computed聲明的計算屬性方法,而僅僅經過methods中聲明的方法也能完成上面的效果,那麼爲何又要使用computed方法呢?函數
由於計算屬性是基於它們的依賴進行緩存的。計算屬性只有在它的相關依賴發生改變時纔會從新求值。這就意味着只要msg尚未發生變化,屢次訪問currentMsg計算屬性會馬上返回以前計算的結果,而不比再次執行函數。一樣的。每當觸發從新渲染時,調用方法將總會執行函數。oop
(3)咱們爲何須要緩存?
假設咱們有一個性能開銷比較大的的計算屬性 A,它須要遍歷一個巨大的數組並作大量的計算。而後咱們可能有其餘的計算屬性依賴於 A 。若是沒有緩存,咱們將不可避免的屢次執行 A 的 getter!若是你不但願有緩存,請用方法來替代。
<body> <div id="app"> <h4>{{alexDesc}}</h4> <button @click="clickHandler">修改</button> </div> <script type="text/javascript" src="./vue.js"></script> <script type="text/javascript"> new Vue({ el:'#app', template:'', data(){ return { myName:'alex', age:18 } }, methods:{ clickHandler(){ this.myName='WUSIR'; this.age=28; } }, computed:{ alexDesc:function () { var str = `${this.myName}它的年齡是${this.age} 歲了能夠去大保健了`;
// 默認只有getter方法 return str; } } }) </script> </body>
var str = `${this.myName}它的年齡是${this.age} 在實時監聽data中聲明的數據的變化。
點擊事件,對數據屬性進行修改,因爲計算屬性的實時監聽,就察覺了數據的修改。
因爲計算屬性方法用模板插值關聯,所以alexDesc函數的返回值就直接顯示在模板中了。
計算屬性默認只有 getter ,不過在須要時也能夠提供一個 setter 。
<body>
<div id="app">
<h4>{{alexDesc}}</h4>
<button @click="clickHandler">修改</button>
</div>
<script type="text/javascript" src="./vue.js"></script>
<script type="text/javascript">
new Vue({
el:'#app',
template:'',
data(){
return {
myName:'alex',
age:18
}
},
methods:{
clickHandler(){
console.log(this.alexDesc);
this.alexDesc = 'ALEX IS SB!!!';
}
},
computed:{
alexDesc:{
// setter
set:function (newValue) {
console.log(newValue);
this.myName = newValue;
},
// getter
get:function(){
var str = `${this.myName}它的年齡是${this.age}
歲了能夠去大保健了`;
return str;
}
}
}
})
</script>
</body>
computed:{ alexDesc:{ // setter set:function (newValue) { console.log(newValue); this.myName = newValue; }, // getter get:function(){ var str = `${this.myName}它的年齡是${this.age} 歲了能夠去大保健了`; return str; } } }
<body> <div id="app"> <input type="text" v-model="alexDesc"> <h4>{{alexDesc}}</h4> <!--<button @click="clickHandler">修改</button>--> </div> <script type="text/javascript" src="./vue.js"></script> <script type="text/javascript"> new Vue({ el:'#app', template:'', data(){ return { myName:'', } }, computed:{ alexDesc:{ // setter,給myName賦新值 set:function (newValue) { this.myName = newValue; }, // getter,實時監聽myName屬性的變化 get:function(){ return this.myName; } } } }) </script> </body>
在input表單中輸入信息,使用v-model進行雙向數據綁定,使用setter給myName賦新值。getter監聽myName屬性的變化,並將值顯示在 <h4>{{ alexDesc }} </h4>。
<audio>標籤是 HTML5 的新標籤。<audio>標籤訂義聲音,好比音樂或其餘音頻流。
<body> <div id="music"> <audio src="../static/那吾克熱-水滴石穿.mp3" controls="" autoplay=""></audio> <ul> <li v-for="(item, index) in musics"> <h3>{{item.id}}--歌曲爲:{{item.name}}</h3> <p>歌手:{{item.author}}</p> </li> </ul> </div> <script type="text/javascript" src="./vue.js"></script> <script type="text/javascript"> var musicData = [{ id:1, name:"那吾克熱-水滴石穿", author:"那吾克熱", songSrc:'../static/那吾克熱-水滴石穿.mp3' }, { id:2, name:"Inna-10 Minutes", author:"Inna", songSrc:'../static/10 Minutes.mp3' }, { id:3, name:"Devotion-My_Prayer", author:"Devotion", songSrc:'../static/My_Prayer.mp3' } ]; new Vue({ el:'#music', data(){ return { musics:musicData } }, template:'' }); </script> </body>
顯示效果:
<body> <div id="music"> <audio v-bind:src="currentSrc" controls="" autoplay=""></audio> <ul> <li v-for="(item, index) in musics" @click="clickHandler(index)"> <!--給每一個li綁定點擊事件--> <h3>{{item.id}}--歌曲爲:{{item.name}}</h3> <p>歌手:{{item.author}}</p> </li> </ul> </div> <script type="text/javascript" src="./vue.js"></script> <script type="text/javascript"> var musicData = [{ id:1, name:"那吾克熱-水滴石穿", author:"那吾克熱", songSrc:'../static/那吾克熱-水滴石穿.mp3' }, { id:2, name:"Inna-10 Minutes", author:"Inna", songSrc:'../static/10 Minutes.mp3' }, { id:3, name:"Devotion-My_Prayer", author:"Devotion", songSrc:'../static/My_Prayer.mp3' } ]; new Vue({ el:'#music', data(){ return { musics:musicData, musicSrc:'../static/那吾克熱-水滴石穿.mp3' } }, methods:{ clickHandler(index){ // 聲明點擊事件 // alert(index); this.musicSrc = this.musics[index].songSrc; // 獲取數組musics中對應index的歌曲資源 } }, computed:{ currentSrc(){ // 實時監聽musicSrc return this.musicSrc; } }, template:'' }); </script> </body>
<body> <div id="music"> <audio v-bind:src="currentSrc" controls="" autoplay=""></audio> <ul> <li v-for="(item, index) in musics" @click="clickHandler(index)"> <!--給每一個li綁定點擊事件--> <h3>{{item.id}}--歌曲爲:{{item.name}}</h3> <p>歌手:{{item.author}}</p> </li> </ul> </div> <script type="text/javascript" src="./vue.js"></script> <script type="text/javascript"> var musicData = [{ id:1, name:"那吾克熱-水滴石穿", author:"那吾克熱", songSrc:'../static/那吾克熱-水滴石穿.mp3' }, { id:2, name:"Inna-10 Minutes", author:"Inna", songSrc:'../static/10 Minutes.mp3' }, { id:3, name:"Devotion-My_Prayer", author:"Devotion", songSrc:'../static/My_Prayer.mp3' } ]; new Vue({ el:'#music', data(){ return { musics:musicData, currentIndex:0 // musicSrc:'../static/那吾克熱-水滴石穿.mp3' } }, methods:{ clickHandler(index){ // 聲明點擊事件 // alert(index); this.currentIndex = index; // 點擊事件修改index } }, computed:{ currentSrc(){ // 實時監聽了兩個屬性:musics、currentIndex return this.musics[this.currentIndex].songSrc // 修改的index會致使獲取的歌曲資源不一樣 } }, template:'' }); </script> </body>
<head> <meta charset="UTF-8"> <title>Title</title> <style type="text/css"> *{ padding: 0; margin: 0; } ul{ list-style: none; } ul li{ margin: 30px 20px; padding: 10px; } ul li.active{ background-color: #20FFFF; } </style> </head> <body> <div id="music"> <audio v-bind:src="currentSrc" controls="" autoplay=""></audio> <ul> <li v-for="(item, index) in musics" @click="clickHandler(index)" :class="{active:currentIndex==index}"> <!--給當前歌曲li添加class=active--> <h3>{{item.id}}--歌曲爲:{{item.name}}</h3> <p>歌手:{{item.author}}</p> </li> </ul> </div> <script type="text/javascript" src="./vue.js"></script> <script type="text/javascript"> var musicData = [{ id:1, name:"那吾克熱-水滴石穿", author:"那吾克熱", songSrc:'../static/那吾克熱-水滴石穿.mp3' }, { id:2, name:"Inna-10 Minutes", author:"Inna", songSrc:'../static/10 Minutes.mp3' }, { id:3, name:"Devotion-My_Prayer", author:"Devotion", songSrc:'../static/My_Prayer.mp3' } ]; new Vue({ el:'#music', data(){ return { musics:musicData, currentIndex:0 // musicSrc:'../static/那吾克熱-水滴石穿.mp3' } }, methods:{ clickHandler(index){ // 聲明點擊事件 // alert(index); this.currentIndex = index; // 點擊事件修改index } }, computed:{ currentSrc(){ // 實時監聽了兩個屬性:musics、currentIndex return this.musics[this.currentIndex].songSrc // 修改的index會致使獲取的歌曲資源不一樣 } }, template:'' }); </script> </body>
點擊事件的時候修改currentIndex,本身的li標籤監聽currentIndex,修改成對應的標籤,添加class=active,顯示效果以下所示:
雖然計算屬性在大多數狀況下更合適,但有時也須要一個自定義的偵聽器。所以Vue 經過 watch
選項提供了一個更通用的方法,來響應數據的變化。當須要在數據變化時執行異步或開銷較大的操做時,這個方式是最有用的。
<body>
<div id="app">
<input type="text" v-model="myName">
<h3>{{myName}}</h3>
</div>
<script type="text/javascript" src="./vue.js"></script>
<script type="text/javascript">
new Vue({
el:'#app',
template:'',
data(){
return {
myName:''
}
},
watch:{
// 檢測單個屬性 命令式
myName:function (value) { // 經過watch來監聽myName屬性
console.log(value);
if (value === 'alex'){
console.log(value+"是sb");
}
}
}
})
</script>
</body>
經過watch來監聽myName屬性的變化,當屬性值爲alex時,控制檯打印alex是sb。
<body> <div id="app"> <input type="text" v-model="myName"> <h3>{{myName}}</h3> </div> <script type="text/javascript" src="./vue.js"></script> <script type="text/javascript"> new Vue({ el:'#app', template:'', data(){ return { myName:'', firstName:'wuSir' } }, watch:{ // 檢測單個屬性 命令式的 myName:function (value) { // 經過watch來監聽myName屬性 console.log(value); if (value === 'alex'){ console.log(value + " " + this.firstName +"是sb"); } } } }) </script> </body>
顯示效果:
偵聽器:偵聽的是單個屬性;
計算屬性:偵聽多個屬性;
Vue 提供了一種更通用的方式來觀察和響應 Vue 實例上的數據變更:偵聽屬性。當你有一些數據須要隨着其它數據變更而變更時,你很容易濫用 watch
——特別是若是你以前使用過 AngularJS。然而,一般更好的作法是使用計算屬性而不是命令式的 watch
回調。
添加按鈕,並給按鈕綁定事件:
<body> <div id="app"> <input type="text" v-model="myName"> <h3>{{myName}}</h3> <button @click="clickHandler">修改</button> </div> <script type="text/javascript" src="./vue.js"></script> <script type="text/javascript"> new Vue({ el:'#app', template:'', data(){ return { myName:'', firstName:'wuSir' } }, methods:{ clickHandler(){ this.myName = '日天'; } }, watch:{ // 檢測單個屬性 命令式的 myName:function (value) { // 經過watch來監聽myName屬性 console.log(value); if (value === 'alex'){ console.log(value + " " + this.firstName +"是sb"); } } } }) </script> </body>
點擊按鈕顯示效果以下:
能夠看到控制檯也輸出「日天」,這個輸出的語句是來自:console.log(value);
若是將事件改成:this.myName = 'alex'; 則還會觸發檢測的if判斷,顯示效果以下所示:
上面的代碼是命令式且重複的,將它與計算屬性的版本進行比較:
<body> <div id="app"> <input type="text" v-model="myName"> <h3>{{myName}}</h3> <button @click="clickHandler">修改</button> </div> <script type="text/javascript" src="./vue.js"></script> <script type="text/javascript"> var vm = new Vue({ el: '#app', data(){ return{ myName: '', firstName: 'wuSir', } }, methods:{ clickHandler(){ this.myName = 'alex'; } }, computed: { fullName: function (value) { // 計算屬性的名字不能與data中屬性同名 if (value === 'alex') { console.log(value + " " + this.firstName + "是sb!") } } } }) </script> </body>
修改成計算屬性的版本,明顯比上面命令式的要好得多。顯示效果以下所示: