v-show和v-if的区别,使用场景

v-show和v-if的区别,使用场景

文章目录

  • v-show和v-if的区别,使用场景
    • 一、v-show与v-if的共同点
      • 1. 功能目标一致
      • 2. 都依赖数据驱动
      • 3. 语法相似
      • 4. 都可用于条件渲染
    • 二、v-show 和 v-if 的区别
    • 三、v-show与v-if原理分析
      • v-show原理
      • v-if原理
    • 四**使用场景对比**

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

v-showv-if都是 Vue.js 框架里用于控制元素在页面上显示与隐藏的指令,它们存在以下一些共同点:

1. 功能目标一致

二者的核心功能都是基于特定条件来决定元素是否在页面中呈现给用户。借助表达式的布尔值(truefalse),来控制元素显示或者隐藏的状态。例如下面的示例代码,通过不同按钮控制两个元素分别使用v-showv-if来切换显示与隐藏:




showFlagifFlagtrue时,对应的元素会显示;为false时,元素则不显示。

2. 都依赖数据驱动

它们都依赖于 Vue 实例的数据属性来动态控制元素的显示与隐藏。数据属性发生变化时,Vue 会自动更新 DOM,从而改变元素的显示状态。这与 Vue 响应式原理紧密相关,只要数据变化,对应的视图就会更新。

3. 语法相似

二者在使用时的语法基本相同,都是在 HTML 标签上以指令形式存在,并且后面跟一个 JavaScript 表达式。例如:

使用v-show

使用v-if

4. 都可用于条件渲染

无论是v-show还是v-if,都能用于根据不同条件渲染不同的内容。在实际开发中,可根据业务逻辑设置不同的条件表达式,从而实现灵活的页面渲染。

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

核心区别

特性 v-if v-show
渲染机制 条件为真时渲染元素,否则销毁 始终渲染元素,通过 CSS 控制显示
DOM 操作 动态添加/移除 DOM 元素 仅切换 display: none 样式
初始开销 低(条件为假时不渲染) 高(无论条件如何都渲染)
切换开销 高(涉及组件销毁/重建) 低(仅修改 CSS 属性)
组件生命周期 触发 created/mounted 等钩子函数 不触发生命周期钩子(始终存在)
组合使用 支持 v-else-ifv-else 无逻辑分支语法

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

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

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

v-show原理

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

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

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

// 引入 vShow 指令的类型定义,VShowElement 可能是自定义的元素类型
import { ObjectDirective } from 'vue';

// 定义 vShow 指令,它是一个对象指令,用于控制元素的显示与隐藏
// 这里指定了指令作用的元素类型为 VShowElement
export const vShow: ObjectDirective<VShowElement> = {
  // beforeMount 钩子函数,在元素挂载到 DOM 之前调用
  // el 是指令绑定的元素
  // { value } 是指令绑定的值,即 v-show="value" 中的 value
  // { transition } 是过渡效果相关的配置对象
  beforeMount(el, { value }, { transition }) {
    // 保存元素原本的 display 样式
    // 如果元素原本的 display 为 'none',则将其存储为空字符串,否则存储当前的 display 值
    el._vod = el.style.display === 'none' ? '' : el.style.display
    // 如果存在过渡效果配置且 value 为 true
    if (transition && value) {
      // 调用过渡效果的 beforeEnter 钩子,准备元素进入过渡
      transition.beforeEnter(el)
    } else {
      // 若没有过渡效果或者 value 为 false,直接设置元素的 display 属性
      setDisplay(el, value)
    }
  },
  // mounted 钩子函数,在元素挂载到 DOM 之后调用
  mounted(el, { value }, { transition }) {
    // 如果存在过渡效果配置且 value 为 true
    if (transition && value) {
      // 调用过渡效果的 enter 钩子,执行元素进入过渡动画
      transition.enter(el)
    }
  },
  // updated 钩子函数,在元素更新之后调用,这里省略了具体实现
  updated(el, { value, oldValue }, { transition }) {
    // ...
  },
  // beforeUnmount 钩子函数,在元素即将从 DOM 中移除之前调用
  beforeUnmount(el, { value }) {
    // 在元素卸载前,根据 value 值设置元素的 display 属性
    setDisplay(el, value)
  }
}

