Vue | 05 计算属性和监听器

news/2024/7/10 1:52:23 标签: vue, frontend technology, framework

内容提要:

  1. 计算属性的使用场景及表示方法

  2. 计算缓存与方法的差异

  3. 计算属性与监听器属性的使用比较

  4. 计算属性的Setter表示方法

  5. 监听器的使用方式

计算属性

在模板内写表达式是非常方便的,但它们仅仅能做一些简单的操作,把太复杂的表达式放在模板中可能会导致臃肿和难以维护。例如:

<div id="example">
    {{ message.split('').reverse().join('') }}
</div>

如上,模板不再是简单的和说明式的。在你读懂它是message的字符串反转之前你不得不读几秒钟。当这样的语法不止一次的出现,情况就会变得很糟糕。

这就是为什么对于复杂一点的逻辑你需要使用计算属性的原因。

基础的例子

<div id="example">
    <p>Original message:"{{ message }}"</p>
    <p>Computed reversed message:"{{ reversedMessage }}</p>
</div>
var vm = new Vue({
    el: '#example',
    data: {
        message: 'Hello'
    },
    computed: {
        // a computed getter
        reversedMessage: function() {
            // 'this'points to the vm instance
            return this.message.split('').reverse().join('')
        }
    }
})

Result:

Original message: "Hello"<br>
Computed reversed message: "olleH"

这里声明了一个计算属性reversedMessage.我们为属性vm.reversedMessage提供了一个getter函数:

console.log(vm.reversedMessage) // => 'olleH'
vm.message = 'Goodbye'
console.log(vm.reversedMessage) // => 'eybdooG'

vm.reversedMessage的值依赖于vm.message.

我们可以像绑定正常的函数一样绑定计算属性。Vue能够意识到vm.reversedMessage依赖vm.message,所以当vm.message更新的时候它能够更新所有vm.reversedMessage的绑定。因为我们已经创建了他们的依赖关系:计算getter函数没有副作用,它更容易测试和理解。

计算缓存 vs 方法

你可能意识到了可以通过一个方法表达式得到同样的结果。

<p>Reversed message: "{{ reversedMessage() }}"</p>
// in component
methods: {
    reverseMessage: function() {
        return this.message.split('').reverse().join('')
    }
}

我们定义了一个相同的函数作为方法来代替计算属性。作为结果,这两种实现是相同的。然而,他们的不同在于计算属性缓存了他们的依赖关系。当依赖关系改变的时候计算属性才会被重新计算。这意味着只要message没有改变,多次访问reversedMessage计算属性将立刻返回之前的结果而不再运行函数。

这也意味着以下属性从不会更新,因为Date.now()没有一个可响应的依赖。

computed:{
    now: function () {
        return Date.now()
    }
}

相比之下,无论是否重新渲染一个方法调用总是会运行函数。

我们为什么需要缓存?想象一下我们有非常耗时的计算属性A,要求遍历一个很大的数组并且做很多的计算。而后我们有其他计算属性反过来依赖A。没有缓存,我们将比实际需要执行A的getter很多次!某些情况下,如果你不需要缓存,就用一个方法代替。

计算 vs 监听器属性

Vue提供了一个更为常用的方式去观察和响应数据的改变在Vue实例:watch properties。当一些数据需要基于一些其他数据做改变的时候,过度使用watch是很诱人的 - 尤其是如果你有一个AngularJS背景。然而,通常使用计算属性要比强制回调watch要好。考虑这个例子:

<div id="demo">
    {{ fullName }}
</div>
var vm = new Vue({
    el: '#demo',
    data: {
        firstName: 'Foo',
        lastName: 'Bar',
        fullName: 'Foo Bar'
    },
    watch: {
        firstName: function (val) {
          this.fullName = val + ' ' + this.lastName  
        },  
        lastName: function (val) {
          this.fullName = this.firstName + ' ' + val
        }
    },
})

上面的代码是强制的和重复的。比较一下计算属性版本:

var vm = new Vue({
    el: '#demo',
    data: {
        firtName: 'Foo',
        lastName: 'Bar'
    },
    computed: {
        fullName: function () {
            return this.firstName + ' ' + this.lastName
       }
    }
})

显然,第二个要好一些。

计算Setter

计算属性默认仅为getter,但是当你需要的时候你也能提供一个setter:

// ...
computed: {
    fullName: {
        // getter
        get: function () {
            return this.firstName + ' ' + this.lastName
        },
        // setter
            set: function (newValue) {
                var names = newValue.split(' ')
                this.firstName = names[0]
                this.lastName = names[names.length - 1]
            }   
    }
}
// ...

现在当你运行vm.fullName = 'John Doe',setter将被调用,vm.firstNamevm.lastName将会被更新。

监听器

虽然计算属性在大多数情况下更合适,有时仍需要一个自定义的监听器。这就是为什么Vue提供了更通用的方式去响应数据的变化通过watch选项。当你执行异步或耗时操作去响应数据改变的时候会更有用。

例如:

<div id="watch-example">
    <p>Ask a yes/no question:
    <input v-model="question">
    </p>
    <p>{{ answer }}</p>
