zoukankan      html  css  js  c++  java
  • 【转】 再探Vue的Watch、Computed、Filter

    【转】 再探Vue的Watch、Computed、Filter

    watch

    看完本小节你将了解:

    • 什么情况下需要watch?
    • 如何对普通属性进行watch?
    • 如何对对象属性进行watch?
    • 什么是深度watch?
    • 如何提高对对象属性watch的效率?
    • 如何让watch立即生效?

    假设我们要实现下面的效果:

    需求:

    我们期望,页面上的FullName = FirstName + LastName,并且当我们在页面上动态的改动FirstName或者LastName时,FullName也可以随着改变。

    实现思路:

    • 通过computed计算FirstName和LastName得到新的属性FullName
    • 对FirstName和LastName进行监听,当他们被改变时,在相关的回调函数中去去改FullName

    其实在开始看实现的代码之后,可以先问问自己,还记不记得什么是数据的单向绑定和双向绑定。

    我们平时在页面上写的 v-model, 实际上做了个双向的数据绑定,实现的效果:如果data中的数据发生了变化,页面上的数据也会实时变化,但是反过来,如果我们在页面上对数据进行修改,data中的属性值同样会被改变。但是问题出在哪里呢?

    问题就出在:我们如何捕获到属性值改变这个事件??? 如果连这个事件我们都捕获不到,又怎么能进一步改变FullName的值呢?

    于是我们使用侦听:watch

    我们可以对某个属性进行侦听:实现的效果就是,当属性被改变时,方法会被自动的回调

    下面是实现代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="./vue/dist/vue.js"></script>
        <script src="./vue-router/dist/vue-router.js"></script>
    </head>
    <body>
    
    <div id="app">
        <p>FirstName: <input type="text" v-model="firstName"></p>
        <p>LastName: <input type="text" v-model="lastName"></p>
        <p>FullName: {{fullName}}</p>
        <button @click="test"> 点我</button>
    </div>
    </body>
    
    <script>
        new Vue({
            el: '#app',
            data: {
                firstName: '',
                lastName: '',
                fullName: ''
            },
            watch: {
                firstName(newName, oldName) {
                    this.fullName = newName + ' ' + this.lastName;
                },
                lastName: {
                    handler(newVal, oldVal) {
                        console.log(newVal)
                        console.log(oldVal)
                        this.fullName = this.firstName + ' ' + newVal;
                    }
                }
            },
            methods: {
                test() {
                    console.log(this.firstName)
                }
            }
        })
    </script>
    </html>
    

    上面的demo中是对普通属性进行监听,那么我们更进一步,如果需要被监听的属性是对象的某个属性呢?

    比如它长成下面的样子:

     				data: {
                fullName: '',
                obj:{
                    firstName: '',
                    lastName: '',
                }
            }
    

    此时还按照上面的写法已经不管用了。

    如果我们监控的是对象中的一个属性,我们可以粗略的对整个东西进行深度监控:, 当然这种效果肯定是能实现的,但是不好的地方也会有,那就是开销太大了,只要是对象的属性值被改动了,回调方法就会被触发

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="./vue/dist/vue.js"></script>
        <script src="./vue-router/dist/vue-router.js"></script>
    </head>
    <body>
    
    <div id="app">
        <p>FirstName: <input type="text" v-model="obj.firstName"></p>
        <p>LastName: <input type="text" v-model="obj.lastName"></p>
        <p>FullName: {{fullName}}</p>
    </div>
    </body>
    
    <script>
        new Vue({
            el: '#app',
            data: {
                obj: {
                    firstName: '123',
                    lastName: '456',
                },
                fullName: '',
    
            },
            watch: {
                obj: {
                    handler(newVal, oldVal) {
                        console.log(newVal)
                        console.log(oldVal)
                    },
                    deep:true
                }
            }
        })
    </script>
    </html>
    

    针对上面效率低的情况,我们可以像下面这样优化:监听对象指定的元素

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="./vue/dist/vue.js"></script>
        <script src="./vue-router/dist/vue-router.js"></script>
    </head>
    <body>
    
    <div id="app">
        <p>FirstName: <input type="text" v-model="obj.firstName"></p>
        <p>LastName: <input type="text" v-model="obj.lastName"></p>
        <p>FullName: {{fullName}}</p>
    </div>
    </body>
    
    <script>
        new Vue({
            el: '#app',
            data: {
                obj: {
                    firstName: '123',
                    lastName: '456',
                },
                fullName: '',
    
            },
            watch: {
               'obj.firstName': {
                    handler(newVal, oldVal) {
                        this.fullName = newVal + ' ' + this.obj.lastName;
                    },
                },
                'obj.lastName': {
                    handler(newVal, oldVal) {
                        this.fullName = this.obj.firstName + ' ' + newVal;
                    },
                }
            }
        })
    </script>
    </html>
    

    上面这个demo的运行起来后,刷新浏览器效果如下:

    可以比较直观的看到,第一次刷新后FullName并没有被渲染上,如果我们想FullName立即被渲染上,可以在watch中添加属性 immediate:true表示立即生效,如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="./vue/dist/vue.js"></script>
        <script src="./vue-router/dist/vue-router.js"></script>
    </head>
    <body>
    
    <div id="app">
        <p>FirstName: <input type="text" v-model="obj.firstName"></p>
        <p>LastName: <input type="text" v-model="obj.lastName"></p>
        <p>FullName: {{fullName}}</p>
    </div>
    </body>
    
    <script>
        new Vue({
            el: '#app',
            data: {
                obj: {
                    firstName: '123',
                    lastName: '456',
                },
                fullName: '',
            },
            watch: {
               'obj.firstName': {
                    handler(newVal, oldVal) {
                        this.fullName = newVal + ' ' + this.obj.lastName;
                    },
                    immediate:true
                },
                'obj.lastName': {
                    handler(newVal, oldVal) {
                        console.log(newVal)
                        console.log(oldVal)
                        this.fullName = this.obj.firstName + ' ' + newVal;
                    },
                    immediate:true
                }
            }
        })
    </script>
    </html>
    

    效果图:

    computed

    很多人都会把computed和watch一起看,对于新学vue或者上学了一段时间又长时间不看的vue的同学,就容易搞不清他们的区别。

    可以看下这份笔记中的计算属性部分:点击查看

    简单的说一下watch和计算属性的区别:

    watch:重点是对data中现有的属性进行侦听,当它的值发生改变时,触发相关回调函数。

    comouted:重点是根据data中现有的属性进行计算,从而得到一个新的属性。

    filter

    如果我们需要对从后端拉去回来的值进行处理,可以考虑使用filter。

    看下面这个简单的Demo: 经过过滤器的处理,我们可以得到最终的结果为100

    过滤器的一个第一个参数就是|左边的msg

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="./vue/dist/vue.js"></script>
        <script src="./vue-router/dist/vue-router.js"></script>
    </head>
    <body>
    <div id="app">
        <p>{{msg|numFormat}}</p>
    </div>
    </body>
    
    <script>
        // 注册全局过滤器
        // 第一个参数就是上面 | 左边的参数
        Vue.filter("numFormat", function (val) {
            return val / 100
        })
    
        var app = new Vue({
            el: '#app',
            data: {
                msg: 10000,
            },
        })
    </script>
    </html>
    

    我们还可以为过滤器添加更多的参数, demo如下

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="./vue/dist/vue.js"></script>
        <script src="./vue-router/dist/vue-router.js"></script>
    </head>
    <body>
    <div id="app">
        <p>{{msg|numFormat(566)}}</p>
    </div>
    </body>
    
    <script>
        // 注册全局过滤器
        // 第一个参数就是上面 | 左边的参数
        Vue.filter("numFormat", function (val,args) {
            return val + args
        })
    
        var app = new Vue({
            el: '#app',
            data: {
                msg: 100,
            },
        })
    </script>
    </html>
    

    此外,我们的过滤器是可以多个串联在一起的。

    {msg | 过滤器1 | 过滤器2 | 过滤器3}
    

    其次我们还能通过v-bind添加过滤器:

    v-bind: msg = "值 | 过滤器"
    

    如果filter出现在单个vue组件中,那这个过滤器就是局部过滤器,仅针对当前vue组件生效。

  • 相关阅读:
    JavaScript cookie详解
    Javascript数组的排序:sort()方法和reverse()方法
    javascript中write( ) 和 writeln( )的区别
    div做表格
    JS 盒模型 scrollLeft, scrollWidth, clientWidth, offsetWidth 详解
    Job for phpfpm.service failed because the control process exited with error code. See "systemctl status phpfpm.service" and "journalctl xe" for details.
    orm查询存在价格为空问题
    利用救援模式破解系统密码
    SSH服务拒绝了密码
    C# 调用 C++ DLL 中的委托,引发“对XXX::Invoke类型的已垃圾回收委托进行了回调”错误的解决办法
  • 原文地址:https://www.cnblogs.com/Javastudy-note/p/13813852.html
Copyright © 2011-2022 走看看