Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

面试官:Vue中的v-show和v-if怎么理解? #4

Open
febobo opened this issue Dec 10, 2020 · 8 comments
Open

面试官:Vue中的v-show和v-if怎么理解? #4

febobo opened this issue Dec 10, 2020 · 8 comments

Comments

@febobo
Copy link
Owner

febobo commented Dec 10, 2020

No description provided.

@febobo
Copy link
Owner Author

febobo commented Dec 11, 2020

一、v-show与v-if的共同点

我们都知道在 vuev-show v-if 的作用效果是相同的(不含v-else),都能控制元素在页面是否显示

在用法上也是相同的

<Model v-show="isShow" />
<Model v-if="isShow" />
  • 当表达式为true的时候,都会占据页面的位置
  • 当表达式都为false时,都不会占据页面位置

二、v-show与v-if的区别

  • 控制手段不同
  • 编译过程不同
  • 编译条件不同

控制手段:v-show隐藏则是为该元素添加css--display:nonedom元素依旧还在。v-if显示隐藏是将dom元素整个添加或删除

编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show只是简单的基于css切换

编译条件:v-if是真正的条件渲染,它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。只有渲染条件为假时,并不做操作,直到为真才渲染

  • v-showfalse变为true的时候不会触发组件的生命周期

  • v-iffalse变为true的时候,触发组件的beforeCreatecreatebeforeMountmounted钩子,由true变为false的时候触发组件的beforeDestorydestoryed方法

性能消耗:v-if有更高的切换消耗;v-show有更高的初始渲染消耗;

三、v-show与v-if原理分析

具体解析流程这里不展开讲,大致流程如下

  • 将模板template转为ast结构的JS对象
  • ast得到的JS对象拼装renderstaticRenderFns函数
  • renderstaticRenderFns函数被调用后生成虚拟VNODE节点,该节点包含创建DOM节点所需信息
  • vm.patch函数通过虚拟DOM算法利用VNODE节点创建真实DOM节点

v-show原理

不管初始条件是什么,元素总是会被渲染

我们看一下在vue中是如何实现的

代码很好理解,有transition就执行transition,没有就直接设置display属性

// https://github.com/vuejs/vue-next/blob/3cd30c5245da0733f9eb6f29d220f39c46518162/packages/runtime-dom/src/directives/vShow.ts
export const vShow: ObjectDirective<VShowElement> = {
  beforeMount(el, { value }, { transition }) {
    el._vod = el.style.display === 'none' ? '' : el.style.display
    if (transition && value) {
      transition.beforeEnter(el)
    } else {
      setDisplay(el, value)
    }
  },
  mounted(el, { value }, { transition }) {
    if (transition && value) {
      transition.enter(el)
    }
  },
  updated(el, { value, oldValue }, { transition }) {
    // ...
  },
  beforeUnmount(el, { value }) {
    setDisplay(el, value)
  }
}

v-if原理

v-if在实现上比v-show要复杂的多,因为还有else else-if 等条件需要处理,这里我们也只摘抄源码中处理 v-if 的一小部分

返回一个node节点,render函数通过表达式的值来决定是否生成DOM

// https://github.com/vuejs/vue-next/blob/cdc9f336fd/packages/compiler-core/src/transforms/vIf.ts
export const transformIf = createStructuralDirectiveTransform(
  /^(if|else|else-if)$/,
  (node, dir, context) => {
    return processIf(node, dir, context, (ifNode, branch, isRoot) => {
      // ...
      return () => {
        if (isRoot) {
          ifNode.codegenNode = createCodegenNodeForBranch(
            branch,
            key,
            context
          ) as IfConditionalExpression
        } else {
          // attach this branch's codegen node to the v-if root.
          const parentCondition = getParentCondition(ifNode.codegenNode!)
          parentCondition.alternate = createCodegenNodeForBranch(
            branch,
            key + ifNode.branches.length - 1,
            context
          )
        }
      }
    })
  }
)

四、v-show与v-if的使用场景

v-ifv-show 都能控制dom元素在页面的显示

v-if 相比 v-show 开销更大的(直接操作dom节点增加与删除)

如果需要非常频繁地切换,则使用 v-show 较好

如果在运行时条件很少改变,则使用 v-if 较好

参考文献

@huyarufitor
Copy link

v-if由false变为true的时候,触发组件的beforeCreate、create、beforeMount、mounted钩子,由true变为false的时候触发组件的beforeDestory、destoryed方法。这句话没懂,有大佬解释一下吗

@baoyichi
Copy link

v-if由false变为true的时候,触发组件的beforeCreate、create、beforeMount、mounted钩子,由true变为false的时候触发组件的beforeDestory、destoryed方法。这句话没懂,有大佬解释一下吗

其实就是true的时候触发创建的钩子,false的时候触发删除的方法,因为不存在更新,也就不关beforeUpdate和updated的事了

@Eysen-ZZT
Copy link

v-if由false变为true的时候,触发组件的beforeCreate、create、beforeMount、mounted钩子,由true变为false的时候触发组件的beforeDestory、destoryed方法。这句话没懂,有大佬解释一下吗

不就是组件的生命周期吗😂

@meigan1007
Copy link

meigan1007 commented Mar 10, 2023

v-if由false变为true的时候,触发组件的beforeCreate、create、beforeMount、mounted钩子,由true变为false的时触发组件的beforeDestory、destoryed方法。这句话没懂,有大佬了解

他这应该说的是用v-if 来渲染组件吧。

@sagashiro
Copy link

v-if由false变为true的时候,触发组件的beforeCreate、create、beforeMount、mounted钩子,由true变为false的时候触发组件的beforeDestory、destoryed方法。这句话没懂,有大佬解释一下吗

好比说你现在做了一个弹框,弹框里有一些数据和逻辑需要每次生成出来的时候都做一次,这个时候把弹框封装成组件,用v-if控制组件显示与隐藏就可以让组件每次生成出来都走一遍完整的生命周期。

@longhaolh
Copy link

在Vue中,v-showv-if都是用于控制元素显示隐藏的指令,但它们具有不同的工作方式和用途:

v-show

  • v-show指令通过改变CSS的 display属性来控制元素的显示与隐藏。

  • 不管初始条件是什么,元素始终会被渲染到DOM中,只是在不满足条件时不可见。

  • 它适合用于频繁切换显示状态的场景,因为它不涉及DOM元素的添加和删除,仅仅是样式的改变。
    *v-show禁止用于有权限控制的模块上,因为它可以被手动打开
    v-if

  • v-if指令则是一种条件渲染,只有当条件为真时,元素才会被渲染到DOM中。

  • 如果条件为假,元素不会被渲染到DOM,也就不存在于文档中。

  • v-if适合用于条件不经常改变的场景。使用 v-if可能涉及更多的DOM操作,因此对于性能开销较大的场景,应谨慎使用。

简而言之,v-show适合用于频繁切换,而 v-if适合于条件很少改变的情况。当你需要完整地添加或移除元素时使用 v-if,当你仅需要改变元素的显示状态时使用 v-show

@Yule-T
Copy link

Yule-T commented Jun 25, 2024

v-if由false变为true的时候,触发组件的beforeCreate、create、beforeMount、mounted钩子,由true变为false的时候触发组件的beforeDestory、destoryed方法。这句话没懂,有大佬解释一下吗

我的理解是,当v-if由false变为true的时候,dom包含的组件会被渲染,会触发生命周期(创建之前,创建,挂载之前,挂载);由true变为false的时候,会触发组件销毁生命周期(销毁之前,销毁)。这个只是我的理解,感觉也是比较浅显的理解,要是有大佬讲解的时候,请也踢踢我

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants