当前位置: 首页 > news >正文

Vue3 面试题及详细答案120道(91-105 )

前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。

前后端面试题-专栏总目录

在这里插入图片描述

文章目录

  • 一、本文面试题目录
      • 91. Vue3 中如何使用 `v-once` 优化性能?
      • 92. 请解释 Vue3 中 `toRef` 与 `toRefs` 的区别及使用场景?
      • 93. Vue3 中如何实现组件的动态切换?
      • 94. 请描述 Vue3 中 `v-for` 与 `v-if` 同时使用的注意事项?
      • 95. Vue3 中如何实现自定义的表单控件(如封装 Input 组件)?
      • 96. 请解释 Vue3 中 `runtime-core` 与 `runtime-dom` 的区别?
      • 97. Vue3 中如何使用 `provide`/`inject` 实现跨层级组件通信并保持响应式?
      • 98. 请描述 Vue3 中模板编译的优化策略?
      • 99. Vue3 中如何使用 `Suspense` 结合异步组件和异步数据加载?
      • 100. 请解释 Vue3 中 `ref` 的实现原理?
      • 101. Vue3 中如何实现组件的懒加载及代码分割?
      • 102. 请对比 Vue3 与 Vue2 的虚拟 DOM 差异?
      • 103. Vue3 中如何使用 `v-slot` 定义和使用插槽?
      • 104. 请描述 Vue3 中 `reactive` 的实现原理?
      • 105. Vue3 中如何实现基于路由的权限控制?
  • 二、120道面试题目录列表

一、本文面试题目录

91. Vue3 中如何使用 v-once 优化性能?

v-once 是 Vue 的内置指令,用于标记元素或组件只渲染一次,后续即使数据变化也不会重新渲染,从而优化性能。

使用场景

  • 内容固定不变的元素(如静态文本、版权信息、固定的标题等)。
  • 渲染代价较高但数据不会变化的组件。

示例

<!-- 静态文本,只渲染一次 -->
<p v-once>© 2023 Vue3 面试题集(内容固定)</p><!-- 数据初始渲染后不变,使用 v-once 避免重复渲染 -->
<div v-once><h2>{{ initialTitle }}</h2><p>{{ initialDescription }}</p>
</div>

注意v-once 会阻止其子元素的响应式更新,因此仅适用于确知内容不会变化的场景,滥用可能导致数据更新后视图不刷新的问题。

92. 请解释 Vue3 中 toReftoRefs 的区别及使用场景?

toReftoRefs 都是用于将响应式对象的属性转为 ref 对象的 API,以保持响应式特性,但适用场景不同:

toRef

  • 功能:将响应式对象的单个属性转为 ref 对象,与原对象保持关联。
  • 场景:仅需使用响应式对象的某个属性,且希望该属性保持响应式。
  • 示例:
    import { reactive, toRef } from 'vue';
    const obj = reactive({ name: 'Vue3', age: 3 });
    const nameRef = toRef(obj, 'name'); // 仅转换 name 属性
    nameRef.value = 'Vue'; // 修改会同步到原对象,触发更新
    

toRefs

  • 功能:将响应式对象的所有属性转为 ref 对象,返回一个包含这些 ref 的普通对象。
  • 场景:需要解构响应式对象的多个属性,且希望所有属性保持响应式。
  • 示例:
    import { reactive, toRefs } from 'vue';
    const obj = reactive({ name: 'Vue3', age: 3 });
    const { name, age } = toRefs(obj); // 所有属性转为 ref
    name.value = 'Vue'; // 同步更新原对象
    age.value = 4; // 同步更新原对象
    

总结toRef 用于单个属性,toRefs 用于多个属性,均用于解决响应式对象解构后丢失响应式的问题。

93. Vue3 中如何实现组件的动态切换?