// 假设 setDisplay 函数用于根据 value 值设置元素的 display 属性
// 当 value 为 true 时显示元素,为 false 时隐藏元素
function setDisplay(el, value) {
  el.style.display = value ? el._vod : 'none';
}

v-if原理

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

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

// 从指定路径导入函数,该函数用于创建结构指令的转换函数
import { createStructuralDirectiveTransform } from '路径相关'; 
// 导入用于处理 v-if 节点生成代码节点的函数
import { processIf } from '路径相关'; 
// 导入用于为分支创建代码生成节点的函数
import { createCodegenNodeForBranch } from '路径相关'; 
// 导入用于获取父条件表达式的函数
import { getParentCondition } from '路径相关'; 

// 定义 transformIf 函数,用于转换 v-if、v-else 和 v-else-if 指令
export const transformIf = createStructuralDirectiveTransform(
  // 正则表达式,用于匹配 v-if、v-else 和 v-else-if 指令
  /^(if|else|else - if)$/,
  // 回调函数,用于处理匹配到的指令节点
  (node, dir, context) => {
    // 调用 processIf 函数处理节点
    return processIf(
      // 指令绑定的节点
      node, 
      // 指令对象
      dir, 
      // 编译上下文
      context, 
      // 处理分支的回调函数
      (ifNode, branch, isRoot) => {
        // 这里省略了部分代码,通常用于对分支进行预处理等操作
        // ...

        // 返回一个函数,该函数会在合适的时候被调用,用于生成代码节点
        return () => {
          // 判断当前分支是否为根分支
          if (isRoot) {
            // 如果是根分支,为该分支创建代码生成节点,并赋值给 ifNode 的 codegenNode 属性
            ifNode.codegenNode = createCodegenNodeForBranch(
              // 当前分支节点
              branch, 
              // 分支的键,用于标识分支
              key, 
              // 编译上下文
              context 
            ) as IfConditionalExpression;
          } else {
            // 如果不是根分支,将当前分支的代码生成节点附加到 v-if 根节点上
            // 获取父条件表达式
            const parentCondition = getParentCondition(ifNode.codegenNode!);
            // 将当前分支的代码生成节点赋值给父条件表达式的 alternate 属性
            parentCondition.alternate = createCodegenNodeForBranch(
              // 当前分支节点
              branch, 
              // 分支的键,根据根节点的分支数量进行计算
              key + ifNode.branches.length - 1, 
              // 编译上下文
              context 
            );
          }
        };
      }
    );
  }
);

使用场景对比

✅ 使用 v-if 的场景:

  • 初始条件不满足时:如权限控制下隐藏敏感内容
  • 元素包含复杂子组件:避免隐藏时仍占用内存
  • 不频繁切换的组件:如页面初始化时决定是否加载某个模块

✅ 使用 v-show 的场景:

  • 频繁切换显示状态:如选项卡切换、折叠面板
  • 需要保持组件状态:如表单输入保留值
    使用场景对比

✅ 使用 v-if 的场景:

  • 初始条件不满足时:如权限控制下隐藏敏感内容
  • 元素包含复杂子组件:避免隐藏时仍占用内存
  • 不频繁切换的组件:如页面初始化时决定是否加载某个模块

✅ 使用 v-show 的场景:

  • 频繁切换显示状态:如选项卡切换、折叠面板
  • 需要保持组件状态:如表单输入保留值
  • 元素渲染成本低:简单 DOM 元素无需优化初始加载

你可能感兴趣的:(前端知识点,前端,javascript,vue.js)