zoukankan      html  css  js  c++  java
  • vue——计算属性和侦听器

    一、计算属性(data中的相关数据)

      侦听多个属性时——计算属性 comuted

      模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如:

    <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 的翻转字符串。显示效果如下:

      

      当你想要在模板中多次引用此处的翻转字符串时,就会更加难以处理。

      所以,对于任何复杂逻辑,都应当使用计算属性

    <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)为什么会这样呢?

      因为Vue知道com.currentMsg依赖与com.msg,因此当com.msg发生改变时,所有依赖com.currentMsg的绑定也会更新。而且最妙的是我们已经以声明的方式创建了这种依赖关系。:计算属性的getter函数是没有副作用的,这使它更易于测试和理解。

    (2)同样的上面操作,我们不用computed声明的计算属性方法,而仅仅通过methods中声明的方法也能完成上面的效果,那么为什么又要使用computed方法呢?

      因为计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。这就意味着只要msg还没有发生变化,多次访问currentMsg计算属性会立刻返回之前计算的结果,而不比再次执行函数。同样的。每当触发重新渲染时,调用方法将总会执行函数。

    (3)我们为什么需要缓存?

      假设我们有一个性能开销比较大的的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 A 。如果没有缓存,我们将不可避免的多次执行 A 的 getter!如果你不希望有缓存,请用方法来替代。

    1、计算属性之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函数的返回值就直接显示在模板中了。

      

    2、计算属性的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方法

       

    3、进一步理解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>。

    4、计算属性案例——音乐播放器

    (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,显示效果如下所示:

      

    二、侦听器(watch)

      虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。因此Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

    1、简单侦听器示例

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

      

    2、结合其他属性一起检测

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

      显示效果:

      

     三、计算属性 vs 侦听属性 对比

      侦听器侦听的是单个属性

      计算属性侦听多个属性; 

      Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch——特别是如果你之前使用过 AngularJS。然而,通常更好的做法是使用计算属性而不是命令式的 watch 回调

    1、命令式的 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判断,显示效果如下所示:

      

    2、计算属性版本

      上面的代码是命令式且重复的,将它与计算属性的版本进行比较:

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

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

      

  • 相关阅读:
    hdu 1042 N!
    hdu 1002 A + B Problem II
    c++大数模板
    hdu 1004 Let the Balloon Rise
    hdu 4027 Can you answer these queries?
    poj 2823 Sliding Window
    hdu 3074 Multiply game
    hdu 1394 Minimum Inversion Number
    hdu 5199 Gunner
    九度oj 1521 二叉树的镜像
  • 原文地址:https://www.cnblogs.com/xiugeng/p/9624650.html
Copyright © 2011-2022 走看看