组件的动态切换指根据条件或状态渲染不同的组件,Vue3 中可通过以下方式实现:

  1. 使用 <component> 标签配合 :is 属性

    <template><!-- :is 绑定组件名称或组件对象 --><component :is="currentComponent"></component><button @click="currentComponent = ComponentA">显示A</button><button @click="currentComponent = ComponentB">显示B</button>
    </template>
    <script setup>
    import { ref } from 'vue';
    import ComponentA from './ComponentA.vue';
    import ComponentB from './ComponentB.vue';
    const currentComponent = ref(ComponentA); // 初始显示 ComponentA
    </script>
    
  2. 通过 v-if/v-else-if/v-else 条件渲染

    <template><ComponentA v-if="type === 'A'"></ComponentA><ComponentB v-else-if="type === 'B'"></ComponentB><ComponentC v-else></ComponentC><button @click="type = 'A'">切换到A</button><button @click="type = 'B'">切换到B</button>
    </template>
    <script setup>
    import { ref } from 'vue';
    import ComponentA from './ComponentA.vue';
    import ComponentB from './ComponentB.vue';
    import ComponentC from './ComponentC.vue';
    const type = ref('A');
    </script>
    

对比

  • <component :is> 适用于组件类型较多、切换频繁的场景,更灵活。
  • v-if 系列适用于条件简单、组件类型较少的场景,可读性更强。

94. 请描述 Vue3 中 v-forv-if 同时使用的注意事项?

在 Vue 中,v-forv-if 同时使用可能导致逻辑混淆和性能问题,需注意以下事项:

  1. 优先级问题

    • Vue3 中 v-for 的优先级高于 v-if,即先循环渲染所有项,再对每个项执行 v-if 判断。
    • 示例:
      <!-- 先循环所有 item,再判断是否显示 -->
      <li v-for="item in list" v-if="item.active" :key="item.id">{{ item.name }}
      </li>
      
    • 问题:即使 item.activefalsev-for 仍会循环该 item,造成不必要的渲染开销。
  2. 优化方案

    • 使用计算属性过滤数据:先过滤出需要渲染的项,再循环,减少循环次数。
      import { ref, computed } from 'vue';
      const list = ref([/* 原始数据 */]);
      const filteredList = computed(() => list.value.filter(item => item.active));
      
      <li v-for="item in filteredList" :key="item.id">{{ item.name }}
      </li>
      
    • 在外层包裹元素使用 v-if:若需整体条件渲染(如列表是否显示),将 v-if 放在 v-for 外层。
      <ul v-if="showList"> <!-- 先判断是否显示列表,再循环 --><li v-for="item in list" :key="item.id">{{ item.name }}</li>
      </ul>
      
  3. 避免逻辑混淆:同时使用时需明确目的(是过滤项还是控制整体显示),优先通过计算属性优化。

95. Vue3 中如何实现自定义的表单控件(如封装 Input 组件)?

封装自定义表单控件需支持 v-model 双向绑定,使组件能像原生表单元素一样使用。Vue3 中实现方式如下:

示例:封装一个带校验的 Input 组件

<!-- CustomInput.vue -->
<template><div class="custom-input"><input:value="modelValue"@input="$emit('update:modelValue', $event.target.value)"@blur="handleBlur":class="{ 'error': hasError }"/><p class="error-message" v-if="hasError">{{ errorMessage }}</p></div>
</template><script setup>
import { defineProps, defineEmits, computed } from 'vue';// 接收 v-model 绑定的值(默认用 modelValue)
const props = defineProps({modelValue: {type: String,default: ''},// 校验规则(可选)validator: {type: Function,default: () => true}
});// 声明可触发的事件
const emit = defineEmits(['update:modelValue', 'blur']);// 校验逻辑
const hasError = computed(() => !props.validator(props.modelValue));
const errorMessage = computed(() => `请输入有效的值(当前值:${props.modelValue})`);// 处理失焦事件
const handleBlur = (e) => {emit('blur', e); // 向外触发 blur 事件
};
</script>

使用自定义 Input 组件

<template><CustomInputv-model="username":validator="validateUsername"@blur="handleInputBlur"/>
</template><script setup>
import { ref } from 'vue';
import CustomInput from './CustomInput.vue';const username = ref('');// 校验规则:用户名长度 >= 3
const validateUsername = (value) => value.length >= 3;// 处理失焦
const handleInputBlur = (e) => {console.log('输入框失焦', e.target.value);
};
</script>

核心原理:通过 modelValue 接收值,update:modelValue 事件更新值,实现 v-model 双向绑定,同时支持自定义事件和校验逻辑。


