跟着AI助理学习Vue3,这一篇文章足够了
在讲述我的学习历程之前,我必须先声明:文档和我,视频和我,都不是好朋友。一提到他们,我就困得像只懒猫,学习效率和记忆能力一落千丈。然而,自从我遇见了GPT4,一切都变得如此不同。
GPT4就像那个学校里的调皮生,给我的学习带来了不少趣味。我和它的交流仿佛是一场精彩绝伦的话剧,我可以让它扮演各种角色,玩转各种场景。这一次,我决定学习Vue3,但我不再需要去硬啃那些令我头疼的API文档。我选择与GPT4并肩作战,一起在知识的矿洞中挖掘珍宝。
过程中,我遇到了一些困难,有些知识点像是一团乱麻。但我有GPT4,它就像一把魔法钥匙,为我打开了那些难题的大门,让我轻松理解。我觉得,这样的学习效率,真的是我从未有过的新体验。
现在,我想分享的这篇文章,就是GPT4和我一起完善的Vue3知识点总结。我必须说,GPT4就像那个学校里的优等生,无论是哪个知识点,它都可以轻松搞定。
接下来,通过这一篇文章,超级详细的带你学习一遍Vue3的知识点。
Vue3基础
如何创建Vue实例
在 Vue3 中,我们不再使用 new Vue() 来创建一个 Vue 实例。取而代之的是一个名为 createApp() 的函数。createApp() 是 Vue3 的新函数,它用于创建并挂载 Vue 应用。
以下是一个简单的 Vue3 应用的创建方式:
// 1. 导入Vue和你的应用组件
import { createApp } from 'vue'
import App from './App.vue'
// 2. 创建Vue应用实例
const app = createApp(App)
// 3. 挂载Vue应用实例到你的HTML元素上
app.mount('#app')
在上述代码中:
- 我们从 'vue' 导入 createApp 函数和你的应用组件 App.vue。
- 使用 createApp 函数和你的根组件创建 Vue 应用实例。这个根组件通常是你的应用的主组件,并且其他所有组件都会作为其子组件。
- 你需要指定一个 HTML 元素(在这里是 id 为 'app' 的元素),将 Vue 应用实例挂载到这个元素上。
在实际开发中,你可能还需要安装和配置各种插件(如 vue-router 或 vuex),然后在创建应用实例之前使用它们。在这种情况下,你可以使用 app.use(plugin)。例如,如果你要使用 Vue Router,代码可能会看起来像这样:
import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import App from './App.vue'
import routes from './routes'
const router = createRouter({
history: createWebHistory(),
routes, // short for `routes: routes`
})
const app = createApp(App)
app.use(router)
app.mount('#app')
总的来说,createApp() 方法为我们提供了一个更清晰和更灵活的方式来创建和配置我们的 Vue 应用。
Vue生命周期钩子函数
Vue 3 的生命周期钩子函数与 Vue 2.x 的生命周期钩子函数在名称和功能上有一些差异。以下是 Vue 3 中可用的主要生命周期钩子:
- beforeCreate 和 created:在 Vue 3 中,这两个生命周期钩子已被移除。Vue 3 使用 setup 函数替代了这两个钩子,setup 函数在组件初始化之后,属性和反应性系统设置之前调用。
- beforeMount:在挂载开始之前被调用,此时模板或渲染函数尚未编译,而 DOM 还未生成。在服务器端渲染期间,此钩子不被调用。
- mounted:在挂载(即,组件被插入其挂载点)结束之后被调用。此时,你可以通过 this 访问到新创建的 vm 实例。注意 mounted 不会保证所有的子组件也都一起被挂载。如果你想等到整个视图都渲染完毕,可以使用 vm.$nextTick。
- beforeUpdate:在数据更改之后,虚拟 DOM 重新渲染和打补丁之前调用。你可以在这个钩子中进一步地更改状态,这不会触发额外的重渲染过程。
- updated:在包含异步组件的组件的数据更改之后,当组件和子组件的虚拟 DOM 重新渲染和打补丁之后立即调用。
- beforeUnmount:在卸载组件之前被调用。在这一阶段,实例仍然完全可用。这是 Vue 2.x 中的 beforeDestroy 钩子。
- unmounted:在卸载(即,组件被销毁)组件之后被调用。这是 Vue 2.x 中的 destroyed 钩子。
注意:在 Vue 3 中,生命周期方法的命名已经改变,以更好地反映它们何时被调用。比如,beforeDestroy 改名为 beforeUnmount,destroyed 改名为 unmounted。如果你正在从 Vue 2.x 迁移到 Vue 3,需要留意这些更改。
以下是一段使用了生命周期钩子函数的 Vue 3 代码示例:
import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from 'vue'
export default {
setup() {
onBeforeMount(() => {
console.log('onBeforeMount')
})
onMounted(() => {
console.log('onMounted')
})
onBeforeUpdate(() => {
console.log('onBeforeUpdate')
})
onUpdated(() => {
console.log('onUpdated')
})
onBeforeUnmount(() => {
console.log('onBeforeUnmount')
})
onUnmounted(() => {
console.log('onUnmounted')
})
// ...
}
}
模板语法和指令
在 Vue 3 中,模板语法仍然是非常关键的概念,以下是一些核心的模板语法特性:
1. 插值
在双大括号 {{ }} 中,可以插入 JavaScript 表达式,例如 {{ message }}。
<template>
<div>{{ message }}</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const message = ref('Hello Vue 3!')
return {
message
}
}
}
</script>
2. 指令:
Vue 提供了一些特殊属性,称为指令,例如 v-if, v-for, v-bind, v-on, v-model。
- v-if:根据表达式的真假决定是否渲染元素。
<template>
<div v-if="showMessage">{{ message }}</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const showMessage = ref(true)
const message = ref('Hello Vue 3!')
return {
showMessage,
message
}
}
}
</script>
- v-for:基于源数据多次渲染元素或模板块。
<template>
<div v-for="(item, index) in items" :key="index">{{ item.text }}</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const items = ref([
{ text: 'Item 1' },
{ text: 'Item 2' },
{ text: 'Item 3' },
])
return {
items
}
}
}
</script>
- v-bind:动态绑定一个或多个特性,或一个组件 prop 到表达式
<template>
<div v-bind:id="dynamicId"></div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const dynamicId = ref('myId')
return {
dynamicId
}
}
}
</script>
- v-on:添加事件监听器
<template>
<button v-on:click="incrementCounter">Click me</button>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const counter = ref(0)
const incrementCounter = () => {
counter.value++
}
return {
incrementCounter
}
}
}
</script>
- v-model:创建双向数据绑定。
在 Vue 中,v-model 指令用于在输入元素和 Vue 实例的数据之间建立双向数据绑定。这意味着当输入元素的值改变时,数据会自动更新,反之亦然。
在内部,v-model 实际上是一个语法糖,它结合了 v-bind 和 v-on。以下是 v-model 的基本使用方法:
<template>
<input v-model="message" placeholder="edit me">
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const message = ref('Hello Vue 3!')
return {
message
}
}
}
</script>
在这个例子中,v-model 指令与 Vue 实例中的 message 数据属性绑定。当用户在输入框中键入内容时,message 的值将随之改变。
对于一些特殊的表单控件,如复选框和单选按钮,v-model 的工作方式会有所不同:
<template>
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const checked = ref(false)
return {
checked
}
}
}
</script>
在这个例子中,v-model 指令与 Vue 实例中的 checked 数据属性绑定。当用户点击复选框时,checked 的值将切换为 true 或 false。
请注意,v-model 不仅仅适用于 元素。它可以用于任何表单控件,包括 和 ,也可以在自定义组件上使用。
另外,在 Vue 3 中,v-model 更具灵活性。在 Vue 2 中,如果你想在一个组件上使用多个 v-model,你必须为它们指定不同的名字(比如:v-model:value, v-model:input)。但在 Vue 3 中,你可以直接使用 v-model,例如:v-model:title, v-model:content,这使得在自定义组件上使用 v-model 变得更加简洁和灵活。
- 计算属性
在 Vue 中,计算属性 (computed properties) 是一种特殊的响应式属性,它的值由一个函数计算得出,并且 Vue 会自动跟踪其依赖项的变化,当依赖项变化时重新计算它的值。
下面是一个基本的计算属性示例:
<template>
<div>
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
</template>
<script>
import { ref, computed } from 'vue';
export default {
setup() {
const message = ref('Hello Vue!');
const reversedMessage = computed(() => message.value.split('').reverse().join(''));
return {
message,
reversedMessage
};
}
}
</script>
在这个例子中,reversedMessage 是一个计算属性,它的值是 message 值的反转。当 message 的值改变时,reversedMessage 的值也会自动更新。
需要注意的是,计算属性默认是懒加载的,也就是说只有在它们的值被实际需要时才会被计算。一旦计算过一次,它们的值就会被缓存起来,只有当它们的依赖项改变时才会重新计算。这使得计算属性在处理大量数据或者复杂计算时非常高效。
在 Vue 3 中,你还可以定义一个 setter 函数来实现可写的计算属性。例如:
<template>
<input v-model="fullname">
</template>
<script>
import { ref, computed } from 'vue';
export default {
setup() {
const firstname = ref('John');
const lastname = ref('Doe');
const fullname = computed({
get: () => `${firstname.value} ${lastname.value}`,
set: (newValue) => {
const [newFirstname, newLastname] = newValue.split(' ');
firstname.value = newFirstname;
lastname.value = newLastname;
}
});
return {
fullname
};
}
}
</script>
在这个例子中,当用户修改 fullname 输入框的值时,setter 函数会被调用,将新的 firstname 和 lastname 值设置到 Vue 实例中。
- 侦听器
侦听器 (Watchers) 是 Vue.js 提供的一种用来响应式地追踪数据变化并执行相应操作的功能。侦听器可以观察和响应 Vue 实例上的数据变化。
以下是一个简单的使用 watch 的示例:
<template>
<div>
<input v-model="question" placeholder="Ask something...">
<p>{{ answer }}</p>
</div>
</template>
<script>
import { ref, watch } from 'vue';
export default {
setup() {
const question = ref('');
const answer = ref('I cannot give you an answer until you ask a question.');
watch(question, (newQuestion, oldQuestion) => {
if (newQuestion.indexOf('?') > -1) {
answer.value = 'That sounds like a question.';
}
});
return {
question,
answer
};
}
}
</script>
在这个例子中,我们使用 watch 创建了一个侦听器,该侦听器监视 question 的值。当 question 的值发生变化时,侦听器的回调函数会被调用。新的值和旧的值会被作为参数传给回调函数。
在 Vue 3 中,侦听器可以在 setup 函数中使用 watch 或者 watchEffect 创建。
- watch 需要一个被观察的源和一个执行当源改变时的回调函数。源可以是响应式引用 (例如 ref 或 reactive 创建的对象),也可以是返回期望响应的数据的函数。
- watchEffect 自动跟踪其内部使用的响应式状态,并在状态改变时重新运行。它比 watch 更为“自动化”,因为你不需要指定观察哪些特定的状态。
在某些情况下,你可能需要手动停止侦听。例如,当你在一个组件中使用 watch 或 watchEffect 创建侦听器,并在组件卸载时停止侦听。在这种情况下,watch 和 watchEffect 函数都会返回一个停止函数,你可以在需要时调用这个函数来停止侦听。
响应式数据
在 Vue 3 中,提供了 ref 和 reactive 两种创建响应式数据的方式。这两种方式各有优势,它们可以适用于不同的场景。
- ref
ref 函数用于创建一个响应式的数据对象。ref 返回的对象拥有一个 .value 属性,通过这个属性可以获取或者修改其值。
import { ref } from 'vue';
const count = ref(0);
console.log(count.value); // 0
count.value++;
console.log(count.value); // 1
- reactive
reactive 用于创建一个响应式的对象。与 ref 不同,reactive 不需要 .value 属性,可以直接访问或修改对象的属性。
import { reactive } from 'vue';
const state = reactive({ count: 0 });
console.log(state.count); // 0
state.count++;
console.log(state.count); // 1
- toRefs
当使用 reactive 创建响应式对象后,我们可能会想将其解构,然而直接解构会导致失去响应性。这时,我们可以使用 toRefs 函数将响应式对象转换为普通对象,该对象的每个属性都是一个 ref,这样就能保持响应性。
import { reactive, toRefs } from 'vue';
const state = reactive({ count: 0 });
const { count } = toRefs(state);
console.log(count.value); // 0
count.value++;
console.log(count.value); // 1
请注意,toRefs 并不会创建新的响应式对象,而是创建了新的 ref 对象,这些 ref 对象引用的还是原来的值。这意味着修改通过 toRefs 解构出来的 ref,原 reactive 对象也会同时改变。
以上就是 ref、reactive 和 toRefs 的基本使用,它们都是 Vue 3 响应性系统的核心部分。
Vue3组件
如何创建和使用Vue3组件
在Vue 3中,组件的创建和使用过程进行了一些改变,尤其是引入了新的setup函数和Composition API,它们提供了一种更直观和灵活的方式来组织和复用代码。
首先,我们来看一个简单的Vue 3组件的创建和使用过程:
<template>
<button @click="increment">
Count is: {{ count }}, double is: {{ double }}
</button>
</template>
<script>
import { ref, computed } from 'vue';
export default {
name: 'Counter',
setup() {
const count = ref(0);
const double = computed(() => count.value * 2);
function increment() {
count.value++;
}
return {
count,
double,
increment
};
}
}
</script>
在上述代码中:
- template 部分定义了组件的HTML结构。我们使用v-on:click或简写形式@click监听按钮的点击事件。
- script 部分使用Vue 3的setup函数和Composition API定义了组件的行为。
- setup函数是Vue 3组件的新入口。在这个函数中,我们可以定义和返回我们的响应式数据和方法。这个函数在创建组件实例,但是在初始化任何声明式逻辑之前被调用。提供的第一个参数是props,第二个参数是context对象,包含了组件的上下文。
- 我们使用ref函数创建了一个响应式的数据count,并使用computed函数创建了一个基于count的计算属性double。
- 我们定义了一个方法increment来增加count的值。
- 最后,我们返回了我们希望在模板中使用的所有响应式数据和方法。
然后,你可以在父组件中引用并使用这个组件,就像这样:
<template>
<Counter />
</template>
<script>
import Counter from './Counter.vue';
export default {
components: {
Counter
}
}
</script>
在这里,我们首先导入了我们刚才创建的Counter组件。然后,我们在components选项中注册了这个组件,这样我们就可以在父组件的模板中使用它了。
Vue3的父组件引用子组件
在 Vue 3 中,父组件可以通过几种方式引用子组件。
- 使用 ref
在你的 HTML 中,你可以在任何元素或者组件上添加 ref 属性。然后,在你的 setup 函数中,你可以通过 ref 方法获取这个元素或组件的引用。这种方式通常用于获取 DOM 元素或者组件实例的引用。
例如:
<template>
<ChildComponent ref="childRef" />
</template>
<script>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
setup() {
const childRef = ref(null);
// 在 onMounted 钩子中可以访问子组件实例
onMounted(() => {
console.log(childRef.value);
});
return {
childRef
};
}
}
</script>
- 使用 provide 和 inject
Vue 提供了 provide 和 inject 方法,允许你在父组件中定义一些值,然后在任何子孙组件中使用这些值,而不需要通过 props 一层层传递。这在开发高阶组件或者插件时特别有用。
例如:
// 父组件
<template>
<ChildComponent />
</template>
<script>
import { provide } from 'vue';
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
setup() {
const value = ref('Hello from parent');
provide('myValue', value);
}
}
</script>
// 子组件
<template>
<div>{{ myValue }}</div>
</template>
<script>
import { inject } from 'vue';
export default {
setup() {
const myValue = inject('myValue');
return {
myValue
};
}
}
</script>
这两种方式都可以实现父子组件的通信,但是它们各有适用的场景。ref 方式适用于需要直接操作子组件或者元素的场景,而 provide 和 inject 方式则适用于跨越多层组件的通信场景。
Vue3组件使用Props
在Vue 3中,props 是组件用来接收从父组件传递过来的数据的。这是一种单向下行绑定:父组件的数据更新会流向子组件,但如果子组件修改了 prop,反过来不会影响父组件。
这是使用props的基本例子:
<!-- 子组件 -->
<template>
<div>{{ message }}</div>
</template>
<script>
export default {
props: ['message']
}
</script>
<!-- 父组件 -->
<template>
<child-component message="Hello from parent!"></child-component>
</template>
- 指定 Prop 类型:
为了使代码更健壮,建议总是为每个 prop 指定一个类型:
<script>
export default {
props: {
message: String,
age: Number
}
}
</script>
- 默认值:
你可以为 prop 设置一个默认值。对于对象或数组,默认值必须是一个函数:
<script>
export default {
props: {
message: {
type: String,
default: "Hello World"
},
list: {
type: Array,
default: () => []
}
}
}
</script>
- Prop 验证:
可以提供一个包含验证要求的对象来对 props 进行更复杂的验证:
<script>
export default {
props: {
age: {
type: Number,
required: true,
validator: value => value >= 18
}
}
}
</script>
这里我们要求 age 必须是一个数字,并且大于或等于 18。validator 是一个自定义的验证函数。
- Prop的不可变性:
请注意,子组件不应更改从父组件接收的 prop。如果需要基于 prop 的值来定义一个可以修改的数据属性,可以在组件内部定义一个 data 属性或计算属性。
通过使用props,Vue.js 允许你创建可重用且可配置的组件,这是构建大型应用程序的基础。
Vue3的slots
在 Vue 3 中,插槽(slots)是一种强大的工具,它可以用来定义组件模板中的一部分,并允许父组件决定如何填充这些部分。
- 默认插槽:
最简单的插槽类型是默认插槽。如果你在组件模板中定义一个 元素,父组件可以在使用组件的地方插入一些内容,这些内容将替代 元素。
例如,以下是一个简单的 Card 组件:
<!-- Card.vue -->
<template>
<div class="card">
<div class="card-body">
<slot></slot>
</div>
</div>
</template>
使用 Card 组件并传递内容到插槽:
<template>
<Card>
<h1>Hello World!</h1>
<p>This is some text inside of a card body.</p>
</Card>
</template>
在这个例子中,我们在 组件中插入了一些内容。这些内容将替代 Card 组件模板中的 。
- 具名插槽:
除了默认插槽,Vue 还支持具名插槽。这允许你定义多个插槽,并在使用组件时指定哪个插槽应接收哪个内容。
例如,以下是一个具有标题插槽和内容插槽的 Card 组件:
<!-- Card.vue -->
<template>
<div class="card">
<div class="card-header">
<slot name="header"></slot>
</div>
<div class="card-body">
<slot name="body"></slot>
</div>
</div>
</template>
使用 Card 组件并传递内容到具名插槽:
<template>
<Card>
<template v-slot:header>
<h1>Hello World!</h1>
</template>
<template v-slot:body>
<p>This is some text inside of a card body.</p>
</template>
</Card>
</template>
在这个例子中,我们为每个插槽提供了一个<template>
元素,并使用 v-slot 指令来指定应该将内容插入到哪个插槽。
- 作用域插槽:
有时,你可能希望子组件向父组件传递数据。在这种情况下,你可以使用作用域插槽。
作用域插槽是一种特殊的插槽,允许子组件将数据传递给插槽。在父组件中,你可以接收这些数据,并在插槽内容中使用它们。
<!-- ChildComponent.vue -->
<template>
<div>
<slot :item="item"></slot>
</div>
</template>
<script>
export default {
data() {
return {
item: { id: 1, name: 'Vue.js' }
}
}
}
</script>
在父组件中,你可以使用 v-slot 指令和一个值(在本例中为 data)来接收传递的数据
<template>
<ChildComponent>
<template v-slot:default="data">
<p>ID: {{ data.item.id }}</p>
<p>Name: {{ data.item.name }}</p>
</template>
</ChildComponent>
</template>
Vue3的新特性
1. Composition API:
Composition API 是 Vue 3 的核心特性,是为了解决更大,更复杂应用的问题而设计的。它提供了一种新的、更加灵活的方式来组织和复用组件逻辑。此 API 主要包括以下几个函数:
- reactive(): 接收一个普通对象并返回其响应式副本。
- ref(): 创建一个响应式的引用。
- computed(): 创建一个响应式的计算属性。
- watch()和watchEffect(): 允许我们对响应式数据进行“观察”并在其改变时运行一些代码。
2. 多个根节点:
Vue 3 允许在单个文件组件(SFC)的模板中包含多个根元素。在 Vue 2 中,如果你试图这样做,会导致编译错误。这意味着我们不再需要添加额外的无意义的元素来包装模板。
// 例如,以下这段代码在 Vue 2 中是无效的,因为它有两个根节点:
<template>
<div>Root Node 1</div>
<div>Root Node 2</div>
</template>
// 在这种情况下,你通常需要添加一个包裹元素,以创建一个有效的模板,如下所示:
<template>
<div>
<div>Root Node 1</div>
<div>Root Node 2</div>
</div>
</template>
// 然而,在 Vue 3 中,你可以在模板中有多个根节点,如下所示:
<template>
<div>Root Node 1</div>
<div>Root Node 2</div>
</template>
3.Teleport
Teleport 是 Vue 3 的一个新特性,它允许你将组件的子元素在 DOM 中的位置“传送”到 DOM 的其他部分。
这个特性对于一些特定的 UI 情况非常有用,例如,当你需要创建一个模态对话框、通知、或者弹出式菜单时,你通常希望这些元素能够跳出其父组件的边界并出现在 DOM 的顶层。
让我们看一个例子:
<div id="app">
<div>Other content...</div>
<teleport to="#end-of-body">
<div>Teleported content...</div>
</teleport>
</div>
<div id="end-of-body"></div>
在这个例子中,我们使用 组件将 "Teleported content..." 从它的父元素中“传送”到 #end-of-body 元素中。即使这个 div 在 DOM 树中的位置和 是相隔很远的,我们也能够以这种方式移动内容。
当你查看生成的 HTML 时,你会发现 "Teleported content..." 确实出现在 #end-of-body 元素中,而不是它在 Vue 模板中的位置。
<div id="app">
<div>Other content...</div>
</div>
<div id="end-of-body">
<div>Teleported content...</div>
</div>
这就是 Vue 3 的 Teleport 特性,它为处理某些 UI 问题提供了更加灵活的解决方案。
4.Suspense
Suspense 是 Vue 3 中的一个新组件,用于处理组件的异步依赖关系。当你的组件依赖于异步操作(例如数据获取)时,Suspense 可以提供一种干净、简洁的方式来处理加载状态和错误状态。
在异步组件中使用 Suspense 非常直接,你可以在你的组件中返回一个 Promise,然后用 Suspense 包裹这个组件。在 Promise 解析之前,Suspense 会渲染它的 fallback 插槽;一旦 Promise 解析,它就会渲染默认的插槽。以下是一个基本的示例:
import { ref } from 'vue';
export default {
async setup() {
const posts = ref(null);
// 这将是一个异步操作,例如 API 调用
const fetchPosts = new Promise((resolve) => {
setTimeout(() => {
resolve([
{ id: 1, title: 'Post 1' },
{ id: 2, title: 'Post 2' },
]);
}, 2000);
});
posts.value = await fetchPosts;
return {
posts,
};
},
};
接下来,我们在父组件中使用 Suspense 来包裹这个组件:
<template>
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<div>Loading...</div>
</template>
</Suspense>
</template>
<script>
import AsyncComponent from './AsyncComponent.vue';
export default {
components: {
AsyncComponent,
},
};
</script>
在这个例子中,当我们等待异步组件的数据时,将会显示 "Loading..."。一旦数据可用,AsyncComponent 将会渲染并显示我们的帖子。
这就是 Suspense 如何在 Vue 3 中工作的基本示例。请注意,这是一个实验性的特性,其 API 在未来可能会有所改变。
Vue3的Router路由管理
在 Vue.js 中,路由是用来管理应用中的各种页面和它们之间跳转的方式。Vue Router 是 Vue.js 官方的路由管理器,它可以让我们更方便地创建单页应用。
首先,你需要通过 npm 安装 Vue Router:
npm install vue-router@next
然后,在你的应用中引入和使用 Vue Router:
// main.js
import { createApp } from 'vue';
import { createRouter, createWebHistory } from 'vue-router';
// 导入组件
import HomeComponent from './components/HomeComponent.vue';
import AboutComponent from './components/AboutComponent.vue';
// 定义路由
const routes = [
{ path: '/', component: HomeComponent },
{ path: '/about', component: AboutComponent },
];
// 创建路由实例
const router = createRouter({
history: createWebHistory(),
routes,
});
// 创建 Vue 应用
const app = createApp(App);
// 使用路由
app.use(router);
// 挂载应用
app.mount('#app');
上面的代码创建了一个 Vue 应用,并且设置了两个路由:首页 ("/") 和关于页面 ("/about")。这两个路由分别对应两个不同的 Vue 组件 (HomeComponent 和 AboutComponent)。当用户在浏览器中访问不同的 URL 时,Vue Router 会动态地加载对应的组件,呈现给用户。
在 Vue 组件中,你可以通过 this.router访问路由器实例,通过this.router 访问路由器实例,通过 this.router访问路由器实例,通过this.route 访问当前路由。你可以使用 和 两个 Vue Router 提供的组件来创建导航菜单和渲染当前路由对应的组件。例如:
<template>
<div>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
<router-view/>
</div>
</template>
上面的代码中, 创建了一个导航链接,当用户点击链接时,应用会导航到该链接对应的路由。 会动态地渲染当前路由对应的组件。
Vue Router 还提供了许多高级功能,如路由参数、嵌套路由、路由守卫等。你可以查阅 Vue Router 的官方文档,了解更多详细的内容。
路由参数:
在某些情况下,你可能需要将动态数据(例如来自数据库的用户ID)作为URL的一部分。你可以在Vue Router的路由配置中使用:前缀来定义路由参数:
const routes = [
{ path: '/user/:id', component: UserComponent },
];
上面的代码中,/user/:id定义了一个路由,其中id是一个动态的路由参数。当用户访问类似/user/123的URL时,123就会作为参数id的值。在对应的UserComponent组件中,你可以通过this.$route.params.id获取到这个值。
嵌套路由:
嵌套路由可以让你更灵活地组织应用的界面结构。在定义路由时,你可以使用children选项来定义子路由:
const routes = [
{
path: '/user/:id',
component: UserComponent,
children: [
{ path: 'profile', component: UserProfileComponent },
{ path: 'posts', component: UserPostsComponent }
]
},
];
上面的代码定义了两个嵌套路由。当用户访问/user/123/profile时,会渲染UserProfileComponent组件;访问/user/123/posts时,会渲染UserPostsComponent组件。
路由守卫:
路由守卫是一些特殊的函数,它们会在路由导航发生之前或之后被调用。你可以使用路由守卫来实现一些高级的路由逻辑,例如权限验证、动态标题等。
以下是一个简单的全局前置守卫的示例:
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
});
在这个例子中,我们在每次路由导航前检查用户是否已经登录。如果用户尚未登录,并且他们试图访问非登录页面,则会被重定向到登录页面。你可以根据需要使用更复杂的逻辑来控制导航的行为。
这就是Vue Router中路由参数、嵌套路由和路由守卫的基本概念。你可以通过阅读Vue Router的官方文档来了解更多详情和更复杂的示例。
Vue3的Pinia状态管理库
Pinia 是 Vue3 的一个状态管理库,它是 Vue 官方的一种对 Vuex 的替代方案,因此它更适合在 Vue3 中使用。
Pinia 提供了一个非常简单的 API,你可以使用它轻松地创建和管理应用的状态。下面是一个基本的 Pinia 使用示例:
首先,你需要安装 pinia:
npm install pinia
在 Vue 3 组件中使用 Pinia 非常直接。首先,我们需要在主程序文件(通常是 main.js 或 main.ts)中安装 Pinia 插件并创建一个 Pinia store:
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';
const app = createApp(App);
// 创建 pinia 实例
const pinia = createPinia();
// 在 app 中使用 pinia
app.use(pinia);
app.mount('#app');
然后,我们可以在 Pinia 中定义一个 store:
import { defineStore } from 'pinia';
export const useCounterStore = defineStore({
id: 'counter',
state: () => ({
count: 0,
}),
getters: {
double: (state) => state.count * 2,
},
actions: {
increment() {
this.count++;
},
},
});
接下来,我们可以在 Vue 组件中使用这个 store:
<template>
<div>
<p>Count: {{ counter.count }}</p>
<p>Double: {{ counter.double }}</p>
<button @click="counter.increment">Increment</button>
</div>
</template>
<script>
import { useCounterStore } from './counterStore';
export default {
setup() {
const counter = useCounterStore();
return { counter };
},
};
</script>
在 Pinia 中,我们通常会定义一个 store,这个 store 对象是应用状态的容器,它由以下几个部分组成:
- state: 这是一个函数,返回一个对象,该对象包含了这个 store 的初始状态。每当一个新的 store 实例被创建时,这个函数就会被调用,以生成新的状态对象。例如:
state: () => ({
count: 0,
}),
- getters: 这是一个对象,它的属性是函数,这些函数可以基于 store 的状态计算出一些值。这些函数的结果会被缓存,只有当它们的依赖发生变化时,它们才会重新计算。例如:
getters: {
double: (state) => state.count * 2,
},
在这个例子中,double getter 将会返回 count 的两倍。如果 count 的值发生了变化,double 将会被重新计算。
- actions: 这是一个对象,它的属性是方法,这些方法可以被用来改变 store 的状态。actions 通常用于处理异步操作,例如 API 调用。例如:
actions: {
increment() {
this.count++;
},
},
在这个例子中,increment action 会增加 count 的值。注意,actions 是通过 this 来访问 state 和其他 actions 的。
在 Pinia 中,你可以使用 defineStore 函数来定义一个 store,然后在组件中使用 useStore 函数来获取这个 store 的实例。这个实例将会包含你在定义时指定的 state、getters 和 actions,你可以在组件中直接使用它们。
转载自:https://juejin.cn/post/7249595460289855543