vue3生态的变化
生态圈
vue2升级到vue3之后,其对应的整体生态圈也随之升级。从 调试工具到路由,全局状态管理到UI组件库,都随之升级了。 升级之后在使用上也有些变化。
版本
vue升级vue3之后,配套的vue-router也升级为vue-router@4.x版本。
vue-router4的语法和3的版本语法基本一致,但是有一些细微的修改。
vue@2 + vue-router@3 + vuex@3 options api
vue@3 + vue-router@4 + vuex@4 composition api
vue-router4的基本使用
目标
掌握vue-router4的基本使用
安装vue-router
两种情况:
- 全新项目
- 老项目中额外添加vue-router
情况1:
如果是全新创建的项目,可以直接在交互工具中选择vue3的版本,再选择vue-router时,就会自动安装并配置vue-router 4
情况2:
老项目中,自己手动安装vue-router。这个不加版本号,表示默认安装最新的。npm i vue-router
使用
安装完成之后,我们就可以来配置使用路由功能了。其基本使用流程与vue-router3一致:
- 配置router。导入组件,配置路由规则
- 在main.js中使用router
- 在App.vue中配置路由出口。
下面是基本目录结构
src
├── router
│ └── index.js
├── pages
│ ├── Home.vue
│ └── Login.vue
└── main.js
创建组件Home.vue和Login.vue
配置router
创建文件router/index.js,内容如下:
import {
createRouter,
createWebHashHistory,
createWebHistory,
} from 'vue-router'
// 1. 创建路由
const router = createRouter({
// 创建history模式的路由
// history: createWebHistory(),
// 创建hash模式的路由
history: createWebHashHistory(),
// 配置路由规则
routes: [
{ path: '/home', component: () => import('../pages/Home.vue') },
{ path: '/login', component: () => import('../pages/Login.vue') },
],
})
export default router
在main.js中导入使用
在main.js中引入
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')
配置路由出口
App.vue中使用
<template>
<router-link to="/home">首页</router-link>
<router-link to="/login">登陆</router-link>
<!-- 路由出口 -->
<router-view></router-view>
</template>
组件中使用route与router
目标
掌握在组件内部使用route和router的方式
背景
在v3中,组件中无法访问this,所以也无法像之前在vue2中采用的this.router来操作路由。
对应的调整为:
vue2 ----> vue3
this.$route ---> const route = useRoute()
this.$router ---> const router = useRouter()
useRoute获取route信息
通过useRoute()可以获取route信息
<script>
import { useRoute } from 'vue-router'
export default {
setup() {
const route = useRoute()
console.log(route.path)
console.log(route.fullPath)
},
}
</script>
useRouter获取router信息
通过useRouter()可以获取router信息
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
const login = () => {
router.push('/home')
}
</script>
Pinia新一代状态管理工具
目标
了解pinia
Pina-新一代状态管理工具
pinia是什么
Pinia 是 Vue.js 的轻量级状态管理库,是vuex的升级版
中文文档: https://pinia.web3doc.top/introduction.html
pinia核心概念
vuex的内容:
● state
● mutations
● actions
● getters
● modules
● plugins
pinia的内容
● state
● actions
● getters
● modules
● plugins
pinia基本使用
目标
掌握pinia的使用步骤
步骤
- 安装 npm i pinia
- 在main.js中use
- 定义模块
- 使用模块
在main.js中引入pinia
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
const pinia = createPinia()
createApp(App).use(pinia).mount('#app')
定义模块
新建文件src/store/counter.js
import { defineStore } from 'pinia'
// 创建store,命名规则: useXxxxStore
// 参数1:store的唯一标识
// 参数2:回调函数,类似于setup()的功能,可以提供state actions getters
import { ref } from 'vue'
const useCounterStore = defineStore('counter', () => {
// 数据(state)
const count = ref(0)
// 修改数据的方法 (action)
const addCount = () => {
count.value++
}
// 以对象形式返回
return {count, addCount}
})
export default useCounterStore
使用模块
步骤:
- 在组件中引入模块
- 调用store函数得到store
- 使用store
<script setup>
// 1. 在组件中引入模块
import useCounterStore from '@/src/store/counter'
// 2. 调用store函数得到store
const counter = useCounterStore()
console.log(counter)
</script>
<template>
// 使用store
count: {{ counter.count }}
<button @click="counter.addCount">点击增加</button>
</template>
pinia中getters的使用
pinia中的getters直接使用computed函数进行模拟,再把getters return出去.
定义getters(计算属性)
import { defineStore } from 'pinia'
// 创建store,命名规则: useXxxxStore
// 参数1:store的唯一表示
// 参数2:回调函数,类似于setup()的功能,可以提供state actions getters
import { ref, computed } from 'vue'
const useCounterStore = defineStore('counter', () => {
// 数据(state)
const count = ref(0)
// 修改数据的方法 (action)
const addCount = () => {
count.value++
}
// 计算属性
const doubleCount = computed(() => count.value * 2)
// 以对象形式返回
return {count, addCount, doubleCount}
})
export default useCounterStore
在组件中使用
<script setup>
import useCounterStore from '@/stores/counter.js'
const counterStore = useCounterStore()
console.log(counterStore)
</script>
<template>
<div>
{{ counterStore.doubleCount }}
<button @click="counterStore.addCount">+1</button>
count: {{ counterStore.count }}
</div>
</template>
pinia中异步actions的使用
目标
掌握pinia中actions的使用
新建一个store来实现
import { defineStore } from 'pinia'
import { ref } from 'vue'
import axios from 'axios'
export default defineStore('newList', () => {
const list = ref([])
const getList = async () => {
const res = await axios.get('http://api-toutiao-web.itheima.net/mp/v1_0/channels')
list.value = res.data.data.channels
}
return { list, getList }
})
在组件中使用
<script setup>
import useCounterStore from '@/stores/counter.js'
const counterStore = useCounterStore()
import useNewsListStore from '@/stores/newsList.js'
import { onMounted } from 'vue';
const newsListStore = useNewsListStore()
onMounted(() => {
newsListStore.getList()
})
</script>
<template>
<div>
{{ counterStore.doubleCount }}
<button @click="counterStore.addCount">+1</button>
count: {{ counterStore.count }}
{{ newsListStore.list }}
</div>
</template>
用storeToRefs来优化pinia的使用
目标
掌握storeToRefs的使用
问题
在模板中使用数据时,要加上模块的名字,例如:
<template>
<h1>根组件---{{ counter.count }}</h1>
<h3>{{ counter.double }}</h3>
</template>
思考:上面代码中的counter 可以省略么?用解构赋值?
结论:如果直接从pinia中解构数据,会丢失响应式。
const counterStore = useCounterStore()
// 这样的count没有响应式效果
const { count } = counterStore
console.log(count, addCount)
storeToRefs
使用storeToRefs可以保证解构出来的数据(state + getter)也是响应式的。注意: 不要对action进行结构
const { state属性名1, state属性名2 } = storeToRefs(模块名)
测试使用
<script setup>
import { storeToRefs } from 'pinia'
import useCounterStore from './store/counter'
const counter = useCounterStore()
// 如果直接从pinia中解构数据,会丢失响应式
const { count, double } = counter
// 使用storeToRefs可以保证解构出来的数据也是响应式的
const { count, double } = storeToRefs(counter)
</script>
持久化
有现成的第三方插件可以使用
https://prazdevs.github.io/pinia-plugin-persistedstate/guide/why.html
- 安装
npm i pinia-plugin-persistedstate
- 配置
import { createPinia } from 'pinia'
// 引入持久化插件
import piniaPluginPersist from 'pinia-plugin-persistedstate'
const store = createPinia()
// 使用该插件
store.use(piniaPluginPersist)
app.use(store)
- 在某个store中使用
参考如下
const useCounterStore = defineStore('counter', () => {
// 以对象形式返回
return {count, addCount, doubleCount}
},{
persist: {
key: 'my-custom-key' // 持久化使用的属性名,默认是 store.$id
storage: sessionStorage, // 默认是localStorage
paths: ['list', 'type'], // 要持久化的属性
}
})