No.大剑师精品GIS教程推荐
0地图渲染基础- 【WebGL 教程】 - 【Canvas 教程】 - 【SVG 教程】
1Openlayers 【入门教程】 - 【源代码+示例 300+】
2Leaflet 【入门教程】 - 【源代码+图文示例 150+】
3MapboxGL【入门教程】 - 【源代码+图文示例150+】
4Cesium 【入门教程】 - 【源代码+综合教程 200+】
5threejs【中文API】 - 【源代码+图文示例200+】

96. 请解释 Vue3 中 runtime-coreruntime-dom 的区别?

Vue3 的核心包被拆分为多个模块,@vue/runtime-core@vue/runtime-dom 是其中两个核心模块,职责不同:

@vue/runtime-core

  • 功能:Vue3 的核心运行时,包含虚拟 DOM、组件系统、响应式核心、生命周期等与平台无关的核心逻辑。
  • 平台无关性:不依赖浏览器 DOM API,可用于非浏览器环境(如 Node.js 服务端渲染、小程序等)。
  • 主要内容:
    • 虚拟 DOM 的创建、渲染、更新逻辑。
    • 组件实例的创建和管理。
    • 响应式系统的核心实现(依赖收集、触发更新)。

@vue/runtime-dom

  • 功能:基于 runtime-core,针对浏览器环境的运行时扩展,提供 DOM 相关的实现。
  • 平台相关性:依赖浏览器 DOM API,负责将虚拟 DOM 转换为真实 DOM。
  • 主要内容:
    • DOM 元素的创建、插入、删除等操作。
    • 事件处理(将虚拟 DOM 事件映射为浏览器原生事件)。
    • 样式、属性的处理(如 classstyle 绑定的 DOM 实现)。

关系runtime-dom 依赖 runtime-core,并在其基础上添加了浏览器特有的功能。开发 Web 应用时,通常引入的 vue 包已包含两者;开发跨平台应用时,可能直接使用 runtime-core 配合特定平台的运行时(如 @vue/runtime-mini-program)。

97. Vue3 中如何使用 provide/inject 实现跨层级组件通信并保持响应式?

provideinject 用于跨层级组件通信(如祖父组件向孙子组件传递数据),结合响应式 API 可保持数据的响应式:

实现步骤

  1. 祖先组件使用 provide 提供响应式数据

    import { provide, ref, reactive } from 'vue';
    const count = ref(0); // ref 响应式数据
    const user = reactive({ name: 'Vue3' }); // reactive 响应式对象// 提供数据(key 为标识,value 为响应式数据)
    provide('countKey', count);
    provide('userKey', user);
    
  2. 后代组件使用 inject 接收数据并保持响应式

    import { inject } from 'vue';// 接收响应式数据(第二个参数为默认值)
    const count = inject('countKey', ref(0));
    const user = inject('userKey', reactive({ name: '默认名称' }));// 使用数据(修改会触发祖先组件及其他依赖组件的更新)
    const increment = () => { count.value++; };
    const changeName = () => { user.name = 'Vue'; };
    
  3. 传递修改方法(推荐):

    • 为避免后代组件直接修改祖先数据导致逻辑混乱,可提供修改方法:
    // 祖先组件
    const count = ref(0);
    const incrementCount = () => { count.value++; };
    provide('countKey', { count, incrementCount });// 后代组件
    const { count, incrementCount } = inject('countKey');
    // 调用方法修改,而非直接修改 count.value
    incrementCount();
    

注意provide 传递的若为响应式数据(ref/reactive),inject 接收后仍保持响应式;若传递非响应式数据,修改后后代组件不会感知,因此需传递响应式数据以保持通信。

98. 请描述 Vue3 中模板编译的优化策略?

