前后端面试题》专栏集合了前后端各个知识模块的面试题,包括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.pswp.cn/news/915982.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/915982.shtml
英文地址,请注明出处:http://en.pswp.cn/news/915982.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SAP-MM-物料进销存表

ABAP库存进销存报表程序摘要 该ABAP程序是一个完整的库存进销存报表系统,主要功能包括: 报表类型选择: 物料库存进销存 批次库存进销存 寄售库存进销存 供应商库存进销存 原料库存进销存 主要功能: 从历史数据表(MARDH, MSKAH, MSLBH, MCHBH等)获取期初库存 处理物料移动数…

这几天都是发癫写的

#include <iostream> #include <vector> #include <unordered_map> #include <algorithm> #include <cmath> // for sqrt// Gen-Sort 实现&#xff08;保持不变&#xff09; void genSort(std::vector<int>& arr) {if (arr.empty()) r…

QT6 源,七章对话框与多窗体(11) 进度对话框 QProgressDialog:属性,公共成员函数,槽函数,信号函数,与源代码带注释

&#xff08;1&#xff09; 本类的继承关系 &#xff1a;可见&#xff0c;进度对话框&#xff0c;也是 QDialog 的子类&#xff0c;在其上面又摆放了一些控件&#xff0c;构成了不同用途的对话框。咱们也可以自定义对话框。只是没有 QT 官方大师们做的好。 人家在定义这 6 个子…

学习游戏制作记录(技能系统)7.24

1.技能系统概念首先让我们了解一下游戏的技能本质是什么&#xff0c;以投掷剑为例子&#xff0c;当玩家使用这个技能时&#xff0c;首先会播放玩家的动画&#xff0c;随后通过技能脚本创建一个剑的对象&#xff0c;当剑回收时会再次调用脚本&#xff0c;让它朝向玩家飞来并销毁…

外部存档(External Archive)机制

前言 提醒&#xff1a; 文章内容为方便作者自己后日复习与查阅而进行的书写与发布&#xff0c;其中引用内容都会使用链接表明出处&#xff08;如有侵权问题&#xff0c;请及时联系&#xff09;。 其中内容多为一次书写&#xff0c;缺少检查与订正&#xff0c;如有问题或其他拓展…

MybatisPlus操作方法详细总结

摘要&#xff1a;本文围绕 MyBatis-Plus 数据操作展开&#xff0c;涵盖标准数据层 CRUD 与分页查询&#xff1b;以及各种的复杂 SQL 查询&#xff1b;映射匹配&#xff08;TableField、TableName 注解&#xff09;与 ID 生成策略&#xff08;TableId 五种类型及全局配置&#x…

【C语言进阶】动态内存管理的面试题||练习

本节内容专门整理了一些动态内存管理的面试题&#xff0c;配有详细的解答。 目录 1. 看代码说结果 2. 看代码说结果 3. 看代码说结果 4.小乐乐与欧几里得 描述 分析1&#xff1a; 分析2&#xff1a; 代码&#xff1a; 5. 空心正方形 分析&#xff1a; 1. 看代码说结…

【图论】倍增与lca

