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>

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

      

  • 相关阅读:
    预览PDF【reactpdf】插件的使用(二)
    多叉merkletree的实现
    中国优秀的架构师是不是出现了严重断层?
    工程师的思维转变
    QCore/Library说明文档
    QParserGenerator代码分析二(A fix&An example)
    山寨STL实现之list
    山寨STL实现笔记
    山寨STL实现之内存池V2
    词法分析器1(正则表达式到εNFA的转换)
  • 原文地址:https://www.cnblogs.com/xiugeng/p/9624650.html
Copyright © 2011-2022 走看看