前端学习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 控制,是前端视图高性能更新的核心机制。
查看9道真题和解析