1.复杂 data 的处理方式
三个案例:
案例一:我们有两个变量: firstName 和 lastName ,希望它们拼接之后在界面上显示;
案例二:我们有一个分数: score
当 score 大于 60 的时候,在界面上显示及格;
当 score 小于 60 的时候,在界面上显示不及格;
案例三:我们有一个变量 message ,记录一段文字:比如 Hello World
某些情况下我们是直接显示这段文字;
某些情况下我们需要对这段文字进行反转;
我们可以有三种实现思路:
思路一:在模板语法中直接使用表达式;
思路二:使用 method 对逻辑进行抽取;
思路三:使用计算属性 computed ;
法1:万物都扔mustache
缺点一:模板中存在大量的复杂逻辑,不便于维护(模板中表达式的初衷是用于简单的计算);
缺点二:当有多次一样的逻辑时,存在重复的代码;
缺点三:多次使用的时候,很多运算也需要多次执行,没有缓存;
<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">
<!-- 插值语法表达式直接进行拼接 -->
<!-- 1.拼接名字 -->
<h2>{{ firstName + " " + lastName }}</h2>
<h2>{{ firstName + " " + lastName }}</h2>
<h2>{{ firstName + " " + lastName }}</h2>
<!-- 2.显示分数等级 -->
<h2>{{ score >= 60 ? '及格': '不及格' }}</h2>
<!-- 3.反转单词显示文本 -->
<h2>{{ message.split(" ").reverse().join(" ") }}</h2>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
// 1.姓名
firstName: "kobe",
lastName: "bryant",
// 2.分数: 及格/不及格
score: 80,
// 3.一串文本: 对文本中的单词进行反转显示
message: "my name is why"
}
},
})
// 2.挂载app
app.mount("#app")
</script>
</body>
</html>
法2:扔函数里面
缺点一:我们事实上先显示的是一个结果,但是都变成了一种方法的调用;
缺点二:多次使用方法的时候,没有缓存,也需要多次计算;
<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">
<!-- 插值语法表达式直接进行拼接 -->
<!-- 1.拼接名字 -->
<h2>{{ getFullname() }}</h2>
<h2>{{ getFullname() }}</h2>
<h2>{{ getFullname() }}</h2>
<!-- 2.显示分数等级 -->
<h2>{{ getScoreLevel() }}</h2>
<!-- 3.反转单词显示文本 -->
<h2>{{ reverseMessage() }}</h2>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
// 1.姓名
firstName: "kobe",
lastName: "bryant",
// 2.分数: 及格/不及格
score: 80,
// 3.一串文本: 对文本中的单词进行反转显示
message: "my name is why"
}
},
methods: {
getFullname() {
return this.firstName + " " + this.lastName
},
getScoreLevel() {
return this.score >= 60 ? "及格": "不及格"
},
reverseMessage() {
return this.message.split(" ").reverse().join(" ")
}
}
})
// 2.挂载app
app.mount("#app")
</script>
</body>
</html>
法3:使用computed
注意:计算属性看起来像是一个函数,但是我们在使用的时候不需要加 () ,这个后面讲 setter 和 getter 时会讲到;
我们会发现无论是直观上,还是效果上计算属性都是更好的选择;
并且计算属性是有缓存的;
<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">
<!-- 插值语法表达式直接进行拼接 -->
<!-- 1.拼接名字 -->
<h2>{{ fullname }}</h2>
<h2>{{ fullname }}</h2>
<h2>{{ fullname }}</h2>
<!-- 2.显示分数等级 -->
<h2>{{ scoreLevel }}</h2>
<!-- 3.反转单词显示文本 -->
<h2>{{ reverseMessage }}</h2>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
// 1.姓名
firstName: "kobe",
lastName: "bryant",
// 2.分数: 及格/不及格
score: 80,
// 3.一串文本: 对文本中的单词进行反转显示
message: "my name is why"
}
},
computed: {
// 1.计算属性默认对应的是一个函数
fullname() {
return this.firstName + " " + this.lastName
},
scoreLevel() {
return this.score >= 60 ? "及格": "不及格"
},
reverseMessage() {
return this.message.split(" ").reverse().join(" ")
}
}
})
// 2.挂载app
app.mount("#app")
</script>
</body>
</html>
认识计算属性 computed
官方并没有给出直接的概念解释,而是说:对于任何包含响应式数据的复杂逻辑,你都应该使用计算属性;
计算属性将被混入到组件实例中
所有 getter 和 setter 的 this 上下文自动地绑定为组件实例;
计算属性 vs methods
在上面的实现思路中,我们会发现计算属性和 methods 的实现看起来是差别是不大的,而且我们多次提到计算属性有缓存的。
接下来我们来看一下同一个计算多次使用,计算属性和 methods 的差异:
<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">
<!-- 1.methods -->
<h2>{{ getFullname() }}</h2>
<h2>{{ getFullname() }}</h2>
<h2>{{ getFullname() }}</h2>
<!-- 2.computed -->
<h2>{{ fullname }}</h2>
<h2>{{ fullname }}</h2>
<h2>{{ fullname }}</h2>
<!-- 修改name值 -->
<button @click="changeLastname">修改lastname</button>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
firstName: "kobe",
lastName: "bryant",
};
},
methods: {
getFullname() {
console.log("getFullname-----");
return this.firstName + " " + this.lastName;
},
changeLastname() {
this.lastName = "why";
},
},
computed: {
fullname() {
console.log("computed fullname-----");
return this.firstName + " " + this.lastName;
},
},
});
// 2.挂载app
app.mount("#app");
</script>
</body>
</html>
这是什么原因呢?
这是因为计算属性会基于它们的依赖关系进行缓存;
在数据不发生变化时,计算属性是不需要重新计算的;
但是如果依赖的数据发生变化,在使用时,计算属性依然会重新进行计算;
计算属性的 setter 和 getter
计算属性在大多数情况下,只需要一个 getter 方法即可,所以我们会将计算属性直接写成一个函数。
但是,如果我们确实想设置计算属性的值呢?
这个时候我们也可以给计算属性设置一个 setter 的方法;但是setter基本不用
<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>
<button @click="setFullname">设置fullname</button>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
firstname: "coder",
lastname: "why"
}
},
computed: {
// 语法糖的写法
// fullname() {
// return this.firstname + " " + this.lastname
// },
// 完整的写法:
fullname: {
get: function() {
return this.firstname + " " + this.lastname
},
set: function(value) {
const names = value.split(" ")
this.firstname = names[0]
this.lastname = names[1]
}
}
},
methods: {
setFullname() {
this.fullname = "kobe bryant"
}
}
})
// 2.挂载app
app.mount("#app")
</script>
</body>
</html>