欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue中v-if和v-show使用區(qū)別源碼分析

 更新時間:2022年09月06日 11:40:41   作者:qb  
這篇文章主要為大家介紹了vue中v-if和v-show使用區(qū)別源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

高頻面試題:vue中的v-showv-if的區(qū)別?

一、v-if

例子:

new Vue({
  el: "#app",
  data() {
    return {
      isShow: false,
    };
  },
  methods: {
    changeStatus() {
      this.isShow = !this.isShow;
    }
  },
  template: `<div><button @click="changeStatus">切換</button><div v-if="isShow">顯示</div></div>`
});

1、render

`with(this){
    return _c('div',[_c('button',{on:{"click":changeStatus}},[_v("切換")]),(isShow)?_c('div',[_v("顯示")]):_e()])
}`

可以看出,這里通過isShow為三目運算符的判斷條件,起始條件下其值為false。

2、vNode

獲取到的vNodev-if條件為false的情況下,獲取到的是空的注釋節(jié)點用來占位,包含屬性isComment: truetext: ""

3、patch

當前例子中,v-iffalse,patch的過程中執(zhí)行到:

else if (isTrue(vnode.isComment)) {
  vnode.elm = nodeOps.createComment(vnode.text);
  insert(parentElm, vnode.elm, refElm);
}

通過nodeOps中的方法創(chuàng)建注釋空節(jié)點,并插入到父元素中,最終執(zhí)行結(jié)果為:

小結(jié)

v-if的情況下,如果起始為false,只會生成空的注釋節(jié)點用來占位,在需要考慮白屏場景下,使用v-if比較合適。

二、v-show

例子:

new Vue({
  el: "#app",
  data() {
    return {
      isShow: false,
    };
  },
  methods: {
    changeStatus() {
      this.isShow = !this.isShow;
    }
  },
  template: `<div><button @click="changeStatus">切換</button><div v-show="isShow">顯示</div></div>`
});

1、render

`with(this){
    return _c('div',[_c('button',{on:{"click":changeStatus}},[_v("切換")]),_c('div',{directives:[{name:"show",rawName:"v-show",value:(isShow),expression:"isShow"}]},[_v("顯示")])])
}`

可以看出,這里與v-if不同的是,里面有directives屬性。

2、vNode

v-if不同的是,這里包含用于描述vNode屬性的data

data: {
    directives: {
        expression: "isShow",
        name: "show",
        rawName: "v-show",
        value: false,
    }
}

3、patch

在當前例子中v-show控制的節(jié)點會執(zhí)行到createElm方法中的以下邏輯:

  {
    createChildren(vnode, children, insertedVnodeQueue);
    if (isDef(data)) {
      invokeCreateHooks(vnode, insertedVnodeQueue);
    }
    insert(parentElm, vnode.elm, refElm);
  }

當執(zhí)行完createChildren(vnode, children, insertedVnodeQueue)vnodeelm中包含outerHTML: "<div>顯示</div>"。

data存在,會執(zhí)行到invokeCreateHooks

function invokeCreateHooks (vnode, insertedVnodeQueue) {
    for (let i = 0; i < cbs.create.length; ++i) {
      cbs.create[i](emptyNode, vnode)
    }
    i = vnode.data.hook // Reuse variable
    if (isDef(i)) {
      if (isDef(i.create)) i.create(emptyNode, vnode)
      if (isDef(i.insert)) insertedVnodeQueue.push(vnode)
    }
}

這里對data中的directives進行處理的方法是cbs.create中的updateDirectives

function updateDirectives (oldVnode: VNodeWithData, vnode: VNodeWithData) {
  if (oldVnode.data.directives || vnode.data.directives) {
    _update(oldVnode, vnode)
  }
}
function _update (oldVnode, vnode) {
  const isCreate = oldVnode === emptyNode
  const isDestroy = vnode === emptyNode
  const oldDirs = normalizeDirectives(oldVnode.data.directives, oldVnode.context)
  const newDirs = normalizeDirectives(vnode.data.directives, vnode.context)
  const dirsWithInsert = []
  const dirsWithPostpatch = []
  let key, oldDir, dir
  for (key in newDirs) {
    oldDir = oldDirs[key]
    dir = newDirs[key]
    if (!oldDir) {
      // new directive, bind
      callHook(dir, 'bind', vnode, oldVnode)
      if (dir.def && dir.def.inserted) {
        dirsWithInsert.push(dir)
      }
    } else {
      // existing directive, update
      dir.oldValue = oldDir.value
      dir.oldArg = oldDir.arg
      callHook(dir, 'update', vnode, oldVnode)
      if (dir.def && dir.def.componentUpdated) {
        dirsWithPostpatch.push(dir)
      }
    }
  }
  // ...
}

