文章目录
-
- [Vue 3 案例复现(动态注册组件及路由重定向)](#Vue 3 案例复现(动态注册组件及路由重定向))
-
- [1. 项目结构](#1. 项目结构)
- [2. Vuex 存储相关信息(`src/store/index.js`)](#2. Vuex 存储相关信息(
src/store/index.js
)) - [3. 动态注册组件示例(`src/router/index.js`)](#3. 动态注册组件示例(
src/router/index.js
)) - [4. 登录组件(`src/views/Login.vue`)](#4. 登录组件(
src/views/Login.vue
))
- 动态组件
- [vue3 中动态路由 应用](#vue3 中动态路由 应用)
-
- [Vue 3 动态路由应用场景](#Vue 3 动态路由应用场景)
- [Vue 3 动态路由实例](#Vue 3 动态路由实例)
- [removeRoute 以及 hasRoute](#removeRoute 以及 hasRoute)
- [思考(当页面被刷新时store 数据会被重置,怎么保持登录状态,并建立当前缓存)](#思考(当页面被刷新时store 数据会被重置,怎么保持登录状态,并建立当前缓存))
- keep-alive
-
- [keep-alive(exclude / include)](#keep-alive(exclude / include))
Vue 3 案例复现(动态注册组件及路由重定向)
1. 项目结构
假设项目有src
目录,src
目录下包含views
(存放组件)、router
(存放路由相关文件)和store
(用于状态管理,这里假设使用 Vuex)。
2. Vuex 存储相关信息(src/store/index.js
)
javascript
import { createStore } from 'vuex';
const store = createStore({
state: {
userRole: null, // 存储用户角色,如 'user' 或 'admin'
permissions: [] // 存储用户权限列表
},
mutations: {
SET_USER_ROLE(state, role) {
state.userRole = role;
},
SET_PERMISSIONS(state, perms) {
state.permissions = perms;
}
},
actions: {
setUserRole({ commit }, role) {
commit('SET_USER_ROLE', role);
},
setPermissions({ commit }, perms) {
commit('SET_PERMISSIONS', perms);
}
}
});
export default store;
3. 动态注册组件示例(src/router/index.js
)
javascript
import { createRouter, createWebHistory } from 'vue-router';
import store from '../store';
import Home from '../views/Home.vue';
import Login from '../views/Login.vue';
// 动态导入组件函数
const loadComponent = (path) => () => import(`../views/${path}.vue`);
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
redirect: '/login'
},
{
path: '/login',
component: Login
},
{
path: '/home',
component: Home
}
]
});
// 模拟获取用户角色和权限后动态注册路由
const updateRoutes = () => {
const userRole = store.state.userRole;
const newRoutes = [];
if (userRole === 'admin') {
newRoutes.push({
path: '/admin/dashboard',
component: loadComponent('AdminDashboard')
});
}
if (userRole === 'user') {
newRoutes.push({
path: '/user/profile',
component: loadComponent('UserProfile')
});
}
router.addRoute(...newRoutes);
};
// 路由守卫,在每次路由变化前检查用户角色和权限,更新路由
router.beforeEach((to, from, next) => {
const userRole = store.state.userRole;
if (!userRole && to.path!== '/login') {
next('/login');
} else {
if (userRole) {
updateRoutes();
}
next();
}
});
export default router;
4. 登录组件(src/views/Login.vue
)
html
<template>
<div>
<h2>Login</h2>
<input type="text" v-model="username" placeholder="Username" />
<input type="password" v-model="password" placeholder="Password" />
<button @click="login">Login</button>
</div>
</template>
<script>
import { useStore } from 'vuex';
export default {
data() {
return {
username: '',
password: ''
};
},
methods: {
login() {
const store = useStore();
// 模拟登录验证,这里简单假设用户名为 'admin' 时是管理员角色
if (this.username === 'admin') {
store.dispatch('setUserRole', 'admin');
store.dispatch('setPermissions', ['admin:dashboard']);
} else {
store.dispatch('setUserRole', 'user');
store.dispatch('setPermissions', ['user:profile']);
}
}
}
};
</script>
在这个示例中:
- 通过 Vuex 存储用户角色和权限信息。
- 在路由模块中,
loadComponent
函数用于动态导入组件。updateRoutes
函数根据用户角色动态添加路由。 - 路由守卫
beforeEach
在每次路由变化前检查用户状态,如果用户未登录且不是访问登录页,则重定向到登录页。如果用户已登录,则根据用户角色更新路由,实现动态注册组件和动态控制路由重定向。实际应用中,可以从后端获取真实的用户角色和权限数据。
动态组件
- 动态组件基础概念
- 在Vue 3中,动态组件允许你根据数据的变化动态地切换显示的组件。这是通过
<component>
标签来实现的,它有一个特殊的属性:is
,这个属性的值可以是一个组件选项对象(例如,通过import
导入的组件)或者组件的名字(如果组件是通过app.component()
方法全局注册的)。
- 在Vue 3中,动态组件允许你根据数据的变化动态地切换显示的组件。这是通过
- 简单的动态组件示例
-
创建组件
-
首先,在
src/views
目录下创建几个组件,例如Home.vue
、Profile.vue
和Admin.vue
。以Home.vue
为例:html<template> <div> <h2>Home Page</h2> </div> </template> <script> export default { name: 'Home' }; </script>
-
-
在父组件中使用动态组件
-
在
src/App.vue
(假设这是父组件)中使用动态组件:html<template> <div> <component :is="currentComponent"></component> <button @click="changeComponent('Home')">Go to Home</button> <button @click="changeComponent('Profile')">Go to Profile</button> <button @click="changeComponent('Admin')">Go to Admin</button> </div> </template> <script> import Home from './views/Home.vue'; import Profile from './views/Profile.vue'; import Admin from './views/Admin.vue'; import { ref } from 'vue'; export default { setup() { const components = { Home, Profile, Admin }; const currentComponent = ref('Home'); const changeComponent = (componentName) => { currentComponent.value = componentName; }; return { currentComponent, changeComponent }; } }; </script>
-
在这个示例中,
currentComponent
是一个ref
,它存储了当前要显示的组件的名字。changeComponent
函数用于根据按钮点击事件来改变currentComponent
的值,从而切换显示的组件。<component :is="currentComponent"></component>
会根据currentComponent
的值动态地渲染相应的组件。
-
-
- 结合路由使用动态组件(动态路由组件)
-
路由配置
-
在
src/router/index.js
中配置路由,假设你已经安装并配置了vue - router
:javascriptimport { createRouter, createWebHistory } from 'vue-router'; import Home from '../views/Home.vue'; import Profile from '../views/Profile.vue'; import Admin from '../views/Admin.vue'; const router = createRouter({ history: createWebHistory(), routes: [ { path: '/', redirect: '/home' }, { path: '/home', component: Home }, { path: '/profile', component: Profile }, { path: '/admin', component: Admin } ] }); export default router;
-
-
在路由组件中使用动态组件(嵌套动态组件)
-
假设在
Profile.vue
组件中,你还想根据用户的不同设置(例如用户的不同状态或者权限)动态地显示内部组件。首先,在src/views
目录下创建UserProfile.vue
和CompanyProfile.vue
组件。 -
然后在
Profile.vue
中使用动态组件:html<template> <div> <h2>Profile Page</h2> <component :is="innerComponent"></component> <button @click="changeInnerComponent('UserProfile')">User Profile</button> <button @click="changeInnerComponent('CompanyProfile')">Company Profile</button> </div> </template> <script> import UserProfile from './UserProfile.vue'; import CompanyProfile from './CompanyProfile.vue'; import { ref } from 'vue'; export default { setup() { const innerComponents = { UserProfile, CompanyProfile }; const innerComponent = ref('UserProfile'); const changeInnerComponent = (componentName) => { innerComponent.value = componentName; }; return { innerComponent, changeInnerComponent }; } }; </script>
-
这样,当用户访问
/profile
路由时,会先显示Profile.vue
组件,然后在Profile.vue
内部,又可以根据用户操作动态地显示UserProfile.vue
或者CompanyProfile.vue
组件。
-
-
- 动态加载组件(异步组件)
- 原理
- 对于大型应用或者有性能优化需求的场景,你可能不希望一次性加载所有组件,而是在需要的时候再加载。Vue 3支持异步加载组件,通过
import()
函数来实现。import()
函数返回一个Promise
,当Promise
被解决时,组件就被加载完成。
- 对于大型应用或者有性能优化需求的场景,你可能不希望一次性加载所有组件,而是在需要的时候再加载。Vue 3支持异步加载组件,通过
- 示例
-
在
src/router/index.js
中修改路由配置,以Admin.vue
为例,将其改为异步加载:javascriptimport { createRouter, createWebHistory } from 'vue-router'; import Home from '../views/Home.vue'; import Profile from '../views/Profile.vue'; const router = createRouter({ history: createWebHistory(), routes: [ { path: '/', redirect: '/home' }, { path: '/home', component: Home }, { path: '/profile', component: Profile }, { path: '/admin', component: () => import('../views/Admin.vue') } ] }); export default router;
-
这样,
Admin.vue
组件只有在用户访问/admin
路由时才会被加载,减少了初始加载时间和资源占用。同时,你也可以在组件内部结合动态组件和异步加载,实现更复杂的动态组件设置。
-
- 原理
vue3 中动态路由 应用
Vue 3 动态路由应用场景
-
用户信息展示
- 场景描述:当有一个用户管理系统,需要查看每个用户的详细信息。不同用户有不同的用户 ID,通过动态路由可以根据用户 ID 加载特定用户的资料页面。
- 示例 :路由可以定义为
/user/:id
,其中:id
是动态参数。在用户列表页面,每个用户的链接可以是/user/1
、/user/2
等,点击链接后会跳转到对应的用户详情页面,页面根据传入的id
从后端获取并展示该用户的信息。
-
分类内容展示
- 场景描述:在一个博客系统或者电商系统中,有不同的分类,每个分类下有多个内容项。通过动态路由可以根据分类 ID 或名称来展示该分类下的内容。
- 示例 :比如电商系统中,路由
/category/:categoryName
,可以有/category/electronics
、/category/clothing
等。点击这些链接后,对应的商品列表页面会根据传入的分类名称从数据库中获取并展示该分类下的商品。
-
多语言支持
- 场景描述:网站需要支持多种语言,根据不同的语言代码加载相应的语言包和页面内容。
- 示例 :路由
/lang/:languageCode
,如/lang/en
、/lang/zh
,页面组件根据languageCode
动态加载对应的语言文本资源和显示相应的界面布局。
Vue 3 动态路由实例
-
项目准备
- 创建一个 Vue 3 项目,可以使用
vue - cli
或者vite
等工具。假设项目结构有src
目录,src
下有views
(存放页面组件)、router
(存放路由相关文件)。
- 创建一个 Vue 3 项目,可以使用
-
路由配置(
src/router/index.js
)
javascript
import { createRouter, createWebHistory } from 'vue-router';
import UserProfile from '../views/UserProfile.vue';
import ProductList from '../views/ProductList.vue';
import NotFound from '../views/NotFound.vue';
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/user/:id',
component: UserProfile,
props: true
},
{
path: '/product/:category',
component: ProductList,
props: true
},
{
path: '/:pathMatch(.*)*',
component: NotFound
}
]
});
export default router;
- 用户资料组件(
src/views/UserProfile.vue
)
html
<template>
<div>
<h2>User Profile for ID: {{ id }}</h2>
<!-- 这里可以根据 id 从后端获取用户数据并展示,比如姓名、年龄等信息 -->
</div>
</template>
<script>
export default {
props: ['id'],
setup(props) {
return {
id: props.id
};
}
};
</script>
- 产品列表组件(
src/views/ProductList.vue
)
html
<template>
<div>
<h2>Products in Category: {{ category }}</h2>
<!-- 根据 category 从后端获取商品列表并展示 -->
</div>
</template>
<script>
export default {
props: ['category'],
setup(props) {
return {
category: props.category
};
}
};
</script>
- 404 组件(
src/views/NotFound.vue
)
html
<template>
<div>
<h2>404 - Page Not Found</h2>
</div>
</template>
- 在
App.vue
中使用路由链接(src/App.vue
)
html
<template>
<div id="app">
<router-link :to="{ name: 'userProfile', params: { id: 1 }}">User 1 Profile</router-link>
<router-link :to="{ name: 'userProfile', params: { id: 2 }}">User 2 Profile</router-link>
<br>
<router-link :to="{ name: 'productList', params: { category: 'electronics' }}">Electronics Products</router-link>
<router-link :to="{ name: 'productList', params: { category: 'clothing' }}">Clothing Products</router-link>
<router-view></router-view>
</div>
</template>
在这个实例中:
- 路由配置了两个动态路由
/user/:id
和/product/:category
,分别用于用户资料展示和产品列表展示。 - 对应的
UserProfile
和ProductList
组件通过props
接收动态参数,并可以在组件内部进行进一步操作。 App.vue
中使用router - link
创建了指向不同动态路由的链接,方便用户导航。同时,还有一个404
页面用于处理未匹配的路由。
removeRoute 以及 hasRoute
-
removeRoute
应用场景及实例- 应用场景
- 权限变更:当用户的权限发生变化,某些路由不再可用时,需要从路由表中移除这些路由。例如,用户从管理员权限降级为普通用户权限,之前管理员权限下的特定路由(如系统设置、用户管理等路由)需要被移除。
- 模块卸载 :在一个复杂的单页应用中,如果有一些可插拔的模块,当这些模块被卸载时,相关的路由也应该被移除。比如一个电商应用中的促销活动模块,活动结束后,相关的促销活动路由(如
/promotion/:id
)应该被移除。
- 实例
-
假设我们有一个简单的应用,包含一个管理员路由
/admin/dashboard
,用户最初以管理员身份登录,后来权限变更为普通用户。 -
在
src/router/index.js
中,路由配置如下:javascriptimport { createRouter, createWebHistory } from 'vue-router'; import Home from '../views/Home.vue'; import AdminDashboard from '../views/AdminDashboard.vue'; const router = createRouter({ history: createWebHistory(), routes: [ { path: '/', redirect: '/home' }, { path: '/home', component: Home }, { path: '/admin/dashboard', component: AdminDashboard } ] }); export default router;
-
在
src/store/index.js
(假设使用Vuex来管理状态)中,当用户权限变更时,触发removeAdminRoute
动作:javascriptimport { createStore } from 'vuex'; export default createStore({ state: { userRole: 'admin' }, mutations: { CHANGE_USER_ROLE(state, role) { state.userRole = role; } }, actions: { removeAdminRoute({ state, commit }, newRole) { const router = require('../router/index.js').default; if (state.userRole === 'admin' && newRole!== 'admin') { router.removeRoute('adminDashboard'); commit('CHANGE_USER_ROLE', newRole); } } } });
-
在
src/App.vue
(或其他合适的地方),模拟权限变更:html<template> <div> <button @click="changeUserRole('user')">Change to User Role</button> <router - view></router - view> </div> </template> <script> import { useStore } from 'vuex'; export default { setup() { const store = useStore(); const changeUserRole = (role) => { store.dispatch('removeAdminRoute', role); }; return { changeUserRole }; } }; </script>
-
- 应用场景
-
hasRoute
应用场景及实例- 应用场景
- 路由检查与导航引导 :在进行页面导航之前,可以使用
hasRoute
来检查目标路由是否存在。这在复杂的路由嵌套或者动态添加/删除路由的场景中非常有用。例如,在一个多模块应用中,一个模块可能会动态添加一些路由,另一个模块在导航时需要确认这些路由是否已经添加,以避免出现404
错误。 - 权限检查与路由隐藏:除了在导航过程中检查路由是否存在,还可以结合用户权限来检查是否有特定的路由。如果用户没有访问某个路由的权限,并且该路由也不存在于当前路由表中(可能已经被移除),可以在界面上隐藏相关的导航链接,提供更好的用户体验。
- 路由检查与导航引导 :在进行页面导航之前,可以使用
- 实例
-
假设我们有一个应用,有两个模块:
ModuleA
和ModuleB
。ModuleA
会动态添加一个路由/moduleA/special
,ModuleB
在导航到/moduleA/special
之前需要检查该路由是否存在。 -
在
src/router/index.js
中,初始路由配置:javascriptimport { createRouter, createWebHistory } from 'vue-router'; import Home from '../views/Home.vue'; import ModuleA from '../views/ModuleA.vue'; const router = createRouter({ history: createWebHistory(), routes: [ { path: '/', redirect: '/home' }, { path: '/home', component: Home }, { path: '/moduleA', component: ModuleA } ] }); export default router;
-
在
ModuleA.vue
中,动态添加路由:html<template> <div> <h2>Module A</h2> <button @click="addSpecialRoute">Add Special Route</button> </div> </template> <script> import { createRouter, createWebHistory } from 'vue-router'; import SpecialPage from '../views/SpecialPage.vue'; export default { setup() { const addSpecialRoute = () => { const router = createRouter({ history: createWebHistory(), routes: [ { path: '/moduleA/special', component: SpecialPage, name:'moduleASpecial' } ] }); router.addRoute('/moduleA', { path: '/moduleA/special', component: SpecialPage, name:'moduleASpecial' }); }; return { addSpecialRoute }; } }; </script>
-
在
ModuleB.vue
(假设是一个导航组件)中,检查路由是否存在并进行导航:html<template> <div> <h2>Module B</h2> <button @click="navigateToSpecialRoute"> Navigate to Special Route in Module A </button> </div> </template> <script> import { useRouter } from 'vue-router'; export default { setup() { const router = useRouter(); const navigateToSpecialRoute = () => { if (router.hasRoute('moduleASpecial')) { router.push('/moduleA/special'); } else { console.log('Route does not exist.'); } }; return { navigateToSpecialRoute }; } } }; </script>
-
- 应用场景
思考(当页面被刷新时store 数据会被重置,怎么保持登录状态,并建立当前缓存)
-
使用浏览器本地存储(Local Storage或Session Storage)保存登录状态相关数据
- 原理
- 浏览器的本地存储可以在页面刷新或关闭后仍然保留数据。当用户登录成功后,将用户的登录状态(如登录令牌、用户信息等)存储到本地存储中。在页面加载时,从本地存储中读取这些数据来恢复登录状态。
- 示例(使用Vuex和Local Storage)
-
存储登录状态到本地存储(在登录成功的逻辑中)
- 在
src/store/actions.js
(假设将登录相关动作放在单独的文件中)中,修改登录动作:
javascriptimport { setItem } from '../utils/localStorageUtil'; // 假设这个函数用于设置本地存储的值 export const login = ({ commit }, user) => { // 模拟登录成功后的逻辑,比如获取用户令牌 const token = 'generated_token'; // 将令牌和用户信息存储到本地存储 setItem('userToken', token); setItem('userInfo', user); commit('SET_USER', user); commit('SET_LOGGED_IN', true); };
- 在
-
从本地存储中恢复登录状态(在应用初始化时)
- 在
src/main.js
中,在创建Vue应用之前,检查本地存储中的登录状态并恢复:
javascriptimport { getItem } from '../utils/localStorageUtil'; import { createApp } from 'vue'; import store from './store'; import App from './App.vue'; import router from './router'; const app = createApp(App); const userToken = getItem('userToken'); const userInfo = getItem('userInfo'); if (userToken && userInfo) { store.commit('SET_USER', userInfo); store.commit('SET_LOGGED_IN', true); } app.use(store).use(router).mount('#app');
- 在
-
- 原理
-
利用Vuex - Persistedstate插件持久化存储状态
- 原理
vuex - persistedstate
插件可以自动将Vuex的状态保存到本地存储或者其他存储介质中,并在应用重新加载时恢复状态。它通过订阅Vuex的变化,将状态数据序列化后存储,在初始化时再反序列化并恢复状态。
- 示例
-
安装插件
- 首先,安装
vuex - persistedstate
:
bashnpm install vuex - persistedstate
- 首先,安装
-
配置插件(在
src/store/index.js
中)javascriptimport { createStore } from 'vuex'; import createPersistedState from 'vuex - persistedstate'; const store = createStore({ state: { user: null, loggedIn: false }, mutations: { SET_USER(state, user) { state.user = user; }, SET_LOGGED_IN(state, loggedIn) { state.loggedIn = loggedIn; } }, plugins: [ createPersistedState({ storage: window.localStorage, paths: ['user', 'loggedIn'] }) ] }); export default store;
-
在这个配置中,
createPersistedState
插件会将user
和loggedIn
这两个状态属性保存到本地存储中,并且在页面刷新后从本地存储中恢复这些状态。
-
- 原理
-
建立缓存机制(以路由组件缓存为例)
- 原理
- 对于一些不需要每次都重新加载的页面组件(比如用户资料页面,在用户登录状态不变的情况下内容不会改变),可以使用Vue的
keep - alive
组件来缓存。keep - alive
会将包裹的组件实例缓存起来,下次再访问该组件时,会直接使用缓存的实例,而不是重新创建。
- 对于一些不需要每次都重新加载的页面组件(比如用户资料页面,在用户登录状态不变的情况下内容不会改变),可以使用Vue的
- 示例(在路由视图中缓存组件)
-
在
src/App.vue
中,使用keep - alive
包裹router - view
:html<template> <div id="app"> <keep - alive> <router - view></router - view> </keep - alive> </div> </template>
-
这样,在路由切换时,如果是已经访问过的组件,会优先从缓存中获取,减少了组件重新加载的次数,对于保持页面状态(如表单填写状态、滚动位置等)也很有帮助。不过要注意,对于一些数据可能会变化的组件,需要正确地处理缓存更新的情况,比如通过
activated
和deactivated
生命周期钩子来更新数据。
-
- 原理
keep-alive
-
keep - alive
实例应用场景-
多标签页系统(Tab System)
- 场景描述:在一个类似浏览器标签页的应用界面中,用户可以在多个页面(标签)之间切换。这些页面可能包含表单、图表、列表等各种内容。例如,一个数据管理系统,用户可以在"用户列表""数据报表""系统设置"等多个标签页之间切换。
keep - alive
优势 :使用keep - alive
可以缓存这些标签页对应的组件。当用户切换回之前访问过的标签页时,组件不需要重新渲染,能够快速恢复之前的状态,提供流畅的用户体验。例如,"用户列表"标签页中的搜索条件、滚动位置和选中的行等信息都能得以保留。
-
向导式表单(Wizard - style Forms)
- 场景描述:在一个包含多个步骤的表单应用中,如电商平台的购物流程(包括购物车、收货地址、支付方式等步骤)或用户注册流程(包含基本信息、验证信息、兴趣爱好等步骤)。
keep - alive
优势 :将每个步骤对应的组件用keep - alive
包裹,可以在用户来回切换步骤时,保持每个步骤表单中已填写的数据和状态。这样可以避免用户因为页面重新加载而丢失数据,减少用户的操作成本和烦躁情绪。
-
复杂的图表展示(Complex Chart Display)
- 场景描述:在数据可视化应用中,有多种复杂的图表,如柱状图、折线图、饼图等,这些图表可能需要从后端获取数据并进行渲染,而且用户可能会频繁切换查看不同类型的图表。
keep - alive
优势 :通过keep - alive
缓存图表组件,当用户切换回之前查看过的图表时,不需要重新获取数据和重新渲染图表,能够快速显示之前的图表状态,提高应用的响应速度,特别是在数据量较大或者获取数据的接口响应较慢的情况下,这种优势更加明显。
-
-
keep - alive
注意点总结-
生命周期钩子的变化
activated
和deactivated
钩子 :被keep - alive
包裹的组件会新增activated
和deactivated
生命周期钩子。activated
钩子在组件从缓存中激活时调用,deactivated
钩子在组件被缓存(切换到其他组件)时调用。在这些钩子中,可以进行一些特定的操作,比如在activated
钩子中重新获取数据(如果数据可能已经更新),或者在deactivated
钩子中暂停一些定时器或动画。- 与其他生命周期钩子的关系 :需要注意的是,当组件被缓存时,
mounted
等生命周期钩子不会再次触发,除非组件被重新创建(例如缓存被清除或者组件对应的v - node
被重新创建)。这意味着如果组件的初始化操作放在mounted
钩子中,并且组件被缓存,这些操作可能不会在每次显示组件时执行,需要根据情况调整到activated
钩子或者其他合适的地方。
-
组件状态更新与缓存更新
- 数据更新问题 :如果缓存的组件中的数据可能会被其他组件或全局状态的变化所影响,需要考虑如何正确地更新缓存组件中的数据。一种方法是在
activated
钩子中检查数据是否需要更新,并根据需要重新获取数据或者更新数据。另一种方法是使用响应式数据(如Vuex中的状态或者ref
/reactive
对象),并在数据变化时通过合适的方式通知缓存组件进行更新。 - 动态组件与
keep - alive
:当keep - alive
包裹动态组件时,需要特别注意组件的切换和缓存更新。如果动态组件的类型或者属性发生变化,可能需要考虑如何处理缓存中的旧组件实例。例如,可以在动态组件切换时,清除旧组件的缓存或者根据新的组件属性更新缓存中的组件。
- 数据更新问题 :如果缓存的组件中的数据可能会被其他组件或全局状态的变化所影响,需要考虑如何正确地更新缓存组件中的数据。一种方法是在
-
缓存的清除与管理
- 手动清除缓存 :在某些情况下,可能需要手动清除
keep - alive
的缓存。例如,当用户执行了某个操作(如退出登录或者更新了某些关键数据)后,希望重新加载所有组件,而不是使用缓存。可以通过keep - alive
组件提供的exclude
或include
属性来控制哪些组件被缓存,或者通过编程方式(如在Vuex
的mutation
或action
中)清除缓存。 - 缓存大小和性能考虑:如果缓存的组件过多或者组件本身占用内存较大,可能会影响应用的性能。需要根据应用的实际情况,合理地选择要缓存的组件,并考虑缓存的生命周期和清除策略,以避免内存泄漏或者性能下降的问题。
- 手动清除缓存 :在某些情况下,可能需要手动清除
keep-alive(exclude / include)
keep - alive
基础回顾
keep - alive
是Vue.js中的一个组件,用于缓存内部的组件。当组件在keep - alive
内部被切换时,它们不会被销毁,而是被缓存起来,下次再显示时可以快速恢复,减少重新渲染的时间。
-
-
include
属性应用实例- 场景描述 :
- 假设我们有一个应用,有三个路由组件:
Home.vue
、Profile.vue
和Settings.vue
。我们希望只缓存Home.vue
和Profile.vue
组件,因为Settings.vue
组件的内容可能会经常变化,每次进入都希望重新加载。
- 假设我们有一个应用,有三个路由组件:
- 代码实现 :
-
在
App.vue
文件中:html<template> <div id="app"> <keep - alive :include="['Home', 'Profile']"> <router - view></router - view> </keep - alive> </div> </template> <script> import { defineComponent } from 'vue'; export default defineComponent({ name: 'App' }); </script>
-
这里的
include
属性是一个数组,数组中的元素是要被缓存的组件的名称。在这个例子中,只有名称为Home
和Profile
的组件会被keep - alive
缓存。需要注意的是,组件名称是在组件定义时通过name
属性指定的。例如,在Home.vue
组件中应该有如下定义:html<template> <div> Home Component </div> </template> <script> export default { name: 'Home' }; </script>
-
- 场景描述 :
-
exclude
属性应用实例- 场景描述 :
- 假设我们有同样的三个路由组件,但是我们希望缓存除了
Settings.vue
之外的所有组件。这种情况可以使用exclude
属性。
- 假设我们有同样的三个路由组件,但是我们希望缓存除了
- 代码实现 :
-
在
App.vue
文件中:html<template> <div id="app"> <keep - alive :exclude="['Settings']"> <router - view></router - view> </keep - alive> </div> </template> <script> import { defineComponent } from 'vue'; export default defineComponent({ name: 'App' }); </script>
-
这里的
exclude
属性也是一个数组,数组中的元素是不被缓存的组件的名称。在这个例子中,名称为Settings
的组件不会被keep - alive
缓存,而Home.vue
和Profile.vue
组件会被缓存。
-
- 场景描述 :
-
结合动态组件的应用实例(进阶)
- 场景描述 :
- 假设我们有一个页面,里面有一个动态组件,根据用户的选择可以切换不同的子组件,如
ComponentA.vue
、ComponentB.vue
和ComponentC.vue
。我们希望根据用户的权限来决定哪些组件可以被缓存。例如,普通用户只能看到ComponentA.vue
和ComponentB.vue
,并且只有ComponentA.vue
可以被缓存;管理员可以看到所有组件,并且ComponentB.vue
和ComponentC.vue
可以被缓存。
- 假设我们有一个页面,里面有一个动态组件,根据用户的选择可以切换不同的子组件,如
- 代码实现 :
-
在父组件(假设为
Parent.vue
)中:html<template> <div> <keep - alive :include="cachedComponents"> <component :is="currentComponent"></component> </keep - alive> <button @click="changeComponent('ComponentA')">Show ComponentA</button> <button @click="changeComponent('ComponentB')">Show ComponentB</button> <button @click="changeComponent('ComponentC')">Show ComponentC</button> </div> </template> <script> import { defineComponent, ref } from 'vue'; import ComponentA from './ComponentA.vue'; import ComponentB from './ComponentB.vue'; import ComponentC from './ComponentC.vue'; export default defineComponent({ setup() { const components = { ComponentA, ComponentB, ComponentC }; const currentComponent = ref('ComponentA'); const userRole = 'user'; // 假设用户角色,实际应用中应该从用户信息获取 const cachedComponents = userRole === 'user'? ['ComponentA'] : ['ComponentB', 'ComponentC']; const changeComponent = (componentName) => { currentComponent.value = componentName; }; return { currentComponent, cachedComponents, changeComponent }; } }); </script>
-
在这个例子中,
cachedComponents
是一个响应式数组,根据用户角色来决定哪些组件应该被包含在keep - alive
的缓存中。动态组件component
会根据currentComponent
的值来切换显示不同的子组件,并且只有在cachedComponents
数组中的组件才会被keep - alive
缓存。
-
- 场景描述 :