最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

高頻面試題: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為三目運(yùn)算符的判斷條件,起始條件下其值為false。

2、vNode

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

3、patch

當(dāng)前例子中,v-iffalsepatch的過程中執(zhí)行到:

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

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

小結(jié)

v-if的情況下,如果起始為false,只會生成空的注釋節(jié)點(diǎn)用來占位,在需要考慮白屏場景下,使用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

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

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

當(dāng)執(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進(jìn)行處理的方法是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)的方式進(jìn)行屬性的綁定

(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進(jìn)行原型掛載。

通過 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é)點(diǎn)樣式屬性display綁定bind、解綁unbind和更新update的方法。

(2)callHook

當(dāng)獲取到可執(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',在當(dāng)前例子中v-show控制的節(jié)點(diǎn)elm就有了屬性outerHTML: "<div style=\"display: none;\">顯示</div>"。

總結(jié)

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

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

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

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

相關(guān)文章

  • Vue computed計(jì)算屬性總結(jié)記錄

    Vue computed計(jì)算屬性總結(jié)記錄

    在vue中,有時候你需要對data中的數(shù)據(jù)進(jìn)行處理,或者對抓取的數(shù)據(jù)進(jìn)行處理之后再掛載呈現(xiàn)到標(biāo)簽中,這時候你就需要計(jì)算屬性了,當(dāng)然看到這里你可能還是不了解那下面我舉幾個實(shí)例并附代碼解釋
    2023-02-02
  • vuejs開發(fā)組件分享之H5圖片上傳、壓縮及拍照旋轉(zhuǎn)的問題處理

    vuejs開發(fā)組件分享之H5圖片上傳、壓縮及拍照旋轉(zhuǎn)的問題處理

    這篇文章主要介紹了vuejs開發(fā)組件分享之H5圖片上傳、壓縮及拍照旋轉(zhuǎn)的問題處理,需要的朋友可以參考下
    2017-03-03
  • Vue使用Vue Elements實(shí)現(xiàn)文件預(yù)覽功能

    Vue使用Vue Elements實(shí)現(xiàn)文件預(yù)覽功能

    在現(xiàn)代 web 開發(fā)中,用戶與系統(tǒng)的交互體驗(yàn)越來越重要,而文件上傳和文件預(yù)覽是最常見的交互場景之一,本文將詳細(xì)介紹如何在 Vue 項(xiàng)目中使用 Vue Elements 來實(shí)現(xiàn)文件預(yù)覽的功能,包括基本使用方法、常見實(shí)例、性能優(yōu)化以及樣式自定義等內(nèi)容,需要的朋友可以參考下
    2025-01-01
  • 詳解Vite的新體驗(yàn)

    詳解Vite的新體驗(yàn)

    這篇文章主要介紹了詳解Vite的新體驗(yàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • vue2結(jié)合element-ui的gantt圖實(shí)現(xiàn)可拖拽甘特圖

    vue2結(jié)合element-ui的gantt圖實(shí)現(xiàn)可拖拽甘特圖

    因?yàn)楣ぷ髦幸玫礁侍貓D,所以我在網(wǎng)上搜索可以用的甘特圖,搜索了好多,但是網(wǎng)上搜到大多數(shù)都很雞肋,不能直接使用,下面這篇文章主要給大家介紹了關(guān)于vue2結(jié)合element-ui的gantt圖實(shí)現(xiàn)可拖拽甘特圖的相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • VUE前端實(shí)現(xiàn)token的無感刷新3種方案(refresh_token)

    VUE前端實(shí)現(xiàn)token的無感刷新3種方案(refresh_token)

    這篇文章主要給大家介紹了關(guān)于VUE前端實(shí)現(xiàn)token的無感刷新3種方案(refresh_token)的相關(guān)資料,為了提供更好的用戶體驗(yàn),我們可以通過實(shí)現(xiàn)Token的無感刷新機(jī)制來避免用戶在使用過程中的中斷,需要的朋友可以參考下
    2023-11-11
  • 淺談vue+webpack項(xiàng)目調(diào)試方法步驟

    淺談vue+webpack項(xiàng)目調(diào)試方法步驟

    本篇文章主要介紹了淺談vue+webpack項(xiàng)目調(diào)試方法步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • 基于Vue+Node.js實(shí)現(xiàn)埋點(diǎn)功能全流程

    基于Vue+Node.js實(shí)現(xiàn)埋點(diǎn)功能全流程

    埋點(diǎn)(Track)是指在應(yīng)用程序、網(wǎng)站或平臺中添加代碼,以記錄特定用戶行為和事件的做法,通過添加埋點(diǎn)代碼,可以觀察和分析用戶行為,以調(diào)整和改進(jìn)產(chǎn)品設(shè)計(jì)和使用體驗(yàn),本文給大家介紹了基于Vue+Node.js實(shí)現(xiàn)埋點(diǎn)功能的全流程,需要的朋友可以參考下
    2025-04-04
  • Vue.js 插件開發(fā)詳解

    Vue.js 插件開發(fā)詳解

    本文會通過一個簡單的vue-toast插件,來幫助了解掌握插件的開發(fā)和使用。具有很好的參考價值,下面跟著小編一起來看下吧
    2017-03-03
  • vue(element ui)el-table樹形表格展示以及數(shù)據(jù)對齊方式

    vue(element ui)el-table樹形表格展示以及數(shù)據(jù)對齊方式

    這篇文章主要介紹了vue(element ui)el-table樹形表格展示以及數(shù)據(jù)對齊方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07

最新評論

微博| 平利县| 揭阳市| 独山县| 屏山县| 康保县| 衡阳市| 锦屏县| 琼中| 河曲县| 民权县| 博乐市| 和顺县| 土默特左旗| 光山县| 凤山县| 手游| 永清县| 岢岚县| 鄂尔多斯市| 会昌县| 临清市| 柳州市| 华安县| 宣武区| 登封市| 馆陶县| 自治县| 山东省| 朝阳区| 上犹县| 沙湾县| 巴彦淖尔市| 长泰县| 万山特区| 华容县| 故城县| 天等县| 青铜峡市| 佛坪县| 塔河县|