计算属性
我们有时候会在模板中绑定表达式来做简单的数据处理,但是如果表达式太长,就会变得臃肿难以维护。
比如以下代码
<div>
{{text.split(',').reverse().join(',')}}
</div>
表达式里面包含了3个操作,并不是很清晰,有时候可能会更加复杂,所以在遇到复杂的逻辑时,我们应该使用计算属性。上例可以用计算属性进行改写:
<div id="app">
{{reverseText}}
</div>
<script>
var app = new Vue({
el:"#app",
data:{
text:"123,456"
},
computed:{
reverseText:funtion(){
return this.text.split(',').reverse().join(',');
}
}
})
</script>
所有的计算属性都以函数的形式写在 Vue 实例内的 computed 选项内,最终返回计算后的结果。
【注意】虽然我们是以函数的形式书写计算属性的,但是在使用时,不能加()
计算属性的特点
1、计算属性中任意一个实例数据发生变化。计算属性就会重新计算,视图也会更新。
以购物车中的计算总价为例:
<div id="app">
总价:{{total}}
</div>
var app = new Vue({
el:"#app",
data:{
product:[
{
name:"iphone 12",
price:"7199",
num:"2"
},
{
name:"LV",
price:"4888",
num:"3"
},
{
name:"six god",
price:"100",
num:"1"
}
]
},
computed: {
total: function () {
var price = 0;
for(var i = 0; i < this.product.length; i++){
price += this.product[i].num * this.product[i].num
}
return price;
}
}
})
当购买数量或增删商品时,计算属性就会自动更新,视图中的总结也会随之变化。
2、每一个计算属性都包含一个getter和setter
上面的例子都是计算属性的默认用法,只是利用了getter来读取。每调用一次计算属性,就相当于调用一次getter属性;当计算属性的值发生变化时,会默认调用setter属性,进行相应的操作例如
<div id="app">
{{fullName}}
</div>
var vm = new Vue({
el: "#app",
data: {
firstName: "尼古拉斯",
lastName: "赵四",
},
computed: {
fullName: {
get: function () {
return this.firstName + "·" + this.lastName
},
set:function (value) {
var arr = value.split("·");
this.firstName = arr[0];
this.lastName = arr[1];
}
}
}
})
当我们在控制台执行 app.fullName='弗拉基米尔·普京’时,setter就会被调用。
绝大多数情况下,我们只会用默认的 getter 方法来读取一个计算属性,在业务中很少用到setter,
所以在声明一个计算属性时,可以直接使用默认的写法,不必将getter,setter都声明。
3、计算属性可以依赖多个Vue实例中的数据
<div id="app1"></div>
<div id="app2">
{{reversedText}}
</div>
<script>
var app1 = new Vue({
el: "#app1",
data: {
text: "123,456"
}
});
var app2 = new Vue({
el: "#app2",
computed: {
reversedText: function () {
//这里是依赖app1实例中的数据text
return app1.text.split(',').reverse().join(',')
}
}
})
</script>
这里我们创建了两个vue实例app1和app2,在app2的计算属性reversedText中,依赖的是app1的数据text,所以当text变化时,实例app2的计算属性也会变化.
计算属性的缓存
其实细心的话就会发现,调用methods里的方法也能实现和计算属性一样的效果,甚至有的方法还能接收参数,使用起来更加的灵活,既然使用methods就可以实现,那为什么还需要计算属性呢?原因就是计算属性是基于依赖缓存的。一个计算属性所依赖的数据发生变化时,他才会重新取值,所以依赖的数据只要不改变。计算属性也就不更新。
举个例子:
<div id="app">
姓名:{{getName()}}
年龄:{{getAge()}}
工作:{{getSay()}}
</div>
var vm = new Vue({
el: "#app",
data: {
name: "葱油饼",
age: "38",
say:"宝,我去输液了,什么液,想你的夜"
},
methods: {
getName() {
console.log("getName执行了")
return this.name;
},
getAge() {
console.log("getAge执行了")
return this.age;
},
getSay() {
console.log("getSay执行了")
return this.say;
}
}
})
当我们在控制台,分别修改name,age,say的值时会发现,getName,getAge,getJob都执行了。
vm.name="小王"
也就是说:当修改其中一个属性时,其他属性的值都没改变,但会发现methods里的方法都被执行
现在我们换成计算属性computed试一下、
<div id="app">
姓名:{{getName}}
年龄:{{getAge}}
工作:{{getSay}}
</div>
var vm = new Vue({
el: "#app",
data: {
name: "葱油饼",
age: "38",
say:"宝,我去输液了,什么液,想你的夜"
},
computed: {
getName() {
console.log("getName执行了")
return this.name;
},
getAge() {
console.log("getAge执行了")
return this.age;
},
getSay() {
console.log("getSay执行了")
return this.say;
}
}
})
当我们在控制台,分别修改name,age,say的值时会发现,当修改其中一个值的时候,只会执行于其相关的方法。
总结
1).methods方法和computed计算属性,两种方式的最终结果确实是完全相同。
2).不同的是计算属性是基于它们的响应式依赖进行缓存的。
只在相关响应式依赖发生改变时它们才会重新求值,多次访问计算属性会立即返回之前的计算结果,而不必再次执行函数。
3)methods方法,每当触发重新渲染时,调用方法将总会再次执行函数。
4).官网的一句话:对于任何复杂逻辑,你都应当使用计算属性。
2.watch监听
2.1 作用
watch监听器会监听data中数据的变化,只要一变化,就能够执行相应的逻辑
2.2 用法
2.2.1 常用用法
监听的数据名放到这里面作为函数名,这个函数里面有两个参数,一个是新值,一个是旧值
<div id="app">
<input type="text" v-model="firstName">
<input type="text" v-model="lastName">
<h1>全名:{{fullName}}</h1>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
firstName: '',
lastName: '',
fullName: ''
},
watch: {
firstName(newVal, oldVal) {
console.log(newVal, oldVal)
this.fullName = newVal + this.lastName
},
lastName(newVal, oldVal) {
this.fullName = this.firstName + newVal
}
}
})
</script>
2.2.2 立即执行
当值第一次绑定的时候,不会执行监听函数,只有值发生改变才会执行。如果在最初绑定值的时候也要执行函数,则就需要用到immediate属性
<div id="app">
<input type="text" v-model="firstName">
<input type="text" v-model="lastName">
<h1>全名:{{fullName}}</h1>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
firstName: '',
lastName: '',
fullName: ''
},
watch: {
firstName(newVal, oldVal) {
console.log(newVal, oldVal)
this.fullName = newVal + this.lastName
},
lastName(newVal, oldVal) {
this.fullName = this.firstName + newVal
},
// 立即执行
immediate: true
}
})
</script>
2.2.3 深度监听
需要监听复杂数据类型(对象)的改变时,普通的watch方法无法监听到对象内部属性的改变,只有data中的数据才能够监听到变化,此时就需要deep属性对对象进行深度监听。
<div id="app">
<!-- 更新对象属性的值 -->
<input type="text" v-model="person.name" />
</div>
<script>
new Vue({
el: '#app',
data: {
person: {
id: 1,
name: '咸鱼'
}
},
watch: {
person: {
handler(newVal, oldVal) {
console.log(newVal, oldVal);
},
// deep:true 更新对象属性的值,会触发监听
deep: true,
}
}
})
</script>
如果是要给对象的某个特定的属性加监听器,则可以这样写
watch: {
//对象的属性名
"person.name": {
handler(newVal, oldVal) {
}
}
}
与computed比较:
- 对比computed而言,computed性能更好,所以能用computed实现就用computed实现。
- 在涉及到异步数据操作的时候,就只能用watch去实现了。
3.过滤器
3.1 基本概念
简单介绍一下过滤器,顾名思义,过滤就是一个数据经过了这个过滤之后出来另一样东西,可以是从中取得你想要的,或者给那个数据添加点什么装饰,那么过滤器则是过滤的工具。
3.2 使用方法
vue中的过滤器分为两种:局部过滤器和全局过滤器
3.2.1 全局过滤器
格式:Vue.filter(“过滤器名称”, 过滤器处理函数)
<div id="app">
<p>{{ year | formartStr}}</p>
</div>
<script>
Vue.filter("formartStr", function (value) {
return value+"年";
});
let vue = new Vue({
el: '#app',
data: {
year: "2021"
}
});
</script>
使用全局过滤器
{{msg | 过滤器名称}}
:value="msg | 过滤器名称"
3.2.2 局部过滤器
创建一个局部过滤器
给创建Vue实例时传递的对象添加filters属性。
filters: {
'过滤器名称':过滤器处理函数
}
局部过滤器只能在自定义的那个Vue实例中使用。
<div id="app1">
<p>{{name | formartStr}}</p>
</div>
<div id="app2">
<!-- 报错 -->
<p>{{name | formartStr}}</p>
</div>
let vue = new Vue({
el: '#app1',
data: {
year: "2021"
},
filters: {
"formartStr": function (value) {
return value+"年";
}
}
});
【注意】
1、当全局过滤器和局部过滤器重名时,会采用局部过滤器。
2、过滤器可以串联
<div id="app1">
<p>{{name | formartStr1 | formartStr2}}</p>
</div>
3、过滤器是 JavaScript 函数,因此可以接收参数
{{ message | filterA(arg1, arg2) }}
上述代码中,filterA的第一个参数是message,第二个参数是‘arg1’,第三个参数是arg2。也就是说,过滤器函数默认第一个参数为 | 前面的内容。
3.3 日期格式化练习
<div id="app">
<p>{{time | dateFormart("yyyy-MM-dd")}}</p>
</div>
Vue.filter("dateFormart", function (value, fmStr) {
let date = new Date(value);
let year = date.getFullYear();
let month = date.getMonth() + 1 + "";
let day = date.getDate() + "";
let hour = date.getHours() + "";
let minute = date.getMinutes() + "";
let second = date.getSeconds() + "";
if(fmStr && fmStr === "yyyy-MM-dd"){
return `${year}-${month.padStart(2, "0")}-${day.padStart(2, "0")}`;
}
return `${year}-${month.padStart(2, "0")}-${day.padStart(2, "0")} ${hour.padStart(2, "0")}:${minute.padStart(2, "0")}:${second.padStart(2, "0")}`;
});
// 这里就是MVVM中的View Model
let vue = new Vue({
el: '#app',
// 这里就是MVVM中的Model
data: {
time: Date.now()
}
});