深入浅析Vue.js计算属性和侦听器


Posted in Javascript onMay 05, 2018

一、 概述

 计算属性

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

<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: {
  // 计算属性的 getter
  reversedMessage: function () {
   // `this` 指向 vm 实例
   return this.message.split('').reverse().join('')
  }
 }
})

    结果:

深入浅析Vue.js计算属性和侦听器

       这里我们声明了一个计算属性 reversedMessage。我们提供的函数将用作属性 vm.reversedMessage 的 getter 函数

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

      你可以像绑定普通属性一样在模板中绑定计算属性。Vue 知道 vm.reversedMessage 依赖于 vm.message,因此当 vm.message 发生改变时,所有依赖 vm.reversedMessage 的绑定也会更新。而且最妙的是我们已经以声明的方式创建了这种依赖关系:计算属性的 getter 函数是没有副作用 (side effect) 的,这使它更易于测试和理解。

二、计算属性缓存 vs 方法

        你可能已经注意到我们可以通过在表达式中调用方法来达到同样的效果

<p>Reversed message: "{{ reversedMessage() }}"</p>

// 在组件中
methods: {
 reversedMessage: 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——特别是如果你之前使用过 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: {
  firstName: '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.firstName 和 vm.lastName 也会相应地被更新。

五、侦听器

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

    例如:

<div id="watch-example">
 <p>
  Ask a yes/no question:
  <input v-model="question">
 </p>
 <p>{{ answer }}</p>
</div>

<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
<!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
<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: {
  // 如果 `question` 发生改变,这个函数就会运行
  question: function (newQuestion, oldQuestion) {
   this.answer = 'Waiting for you to stop typing...'
   this.getAnswer()
  }
 },
 methods: {
  // `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
  // 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
  // AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
  // `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
  // 请参考:https://lodash.com/docs#debounce
  getAnswer: _.debounce(
   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
     })
   },
   // 这是我们为判定用户停止输入等待的毫秒数
   500
  )
 }
})
</script>

    结果:当没有输入?号,那么显示如下:

深入浅析Vue.js计算属性和侦听器

    当有?时候会输出“yes”或者“no”

 具体案例效果地址:侦听器

深入浅析Vue.js计算属性和侦听器

 在这个示例中,使用 watch 选项允许我们执行异步操作 (访问一个 API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

总结

以上所述是小编给大家介绍的Vue.js计算属性和侦听器,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

Javascript 相关文章推荐
IE6下通过a标签点击切换图片的问题
Nov 14 Javascript
JavaScript中的原始值和复杂值
Jan 07 Javascript
jQuery插件HighCharts实现的2D堆条状图效果示例【附demo源码下载】
Mar 14 Javascript
vue构建单页面应用实战
Apr 10 Javascript
jQuery Ajax自定义分页组件(jquery.loehpagerv1.0)实例详解
May 01 jQuery
bootstrap的常用组件和栅格式布局详解
May 02 Javascript
利用node.js如何创建子进程详解
Dec 09 Javascript
微信小程序云开发修改云数据库中的数据方法
May 18 Javascript
layui使用button按钮 点击出现弹层 弹层中加载表单的实例
Sep 04 Javascript
javascript二维数组和对象的深拷贝与浅拷贝实例分析
Oct 26 Javascript
解决vue+ element ui 表单验证有值但验证失败问题
Jan 16 Javascript
antd 表格列宽自适应方法以及错误处理操作
Oct 27 Javascript
详解js跨域请求的两种方式,支持post请求
May 05 #Javascript
vue 注册组件的使用详解
May 05 #Javascript
Vue三层嵌套路由的示例代码
May 05 #Javascript
动态加载JavaScript文件的3种方式
May 05 #Javascript
Node.js的Koa实现JWT用户认证方法
May 05 #Javascript
浅谈vue项目可以从哪些方面进行优化
May 05 #Javascript
Angular模版驱动表单的使用总结
May 05 #Javascript
You might like
第二章 PHP入门基础之php代码写法
2011/12/30 PHP
微信支付开发教程(一)微信支付URL配置
2014/05/28 PHP
分析PHP中单双引号的误区和双引号小隐患
2016/07/19 PHP
利用php的ob缓存机制实现页面静态化方法
2017/07/09 PHP
jQuery UI AutoComplete 自动完成使用小记
2010/08/21 Javascript
使用JS获取当前地理位置方法汇总
2014/12/18 Javascript
JS实现黑色风格的网页TAB选项卡效果代码
2015/10/09 Javascript
JS插件overlib用法实例详解
2015/12/26 Javascript
JavaScript实现字符串与日期的互相转换及日期的格式化
2016/03/07 Javascript
js实现ctrl+v粘贴上传图片(兼容chrome、firefox、ie11)
2016/03/09 Javascript
node.js学习之base64编码解码
2016/10/21 Javascript
jQuery常见面试题之DOM操作详析
2017/07/05 jQuery
原生js封装的ajax方法示例
2018/08/02 Javascript
说说如何在Vue.js中实现数字输入组件的方法
2019/01/08 Javascript
JavaScript工具库MyTools详解
2020/01/01 Javascript
vue+ElementUI 关闭对话框清空验证,清除form表单的操作
2020/08/06 Javascript
[45:52]2018DOTA2亚洲邀请赛 4.1小组赛 A组加赛 LGD vs Liquid
2018/04/02 DOTA
深入解析Python中函数的参数与作用域
2016/03/20 Python
python读取二进制mnist实例详解
2017/05/31 Python
pyqt5的QWebEngineView 使用模板的方法
2018/08/18 Python
python pandas实现excel转为html格式的方法
2018/10/23 Python
Python元组知识点总结
2019/02/18 Python
python matplotlib库直方图绘制详解
2019/08/10 Python
django+tornado实现实时查看远程日志的方法
2019/08/12 Python
pytorch 输出中间层特征的实例
2019/08/17 Python
.dcm格式文件软件读取及python处理详解
2020/01/16 Python
基于Python生成个性二维码过程详解
2020/03/05 Python
python 成功引入包但无法正常调用的解决
2020/03/09 Python
使用Python开发个京东上抢口罩的小实例(仅作技术研究学习使用)
2020/03/10 Python
安装不同版本的tensorflow与models方法实现
2021/02/20 Python
英国著名的茶叶品牌:Whittard of Chelsea
2016/09/22 全球购物
字符串str除首尾字符外的其他字符按升序排列
2013/03/08 面试题
资料员岗位职责
2013/11/17 职场文书
借款民事起诉状范文
2015/05/19 职场文书
丧事答谢词大全
2015/09/30 职场文书
Python获取江苏疫情实时数据及爬虫分析
2021/08/02 Python