Vue3 的模板编译阶段进行了多项优化,减少运行时的虚拟 DOM 对比开销,提升渲染性能,主要策略如下:

  1. 静态提升(Static Hoisting)

    • 将模板中的静态内容(如固定文本、无绑定的元素)提取到渲染函数外,仅编译一次,避免每次渲染重新创建虚拟节点。
    • 示例:
      <!-- 静态内容会被提升 -->
      <div><h1>静态标题</h1><p>{{ dynamicText }}</p>
      </div>
      
  2. Patch Flag(补丁标记)

    • 对动态节点添加标记(如 /* TEXT *//* CLASS */),标记节点的动态部分(文本、类名、属性等)。
    • 运行时对比虚拟 DOM 时,仅需关注带标记的动态节点及其标记的动态部分,跳过静态节点,减少对比时间。
    • 示例:动态文本节点会被标记为 TEXT,更新时仅检查文本内容。
  3. 缓存事件处理函数

    • 对模板中的事件处理函数(如 @click="handleClick")进行缓存,避免每次渲染创建新的函数实例,减少虚拟 DOM 的不必要更新。
  4. Block 树优化

    • 将模板按动态节点的分布划分为多个 Block(块),每个 Block 包含一组相邻的动态节点。
    • 运行时更新时,仅需遍历包含动态节点的 Block,进一步缩小对比范围。
  5. 条件编译

    • 根据不同的环境(如开发/生产)或特性(如是否支持 Proxy)生成不同的编译结果,优化运行时代码。

这些优化使 Vue3 的渲染性能相比 Vue2 提升约 55%(官方数据),尤其在大型应用中效果显著。

99. Vue3 中如何使用 Suspense 结合异步组件和异步数据加载?

Suspense 可同时处理异步组件和组件内部的异步数据加载,统一管理加载状态,提升用户体验:

实现步骤

  1. 定义异步组件(包含异步数据加载)

    <!-- AsyncDataComponent.vue -->
    <template><div><h2>{{ user.name }}</h2><p>年龄:{{ user.age }}</p></div>
    </template><script setup>
    // 异步加载数据(setup 中使用 await)
    const fetchUser = async () => {const res = await fetch('/api/user');return res.json();
    };
    const user = await fetchUser(); // 异步数据
    </script>
    
  2. 在父组件中用 Suspense 包裹异步组件

    <template><Suspense><!-- 默认插槽:异步内容(组件 + 数据) --><template #default><AsyncDataComponent /></template><!-- fallback 插槽:加载中状态 --><template #fallback><div class="loading"><span>加载用户数据中...</span><div class="spinner"></div></div></template></Suspense>
    </template><script setup>
    // 异步导入组件(结合动态导入)
    import { defineAsyncComponent } from 'vue';
    const AsyncDataComponent = defineAsyncComponent(() => import('./AsyncDataComponent.vue')
    );
    </script>
    

工作流程

  • 父组件加载时,Suspense 先显示 fallback 插槽的加载状态。
  • 同时触发两个异步操作:异步组件的加载(defineAsyncComponent)和组件内部的数据加载(await fetchUser())。
  • 所有异步操作完成后,Suspense 切换到 default 插槽,显示加载完成的内容。

注意:若任一异步操作失败,需通过错误边界(onErrorCaptured)捕获错误,避免应用崩溃。

100. 请解释 Vue3 中 ref 的实现原理?

ref 是 Vue3 中用于创建响应式数据的核心 API,支持基本类型和对象,其实现原理如下:

  1. 包装基本类型

    • 对于基本类型(stringnumber 等),ref 将其包装为一个包含 value 属性的对象(RefImpl 实例)。
    • value 属性通过 gettersetter 实现响应式:
      • getter:访问 value 时,触发依赖收集(track),记录使用该值的副作用函数。
      • setter:修改 value 时,触发依赖更新(trigger),执行所有关联的副作用函数(如组件渲染)。
  2. 处理对象类型

    • 若传入 ref 的是对象或数组,ref 会自动调用 reactive 将其转为响应式对象(Proxy 代理)。
    • 此时 ref.value 指向该响应式对象,访问或修改对象的属性时,由 reactive 的 Proxy 机制处理响应式。
  3. 自动解包

    • 在模板中使用 ref 时,Vue 会自动解包(无需 .value),直接访问值。
    • reactive 对象中访问 ref 属性时,也会自动解包:
      const count = ref(0);
      const obj = reactive({ count });
      console.log(obj.count); // 0(自动解包,等价于 count.value)
      

简化伪代码

class RefImpl {constructor(value) {// 若为对象,转为 reactivethis._value = isObject(value) ? reactive(value) : value;}get value() {track(this, 'get', 'value'); // 收集依赖return this._value;}set value(newValue) {if (newValue !== this._value) {this._value = isObject(newValue) ? reactive(newValue) : newValue;trigger(this, 'set', 'value'); // 触发更新}}
}function ref(value) {return new RefImpl(value);
}

总结ref 通过包装对象的 value 属性实现基本类型的响应式,通过 reactive 处理对象类型,同时支持自动解包以简化使用。

101. Vue3 中如何实现组件的懒加载及代码分割?

组件懒加载通过动态导入(import())实现,配合打包工具(如 Webpack、Vite)的代码分割功能,将组件代码拆分为单独的 chunk,按需加载,减少初始加载体积。

实现方式

