目录
1_computed计算属性使用
1.1_复杂data的处理方式
在模板中可以直接通过插值语法显示一些data中的数据,比如下面的代码
<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 hhh"
}
},
})
// 2.挂载app
app.mount("#app")
</script>
</body>
在某些情况,需要对数据进行一些转化后再显示,或者将多个数据结合起来进行显示;
- 比如需要对多个data数据进行运算、三元运算符来决定结果、数据进行某种转化后显示;
- 在模板中使用表达式,可以非常方便的实现,但是设计它们的初衷是用于简单的运算;
- 在模板中放入太多的逻辑会让模板过重和难以维护;
- 并且如果多个地方都使用到,那么会有大量重复的代码;
将逻辑抽离出去的方法?
- 一种方式就是将逻辑抽取到一个method中,放到methods的options中;但是,这种做法有一个直观的弊端,就是所有的data使用过程都会变成了一个方法的调用;
<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 hhh"
}
},
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>
- 另外一种方式就是使用计算属性computed;
1.2_计算属性computed
如何理解?
- 官方并没有给出直接的概念解释;
- 而是说:对于任何包含响应式数据的复杂逻辑,你都应该使用计算属性;
- 计算属性将被混入到组件实例中: 所有 getter 和 setter 的 this 上下文自动地绑定为组件实例;
计算属性的用法:
- 选项:computed
- 类型:{ [key: string]: Function | { get: Function, set: Function } }
按照1.1的代码,使用computed属性
<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 hhh"
}
},
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>
1.3_计算属性 vs methods
虽然计算属性和methods的实现代码看起来差别不大,但是计算属性有缓存的。
计算属性会基于它们的依赖关系进行缓存;
- 在数据不发生变化时,计算属性是不需要重新计算的;但是methods是调用一次,就计算一次,对比之下,比较消耗性能。
- 但是如果依赖的数据发生变化,在使用时,计算属性依然会重新进行计算;
所以,建议优先使用计算属性computed
1.4_计算属性的setter和getter(了解)
计算属性在大多数情况下,只需要一个getter方法即可,所以会将计算属性直接写成一个函数。
<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: "hhh"
}
},
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>
2_侦听器watch
2.1_认识
侦听器?
- 开发中在data返回的对象中定义了数据,这个数据通过插值语法等方式绑定到template中;
- 当数据变化时,template会自动进行更新来显示最新的数据;
- 但是在某些情况下,希望在代码逻辑中监听某个数据的变化,这时就需要侦听器watch来完成了;
侦听器的用法如下:
- 选项:watch
- 类型:{ [key: string]: string | Function | Object | Array}
案例:
- 比如现在希望用户在input中输入一个问题;
- 每当用户输入了最新的内容,就获取到最新的内容,并且使用该问题去服务器查询答案;
- 那么,就需要实时的去获取最新的数据变化;
<body>
<div id="app">
<h2>{
{message}}</h2>
<button @click="changeMessage">修改message</button>
</div>
<script src="../lib/vue.js"></script>
<script>
// Proxy -> Reflect
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
message: "Hello Vue",
info: {
name: "hhh", age: 18 }
}
},
methods: {
changeMessage() {
this.message = "你好啊, 李银河!"
this.info = {
name: "kobe" }
}
},
watch: {
// 1.默认有两个参数: newValue/oldValue
message(newValue, oldValue) {
console.log("message数据发生了变化:", newValue, oldValue)
},
info(newValue, oldValue) {
// 2.如果是对象类型, 那么拿到的是代理对象 Proxy
console.log("info数据发生了变化:", newValue, oldValue)
// Proxy(Object) {name: 'kobe'}
// Proxy(Object) {name: 'hhh', age: 18}
console.log(newValue.name, oldValue.name) //kobe hhh
// 3.获取原生对象
console.log({
...newValue }) //{name: 'kobe'}
console.log(Vue.toRaw(newValue)) //{name: 'kobe'}
}
}
})
// 2.挂载app
app.mount("#app")
</script>
</body>
2.2_侦听器watch的配置选项
一个例子:
- 当点击按钮的时候会修改info.name的值;
- 这个时候使用watch来侦听info,可以侦听到吗?答案是不可以。
因为默认情况下,watch只是在侦听info的引用变化,对于内部属性的变化是不会做出响应的:
- 这个时候可以使用一个选项deep进行更深层的侦听;
- 注意watch里面侦听的属性对应的也可以是一个Object;
immediate属性,一开始的就会立即执行一次:
- 这个时候使用immediate选项;
- 这个时候无论后面数据是否有变化,侦听的函数都会执行一次;
<body>
<div id="app">
<h2>{
{ info.name }}</h2>
<button @click="changeInfo">修改info</button>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
info: {
name: "hhh", age: 18 }
}
},
methods: {
changeInfo() {
// 1.创建一个新对象, 赋值给info
// this.info = { name: "kobe" }
// 2.直接修改原对象某一个属性
this.info.name = "kobe"
}
},
watch: {
// 默认watch监听不会进行深度监听
// info(newValue, oldValue) {
// console.log("侦听到info改变:", newValue, oldValue)
// }
// 修改代码,进行深度监听
info: {
handler(newValue, oldValue) {
console.log("侦听到info改变:", newValue, oldValue)
console.log(newValue === oldValue)
},
// 监听器选项:
// info进行深度监听
deep: true,
// 第一次渲染直接执行一次监听器
immediate: true
},
"info.name": function(newValue, oldValue) {
console.log("name发生改变:", newValue, oldValue)
}
}
})
// 2.挂载app
app.mount("#app")
</script>
</body>