computed

在指令章节讲过,插值{{ }}和指令都接受变量和表达式的写法,使用表达式可以进行简单的二元或三元运算。但如果要执行更加复杂的计算或频繁重复的计算,如果还是直接写在指令的表达式中会让代码过于臃肿,不好看不优雅。这个时候可以使用computed属性。

比如:

<!-- 假设后端返回的价格单位是分,显示格式要求¥0.00元 -->
<!-- bad -->
<div>总价:¥ {{ (price / 100).toFixed(2) }}元</div>
<!-- good -->
<div>总价:{{ total }}</div>
computed: {
total() {
return `¥ ${(this.price / 100).toFixed(2)}元`
}
},

计算属性就是data对象的一个扩展和增强版本。data中的值可以进行读写操作,同样计算属性的值也是可读可写的。

// 单纯读取时,函数写法,默认调用get方法
computed: {
total() {
return `¥ ${(this.price / 100).toFixed(2)}元`
}
}, // 可读可写时,对象写法
computed: {
total: {
get: function () {
return `¥ ${this.price.toFixed(2)}元`
},
set: function (newValue) {
this.price = newValue / 100
}
}
}

常规想法,在这里容易产生一个误区,当我对计算属性赋值,如this.total = 250,total值会被覆盖直接等于250。但是,实际对计算属性赋值,如果是对象形式,只是会触发执行set函数,具体视图如何显示,取决于我们在set函数体内的执行代码,有没有更新get中的依赖值。

看个例子

点击查看DEMO:computed by get and set

<div id="app">
<div>总价:{{ total }}</div>
<button @click="changePrice">price加1</button>
<button @click="changeTotal">直接赋值total</button>
<div>赋值列表:{{ memorySetterList }}</div>
</div>
new Vue({
el: "#app",
data: {
price: 100,
memorySetterList: [],
},
computed: {
total: {
get(){
return `¥ ${this.price.toFixed(2)}元`
},
set(setVal) {
this.memorySetterList.push(setVal)
}
}
},
methods: {
changeCount() {
this.price++
},
changeDouble() {
console.log("setBefore:this.total:",this.total)
this.total += 50
console.log("setAfter:this.total:",this.total)
}
}
})

结果显示,this.total的值变不会有改变,赋值列表每次都是同样的值,并每点一次加50的效果。只有当price值改变才会触发更新。所以直接对计算属性赋值this.price = someValue只是被this.totalsetter方法捕捉到而已。

这也正是计算属性的特点一:依赖改变才会改变

上面的例子如果要实现对total赋值的同时,视图中{{ total }}也显示改变,可以在计算属性的setter中对其依赖值price进行改变。

computed: {
total: {
get: function () {
return `¥ ${this.price.toFixed(2)}元`
},
set: function (newValue) {
this.price = newValue / 100
}
}
}

计算属性的另一个特点:值会被缓存

多处调用计算属性,都是相同的值。并且依赖改变,多处调用的值都是会同时更新。

<div id="app">
<div>count1:{{ count1 }}</div>
<div>addCount1ByComputed: {{ addCount1ByComputed}}</div>
<div>addCount2ByMethod:{{count2}}</div>
</div>
var vm = new Vue({
el: "#app",
data: {
count1: 1,
count2: 1,
},
computed: {
addCount1ByComputed() {
return this.count1 * 10
}
},
methods: {
addCount2ByMethod() {
this.count2++
},
},
mounted() {
console.log("========computed========")
for (let i=0; i<5; i++) {
console.log(this.addCount1ByComputed)
}
console.log("=======methods=======")
for (let i=0; i<5; i++) {
this.addCount2ByMethod()
console.log(this.count2)
}
},
})

计算属性的特点:

  • 只有当计算属性所依赖的值改变时,才会重新触发执行函数改变其值。
  • 计算属性会被缓存,如果其依赖值不改变,即使在多个地方多次调用,函数体代码也不会被执行,只是取用已经被缓存的值。

总结

我理解computed就是对数据的显示的一种包装,这种包装的需要可能是出于数据格式的美化或数据调用上简化复用考虑。而computedget方法提供一种包装方法,set也是一种包装方法。只是大部分情况下,一种get方法已足够我们解决需求。很少有get解决起来还不够完美的情况下再需要使用set配合的情况。

但也确实有需要get/set同时包装一个数据对象的情况,比如根据后端请求回的商品价格price是分的单位,但现在视图上渲染需要按一定格式如¥0.00元格式,并且在其它地方使用price参与运算需要元的单位。

一般常规的做法是,在每个调用price都手动除一次100,或者在请求成功的回调中对price先转化元单位,再赋值到data中响应。但也可以使用computedset方法处理转为元再赋值this.price,实现price相关包装逻辑都在一起。如下例:

<div>总价:{{ total }}</div>
new Vue({
el: "#app",
data: {
price: '',
},
computed: {
total: {
get: function () {
return `¥ ${this.price.toFixed(2)}元`
},
set: function (newValue) {
this.price = newValue / 100
}
}
}
}),
mounted() {
this.request_getGoodsPrice()
.then(
// 常规写法
// res => this.price = res.totalPrice / 100
// 使用set方法,将price的处理逻辑合在一起,都是total的计算属性方法中。
res => this.total = res.totalPrice
)
}