</div>
<!-- Since there is already a rich ecosystem of ajax libraris -->
<!-- and collections of general-purpose utility methods, Vue core -->
<!-- is able to remain small by not reinventing them. This also -->
<!-- gives you the freedom to use what you're familiar with.' -->
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>  
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
    el: '#watch-example',
    data: {
        question: '',
        answer: 'I cannot give you an answer until you ask a question!'
    },
    watch: {
        // whenever question changes, this function will run
        question: function (newQuestion, oldQuestion) {
            this.answer = 'Waiting for you to stop typing...'
            this.debouncedGetAnswer()
        }
    },
    created: function () {
        // _.debounce is a funciton provided by lodash to limit how often a particularly expensive operation can be run.In this case, we want to limit how often we access yesno.wtf/api, waiting until the user has completely finished typing before making the ajax request. To learn more about the _.debounce function (and its cousin _.throttle), visit: https://lodash.com/docs#debounce
        this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
    },
    methods: {
        getAnswer: function () {
            if (this.question.indexOf('?') === -1) {
                this.answer = 'Questions usually contain a question mark. ;-)'
                return
            }
            this.answer = 'Thinking...'
            var vm = this
            axios.get('https:// yesno.wtf/api')
                .then(function (response)) {
                      vm.answer = _.capitalize(response.data.answer)
                      })
        .catch(function (error)) {
    			vm.answer = 'Error! Could not reach the API. ' + error
			})
        }
    }
})
</script>

Result:

问题输入改变时,文字提示会实时改为:Waiting for you to stop typing …

问题不规范:

watcher-question mark

请求中:

watcher-Thinking

请求回来:
watcher-error

在这个例子里,使用watch操作允许我们执行一个异步的操作(访问一个API的时候),限制我们操作的频率,当得到最后的回答时立刻改变状态。用计算属性是做不到的。

除了watch选项,你也可以使用命令vm.$watch API.


http://www.niftyadmin.cn/n/1035785.html

相关文章

Vue | 06 类和样式绑定

内容提要&#xff1a; 绑定HTML classes的语法&#xff1a;对象语法、数组语法、在组件上的使用绑定内联样式的语法&#xff1a;对象语法、数组语法、自动加前缀与多个值的使用 对于数据绑定的一种常见需要是操作元素的类列表和它的内联样式。由于它们都是属性&#xff0c;我们…

Vue | 07 条件渲染

v-if的用法详解v-show的用法v-if与v-show的用法比较v-if与v-for联合使用的建议 v-if 在字符串模板里&#xff0c;例如 Handlebars&#xff0c;我们像这样写一个条件模块&#xff1a; <!-- Handlebars template --> {{#if ok}} <h1>Yes</h1> {{/if}}在Vue我…

三.自定义View onMeasure onLayout onDraw

知识点整理1 View树的绘制流程1.1 View的添加2.1 View绘制流程1 View树的绘制流程 View树的绘制流程是谁负责的&#xff1f; view树的绘制流程是通过ViewRoot去负责绘制的&#xff0c;主要作用是View树的管理者&#xff0c;负责将DecorView和PhoneWindow“组合”起来。 View树…

Vue | 08 列表渲染

内容提要: v-for映射数组与对象的用法 key值的作用与用法 数组变化检测 3.1 数组可变方法 3.2 如何替换数组 3.3 数组index/length赋值不能响应变化的处理方法 对象无法响应变化的处理 如何显示过滤/或排序的结果 v-for与范围、template上使用v-for v-for与v-if的优先级处…

四.自定义View MeasureSpec

知识点整理MeasureSpec定义SpecMode 有如下三种&#xff1a;MeasureSpec 意义&#xff1a;MeasureSpec值的确定MeasureSpec 1.自定义View时&#xff0c;在onMeasure时&#xff0c;会用到MeasureSpec&#xff0c;MeasureSpec通俗的讲叫测量规格。 2.一个普通View的最终宽高有父…

Vue | 09 事件处理

内容提要&#xff1a; 事件监听、方法事件的处理、内联方法处理事件修饰符、键修饰符、系统修饰符键&#xff08;.exact修饰符、鼠标事件修饰符&#xff09;在HTML中监听事件的好处 监听事件 当事件被触发的时候我们可以使用v-on指令去监听DOM事件和运行一些JavaScript。 例如…

五 自定义View LayoutParams

知识点整理1. LayoutParams2. MarginLayoutParams3 LayoutParams与View如何建立联系4 自定义LayoutParams4.1 创建自定义属性4.2 继承MarginLayout4.3 重写ViewGroup中几个与LayoutParams相关的方法5 LayoutParams常见的子类1. LayoutParams LayoutParams翻译过来就是布局参数…

四个视角理解Activity的启动

知识点整理理解角度一.Android 软件体系结构二. Task 启动方式三.Activity的生命周期全面分析3.1 生命周期分为两种&#xff1a;1.典型情况下的生命周期分析2.异常情况下的生命周期分析2.1 系统配置变化导致Activity销毁重建2.2 资源内存不足导致低优先级的Activity被回收3.2 生…