一、计算属性
1.1 什么是计算属性
首先通过一个示例来介绍计算属性,需求是把一个字符串倒序显示,具体代码如示例1所示:
<template>
<div class="hello">
<h1>{{msg}}转为{{msg.split('').reverse().join('')}}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
浏览器显示效果图:
总结:通过浏览器显示效果图可知,在插值表达式中通过调用一系列的字符串方法,把“Welcome to Your Vue.js App”字符串进行了倒序显示。再看示例1的代码,如果插值表达式中的代码过长或者逻辑较为复杂,就会变得臃肿不堪甚至难以阅读和维护,所以在遇到复杂的逻辑时,官方不推荐使用插值表达式,而是使用计算属性把逻辑复杂的代码进行分离。
用计算属性改写示例1的代码,具体代码如下:
<template>
<div class="hello">
<h1>计算属性:{{reversedMsg}}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
computed:{
reversedMsg:function(){
return this.msg.split('').reverse().join('')
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
?浏览器效果图:
?通过浏览器中的显示可以看到,利用计算属性依然可以完成字符串的倒序显示,计算属性可以分离逻辑代码,使代码的易维护性增强。以后遇到这种逻辑较为复杂的代码,均可以使用计算属性进行分离。所有计算属性都以函数的形式写在vue实例的compted选项内,最终返回计算后的结果。
1.2 计算属性用法
?????? 在一个计算属性里可以完成各种复杂的逻辑,包括运算、函数调用等,只要最终返回一个结果就可以。除了上面示例中的简单用法外,计算属性还可以依赖多个Vue实例的数据,只要其中任何一个数据变化,计算属性就会重新执行,视图也会更新。下面通过购物车商品总价的示例来展示,具体代码如下:
<template>
<div class="hello">
<h1>总价:{{prices}}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
package1:[
{
name:"iphone8",
price:5688,
count:1
},
{
name:"ipad",
price:2888,
count:1
}
],
package2:[
{
name:"apple",
price:3,
count:5
},
{
name:"banana",
price:6,
count:3
}
]
}
},
computed:{
prices:function(){
var prices=0;
for(var i=0;i<this.package1.length;i++){
prices+=this.package1[i].price*this.package1[i].count;
}
for(var i=0;i<this.package2[i].length;i++){
prices+=this.package2[i].price*this.package2[i].count;
}
return prices;
}
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
?1.3 props动态传值与计算属性computed的结合
当props作为需要被转变的原始值传入,这时使用计算属性就可以了。动态加样式改变盒子的宽度。
示例代码(父组件App.vue):
<template>
<div id="app">
<Child :width="200"></Child>
</div>
</template>
<script>
import Child from './components/Child.vue'
export default {
components: { Child },
name: 'App'
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
子组件代码(Child.vue):
<template>
<div :style="style" class="page">
组件内容
</div>
</template>
<script>
export default {
name:'Child',
data(){
return{
}
},
props:['width'],
computed:{
style:function(){
return{
width:this.width+"px"
}
}
}
}
</script>
<style>
.page{
border:1px solid #000;
}
</style>
页面效果图:
因为在传递宽度的时候要带单位(px),但每次都要写太麻烦,而且数值的计算一般都不带单位,所以统一在组件内使用计算属性实现。
1.4 计算属性缓存
我们从前面这些案例可以看到,调用methods里面的方法也可以与计算属性起到同样的作用,比如这里把示例1的功能用methods改写。
methods改写后的示例代码:
<template>
<div class="hello">
<!-- 这里的reversedMsg是方法,必须要带括号 -->
<h1>methods改写:{{reversedMsg()}}</h1>
<h1>methods改写:{{reversedMsg()}}</h1>
<h1>methods改写:{{reversedMsg()}}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
computed:{
},
methods:{
reversedMsg(){
console.log("reversedMsg函数被调用了!")
return this.msg.split('').reverse().join('')
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
显示效果:
?通过上面的改写,没有使用计算属性,而是在method里面定义了一个方法实现相同的效果,甚至该方法还可以接收参数,使用起来更加灵活。那既然使用methods就可以实现,为什么还要计算属性呢?
原因是计算属性是基于它的依赖缓存的,一个计算属性所依赖的数据发生变化,它才会重新取值,所以msg只要不改变,计算属性就不会更新,只解析一次。但是methods不同,只要重新渲染,它就会被调用,函数就会被执行。
所以,究竟是使用计算属性还是methods取决于是否需要缓存,当遍历大数组和计算量很大时,应当使用计算属性,除非不希望得到缓存。
?二、侦听器
2.1 什么是侦听器
Vue提供了一种更通用的方式来观察和响应Vue实例上的数据变动,称为侦听器。
下面通过实例代码来讲解侦听器的使用,具体代码如下:
<template>
<div class="hello">
<input type="text" v-model="firstName"/>
<input type="text" v-model="lastName"/>
<h1>{{fullName}}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
firstName:"Foo",
lastName:"Bar",
fullName:"Foo Bar"
}
},
watch:{
firstName:function(val){
this.fullName=val+" "+this.lastName
},
lastName:function(val){
this.fullName=this.firstName+" "+val
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
浏览器效果图:
?2.2? 计算属性VS侦听器
上面示例中的代码是命令式且重复的,将它使用计算属性修改之后进行比较,代码如下所示:
<template>
<div class="hello">
<input type="text" v-model="firstName"/>
<input type="text" v-model="lastName"/>
<h1>{{fullName}}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
firstName:"Foo",
lastName:"Bar",
}
},
computed:{
fullName:function(){
return this.firstName+""+this.lastName
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
?使用计算属性改写后感觉代码更简洁了。那为什么还要使用侦听器呢?
现在有一个需求:文本输入框中中的firstName和lastName其中一个内容发生了改变,fullName过1s钟之后再更新这个变化。
1.使用watch侦听器改写代码
<template>
<div class="hello">
<input type="text" v-model="firstName"/>
<input type="text" v-model="lastName"/>
<h1>{{fullName}}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
firstName:"Foo",
lastName:"Bar",
fullName:"Foo Bar"
}
},
// computed:{
// fullName:function(){
// return this.firstName+""+this.lastName
// }
// }
watch:{
firstName(val){
setTimeout(()=>{
this.fullName=val+" "+this.lastName
},1000)
},
lastName(val){
setTimeout(()=>{
this.fullName=this.firstName+" "+val
},1000)
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
2.使用计算属性computed改写代码,发现运行不出来结果,无法实现定时功能(异步操作)。
computed和watch之间的区别: ?? ?? 1.computed能完成的功能,watch都可以完成。 ?? ?? 2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。 两个重要的小原则: ?? 1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。 ?? 2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,这样this的指向才是vm 或 组件实例对象。
|