vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > vue3动态路由+动态组件+缓存应用

vue3动态路由+动态组件+缓存应用方式

作者:放逐者-保持本心,方可放逐

这篇文章主要介绍了vue3动态路由+动态组件+缓存应用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

Vue3 案例复现(动态注册组件及路由重定向)

1. 项目结构

假设项目有src目录,src目录下包含views(存放组件)、router(存放路由相关文件)和store(用于状态管理,这里假设使用 Vuex)。

2. Vuex 存储相关信息(src/store/index.js)

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)

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)

<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>

在这个示例中:

动态组件

动态组件基础概念

简单的动态组件示例

首先,在src/views目录下创建几个组件,例如Home.vueProfile.vueAdmin.vue

Home.vue为例:

<template>
  <div>
    <h2>Home Page</h2>
  </div>
</template>
<script>
export default {
  name: 'Home'
};
</script>

src/App.vue(假设这是父组件)中使用动态组件:

<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,它存储了当前要显示的组件的名字。

结合路由使用动态组件(动态路由组件)

src/router/index.js中配置路由,假设你已经安装并配置了vue - router

import { 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.vueCompanyProfile.vue组件。

然后在Profile.vue中使用动态组件:

<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>

动态加载组件(异步组件)

对于大型应用或者有性能优化需求的场景,你可能不希望一次性加载所有组件,而是在需要的时候再加载。

Vue 3支持异步加载组件,通过import()函数来实现。import()函数返回一个Promise,当Promise被解决时,组件就被加载完成。

src/router/index.js中修改路由配置,以Admin.vue为例,将其改为异步加载:

import { 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 动态路由应用场景

用户信息展示

分类内容展示

多语言支持

Vue 3 动态路由实例

项目准备

路由配置(src/router/index.js

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

<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

<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

<template>
  <div>
    <h2>404 - Page Not Found</h2>
  </div>
</template>

App.vue中使用路由链接(src/App.vue

<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>

在这个实例中:

removeRoute 以及 hasRoute

removeRoute应用场景及实例

应用场景

实例

import { 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;
import { 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);
      }
    }
  }
});
<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应用场景及实例

应用场景:

实例:

import { 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;
<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>
<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)

import { 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);
};

从本地存储中恢复登录状态(在应用初始化时)

import { 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插件持久化存储状态

原理:

示例:

安装插件:

npm install vuex - persistedstate

首先,安装vuex - persistedstate

配置插件(在src/store/index.js中)

import { 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;

建立缓存机制(以路由组件缓存为例)

原理:

示例(在路由视图中缓存组件):

<template>
  <div id="app">
    <keep - alive>
      <router - view></router - view>
    </keep - alive>
  </div>
</template>

keep-alive

keep - alive实例应用场景

多标签页系统(Tab System)

向导式表单(Wizard - style Forms)

复杂的图表展示(Complex Chart Display)

keep - alive注意点总结:

keep-alive(exclude / include)

生命周期钩子的变化

组件状态更新与缓存更新

缓存的清除与管理

keep - alive基础回顾

include属性应用实例

场景描述

代码实现

<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>
<template>
  <div>
    Home Component
  </div>
</template>
<script>
export default {
  name: 'Home'
};
</script>

exclude属性应用实例:

场景描述

代码实现

<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>

结合动态组件的应用实例(进阶)

场景描述

代码实现

<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>

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文