Vue3学习笔记:Day3 data、方法和计算属性

Vue3应用data属性和methods应用方法以及计算属性

Data property

在创建Vue应用的时候,会调用组件的data方法,所以data方法要返回一个JS对象,应用通过$data暴露出来,在data中的所有顶级属性都会直接从应用调用

在Vue应用运行时,自身的响应式系统会追踪data中的properties,检查是否更新并做出响应,所以对于没有定义在data中的properties,其更新后Vue不会做出响应

使用$前缀暴露的是Vue内置API,内部properties使用_前缀,在定义properties时应该避免这两个前缀

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const app = Vue.createApp({
data() {
return { count: 4 }
}
})

const vm = app.mount('#app')

console.log(vm.$data.count) // => 4
console.log(vm.count) // => 4

// 修改 vm.count 的值也会更新 $data.count
vm.count = 5
console.log(vm.$data.count) // => 5

// 反之亦然
vm.$data.count = 6
console.log(vm.count) // => 6

方法

Vue应用的方法定义在methods中,Vue会自动将应用实例绑定到this上,所以要避免使用箭头函数

方法同Properties一样可以直接从实例中访问,并且如果调用的方法使用了data中的Properties,会作为渲染依赖项进行跟踪

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const app = Vue.createApp({
data() {
return { count: 4 }
},
methods: {
increment() {
// `this` 指向该组件实例
this.count++
}
}
})

const vm = app.mount('#app')

console.log(vm.count) // => 4

vm.increment()

console.log(vm.count) // => 5
1
<button @click="increment">Up vote</button>

防抖和节流

防抖和节流函数使用其他库来实现,如Lodash

1
<script src="https://unpkg.com/lodash@4.17.20/lodash.min.js"></script>

防抖函数_.debounce(func, [wait=0], [options={}])

节流函数_.throttle(func, [wait=0], [options={}])

绑定方法有两种,只使用一次可以通过methods属性中直接调用

1
2
3
4
5
6
7
8
9
10
11
<script src="https://unpkg.com/lodash@4.17.20/lodash.min.js"></script>
<script>
Vue.createApp({
methods: {
// 用 Lodash 的防抖函数
click: _.debounce(function() {
// ... 响应点击 ...
}, 500)
}
}).mount('#app')
</script>

如果实现防抖函数的复用,可以添加在生命周期钩子created

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
app.component('save-button', {
created() {
// 使用 Lodash 实现防抖
this.debouncedClick = _.debounce(this.click, 500)
},
unmounted() {
// 移除组件时,取消定时器
this.debouncedClick.cancel()
},
methods: {
click() {
// ... 响应点击 ...
}
},
template: `
<button @click="debouncedClick">
Save
</button>
`
})

计算属性

虽然在HTML模板中可以计算JS的表达式,但是在模板中过多的计算会让模板变得复杂并且难以维护,而且有些地方并不允许JS表达式,或者不太方便,所以复杂的计算要放在计算属性中调用

1
2
3
4
<div id="computed-basics">
<p>Has published books:</p>
<span>{{ publishedBooksMessage }}</span>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Vue.createApp({
data() {
return {
author: {
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
}
}
},
computed: {
// 计算属性的 getter
publishedBooksMessage() {
// `this` 指向 vm 实例
return this.author.books.length > 0 ? 'Yes' : 'No'
}
}
}).mount('#computed-basics')

侦听器

自定义的侦听器是相应数据变化的通用方法,适合在数据变化时执行异步或开销很大的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<div id="watch-example">
<p>
Ask a yes/no question:
<input v-model="question" />
</p>
<p>{{ answer }}</p>
</div>
<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
<!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script>
const watchExampleVM = Vue.createApp({
data() {
return {
question: '',
answer: 'Questions usually contain a question mark. ;-)'
}
},
watch: {
// 每当 question 发生变化时,该函数将会执行
question(newQuestion, oldQuestion) {
if (newQuestion.indexOf('?') > -1) {
this.getAnswer()
}
}
},
methods: {
getAnswer() {
this.answer = 'Thinking...'
axios
.get('https://yesno.wtf/api')
.then(response => {
this.answer = response.data.answer
})
.catch(error => {
this.answer = 'Error! Could not reach the API. ' + error
})
}
}
}).mount('#watch-example')
</script>

在watch中定义的函数,会监听其绑定的数据是否发生变化,如果发生变化就会被执行。

此处侦听器的名字要和绑定变量名相同,并且函数第一个变量是变化后的,第二个变量是变化前的,都是可选的

方法属性、计算属性、侦听器的区别

方法属性vs计算属性

使用计算属性会为这个函数生成缓存,缓存会和计算属性中使用的properties绑定作为依赖项,缓存的作用是当绑定的属性值没有发生改变时,再次调用计算属性函数,不会执行函数而是直接将上一次储存在缓存中的结果输出,提高了效率。所以单纯的计算或者数据变换的过程使用计算属性会效率更高

计算属性vs侦听器

在开发使用时,不要一想到数据变化就要使用侦听器,要根据情况选择

如拼接名字,姓名分为姓和名,如果使用侦听器来实现就需要在姓和名两变量上分别定义侦听器来拼接,但如果使用计算属性,只需要根据姓和名计算出姓名即可

1
<div id="demo">{{ fullName }}</div>

侦听器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const vm = Vue.createApp({
data() {
return {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
}
},
watch: {
firstName(val) {
this.fullName = val + ' ' + this.lastName
},
lastName(val) {
this.fullName = this.firstName + ' ' + val
}
}
}).mount('#demo')

计算属性

1
2
3
4
5
6
7
8
9
10
11
12
13
const vm = Vue.createApp({
data() {
return {
firstName: 'Foo',
lastName: 'Bar'
}
},
computed: {
fullName() {
return this.firstName + ' ' + this.lastName
}
}
}).mount('#demo')