其他
路由
路由懒加载组件
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// const 组件名 = () => import('组件路径');
const Home = () => import('@/componnets/home');
const Index = () => import('@/components/index');
{
path: '/home',
name: 'home',
component: Home
}, {
path: '/index',
name: 'index',
component: Index
}
|
模板形式
选项式更容易理解,但推荐组合式
选项式
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
|
<script>
export default {
// data() 返回的属性将会成为响应式的状态
// 并且暴露在 `this` 上
data() {
return {
count: 0
}
},
// methods 是一些用来更改状态与触发更新的函数
// 它们可以在模板中作为事件处理器绑定
methods: {
increment() {
this.count++
}
},
// 生命周期钩子会在组件生命周期的各个不同阶段被调用
// 例如这个函数就会在组件挂载完成后被调用
mounted() {
console.log(`The initial count is ${this.count}.`)
}
}
</script>
<template>
<button @click="increment">Count is: {{ count }}</button>
</template>
|
组合式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<script setup>
import { ref, onMounted } from 'vue'
// 响应式状态
const count = ref(0)
// 用来修改状态、触发更新的函数
function increment() {
count.value++
}
// 生命周期钩子
onMounted(() => {
console.log(`The initial count is ${count.value}.`)
})
</script>
<template>
<button @click="increment">Count is: {{ count }}</button>
</template>
|
ES 模块
在 Html 的 script 标签中,原来只能添加简单的 JS 语句,现在添加属性 type="module" 之后就可以使用 import 语句。
未使用 ES 模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<body>
<div id="app">
</div>
</body>
<script>
const { createApp, ref } = Vue
createApp({
setup() {
const message = ref('Hello vue!')
return {
message
}
}
}).mount('#app')
</script>
|
使用 ES 模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<div id="app">{{ message }}</div>
<script type="module">
import { createApp, ref } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
createApp({
setup() {
const message = ref('Hello Vue!')
return {
message
}
}
}).mount('#app')
</script>
|
异常捕捉
1
2
3
4
5
6
7
|
var app = createApp(App)
app.use(Antd).mount('#app')
app.config.errorHandler = (err, instance, info) => {
// 处理错误,例如:报告给一个服务
}
|
全局属性
1
2
3
4
5
|
var app = createApp(App)
app.use(Antd).mount('#app')
app.config.globalProperties.msg = 'hello'
|
这使得 msg 在应用的任意组件模板上都可用,并且也可以通过任意组件实例的 this 访问到:
1
2
3
4
5
|
export default {
mounted() {
console.log(this.msg) // 'hello'
}
}
|
动态绑定多个值
如果你有像这样的一个包含多个 attribute 的 JavaScript 对象:
1
2
3
4
|
const objectOfAttrs = {
id: 'container',
class: 'wrapper'
}
|
通过不带参数的 v-bind,你可以将它们绑定到单个元素上:
template
1
|
<div v-bind="objectOfAttrs"></div>
|
等待DOM渲染更新
1
2
3
4
5
6
7
|
import { nextTick } from 'vue'
async function increment() {
count.value++
await nextTick()
// 现在 DOM 已经更新了
}
|
优化
避免不必要的组件抽象
有些时候我们会去创建无渲染组件或高阶组件 (用来渲染具有额外 props 的其他组件) 来实现更好的抽象或代码组织。虽然这并没有什么问题,但请记住,组件实例比普通 DOM 节点要昂贵得多,而且为了逻辑抽象创建太多组件实例将会导致性能损失。
ref 和 reactive
reactive() API 有一些局限性:
-
有限的值类型:它只能用于对象类型 (对象、数组和如 Map、Set 这样的集合类型)。它不能持有如 string、number 或 boolean 这样的原始类型。
-
不能替换整个对象:由于 Vue 的响应式跟踪是通过属性访问实现的,因此我们必须始终保持对响应式对象的相同引用。这意味着我们不能轻易地“替换”响应式对象,因为这样的话与第一个引用的响应性连接将丢失:
js
1
2
3
4
5
|
let state = reactive({ count: 0 })
// 上面的 ({ count: 0 }) 引用将不再被追踪
// (响应性连接已丢失!)
state = reactive({ count: 1 })
|
-
对解构操作不友好:当我们将响应式对象的原始类型属性解构为本地变量时,或者将该属性传递给函数时,我们将丢失响应性连接:
js
1
2
3
4
5
6
7
8
9
10
11
|
const state = reactive({ count: 0 })
// 当解构时,count 已经与 state.count 断开连接
let { count } = state
// 不会影响原始的 state
count++
// 该函数接收到的是一个普通的数字
// 并且无法追踪 state.count 的变化
// 我们必须传入整个对象以保持响应性
callSomeFunction(state.count)
|
由于这些限制,我们建议使用 ref() 作为声明响应式状态的主要 API。
方法vs计算属性
计算属性值会基于其响应式依赖被缓存,重复使用的属性应该以计算属性的方式存在。
1
2
3
|
const publishedBooksMessage = computed(() => {
return author.books.length > 0 ? 'Yes' : 'No'
})
|
注意:
因为 Date.now() 并不是一个响应式依赖,下面的计算属性永远不会更新:
1
|
const now = computed(() => Date.now())
|
根据属性渲染样式
可以绑定一个返回对象的计算属性。这是一个常见且很有用的技巧:
1
2
3
4
5
6
7
|
const isActive = ref(true)
const error = ref(null)
const classObject = computed(() => ({
active: isActive.value && !error.value,
'text-danger': error.value && error.value.type === 'fatal'
}))
|
1
|
<div :class="classObject"></div>
|