Vue 中v-if 和 v-show实现的区别

Vue中提供了v-if 和v-show 指令来方便我们控制模版的显示逻辑,本文我们主要是通过简单的源码来分析两者的区别。
一:使用方式

test
test

二:实现机制
v-if 在条件变量为false的时候,不生成dom,v-show 则肯定存在dom,只不过dom的display的值是none
我们先来看看v-if的底层实现

#读取v-if v-else v-else-if 生对应的条件属性存起来供其他函数来使用
function processIf (el) {
    var exp = getAndRemoveAttr(el, 'v-if');
    if (exp) {
      el.if = exp;
      addIfCondition(el, {
        exp: exp,
        block: el
      });
    } else {
      if (getAndRemoveAttr(el, 'v-else') != null) {
        el.else = true;
      }
      var elseif = getAndRemoveAttr(el, 'v-else-if');
      if (elseif) {
        el.elseif = elseif;
      }
    }
  }
  #根据上面的条件属性生成render函数字符串
function genIfConditions (
    conditions,
    state,
    altGen,
    altEmpty
  ) {
    if (!conditions.length) {
      return altEmpty || '_e()'
    }
    var condition = conditions.shift();
    if (condition.exp) {
      // 重点在这里,生成了一个三元表达式
      return ("(" + (condition.exp) + ")?" + (genTernaryExp(condition.block)) + ":" + (genIfConditions(conditions, state, altGen, altEmpty))) 
    } else {
      return ("" + (genTernaryExp(condition.block)))
    }
    // v-if with v-once should generate code like (a)?_m(0):_m(1)
    function genTernaryExp (el) {// 处理v-once 只响应第一次渲染的情况
      return altGen
        ? altGen(el, state)
        : el.once
          ? genOnce(el, state)
          : genElement(el, state)
    }
  }

v-if
可以看到生成的render函数表达式里,会判断show变量是否为true,是的话才会调用_c来创建dom。
再来看v-show

var show = {
    bind: function bind (el, ref, vnode) {
      var value = ref.value;

      vnode = locateNode(vnode);
      var transition$$1 = vnode.data && vnode.data.transition;
      var originalDisplay = el.__vOriginalDisplay =
        el.style.display === 'none' ? '' : el.style.display;
      if (value && transition$$1) {
        vnode.data.show = true;
        enter(vnode, function () {
          el.style.display = originalDisplay;
        });
      } else {
        el.style.display = value ? originalDisplay : 'none'; // 在这里控制style的display属性
      }
    },

    update: function update (el, ref, vnode) {
      var value = ref.value;
      var oldValue = ref.oldValue;

      /* istanbul ignore if */
      if (!value === !oldValue) { return }
      vnode = locateNode(vnode);
      var transition$$1 = vnode.data && vnode.data.transition;
      if (transition$$1) {
        vnode.data.show = true;
        if (value) {
          enter(vnode, function () {
            el.style.display = el.__vOriginalDisplay;
          });
        } else {
          leave(vnode, function () {
            el.style.display = 'none';
          });
        }
      } else {
        el.style.display = value ? el.__vOriginalDisplay : 'none';
      }
    },

    unbind: function unbind (
      el,
      binding,
      vnode,
      oldVnode,
      isDestroy
    ) {
      if (!isDestroy) {
        el.style.display = el.__vOriginalDisplay;
      }
    }
  };

  var platformDirectives = {// 平台的两个内置指令v-model  和 v-show
    model: directive,
    show: show
  };

v-show 是vue核心的内置指令之一(还有一个是v-model)指令的机制我们择日再解读。
我们可以看到v-show 指令处理的时候是通过控制dom的style的display来控制的。也就是说dom是一值存在的。

三:总结
从表现上看,v-if 和v-show都可以控制dom的显示和隐藏。
v-if 是惰性的,当条件是false的时候不渲染dom,而v-show 无论如何都渲染dom。
v-if 切换开销大,v-show 初始渲染开销大。所以对于频繁切换的组件,建议使用v-show。
v-if 还有一些配合使用的指令比如v-else-if v-else。
v-show 不支持在template上绑定,也不支持和v-else配合使用

你可能感兴趣的:(前端)