  1. 路由级懒加载(最常用):

    // router/index.js
    import { createRouter, createWebHistory } from 'vue-router';// 动态导入组件,打包时会分割为单独的 chunk
    const Home = () => import('../views/Home.vue');
    const About = () => import('../views/About.vue');// 更精细的分割:指定 chunk 名称(Webpack 语法)
    const User = () => import(/* webpackChunkName: "user" */ '../views/User.vue');const routes = [{ path: '/', component: Home },{ path: '/about', component: About },{ path: '/user', component: User }
    ];
    const router = createRouter({ history: createWebHistory(), routes });
    
  2. 组件级懒加载(非路由组件):

    import { defineAsyncComponent } from 'vue';// 懒加载组件,支持加载状态和错误处理
    const LazyComponent = defineAsyncComponent({loader: () => import('./LazyComponent.vue'), // 动态导入loadingComponent: Loading, // 加载中显示的组件errorComponent: Error, // 加载失败显示的组件delay: 200 // 延迟 200ms 显示加载组件(避免闪烁)
    });
    
  3. 在模板中使用懒加载组件

    <template><button @click="showLazy = true">显示懒加载组件</button><LazyComponent v-if="showLazy" />
    </template>
    <script setup>
    import { ref } from 'vue';
    import LazyComponent from './LazyComponent'; // 导入懒加载组件
    const showLazy = ref(false);
    </script>
    

优势

  • 减少初始加载的 JavaScript 体积,提升首屏加载速度。
  • 按需加载组件代码,节省带宽和资源。

注意:懒加载组件会增加用户交互时的加载延迟,需配合加载状态提示(如 defineAsyncComponentloadingComponent)优化体验。

102. 请对比 Vue3 与 Vue2 的虚拟 DOM 差异?

Vue3 对虚拟 DOM 进行了重构和优化,相比 Vue2 有以下差异:

特性Vue3 虚拟 DOMVue2 虚拟 DOM
结构优化采用扁平化的虚拟 DOM 结构,减少嵌套层级嵌套层级较深,递归对比开销大
编译时优化结合模板编译,生成带 Patch Flag 的虚拟节点纯运行时对比,无编译时优化
对比范围仅对比带 Patch Flag 的动态节点及标记的动态部分全量对比所有节点,包括静态节点
性能提升大型应用中渲染性能提升约 55%(官方数据)渲染性能随节点数量增加下降较明显
数组处理优化数组更新,减少不必要的元素移动数组更新时可能导致大量元素重新渲染
Tree-shaking支持 Tree-shaking,仅打包使用的虚拟 DOM 方法虚拟 DOM 方法打包时无法剔除,体积较大

核心优化点

  • Vue3 通过 Patch Flag 标记动态节点的动态部分(如文本、属性),运行时仅对比这些部分,跳过静态节点。
  • Vue3 的虚拟 DOM 生成逻辑与模板编译深度结合,编译阶段即可确定节点的动态特性,减少运行时计算。
  • Vue3 对虚拟节点的创建进行了优化,避免不必要的对象创建和属性复制。

示例

  • Vue3 中带 Patch Flag 的虚拟节点(编译后):
    // 动态文本节点被标记为 TEXT
    createVNode('p', null, [createTextVNode(`${msg}`, 1 /* TEXT */)]);
    
  • 运行时对比时,仅检查标记为 TEXT 的节点的文本内容,忽略其他静态部分。

103. Vue3 中如何使用 v-slot 定义和使用插槽?

v-slot 是 Vue 中用于定义和使用插槽的指令,替代了 Vue2 中的 slotslot-scope,Vue3 中使用方式如下:

  1. 默认插槽

    • 子组件定义默认插槽:
      <!-- Child.vue -->
      <template><div class="child"><slot></slot> <!-- 默认插槽出口 --></div>
      </template>
      