這里主要做了兩件事,通過normalizeDirectives獲取到關(guān)于v-show的操作,通過callHook$1(dir, 'bind', vnode, oldVnode)的方式進行屬性的綁定

(1)normalizeDirectives

function normalizeDirectives$1 (
  dirs,
  vm
) {
  var res = Object.create(null);
  if (!dirs) {
    // $flow-disable-line
    return res
  }
  var i, dir;
  for (i = 0; i < dirs.length; i++) {
    dir = dirs[i];
    if (!dir.modifiers) {
      // $flow-disable-line
      dir.modifiers = emptyModifiers;
    }
    res[getRawDirName(dir)] = dir;
    dir.def = resolveAsset(vm.$options, 'directives', dir.name, true);
  }
  // $flow-disable-line
  return res
}
/**
 * Resolve an asset.
 * This function is used because child instances need access
 * to assets defined in its ancestor chain.
 */
function resolveAsset (
  options,
  type,
  id,
  warnMissing
) {
  /* istanbul ignore if */
  if (typeof id !== 'string') {
    return
  }
  var assets = options[type];
  // check local registration variations first
  if (hasOwn(assets, id)) { return assets[id] }
  var camelizedId = camelize(id);
  if (hasOwn(assets, camelizedId)) { return assets[camelizedId] }
  var PascalCaseId = capitalize(camelizedId);
  if (hasOwn(assets, PascalCaseId)) { return assets[PascalCaseId] }
  // fallback to prototype chain
  var res = assets[id] || assets[camelizedId] || assets[PascalCaseId];
  if (process.env.NODE_ENV !== 'production' && warnMissing && !res) {
    warn(
      'Failed to resolve ' + type.slice(0, -1) + ': ' + id,
      options
    );
  }
  return res
}

這里通過dir.def = resolveAsset(vm.$options, 'directives', dir.name, true)的方式去解析directives中存在的操作方法,resolveAsset方法中typedirectives,即從Vueoptions中獲得directives的值為一個原型上存在modelshow方法的對象。

那么這里有個疑問,這個directives是什么時候掛載上去的呢?
答案:在源碼文件platform/web/runtime/index.js有代碼extend(Vue.options.directives, platformDirectives),將modelshow進行原型掛載。

通過 var res = assets[id] || assets[camelizedId] || assets[PascalCaseId]我們獲得了show方法:

export default {
  bind (el: any, { value }: VNodeDirective, vnode: VNodeWithData) {
    vnode = locateNode(vnode)
    const transition = vnode.data && vnode.data.transition
    const originalDisplay = el.__vOriginalDisplay =
      el.style.display === 'none' ? '' : el.style.display
    if (value && transition) {
      vnode.data.show = true
      enter(vnode, () => {
        el.style.display = originalDisplay
      })
    } else {
      el.style.display = value ? originalDisplay : 'none'
    }
  },
  // 這里還有unbind和update方法
}

這里定義了節(jié)點樣式屬性display綁定bind、解綁unbind和更新update的方法。

(2)callHook

當獲取到可執(zhí)行的showbind方法后再看callHook(dir, 'bind', vnode, oldVnode)

function callHook (dir, hook, vnode, oldVnode, isDestroy) {
  const fn = dir.def && dir.def[hook]
  if (fn) {
    try {
      fn(vnode.elm, dir, vnode, oldVnode, isDestroy)
    } catch (e) {
      handleError(e, vnode.context, `directive ${dir.name} ${hook} hook`)
    }
  }
}

這里的fn就是show中的bind方法,最終執(zhí)行到邏輯el.style.display = value ? originalDisplay : 'none',在當前例子中v-show控制的節(jié)點elm就有了屬性outerHTML: "<div style=\"display: none;\">顯示</div>"。

