vue——計算屬性和偵聽器

1、計算屬性(data中的相關數據)

  偵聽多個屬性時——計算屬性 comutedjavascript

  模板內的表達式很是便利,可是設計它們的初衷是用於簡單運算的。在模板中放入太多的邏輯會讓模板太重且難以維護。例如: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!若是你不但願有緩存,請用方法來替代。

一、計算屬性之computed

<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>

(1)頁面顯示效果

  

(2)按鈕點擊後顯示效果

   

(3)分析程序

  var str = `${this.myName}它的年齡是${this.age}   在實時監聽data中聲明的數據的變化

  點擊事件,對數據屬性進行修改,因爲計算屬性的實時監聽,就察覺了數據的修改。

  因爲計算屬性方法用模板插值關聯,所以alexDesc函數的返回值就直接顯示在模板中了。

  

二、計算屬性的setter方法

  計算屬性默認只有 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>

(1)計算屬性setter固定編寫套路

computed:{
    alexDesc:{
        // setter
        set:function (newValue) {
            console.log(newValue);
            this.myName = newValue;
        },
        // getter
        get:function(){
            var str = `${this.myName}它的年齡是${this.age}
                歲了能夠去大保健了`;

            return str;
        }
    }
}

(2)顯示效果

  

(3)點擊事件傳值給計算屬性setter方法

   

三、進一步理解setter用途

<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>。

四、計算屬性案例——音樂播放器

(1)構建音樂播放器頁面

  <audio>標籤是 HTML5 的新標籤。<audio>標籤訂義聲音,好比音樂或其餘音頻流。

  • autoplay屬性:若是出現該屬性,則音頻在就緒後立刻播放。
  • src屬性:要播放音頻的URL。
  • controls屬性:若是出現該屬性,則向用戶顯示控件,好比播放控件。
  • loop屬性:若是出現該屬性,則每當音頻結束時從新開始播放。
  • muted屬性:規定視頻輸出應該被靜音。
  • preload屬性:若是出現該屬性,則音頻在頁面加載時進行加載,並預備播放。若是使用 "autoplay",則忽略該屬性。

 

<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>

  顯示效果:

  

(2)計算屬性監聽切換播放歌曲

<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>

(3)再也不監聽musicSrc,改成監聽musics數組

<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>

(4)添加點選切換樣式

<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,顯示效果以下所示:

  

 

2、偵聽器(watch)

  雖然計算屬性在大多數狀況下更合適,但有時也須要一個自定義的偵聽器。所以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>

  顯示效果:

  

 3、計算屬性 vs 偵聽屬性 對比

  偵聽器偵聽的是單個屬性

  計算屬性偵聽多個屬性; 

  Vue 提供了一種更通用的方式來觀察和響應 Vue 實例上的數據變更:偵聽屬性。當你有一些數據須要隨着其它數據變更而變更時,你很容易濫用 watch——特別是若是你以前使用過 AngularJS。然而,一般更好的作法是使用計算屬性而不是命令式的 watch 回調

一、命令式的 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>

  修改成計算屬性的版本,明顯比上面命令式的要好得多。顯示效果以下所示:

  

相關文章
相關標籤/搜索