    • 父组件使用默认插槽:
      <Child><template v-slot:default> <!-- v-slot:default 可省略 --><p>这是默认插槽的内容</p></template>
      </Child>
      <!-- 简化写法 -->
      <Child><p>这是默认插槽的内容</p>
      </Child>
      
  2. 具名插槽(多个插槽区分):

    • 子组件定义具名插槽:
      <!-- Child.vue -->
      <template><div><slot name="header"></slot> <!-- 头部插槽 --><slot></slot> <!-- 默认插槽 --><slot name="footer"></slot> <!-- 底部插槽 --></div>
      </template>
      
    • 父组件使用具名插槽:
      <Child><template v-slot:header> <!-- 头部内容 --><h1>标题</h1></template><p>正文内容(默认插槽)</p><template v-slot:footer> <!-- 底部内容 --><p>版权信息</p></template>
      </Child>
      
  3. 作用域插槽(子组件向父组件传递数据):

    • 子组件在插槽中传递数据:
      <!-- Child.vue -->
      <template><div><slot name="item" :data="user" :index="0"></slot></div>
      </template>
      <script setup>
      import { reactive } from 'vue';
      const user = reactive({ name: 'Vue3' });
      </script>
      
    • 父组件接收插槽数据:
      <Child><template v-slot:item="slotProps"> <!-- slotProps 接收数据 --><p>名称:{{ slotProps.data.name }}</p><p>索引:{{ slotProps.index }}</p></template>
      </Child>
      <!-- 解构简化 -->
      <template v-slot:item="{ data, index }"><p>名称:{{ data.name }},索引:{{ index }}</p>
      </template>
      

简化语法v-slot:name 可缩写为 #name,如 #header 等价于 v-slot:header

104. 请描述 Vue3 中 reactive 的实现原理?

reactive 是 Vue3 中用于创建响应式对象的 API,基于 ES6 的 Proxy 实现,其核心原理如下:

  1. Proxy 代理对象

    • reactive 接收一个对象,返回该对象的 Proxy 代理实例。
    • Proxy 可拦截对象的多种操作(getsetdeleteProperty 等),从而实现响应式。
  2. 依赖收集(get 拦截)

    • 当访问代理对象的属性(如 obj.name)时,get 拦截器被触发。
    • 此时调用 track 函数,收集当前活跃的副作用函数(如组件渲染函数、watch 回调),建立属性与副作用函数的依赖关系。
  3. 触发更新(set/deleteProperty 拦截)

    • 当修改属性(obj.name = 'new')或删除属性(delete obj.name)时,setdeleteProperty 拦截器被触发。
    • 此时调用 trigger 函数,找到该属性的所有依赖的副作用函数并执行,触发组件更新或回调函数执行。
  4. 递归代理嵌套对象

