携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情 >>
computed
前面我们使用Mustache 来包裹数据并在里面使用表达式进行一些数据的拼接或计算,这样十分不优雅,那么有什么办法解决呢?
首先想到的就是,定义一个方法拼接数据,然后将之返回给Mustache 中,可以先来试试,如下:
我们得到了和Mustache 中书写同样的效果。
<!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>Document</title>
</head>
<body>
<div id="app">
<h2>{{firstName+" "+lastName}}</h2>
<h2>{{getFullName()}}</h2>
<h2></h2>
</div>
<script src="../lib/vue.mini.js"></script>
<script>
const app=Vue.createApp({
data(){
return{
firstName:'kobe',
lastName:'bryant',
score:80
}
},
methods:{
getFullName(){
return this.firstName+" "+this.lastName
}
}
})
app.mount('#app')
</script>
</body>
</html>
上诉的调用方法来进行,感觉在Mustache 中调用方法有点奇怪,它不是应该直接拿到静态内容展示才比较好的吗?而且每次就算数据没有改变我们都会调用一下方法,过于浪费性能了。
那我们可以使用computed 计算属性,如下,我们通过计算属性判断成绩的级别,当大于等于九十分时为优秀,然后直接在Mustache 中添加计算属性内的语法糖,这里看着和调用方法一样其实不然,fullName 和getLevel 只是只读情况下的语法糖。
<!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>Document</title>
</head>
<body>
<div id="app">
<h2>{{fullName}}</h2>
<h2>{{getLevel}}</h2>
<h2></h2>
</div>
<script src="../lib/vue.mini.js"></script>
<script>
const app=Vue.createApp({
data(){
return{
firstName:'kobe',
lastName:'bryant',
score:80
}
},
computed:{
fullName(){
return this.firstName+" "+this.lastName
},
getLevel(){
const score=this.score
if(score>=90){
return '优秀'
}else if(score>=80){
return '良好'
}else if(score>=60){
return '及格'
}
}
}
})
app.mount('#app')
</script>
</body>
</html>
computed详解
computed完整的写法如下,但是通常情况下只使用只读的computed 即可:
computed:{
fullName:{
get:()=>(),
set:(value)=>void
}
}
当对data 中的数据进行修改时,setter 会被调用,之后get就会自动调用
注意: 虽然我们可以将计算属性看作非只读的,但是官方还是建议将计算属性的返回值视为只读的,并且不要在计算函数中做异步请求活着更改DOM
watch
在某些情况下我们需要应对一些状态的变化,并根据这些变化运行某些副作用,这时候就需要watch 了,在每次响应式property发生变化时触发一个函数。如下所示:当一个info发生变化的时候,会触发副作用,但是如果info.name 修改了,默认情况下是不会触发副作用的,因为算是浅层监听。
<!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>Document</title>
</head>
<body>
<div id="app">
<h2>{{message}}</h2>
<button @click="changeMessage">改变message</button>
</div>
<script src="../lib/vue.mini.js"></script>
<script>
const app=Vue.createApp({
data(){
return{
message:'hello',
info:{name:'why',age:18}
}
},
methods:{
changeMessage(){
this.message='你好啊,李银河',
this.info={name:'hello',age:10}
}
},
watch:{
// 1. 默认有两个参数 newValue,oldValue
message(newValue,oldValue){
console.log('message发生改变',newValue,oldValue)
},
info(newValue,oldValue){
// 如果是对象 拿到的是代理对象 想要拿到原始对象
console.log('info改变了',Vue.toRaw(newValue),oldValue)
}
}
})
app.mount('#app')
</script>
</body>
</html>
watch的选项
如下,如果想要深层监听对象的话,就可以使用deep:true ,有时候我们有一个需求,比如页面初始化的时候进行网络请求,那么就可以使用immediate:true 让它第一次渲染时就执行一次监听器。但是即时深层监听,只要没有替换对象本身,虽然触发了副作用,但是这里的newValue 和oldValue 是相同的。
<!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>Document</title>
</head>
<body>
<div id="app">
<h2>{{message}}</h2>
<button @click="changeMessage">改变message</button>
</div>
<script src="../lib/vue.mini.js"></script>
<script>
const app=Vue.createApp({
data(){
return{
message:'hello',
info:{name:'why',age:18}
}
},
methods:{
changeMessage(){
this.message='你好啊,李银河',
this.info.name='hello'
}
},
watch:{
// 1. 默认有两个参数 newValue,oldValue
message(newValue,oldValue){
console.log('message发生改变',newValue,oldValue)
},
info:{
handler(newValue,oldValue){
console.log('info改变了',Vue.toRaw(newValue),oldValue)
},
deep:true,
// 第一次渲染时 想要执行一次监听器
immediate:true
}
}
})
app.mount('#app')
</script>
</body>
</html>