美文网首页
Java程序猿的Vue爬坑之路(一)计算属性&侦听属性

Java程序猿的Vue爬坑之路(一)计算属性&侦听属性

作者: 清晨先生2 | 来源:发表于2019-05-31 22:33 被阅读0次

    Vue 的模板内的表达式非常便利,但是万物应有度。在模板中放入太多的逻辑会使代码过于繁重和难以维护。例如:

    <h1>
      {{title.split('').reverse().join('')}}
    </h1>
    

    在这个地方 这个表达式可能就不再是简单的声明式逻辑,我们必须要看一段时间,才能意识到这里是想要显示title值得翻转字符串,如果在代码中大量的引用title的翻转字符串时就会更为难以处理。换言之,如果我们更改下这个表达式,翻转后再次去掉某个字符,页面所有引用该翻转字符串的地方都要重复的进行表达式的更改

    所以,对于任何的对对象原属性(值)的重复或复杂逻辑,二次/多次 处理后进行引用的属性 都应该统一封装,统一声明引用 而在VUE内 我们可以视情况而定 选择 计算属性、侦听器、自定义函数 三种方式进行处理封装。下面具体介绍这三种方式处理数据的方式和引用方式

    计算属性

    计算属性处理数据定义在computed内 ,在模板内使用和使用data内的属性方式一致,可以视为 data的一个包装属性吧

    代码示例:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        </head>
        <body >
            <div id="person">
                <label>原名称:</label>
                <input v-model="person.name" />
                <label>翻转名称:</label>
                <input v-model="reversePersonName" />
                <label>性别:</label>
                <input v-model="person.sex" />
                <label>年龄:</label>
                <input v-model="person.age" />
            </div>
        </body>
        <script>
            new Vue({
                el:"#person",
                data:{
                    person:{
                        name:'Tom',
                        sex:'男',
                        age:18
                    }
                },
                computed:{
                    reversePersonName:function(){
                        return this.person.name.split('').reverse().join('')
                    }
                }
            })
        </script>
    </html>
    
    

    以计算属性的方式对数据进行处理,即第一次渲染该计算属性时,对该数据进行处理后会基于它们的响应式依赖进行缓存,只在相关响应式依赖发生改变后才会进行重新求值。这就意味着 如果name的值没有发生改变 ,多次对reversePersonName进行访问都会立即返回之前的计算结果,而不会进行重复的进行计算。

    而当我们对 原名称 person.name属性的值进行改变时reversePersonName这个计算属性也会重新执行函数 对数据进行修改并更新缓存 重新渲染数据

    但是 官方文档也有提到 计算属性并不支持异步操作比如 调用一个异步的API(AJAX)

    下面我们模仿下异步操作 代码:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        </head>
        <body >
            <div id="person">
                <label>原名称:</label>
                <input v-model="person.name" />
                <label>翻转名称:</label>
                <input v-model="reversePersonName" />
                <label>性别:</label>
                <input v-model="person.sex" />
                <label>年龄:</label>
                <input v-model="person.age" />
            </div>
        </body>
        <script>
            new Vue({
                el:"#person",
                data:{
                    person:{
                        name:'Tom',
                        sex:'男',
                        age:18
                    }
                },
                computed:{
                    reversePersonName:function(){
                        var value=this.person.name.split('').reverse().join('')
                        console.log('计算属性监听到Name发生变化:'+value)
                         // 模仿异步请求接口调用 假设该请求需要1000毫秒才能返回数据 
                        setTimeout(function () {
                            return value
                        }, 1000);
                        
                    }
                }
            })
        </script>
    </html>
    

    代码执行渲染后发现 计算属性已经无法正常渲染数据 甚至初始化渲染时 都无法正常渲染数据

    image-20190531232246827.png

    侦听器(侦听属性)

    侦听器/侦听属性 顾名思义 watch : 这个东西就是一个类似html里的onchange事件的东西,不同的是onchange是用来监听html元素/值的变化 ,watch是用来监听vue实例里的属性的变化的

    不同的是侦听器,只是一个用来监听数据变化的并不能直接在模板直接引用或调用

    使用侦听器想要达到和计算属性同样的效果,必须要增加一个属性来存储进行计算后的结果 随后进行渲染

    代码示例:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        </head>
        <body >
            <div id="person">
                <label>原名称:</label>
                <input v-model="name" />
                <label>翻转名称:</label>
                <input v-model="reversePersonName" />
                <label>性别:</label>
                <input v-model="sex" />
                <label>年龄:</label>
                <input v-model="age" />
            </div>
        </body>
        <script>
            var alt = new Vue({
                el:"#person",
                data:{
                    name:'Tom',
                    sex:'男',
                    age:18,
                    reversePersonName:'moT'
                },
                watch:{
                    name:function(val){
                        this.reversePersonName=val.split('').reverse().join('')
                    }
                }
            })
        </script>
    </html>
    

    运行结果:


    image-20190531225105857.png

    这段代码运行渲染后,结果看起来很正常并且对原名称进行修改 翻转名称也会随之改变 对不对!但是! 还没完!

    当我们把这些属性包装到一个对象内:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        </head>
        <body >
            <div id="person">
                <label>原名称:</label>
                <input v-model="person.name" />
                <label>翻转名称:</label>
                <input v-model="person.reversePersonName"/>
                <label>性别:</label>a
                <input v-model="person.sex" />
                <label>年龄:</label>
                <input v-model="person.age" />
            </div>
        </body>
        <script>
            var alt = new Vue({
                el:"#person",
                data:{
                    person:{
                        name:'Tom',
                        sex:'男',
                        age:18,
                        reversePersonName:'moT'
                    }
                },
                watch:{
                    person:function(val){
                        console.log(val)
                        this.person.reversePersonName=val.name.split('').reverse().join('')
                    }
                    
                }
            })
        </script>
    </html>
    
    

    这个时候渲染结果看起来还是很正常,但是!当你对person的name进行重新赋值或者直接改变input值时,你会发现。 翻转名称的值竟然没有同步更新!!!


    image-20190531225357661.png

    后来查了官方给的文档和部分网上资料,发现了原因

    侦听器默认情况下必须要对侦听的属性 进行更改时才会正常更新缓存 重新渲染数据,因为它默认是没开启深度监听的,这种情况下 不会监听对象内部的属性变化,数组是可以的

    侦听器可以定义三个参数

    • 第一个 handler:其值是一个回调函数。即监听到变化时应该执行的函数。
    • 第二个 deep:其值是true或false;确认是否深入监听。(一般监听时是不能监听到对象属性值的变化的,数组的值变化可以听到。)
    • 第三个 immediate:其值是true或false;确认是否以当前的初始值执行handler的函数

    所以我们侦听器可以换成这种写法:

    watch:{
            person:{
                    handler:function(newVal,oldVal){
                            this.person.reversePersonName=val.name.split('').reverse().join('')
                    },
                    deep:true,
                    immediate:true
            }
    
    }
    

    并且侦听器是支持异步操作的(执行一个异步API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

    模仿异步API访问 代码示例:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        </head>
        <body >
            <div id="person">
                <label>原名称:</label>
                <input v-model="person.name" />
                <label>翻转名称:</label>
                <input v-model="person.reversePersonName"/>
                <label>性别:</label>a
                <input v-model="person.sex" />
                <label>年龄:</label>
                <input v-model="person.age" />
            </div>
        </body>
        <script>
            var alt = new Vue({
                el:"#person",
                data:{
                    person:{
                        name:'Tom',
                        sex:'男',
                        age:18,
                        reversePersonName:'moT'
                    }
                },
                watch:{
                    person:{
                        handler:function(newval,oldval){
                            this.person.reversePersonName='计算中:模拟API访问...'
                            setTimeout(function () {
                                this.reversePersonName=newval.name.split('').reverse().join('')
                            }, 0)
                        },
                        deep:true,
                        immediate:true
                    }
                }
            })
        </script>
    </html>
    

    自定义函数

    自定义函数处理数据方式如下,我们在模板内 调用函数来获取并渲染数据

    使用自定义函数来处理并渲染数据是不会使用缓存的,即:无论原属性的值 有没有发生变化 每次在模板内引用该函数,都会重新计算并渲染数据,这样在大量的数据操作时对网页渲染性能造成的影响降是灾难级的,慎用。

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        </head>
        <body >
            <div id="person">
                <label>名称:{{reversePersonName()}}</label>
                
                <label>性别:</label>
                <input v-model="person.sex" />
                <label>年龄:</label>
                <input v-model="person.age" />
            </div>
        </body>
        <script>
            new Vue({
                el:"#person",
                data:{
                    person:{
                        name:'Tom',
                        sex:'男',
                        age:18
                    }
                },
                methods:{
                    reversePersonName:function(){
                        return this.person.name.split('').reverse().join('');
                    }
                }
            })
        </script>
    </html>
    
    

    相关文章

      网友评论

          本文标题:Java程序猿的Vue爬坑之路(一)计算属性&侦听属性

          本文链接:https://www.haomeiwen.com/subject/vdentctx.html