    • 当访问对象的嵌套属性(如 obj.user.name)时,get 拦截器会检查该属性是否为对象,若是则递归调用 reactive 使其成为响应式对象(懒代理)。

简化伪代码

function reactive(target) {return new Proxy(target, {get(target, key, receiver) {// 递归代理嵌套对象const value = Reflect.get(target, key, receiver);if (isObject(value)) {return reactive(value);}// 收集依赖track(target, key);return value;},set(target, key, value, receiver) {const oldValue = Reflect.get(target, key, receiver);if (value !== oldValue) {Reflect.set(target, key, value, receiver);// 触发更新trigger(target, key);}return true;},deleteProperty(target, key) {Reflect.deleteProperty(target, key);// 触发更新trigger(target, key);return true;}});
}

注意

  • reactive 仅支持对象和数组,不支持基本类型(基本类型需用 ref)。
  • 代理对象与原对象不相等(reactive(obj) !== obj),需使用代理对象才能触发响应式。

105. Vue3 中如何实现基于路由的权限控制?

基于路由的权限控制指根据用户权限动态显示或隐藏路由,阻止未授权用户访问受保护的页面。Vue3 中结合 Vue Router 实现方式如下:

  1. 定义路由元信息(meta

    // router/index.js
    const routes = [{ path: '/login', component: Login },{ path: '/403', component: Forbidden }, // 无权限页面{path: '/dashboard',component: Dashboard,meta: { requiresAuth: true, roles: ['admin', 'editor'] } // 需认证和特定角色},{path: '/admin',component: Admin,meta: { requiresAuth: true, roles: ['admin'] } // 仅 admin 可访问}
    ];
    
  2. 全局前置守卫验证权限

    import { createRouter } from 'vue-router';
    const router = createRouter({ /* 配置 */ });router.beforeEach((to, from, next) => {// 1. 无需认证的路由直接放行(如登录页)if (!to.meta.requiresAuth) {next();return;}// 2. 需认证:检查用户是否登录const isLogin = localStorage.getItem('token');if (!isLogin) {next('/login?redirect=' + to.path); // 未登录,跳转到登录页并记录目标路径return;}// 3. 检查角色权限const userRoles = JSON.parse(localStorage.getItem('roles')) || [];const requiredRoles = to.meta.roles || [];if (requiredRoles.length === 0 || requiredRoles.some(role => userRoles.includes(role))) {next(); // 权限匹配,放行} else {next('/403'); // 无权限,跳转到 403 页面}
    });
    
  3. 动态生成路由(基于用户权限)

    • 对于权限差异大的场景,可在登录后根据用户权限动态添加路由:
      // 登录成功后
      const addRoutesByRole = (roles) => {const dynamicRoutes = roles.includes('admin') ? [/* admin 专属路由 */] : [/* 普通用户路由 */];dynamicRoutes.forEach(route => {router.addRoute(route); // 动态添加路由});
      };
      
  4. 在组件中隐藏无权限的导航

    <!-- 导航组件 -->
    <template><nav><router-link to="/dashboard" v-if="hasPermission(['admin', 'editor'])">仪表盘</router-link><router-link to="/admin" v-if="hasPermission(['admin'])">管理员页面</router-link></nav>
    </template>
    <script setup>
    const hasPermission = (requiredRoles) => {const userRoles = JSON.parse(localStorage.getItem('roles')) || [];return requiredRoles.some(role => userRoles.includes(role));
    };
    </script>
    

核心逻辑:通过路由元信息标记权限要求,全局守卫验证登录状态和角色权限,动态控制路由访问和导航显示,确保未授权用户无法访问受保护资源。

二、120道面试题目录列表

文章序号vue3面试题120道
1vue3 面试题及详细答案(01 - 15)
2vue3 面试题及详细答案(16 - 30)
3vue3 面试题及详细答案(31 - 45)
4vue3 面试题及详细答案(46 - 60)
5vue3 面试题及详细答案(61 - 75)
6vue3 面试题及详细答案(76 - 90)
7vue3 面试题及详细答案(91 - 105)
8vue3 面试题及详细答案(106 - 120)
http://www.xdnf.cn/news/1180657.html

相关文章:

  • 开立医疗2026年校园招聘
  • 论文复现-windows电脑在pycharm中运行.sh文件
  • 工具篇之开发IDEA插件的实战分享
  • C# 方法执行超时策略
  • 处理URL请求参数:精通`@PathVariable`、`@RequestParam`与`@MatrixVariable`
  • Lua元表(Metatable)
  • Python 使用环境下编译 FFmpeg 及 PyAV 源码(英特尔篇)
  • TDengine 转化类函数 TO_CHAR 用户手册
  • 【数字IC验证学习------- SOC 验证 和 IP验证和形式验证的区别】
  • 借助 VR 消防技术开展应急演练,检验完善应急预案​
  • 数据库底层索引讲解-排序和数据结构
  • 主流 BPM 厂商产品深度分析与选型指南:从能力解析到场景适配
  • 基于深度学习的CT图像3D重建技术研究
  • Python-初学openCV——图像预处理(二)
  • MySQL 表的操作
  • 大模型Prompt优化工程
  • Shell的正则表达式
  • JVM原理及其机制(二)
  • Web前端:JavaScript findIndex⽅法
  • MySQL数据库迁移至国产数据库测试案例
  • Spring MVC 统一响应格式:ResponseBodyAdvice 从浅入深
  • redis常用数据类型
  • 智慧工厂网络升级:新型 SD-WAN 技术架构与应用解析
  • Leetcode 07 java
  • 13-C语言:第13天笔记
  • C++第一节课入门
  • 基础NLP | 02 深度学习基本原理
  • PDF转Markdown - Python 实现方案与代码
  • 爬虫逆向--Day12--DrissionPage案例分析【小某书评价数据某东评价数据】
  • 使用爬虫获取游戏的iframe地址