先来看看用计算属性和方法来实现同一效果:
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>watch和computed(computed实现)</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="root">
<p v-html="html"></p>
姓:<input type="text" v-model="firstName" /><br />
名:<input type="text" v-model="lastName" /><br />
姓名:
<h4>计算属性实现</h4>
<h3>{{fullName}}</h3>
<h4>方法实现</h4>
<h3>{{getFullName()}}</h3>
</div>
<script>
const vm = new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三',
},
computed: {
fullName() {
return this.firstName '-' this.lastName;
},
},
methods: {
getFullName() {
return this.firstName '-' this.lastName;
},
},
});
</script>
</body>
</html>
两种方式的最终结果都是完全相同的(这里解释一下为什么会相同:当计算属性所依赖的数据发生改变时,计算属性会重新调用;当data中的任何一个数据发生变化时,Vue的模板都会重新解析一遍(Vue都会拿过来模板整体再阅读一遍),所以方法也被调用了一次)
看起来用计算属性和方法好像都可以,其实它们两个有着本质的区别:
主要区别:
1. 调用方式不同
(以上边代码为例)
- computed在HTML中的插值语法:
{{fullName}}
computed定义的方法是以属性的形式访问的,和data中的属性访问形式一样 - methods在HTML中的插值语法:
{{getFullName()}}
methods定义的方法,必须加上()来调用,否则会出现如下情况:
2. 是否有缓存
computed是有缓存机制的,而methods没有
验证:
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>watch和computed(computed实现)</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="root">
姓:<input type="text" v-model="firstName" /><br />
名:<input type="text" v-model="lastName" /><br />
姓名:
<h4>计算属性实现:</h4>
<h3>①{{fullName}}</h3>
<h3>②{{fullName}}</h3>
<h3>③{{fullName}}</h3>
<h3>④{{fullName}}</h3>
<h3>⑤{{fullName}}</h3>
<h4>方法实现:</h4>
<h3>⑥{{getFullName()}}</h3>
<h3>⑦{{getFullName()}}</h3>
<h3>⑧{{getFullName()}}</h3>
<h3>⑨{{getFullName()}}</h3>
<h3>⑩{{getFullName()}}</h3>
<hr>
测试计算属性和方法的调用机制:
<h1>{{test}}</h1>
</div>
<script>
const vm = new Vue({
el: '#root',
data: {
firstName: '张',
lastName: '三',
test: 0,
},
computed: {
fullName() {
console.log('computed');
return this.firstName '-' this.lastName;
},
},
methods: {
getFullName() {
console.log('methods');
return this.firstName '-' this.lastName;
},
},
});
</script>
</body>
</html>
可以看到,刷新页面,初始打印一个computed,五个methods。
这说明计算属性调用了缓存机制,只打印了一次,后边的四次{{fullName}}
并没有被调用(因为后四次直接获取了第一次缓存下来的值,计算属性会立即返回之前的计算结果,而不必再次执行函数。),试想一下,如果我再html中写的不是5次<h3>{{fullName}}</h3>
,而是10000次甚至100000000次,如果没有缓存机制,他会执行100000000次,而有了缓存机制,它只用执行一次,后边不管多少次,直接拿第一次缓存的值即可,这大大节省了运算时间(尤其是要多次计算一个很复杂的属性的时候);方法被调用了五次,因为方法没有缓存机制,写了几次调用,函数就执行几次。
缓存机制的另外一个好处就是,当你修改计算属性所依赖的数据时,计算属性同样只会执行一次,后边任意多少次只需要拿第一次缓存下来的值即可;而方法的话,修改任意data中的值,html中写了多少次调用,就会调用多少次,这也可以从我修改firstName的值的时候,只打印一次computed,打印五次methods来验证。
3. 调用的时机不同
计算属性:只有当你修改计算属性所依赖的数据时,才会被调用(如上GIF,当我修改test的值时,计算属性没有被调用,修改firstName时才会被调用)。比如:
代码语言:javascript复制computed: {
fullName: function () {
return Date.now()
}
}
如果计算属性改成这个,那么便不会再执行,因为Date.now()不是响应式依赖。
方法:当data中的任何一个数据发生变化时,Vue的模板都会重新解析一遍(Vue都会拿过来模板整体再阅读一遍),同时方法也会被调用(如上GIF,当我修改test和firstName的值时,方法都会被调用)。
4. 是否可以传参
计算属性不可以传参,而方法可以传参。
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>test3</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<!-- 计算属性不能传参: -->
<h1>{{fullName}}</h1>
<!-- 方法可以传参: -->
<h1>{{getName('大潘')}}</h1>
</div>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el: '#root',
data: {
eName: 'Dapan',
cName: '潘潘',
},
computed: {
fullName() {
return this.eName '-' this.cName;
},
},
methods: {
getName(name) { //接收传过来的参数:'大潘'
return this.eName '-' name;
},
},
});
</script>
</body>
</html>
其他说明
computed和methods不可以重名,Vue会把 methods
和 data
里的东西,全部代理到Vue生成的对象中,这会将computed中重名属性覆盖。
计算属性的简写形式:
代码语言:javascript复制computed: {
fullName() {
return this.eName '-' this.cName;
},
},
而计算属性的一般形式:
代码语言:javascript复制fullName: {
get() {
return this.eName '-' this.cName;
},
set(val) {
// 代码
},
},
在计算属性中传入的是一个属性,而在这个属性又有两个方法(getter和setter)。在读取数据时Vue自动调用getter,在设置值时使用setter,所以我们现在能够理解,为什么使用计算属性时不需要像调用方法时在后面跟上小括号,因为我们确实只是在使用属性而已。
关注公众号:学编程的GISer,获取更多干货知识!