<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
高頻面試題:vue
中的v-show
和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>` });
`with(this){ return _c('div',[_c('button',{on:{"click":changeStatus}},[_v("切換")]),(isShow)?_c('div',[_v("顯示")]):_e()]) }`
可以看出,這裡通過isShow
為三目運運算元的判斷條件,起始條件下其值為false
。
獲取到的vNode
在v-if
條件為false
的情況下,獲取到的是空的註釋節點用來佔位,包含屬性isComment: true
和text: ""
。
當前例子中,v-if
為false
,patch
的過程中執行到:
else if (isTrue(vnode.isComment)) { vnode.elm = nodeOps.createComment(vnode.text); insert(parentElm, vnode.elm, refElm); }
通過nodeOps
中的方法建立註釋空節點,並插入到父元素中,最終執行結果為:
在v-if
的情況下,如果起始為false
,只會生成空的註釋節點用來佔位,在需要考慮白屏場景下,使用v-if
比較合適。
例子:
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>` });
`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
屬性。
與v-if
不同的是,這裡包含用於描述vNode
屬性的data
:
data: { directives: { expression: "isShow", name: "show", rawName: "v-show", value: false, } }
在當前例子中v-show
控制的節點會執行到createElm
方法中的以下邏輯:
{ createChildren(vnode, children, insertedVnodeQueue); if (isDef(data)) { invokeCreateHooks(vnode, insertedVnodeQueue); } insert(parentElm, vnode.elm, refElm); }
當執行完createChildren(vnode, children, insertedVnodeQueue)
後vnode
中elm
中包含outerHTML: "<div>顯示</div>"
。
data
存在,會執行到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
獲取到關於v-show
的操作,通過callHook$1(dir, 'bind', vnode, oldVnode)
的方式進行屬性的繫結
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
方法中type
為directives
,即從Vue
的options
中獲得directives
的值為一個原型上存在model
和show
方法的物件。
那麼這裡有個疑問,這個directives
是什麼時候掛載上去的呢?
答案:在原始碼檔案platform/web/runtime/index.js
有程式碼extend(Vue.options.directives, platformDirectives)
,將model
和show
進行原型掛載。
通過 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方法 }
這裡定義了節點樣式屬性display
繫結bind
、解綁unbind
和更新update
的方法。
當獲取到可執行的show
中bind
方法後再看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
方法,最終執行到邏輯el.style.display = value ? originalDisplay : 'none'
,在當前例子中v-show
控制的節點elm
就有了屬性outerHTML: "<div style="display: none;">顯示</div>"
。
當v-show
點選切換成true
時將會通過diff演演算法進行本地複用策略的優化,執行到v-show
節點控制的節點渲染時節點key
相同,採取原地複用的原則只對其屬性display
進行修改比從佔位空註釋節點變為真實節點更優,如果在transition
這種頻繁切換的場景中,進行v-show
控制展示隱藏更合理。
v-if
和v-show
的使用需要根據場景,一般來說,v-if
有更高的切換開銷,更多的使用在需要考慮白屏時間或者切換次數很少的場景;
而 v-show
有更高的初始渲染開銷但切換開銷較小,因此,如果在transition
控制的動畫或者需要非常頻繁地切換場景,則使用 v-show
較好。
以上就是vue中v-if和v-show使用區別原始碼分析的詳細內容,更多關於vue v-if v-show區別的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45