前端学习29 相关面试题3
1.vue3封装一个只读变量
我们可以使用readonly API来实现这个功能,它涉及代理模式,我们通过一个代理包装对象,对外之报读可读的能力,隐藏写能力。
// dataStore.js import { reactive, readonly } from 'vue' const _state = reactive({ count: 0, message: 'Hello' }) // 封装:外部只能读,不能写 export const state = readonly(_state) // 内部函数:可用于更新状态 export function increment() { _state.count++ } //外部使用 import { state, increment } from './dataStore' console.log(state.count) // ✅ 读取 state.count = 10 // ❌ 报错或无效(readonly) increment() // ✅ 间接修改 console.log(state.count) // => 1
实际就是 Vue3 内置对 Proxy 代理模式的应用,对外封装了只读接口,实现了状态隔离与封装控制。这在模块化开发和状态安全控制中非常实用。
2.自定义指令(权限访问封装到指令级别)
在项目中我们通过封装 Vue3 的自定义指令 v-permission 实现组件级的权限控制。该指令会在绑定元素挂载时执行权限判断逻辑,结合 Vuex 或 localStorage 中的权限列表,判断用户是否具备某操作权限,如果没有则通过操作真实 DOM(如 el.parentNode.removeChild(el))移除对应元素。我们通常在 main.js 中将指令全局注册,使其可在任意组件中使用,也可以按需局部注册。指令内部可访问虚拟节点。
- 在指令中,我们可以通过 el 获取当前绑定元素,通过 binding.value 获取权限标识,然后从全局状态(如 Vuex)或缓存(如 localStorage)中获取当前用户权限列表。若用户权限不包含目标权限,则隐藏或移除对应元素
export default { mounted(el, binding, vnode) { //el 指令绑定到的元素。这可以用于直接操作 DOM。 // bind.value 传递给指令的值。例如在 v-permission="1 + 1" 中,值是 2 // const const requiredPermission = binding.value //获取相应的权限 const userPermissions = vnode.dirs[0].instance.$store.state.user.permissions if (!userPermissions.includes(requiredPermission)) { // 无权限,移除 DOM 元素 el.parentNode && el.parentNode.removeChild(el) } } }
- 全局注册指令
import { createApp } from 'vue' import App from './App.vue' import permission from './directives/permission.js' const app = createApp(App) app.directive('permission', permission)
- 局部注册
import permission from '@/directives/permission.js' export default { directives: { permission } }
- 使用
<el-button v-permission="'user:add'">添加用户</el-button>
总结:在项目中我们通过自定义指令 v-permission 实现前端权限控制。该指令在组件挂载时读取 localStorage 或 Vuex 中的权限码,通过钩子函数判断用户是否拥有某权限,如无权限则直接操作真实 DOM 将其移除。我们在 main.js 全局注册指令,方便项目中各组件使用。整个过程基于代理模式。
3. Vnode
vnode 本质上是用来描述 DOM 的 JavaScript 对象,它在 Vue.js 中可以描述不同类型的节点,比如普通元素节点、组件节点等。
普通 HTML 元素:每一个 HTML 标签都会生成一个 vnode;
自定义组件:组件本身也会生成一个 vnode,Vue 会再递归渲染它的内部模板为 vnode 子树。
//普通HTML元素 { type: 'div', props: { class: 'box' }, children: [ { type: 'p', props: null, children: 'Hello' } ] } //自定义组件 { type: MyComponent, props: {}, children: null, component: { ... } // 组件实例,渲染后挂载上去 }
Vue 使用 JavaScript 构建出一个抽象的 VNode 树结构,初次渲染时生成真实 DOM,后续数据变更时通过 diff 算法对比新旧 VNode 并执行最小 DOM 更新,整个过程完全由 JavaScript 控制,是前端视图高性能更新的核心机制。