vue-learning:16 - js - computed的更多相关文章

  1. Vue教程:计算属性computed与侦听器watch(三)

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

  2. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十五 ║Vue基础:JS面向对象&字面量& this字

    缘起 书接上文<从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十四 ║ VUE 计划书 & 我的前后端开发简史>,昨天咱们说到了以我的经历说明的web开发经历的 ...

  3. Vue学习笔记:methods、computed、watch的区别

    自:https://www.jb51.net/article/120073.htm 首先要说,methods,watch和computed都是以函数为基础的,但各自却都不同 而从作用机制和性质上看,m ...

  4. vue-learning:20 - js - 区别:filters / data / computed / watch / methods

    区别:filters / data / computed / watch / methods 在配置对象options中,filters/data/computed/watch/methods的每一项 ...

  5. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 二十三║Vue实战:Vuex 其实很简单

    前言 哈喽大家周五好,马上又是一个周末了,下周就是中秋了,下下周就是国庆啦,这里先祝福大家一个比一个假日嗨皮啦~~转眼我们的专题已经写了第 23 篇了,好几次都坚持不下去想要中断,不过每当看到群里的交 ...

  6. Vue中使用Cropper.js裁剪图片

    Cropper.js是一款很好用的图片裁剪工具,可以对图片的尺寸.宽高比进行裁剪,满足诸如裁剪头像上传.商品图片编辑之类的需求. github: https://github.com/fengyuan ...

  7. vue初学:基础概念

    一.vue使用步骤: 1.引包vue.js 2.html中写要操作的DOM节点 3.创建vue对象:new Vue({options}); 4.配置options:el:(要操作的对象,用选择器,同j ...

  8. vue中config/index.js:配置的详细理解

    当我们需要和后台分离部署的时候,必须配置config/index.js: 用vue-cli 自动构建的目录里面  (环境变量及其基本变量的配置) var path = require('path') ...

  9. Vue教程:组件Component详解(六)

    一.什么是组件? 组件 (Component) 是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功 ...

随机推荐

  1. 小爬爬6.scrapy回顾和手动请求发送

    1.数据结构回顾 #栈def push(self,item) def pop(self) #队列 def enqueue(self,item) def dequeue(self) #列表 def ad ...

  2. Myeclipse运行提示错误: 找不到或无法加载主类 test.test1 终极解决办法

    前提是代码没有问题 简单粗暴的解决办法: 重启电脑 解决办法2: 1.在控制台中点开“Problems”,查看里面的错误.如果是多个项目,可以将其他项目暂时关闭. 根据错误进行处理. 2.把项目cle ...

  3. oralce update操作

    1.基本语法:update  表名 set 列名=表达式 [列名=表达式. . . ] where 条件 2.使用的注意事项: v  UPDATE语法可以用新值更新原有表行中的各列 把zs的性别改为女 ...

  4. [linux]vmware中linux虚拟机扩容 标签: vmware虚拟机linux 2016-09-05 08:03 315人阅读 评

    扩容原因 现阶段,虚拟机的标配都是1G内存和20G硬盘,大部分时候是够用的,但是也会出现虚拟机里面东西放多了硬盘不够用的情况,这种情况下,除了清理垃圾,另外就只能给虚拟机扩容了.因为window扩容相 ...

  5. LeetcCode102 Binary Tree Level Order Traversal

    Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, ...

  6. 【git基本操作】总结

    "git fetch GitLab: Your account has been blocked.fatal: Could not read from remote repository. ...

  7. MySQL统计同比环比SQL

    大体思路: MySQL没有类似oracle方便的统计函数,只能靠自己去硬计算:通过时间字段直接增加年份.月份,然后通过left join关联时间字段去计算环比.同比公式即可 原始表结构: 求同比SQL ...

  8. Xcode无法退出,报错提示 The document “xxx.h” could not be saved. The file doesn’t exist.

    记录一个问题 场景:Xcode编辑一个工程时直接在工程内部修改了某个目录的文件夹名字,而后删除了其下的某 .h.m 文件 之后总是提示上述错误且无法强制退出Xcode,clean等操作基本没用 查找本 ...

  9. C++大体概况 标签: c++总结 2015-01-31 20:41 792人阅读 评论(15) 收藏

    今年又一次报名了二级的C++考试,现在再来把C++总结一下,也不能算是总结,大体提炼了一下需要注意的地方,考试之前打算把这些东西好好看一看,今年一定要过啊! 前两天才知道,unix是用C语言编写的,这 ...

  10. python环境测试MySQLdb、DBUtil、sqlobject性能

    python环境测试MySQLdb.DBUtil.sqlobject性能 首先介绍下MySQLdb.DBUtil.sqlobject: (1)MySQLdb 是用于Python连接Mysql数据库的接 ...