一、计算属性
概念:基于现有的数据,计算出来的新属性。 依赖的数据变化,自动重新计算。
例如,如果篮球数量变成2个,礼物总数会重新计算
语法:
① 声明在 computed 配置项中,一个计算属性对应一个函数
② 使用起来和普通属性一样使用 {{ 计算属性名 }}
计算属性 → 可以将一段 求值的代码 进行封装,如下所示
computed: {
计算属性名 () {
基于现有数据,编写求值逻辑
return 结果
}
},
代码举例
<div id="app">
<h3>小黑的礼物清单</h3>
<table>
<tr>
<th>名字</th>
<th>数量</th>
</tr>
<tr v-for="(item, index) in list" :key="item.id">
<td>{{ item.name }}</td>
<td>{{ item.num }}个</td>
</tr>
</table>
<!-- 目标:统计求和,求得礼物总数 -->
<p>礼物总数:{{ totalCount }} 个</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
// 现有的数据
list: [
{ id: 1, name: '篮球', num: 2 },
{ id: 2, name: '玩具', num: 2 },
{ id: 3, name: '铅笔', num: 5 },
]
},
// 计算属性: 基于现有的数据计算得出的结果, 如果依赖数据发生变化会自动重新计算并渲染
// 计算属性的语法: 本质是一个方法, 使用时当做属性来用
computed: {
totalCount() {
// 必须要返回一个结果, 这个结果是基于现有的数据计算得来的
// 计算属性的函数中也可以用 this 访问到实例对象
return this.list.reduce((sum, item) => sum + item.num, 0)
}
}
})
</script>
computed 计算属性 vs methods 方法
computed 计算属性:
作用:封装了一段对于数据的处理,求得一个结果。
语法:
① 写在 computed 配置项中
② 作为属性,直接使用 → this.计算属性 {{ 计算属性 }}
methods 方法:
作用:给实例提供一个方法,调用以处理业务逻辑。
语法:
① 写在 methods 配置项中
② 作为方法,需要调用 → this.方法名( ) {{ 方法名() }} @事件名="方法名"
computed计算属性很重要的特性:带缓存功能(提升性能):
首次计算后将结果缓存起来,后续如果有依赖的数据变化,就计算一次后继续缓存,多次访问只会计算一次,后面的几次都会从缓存中读取数据
如果依赖的数据更新,也会重新计算,然后重复上述操作
也就是控制台只会打印一次‘我是 computed 里的求和属性’,页面上会打印3次
<h3>小黑的礼物清单<span>{{ totalCount }}</span></h3>
<h3>小黑的礼物清单<span>{{ totalCount }}</span></h3>
<h3>小黑的礼物清单<span>{{ totalCount }}</span></h3>
computed: {
totalCount () {
console.log('我是 computed 里的求和属性')
return this.list.reduce((sum, item) => sum + item.num, 0)
}
}
计算属性会对计算出来的结果缓存,再次使用直接读取缓存,
依赖项变化了,会自动重新计算 → 并再次缓存
计算属性完整写法
计算属性默认的简写,只能读取访问,不能 "修改"。如果要 "修改" → 需要写计算属性的完整写法。
语法如下图所示
get翻译过来叫获取
set翻译过来叫设置
代码举例
<div id="app">
姓:<input type="text" v-model="firstName"> +
名:<input type="text" v-model="lastName"> =
<span>{{ fullName }}</span><br><br>
<button @click="change">改名卡</button>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.14/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
firstName: '刘',
lastName: '备',
},
methods: {
// 需求: 点击改名卡, 将刘备修改成黄忠
// 计算属性能不能修改? 简写形式是不能修改的, 因为函数无法被赋值成数据
// 完整写法可以被赋值, 当计算属性被赋值时, 计算属性的 set 会执行
change() {
this.fullName = '赵云'
}
},
computed: {
// 简写:
// fullName() {
// return this.firstName + this.lastName
// }
// 完整写法: 计算属性是一个对象
// 对象中拥有两个方法: get / set
// get 相当于就是以前的简写函数
fullName: {
// 计算属性被访问时, 自动执行 get 函数并返回结果
// 必须有返回值
get() {
// console.log('我是 get 我执行了')
return this.firstName + this.lastName
},
// 当计算属性被修改(赋值)时, 自动执行 set 函数, 并传入赋予的值
// 参数来接收赋予的值
set(val) {
// console.log('我是 set 我执行了', val.substring(0, 1), val.substring(1))
//substring(索引,截取几个)
this.firstName = val.substring(0, 1)
// Substring(1)不传第二个参数 代表截取到末尾,从索引为1开始,一直截取到末尾
this.lastName = val.substring(1)
}
}
}
})
</script>
执行原理:
修改了fullName,一旦修改了fullName,就会执行set()函数,它执行会把‘赵云’传到val里。然后我们 赵 赋值给firstName, 云 赋值给lastName,两个值一改,双向数据绑定,又会把值更新到imput这里,由于firstName和lastName改了,get函数检测到数据的变化,会执行get函数里的内容,重新计算,从而改变最最后的值
二、 watch 侦听器
作用:监视数据变化,执行一些 业务逻辑 或 异步操作。
语法:
- 简单写法 → 简单类型数据,直接监视
watch监听data里的数据,数据的属性名必须和data里的属性名同名(也就是words)
只能监听基本数据类型,如果需要监听引用数据类型 需要使用完整写法
const app = new Vue({
el: '#app',
data: {
obj: {
words: ''
}
},
// 具体讲解:(1) watch语法 (2) 具体业务实现
watch: {
// 监听 words 数据
// words() {},
// 1. 监听器的名字需要和数据名完全相同
// 2. 当数据变化时自动执行该函数
// 3. 如果数据是一个对象的属性, 可以把函数名定义成 => 对象.属性
// 4. 侦听器有两个参数, 参数1 是新值, 参数2 是旧值
// 绝大部分情况下旧值都不会使用, 仅使用新值即可
'obj.words'(newVal, oldVal) {
// console.log('words变了!')
console.log(newVal, oldVal)
}
}
})
业务实现
<!-- 翻译框 -->
<div class="box">
<div class="input-wrap">
<textarea v-model="obj.words"></textarea>
<span><i>⌨️</i>文档翻译</span>
</div>
<div class="output-wrap">
<div class="transbox">{{ result }}</div>
</div>
</div>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.14/vue.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.6/axios.min.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
obj: {
words: ''
},
result: ''
},
// 具体讲解:(1) watch语法 (2) 具体业务实现
watch: {
// 监听 words 数据
// words() {},
// 1. 监听器的名字需要和数据名完全相同
// 2. 当数据变化时自动执行该函数
// 3. 如果数据是一个对象的属性, 可以把函数名定义成 => 对象.属性
// 4. 侦听器有两个参数, 参数1 是新值, 参数2 是旧值
// 绝大部分情况下旧值都不会使用, 仅使用新值即可
async 'obj.words'() {
// console.log('words变了!')
// console.log(newVal, oldVal)
// console.log(this.obj.words)
const res = await axios({
url: 'https://applet-base-api-t.itheima.net/api/translate',
params: {
words: this.obj.words
}
})
// console.log(res.data.data)
// 赋值过去就是渲染
this.result = res.data.data
}
}
})
- 完整写法 → 添加额外配置项
比如:监听一整个对象
(1) deep: true 对复杂类型深度监视
(2) immediate: true 初始化立刻执行一次handler方法
完整写法总结:
handler: 当数据变化时自动触发
deep: 开启深度侦听, 默认情况下只能监听基本数据类型, 必须开启它才能监听引用数据类型的变化
immediate: 初次进入页面自动触发一次
完整写法的案例:
<div id="app">
<!-- 条件选择框 -->
<div class="query">
<span>翻译成的语言:</span>
<select v-model="obj.lang">
<option value="italy">意大利</option>
<option value="english">英语</option>
<option value="german">德语</option>
</select>
</div>
<!-- 翻译框 -->
<div class="box">
<div class="input-wrap">
<textarea v-model="obj.words"></textarea>
<span><i>⌨️</i>文档翻译</span>
</div>
<div class="output-wrap">
<div class="transbox">{{ result }}</div>
</div>
</div>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.14/vue.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.6/axios.min.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
obj: {
words: '玖月吖',
lang: 'english'
},
result: ''
},
// 具体讲解:(1) watch语法 (2) 具体业务实现
watch: {
// 对象不能使用简单写法来监视!
// async obj() {
// 如果想监视对象的变化, 必须使用完整写法
// 默认情况下只有在数据变化时才会触发监听器的执行
// 如果希望进入页面就执行一次函数, 可以再加一个配置: immediate: true
obj: {
immediate: true, // 初始化时触发一次
deep: true, // 开启深度侦听, 可以监听引用类型
// handler 会在数据变化时自动执行
async handler() {
// const { words, lang } = this.obj
// console.log('obj 变了!')
// console.log(newVal, oldVal)
// console.log(this.obj.words)
const res = await axios({
url: 'https://applet-base-api-t.itheima.net/api/translate',
params: this.obj
// params: {
// words,
// lang
// }
})
// console.log(res.data.data)
// 赋值过去就是渲染
this.result = res.data.data
}
}
}
})
</script>
ps:翻译器不是真正的翻译器,没有翻译的功能,翻译的结果都不是正确的,这里主要是告诉大家watch的用法