VUE的计算属性和侦听器
综合案例
先看一个综合的案例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>计算属性和侦听器</title>
<link rel="icon" href="../logo.svg">
</head>
<body>
<div id="root">
<input type="text" v-model="title" />
<h1>表达式:{{title.split('').reverse().join('')}}</h1>
<h1>计算属性:{{reTitle}}</h1>
<h1>方法:{{reverTitle() }}</h1>
<h1>侦听器:{{reverseTitle}}</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
Vue.config.productionTip=false;
var vm = new Vue({
el:"#root",
data:{ //数据
title:"Hello World!",
msg:"Vue",
reverseTitle:"",//侦听器需要提提前定义好一个承接新数据的属性
},
computed:{ //计算属性
reTitle(){return this.title.split('').reverse().join('')}
},
methods: {//方法
reverTitle(){return this.title.split('').reverse().join('')}
},
watch:{ //侦听器
title:{
deep: true,
immediate: true,
handler:function(val, oldVal){
this.reverseTitle= this.title.split('').reverse().join('');
}
}
}
})
</script>
</body>
</html>
结果:
计算属性 computed
- 需要的属性不存在,要通过已有的响应式属性计算得到。
- 原理:借助底层Object.defineproperty方法提供的getter和setter。
- get函数执行的时机
- 初次读取时会执行一次。
- 当依赖的数据发生变化时会被再次调用。
- 注意:
- 因为 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例,所以getter 和 setter 函数不可以用箭头函数,否则this不再指向vue实例。
- 计算属性默认只有 getter,不过在需要时你也可以提供一个 setter。
- 当计算属性只需要一个getter时,可以简写成一个函数。
- 计算属性会最终出现在vm实例上,直接读取使用即可。
- 计算属性的结果会被缓存,除非依赖的响应式 property 变化才会重新计算(非响应式的会更新)。
- computed的两种写法:
效果:<div id="root"> <p>姓:<input type="text" v-model="firstName"></p> <p>名:<input type="text" v-model="lastName"></p> <P>全名:{{fullName}}</P> <P>全名:{{fullName2}}</P> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <script> Vue.config.productionTip=false; var vm = new Vue({ el:"#root", data:{ firstName:"张", lastName:"三", }, computed:{ // 完整写法 fullName:{ get(){ return this.firstName + "-" + this.lastName; } ,set(value){ this.firstName = value.split("-")[0]; this.lastName = value.split("-")[1]; } } // 简写:只需要读取,不可修改时用简写形式。 ,fullName2(){ return this.firstName + this.lastName; } } }) </script>
侦听器 watch
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。计算属性和侦听器都可以实现的就选择计算属性。
-
选项/ 数据/ watch
{ [key: string]: string | Function | Object | Array }
-
实例 property / vm.$watch
vm.$watch( expOrFn, callback, [options] )
- 参数:
{string | Function} expOrFn
{Function | Object} callback
{Object} [options]
{boolean} deep
{boolean} immediate
案例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>计算属性和侦听器</title>
<link rel="icon" href="../logo.svg">
</head>
<body>
<div id="root">
<h1>{{title}}</h1>
<p>姓:<input type="text" v-model="student.firstName"></p>
<p>名:<input type="text" v-model="student.lastName"></p>
<P>全名:{{student.firstName}}{{student.lastName}}</P>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
Vue.config.productionTip=false;
var vm = new Vue({
el:"#root",
data:{
title:"侦听器",
student:{
firstName:"张",
lastName:"三"
}
},
watch:{
title(val,oldValue){
console.log("title")
console.log('title: new: %s', val, ' old: %s', oldValue)
},
'student.lastName':{
immediate:true,
deep:true,
handler(val,oldVal){
console.log("lastName---")
console.log('lastName: new: %s', val, ' old: %s', oldVal)
}
}
}
})
/* //第一个参数可以是字符串:被监视vm的属性
vm.$watch('student.firstName',function (newVal, oldVal){
this.likes = newVal;
console.log("firstName监视被触发:newVal ,oldVal =>",newVal, oldVal);
},{immediate:true, deep:true,})
*/
//第一个参数可以是函数:侦听该函数返回的值
var unwatch= vm.$watch(function(){
//也可以侦听一个计算出来结果,就像监听一个未被定义的计算属性
return this.student.firstName; //监听此函数的返回值。
},function (newVal, oldVal){
this.likes = newVal;
console.log("firstName监视被触发:newVal ,oldVal =>",newVal, oldVal);
},{immediate:true,deep:true})
// vm.$watch 返回一个取消观察函数,用来停止触发回调:之后取消观察, unwatch()
</script>
</body>
</html>
结果展示:
回顾一下开始的综合案例,一个效果可以通过很多办法实现,可以在模板语法内部直接用表达式写逻辑,可以用方法,可以用计算属性,也可以用侦听器,条条大路通罗马。但是每一个方法之间还是有区别的。
计算属性 VS 侦听器
- 计算属性 VS 表达式:
- 模板内虽然可以用表达式处理简单的逻辑,但是这样会导致代码的易读性太差。
- 所以模板内最好只放数值或字符串类型的值。
- 计算属性 VS 方法:
- 在表达式中调用方法可以达到同样的效果。
- 但是计算属性是基于它们的响应式依赖进行缓存的。
- 每当触发重新渲染时,调用方法将总会再次执行函数。
- 计算属性 vs 侦听属性:
- 当有一些数据需要随着其它数据变动而变动时,如果计算属性和侦听器都可以实现,就选择计算属性。