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>

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

  

相关文章
相关标签/搜索