v-show 失效?原因竟然是这!

职场   2024-09-29 08:36   江苏  

点击下方“前端开发爱好者”,选择“设为星标

第一时间关注技术干货!

大家好,我是 xy👨🏻‍💻。今天,我要给大家讲讲我们在项目开发中遇到的一个关于 v-show 的小插曲,这个问题让团队的一位小伙伴头疼了好一阵子。

v-show 的便利

对于使用 Vue 的开发者来说,v-show 指令是控制元素显示与隐藏的利器。它简单易用,只需一个布尔表达式,就能轻松控制元素的显示状态。

然而,最近我们团队的一位小伙伴在尝试用 v-show 控制子组件的显示隐藏时,遇到了一个难题。尽管条件设置正确,子组件却并没有按预期显示或隐藏,而且控制台也没有给出任何错误提示。

问题复现

在父组件中,我们通过 v-show 来控制子组件的显示隐藏:

父组件代码:

<template>
  <div>
    <p>父组件</p>
    <p>以下是子组件列表:</p>
    <!-- 子组件 -->
    <ChildList v-show="showList"/>
  </div>
</template>

子组件代码:

<template>
  <p v-for="(item, index) in list" :key="index">{{index + 1}}: {{item.name}}</p>
</template>

代码看起来没问题,但 v-show 并没有让子组件按预期工作。

探索原因

起初,我们尝试用 v-if 替换 v-show,问题确实解决了。

但好奇心驱使我们深入探究为什么 v-show 会失效。

深入源码

v-show 的源码实现中,相关的代码位于 packages/runtime-dom/src/directives/vShow.ts 文件中。

以下是 v-show 指令的生命周期钩子的实现:

export const vShow: ObjectDirective<VShowElement> & { name?: 'show' } = {
  beforeMount(el, { value }, { transition }) {
    el[vShowOriginalDisplay] =
      el.style.display === 'none' ? '' : el.style.display
    if (transition && value) {
      // 处理 transition 逻辑
      transition.beforeEnter(el)
    } else {
      setDisplay(el, value)
    }
  },
  mounted(el, { value }, { transition }) {
    if (transition && value) {
      // 处理 transition 逻辑
      transition.enter(el)
    }
  },
  updated(el, { value, oldValue }, { transition }) {
    if (!value === !oldValue) return
    if (transition) {
      if (value) {
        transition.beforeEnter(el)
        setDisplay(el, true)
        // 处理 transition 逻辑
        transition.enter(el)
      } else {
        transition.leave(el, () => {
          setDisplay(el, false)
        })
      }
    } else {
      setDisplay(el, value)
    }
  },
  beforeUnmount(el, { value }) {
    setDisplay(el, value)
  },
}

在这段代码中,setDisplay 函数是实际改变元素 display 属性的地方:

function setDisplay(el: VShowElement, value: unknown): void {
  el.style.display = value ? el._vod : 'none';
}

通过查看 Vue3 的源码,我们发现 v-show 指令的实现依赖于组件的根节点。

如果组件没有根节点,setDisplay 函数将无法正确执行,导致 v-show 失效。

解决问题

确保使用 v-show 的组件有一个根节点,这样可以避免失效的情况发生。在 Vue 3 文档中,推荐使用 v-if 来条件性渲染组件,因为 v-if 可以确保组件的生命周期钩子在元素实际被创建或销毁时被正确调用。

这个小插曲提醒我们,即使是看似简单的 v-show 指令,也有其使用的限制和条件。在 Vue 3 中,确保组件有一个根节点,是避免 v-show 失效的关键。同时,这也让我们更加深入地理解了 Vue 的工作原理。

如果你在开发中也遇到了类似的问题,或者有其他的前端技巧想要分享,欢迎在评论区交流!👨‍💻🚀

写在最后

公众号前端开发爱好者 专注分享 web 前端相关技术文章视频教程资源、热点资讯等,如果喜欢我的分享,给 🐟🐟 点一个 👍 或者 ➕关注 都是对我最大的支持。

欢迎长按图片加好友,我会第一时间和你分享前端行业趋势面试资源学习途径等等。

添加好友备注【进阶学习】拉你进技术交流群

关注公众号后,在首页:

  • 回复 面试题,获取最新大厂面试资料。
  • 回复 简历,获取 3200 套 简历模板。
  • 回复 React 实战,获取 React 最新实战教程。
  • 回复 Vue 实战,获取 Vue 最新实战教程。
  • 回复 ts,获取 TypeScript 精讲课程。
  • 回复 vite,获取 Vite 精讲课程。
  • 回复 uniapp,获取 uniapp 精讲课程。
  • 回复 js 书籍,获取 js 进阶 必看书籍。
  • 回复 Node,获取 Nodejs+koa2 实战教程。
  • 回复 数据结构算法,获取数据结构算法教程。
  • 回复 架构师,获取 架构师学习资源教程。
  • 更多教程资源应有尽有,欢迎 关注获取。

前端开发爱好者
分享 web 前端相关技术文章、工具资源、精选课程、视频教程资源、热点资讯等
 最新文章