前端学习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 控制,是前端视图高性能更新的核心机制。

全部评论

相关推荐

评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务