總結(jié)

v-show點擊切換成true時將會通過diff算法進行本地復(fù)用策略的優(yōu)化,執(zhí)行到v-show節(jié)點控制的節(jié)點渲染時節(jié)點key相同,采取原地復(fù)用的原則只對其屬性display進行修改比從占位空注釋節(jié)點變?yōu)檎鎸嵐?jié)點更優(yōu),如果在transition這種頻繁切換的場景中,進行v-show控制展示隱藏更合理。

v-ifv-show的使用需要根據(jù)場景,一般來說,v-if 有更高的切換開銷,更多的使用在需要考慮白屏時間或者切換次數(shù)很少的場景;

而 v-show 有更高的初始渲染開銷但切換開銷較小,因此,如果在transition控制的動畫或者需要非常頻繁地切換場景,則使用 v-show 較好。

以上就是vue中v-if和v-show使用區(qū)別源碼分析的詳細內(nèi)容,更多關(guān)于vue v-if v-show區(qū)別的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • vue3中watch與watchEffect的區(qū)別

    vue3中watch與watchEffect的區(qū)別

    vue3 新增的 Composition API中的 watchEffect 和 watch都可在 setup() 函數(shù)中使用,本文重點介紹vue3中watch與watchEffect的區(qū)別,感興趣的朋友一起看看吧
    2023-02-02
  • Vue?websocket封裝實現(xiàn)方法詳解

    Vue?websocket封裝實現(xiàn)方法詳解

    項目中需要使用websocke,這個是我自己修修改改好多次之后用得最順手的一版,分享一下。這個封裝需要搭配vuex使用,因為收到的數(shù)據(jù)都保存在vuex中了,真的絕絕子好用,解決了我一大堆問題
    2022-09-09
  • vue 實現(xiàn)可拖曳的樹狀結(jié)構(gòu)圖

    vue 實現(xiàn)可拖曳的樹狀結(jié)構(gòu)圖

    這篇文章主要介紹了vue 實現(xiàn)可拖曳的樹狀結(jié)構(gòu)圖,幫助大家更好的理解和學習使用vue框架,感興趣的朋友可以了解下
    2021-04-04
  • vue2+element-ui使用vue-i18n進行國際化的多語言/國際化詳細教程

    vue2+element-ui使用vue-i18n進行國際化的多語言/國際化詳細教程

    這篇文章主要給大家介紹了關(guān)于vue2+element-ui使用vue-i18n進行國際化的多語言/國際化的相關(guān)資料,I18n是Vue.js的國際化插件,項目里面的中英文等多語言切換會使用到這個東西,需要的朋友可以參考下
    2023-12-12
  • vue實現(xiàn)移動端圖片上傳功能

    vue實現(xiàn)移動端圖片上傳功能

    這篇文章主要為大家詳細介紹了vue實現(xiàn)移動端圖片上傳功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • vue中關(guān)于computed的this指向問題

    vue中關(guān)于computed的this指向問題

    這篇文章主要介紹了vue中關(guān)于computed的this指向問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • vue中Axios的封裝與API接口的管理詳解

    vue中Axios的封裝與API接口的管理詳解

    這篇文章主要給大家介紹了關(guān)于vue中Axios的封裝與API接口的管理的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-08-08
  • vue組件生命周期鉤子使用示例詳解

    vue組件生命周期鉤子使用示例詳解

    這篇文章主要為大家介紹了vue組件生命周期鉤子使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2022-04-04
  • vue監(jiān)聽滾動事件實現(xiàn)滾動監(jiān)聽

    vue監(jiān)聽滾動事件實現(xiàn)滾動監(jiān)聽

    本文主要介紹了vue監(jiān)聽滾動事件實現(xiàn)滾動監(jiān)聽的相關(guān)資料。具有很好的參考價值。下面跟著小編一起來看下吧
    2017-04-04
  • vue實現(xiàn)2048小游戲功能思路詳解

    vue實現(xiàn)2048小游戲功能思路詳解

    這篇文章主要介紹了vue實現(xiàn)2048小游戲功能,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-05-05

最新評論