void dfs(long u,long father){ dep[u]dep[father]1;//只在这里初始化depfor(long i1;(1<<i)<dep[u];i)fa[u][i]fa[fa[u][i-1]][i-1];//只这里用的倍增for(long ihead[u];~i;iedge[i].next){long vedge[i].to;if(vfather)continue;fa[v][0]u;dfs(v,u); }} long lca(lo…

VS Code 美化插件

目录1. Better Comments 更好的注释2. indent-rainbow 彩虹的缩进3. Trailing Spaces 尾随的空格4. Gruvbox Material 护眼的材质5. Md Editor 博客编辑器6. 待补充推荐笔记&#xff1a;VS Code写代码必备的五款代码美化插件 1. Better Comments 更好的注释 Better Comments Be…

火语言 RPA 在日常运维中的实践

在系统运维和技术支持工作中&#xff0c;总有一些操作像 “固定程序” 一样循环往复&#xff1a;定期检查服务器状态、批量处理用户权限申请、手动清理系统日志…… 这些工作步骤固定、逻辑简单&#xff0c;却占用了大量本可用于故障排查和系统优化的时间。近期在优化运维团队的…

FOUPK3system5XOS系统 NTX V2.0发布通知

FOUPK3system5XOS系统NTX V2.0发布通知更新1.系统安全&#xff1a;使用FOUPK3system5XOS NOS X9新内核与FOUPK3system5XOS系统19.63正式版一样提供更好的安全性2.原生应用&#xff1a;启用FOUPK3system5XOS ONS X9 API 72服务FOUPK3system5XOS系统 NTX V2.0用户支持使用FOUPK3…

爬虫算法原理解析

文章目录 核心算法原理 1. 图遍历算法 广度优先搜索(BFS) 深度优先搜索(DFS) 2. URL调度算法 优先级队列调度 3. 页面去重算法 基于哈希的去重 基于布隆过滤器的去重 4. 链接提取与规范化 5. 抓取频率控制算法 6. 增量爬取算法 高级算法策略 1. PageRank算法在爬虫中的应用 2. …

探索双链表:C语言中的链式结构魔法

目录 引言 一、双链表基础 1.1、什么是双链表&#xff1f; 1.2、双链表节点的结构定义 二、双链表的基本操作 2.1、双链表的初始化 2.2、尾插法 2.3、头插 2.4、判断双链表是否为空 2.5、尾删法 2.6、头删法 2.7、查找 2.8、双链表在指定位置之前插入 2.9、双链表…

HTML5 + CSS3模拟西门庆、武大郎和潘金莲的精彩520微信聊天,看完我又相信爱情了

今天520了&#xff0c;我用HTML5 CSS3模拟了西门庆、武大郎和潘金莲的精彩微信聊天&#xff0c;希望你看完以后可以在紧张的工作中&#xff0c;放松一下&#xff0c;开心一下&#xff0c;同时祝你在这个520可以过得开心快乐。 目录 1 实现思路 1.1 聊天实现素材 1.2 HTML布…

【Linux】Linux了解与基本指令(1)

hello~ 很高兴见到大家! 这次带来的是C中关于Linux基本指令这部分的一些知识点,如果对你有所帮助的话,可否留下你宝贵的三连呢? 个 人 主 页: 默|笙 文章目录一、认识Linux二、操作系统&#xff08;OS&#xff09;三、基本指令1. 目录与普通文件1.1 目录1.2 普通文件2. pwd 与…

dify 学习笔记

目录 启动项目 浏览器访问&#xff1a; dify删除工作流 代码是开源dify 启动项目 cd E:\project\qwen\dify-main\docker docker compose up -d 浏览器访问&#xff1a; http://127.0.0.1/apps dify删除工作流 右下角&#xff0c;三个点&#xff0c;点击弹出框&#xff0…

【YOLOv8改进 - 特征融合】FCM:特征互补映射模块 ,通过融合丰富语义信息与精确空间位置信息,增强深度网络中小目标特征匹配能力

YOLOv8目标检测创新改进与实战案例专栏 专栏目录: YOLOv8有效改进系列及项目实战目录 包含卷积,主干 注意力,检测头等创新机制 以及 各种目标检测分割项目实战案例 专栏链接: YOLOv8基础解析+创新改进+实战案例 文章目录 YOLOv8目标检测创新改进与实战案例专栏 介绍 摘要 文…

算法训练营day30 贪心算法④ 重叠问题 452. 用最少数量的箭引爆气球、435. 无重叠区间 、 763.划分字母区间

贪心算法的第四篇博客&#xff0c;主要是重叠问题的练习&#xff0c;思路都较为简单&#xff0c;最后一题可能需要着重思考一下 452. 用最少数量的箭引爆气球 遍历数组&#xff0c;如果存在重叠则减少一支箭&#xff08;不重叠则增加一支箭&#xff09; 重叠的判定&#xff1a…

Gradio, Streamlit, Dash:AI应用开发的效率之选

在人工智能时代&#xff0c;如何快速将模型原型转化为交互式应用&#xff0c;是许多开发者面临的挑战。Gradio、Streamlit 和 Dash 作为流行的Python框架&#xff0c;各自以其独特的优势&#xff0c;帮助我们高效地构建AI应用界面。本文将深入对比这三大框架的优缺点、适用场景…

数学基础弱能学好大数据技术吗?

很多同学刚进入大学&#xff0c;一听到“大数据”“数据分析”这些词&#xff0c;就觉得必须得是数学大佬才能玩得转。高数线代概率论&#xff0c;光听名字就头大&#xff0c;更别说那些复杂的公式和推导了。但事实真的是这样吗&#xff1f;数学不好&#xff0c;就不能学大数据…