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

全部评论

相关推荐

你在组件库项目中用到了Vue3的Composition&nbsp;API对比Options&nbsp;API有什么优势&nbsp;vue2v3原理分别是什么,v3解决了v2的什么问题Pinia和Vuex的区别是什么为什么选择Pinia做状态管理如何实现Vue3组件的全局注册和按需引入需要处理哪些问题性能优化具体指标几个要了解你提到首屏渲染从3s优化到1.6s具体做了哪些措施如何量化效果项目里如何处理errorIntersection&nbsp;Observer除了图片懒加载还能解决哪些前端问题,懒加载原理,别的方案了解吗为什么选择Vitest而不是Jest,Vitest在Vite项目中的优势是什么,如何写一个测试用例PostCSS和SassLess有什么区别你们为什么用BEM+PostCSS的方案组件库的TypeScript类型推导是如何设计的&nbsp;遇到过的复杂类型问题怎么解决ts在项目的好处坏处,项目用了ts吗具体聊聊某个组件设计细节&nbsp;某个复杂功能是如何实现单元测试覆盖率90%是如何统计的包含哪些场景,如何测试组件的交互行为电商项目里面路由权限拦截的具体实现方案如何和后端权限系统配合购物车数据持久化方案的选择过程对比localStorage和IndexedDB,和别的状态存储方式的区别如果商品列表页出现滚动卡顿你会如何排查和解决从输入URL到页面渲染详细说明HTTP缓存强缓存协商缓存的作用节点浏览器Event&nbsp;Loop机制如何影响Vue的nextTick实现CSS变量和预处理器变量如Sass变量在浏览器渲染流程中的区别常见的git命令,如果git&nbsp;merge出现冲突你的标准解决流程是什么如何预防冲突你的组件库和Element&nbsp;Plus有什么区别解决了什么Element没有解决的问题为什么选择读研为什么选择前端而不是后端对新的前端前沿技术有关注吗,具体了解的是什么了解最新的es特性吗,不是es6,说说你知道的最新的js语法
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务