摘要:前言最近加入到新項(xiàng)目組負(fù)責(zé)前端技術(shù)預(yù)研和選型,一直偏向于以為代表的技術(shù)線,于是查閱各類資料想說服老大向這方面靠,最后得到的結(jié)果是資料是英語(yǔ)無所謂,最重要是上符合要求,技術(shù)的事你說了算。但當(dāng)我們需要?jiǎng)討B(tài)實(shí)例化元素時(shí),命令式則是最佳的選擇。
前言
?最近加入到新項(xiàng)目組負(fù)責(zé)前端技術(shù)預(yù)研和選型,一直偏向于以Polymer為代表的WebComponent技術(shù)線,于是查閱各類資料想說服老大向這方面靠,最后得到的結(jié)果是:"資料99%是英語(yǔ)無所謂,最重要是UI/UX上符合要求,技術(shù)的事你說了算。",于是我只好乖乖地去學(xué)UI/UX設(shè)計(jì)的事,木有設(shè)計(jì)師撐腰的前端是苦逼的:(嘈吐一地后,還是擠點(diǎn)時(shí)間總結(jié)一下WebComponent的內(nèi)容吧,為以后作培訓(xùn)材料作點(diǎn)準(zhǔn)備。
浮在水面上的痛 組件噪音太多了!?在使用Bootstrap的Modal組件時(shí),我們不免要Ctrl+c然后Ctrl+v下面一堆代碼
?一個(gè)不留神誤刪了一個(gè)結(jié)束標(biāo)簽,或拼錯(cuò)了某個(gè)class或?qū)傩阅蔷捅吡耍藭r(shí)一個(gè)語(yǔ)法高亮、提供語(yǔ)法檢查的編輯器是如此重要?。〉俏移鋵?shí)只想配置個(gè)Modal而已。
?由于元素信息由標(biāo)簽標(biāo)識(shí)符,元素特性和樹層級(jí)結(jié)構(gòu)組成,所以排除噪音后提取的核心配置信息應(yīng)該如下(YAML語(yǔ)法描述):
dialog: modal: true children: header: title: Modal title closable: true body: children: p: textContent: One fine body… footer children: button: type: close textContent: Close button: type: submit textContent: Save changes
轉(zhuǎn)換成HTML就是
而像Alert甚至可以極致到這樣
是不是很簡(jiǎn)單?。?/alert>
可惜瀏覽器木有提供
既然瀏覽器木有提供,那我們自己手寫一個(gè)吧!
復(fù)盤找問題?雖然表面上實(shí)現(xiàn)了需求,但存在2個(gè)明顯的缺陷
不完整的元素實(shí)例化方式
原生元素有2種實(shí)例化方式
聲明式
命令式
// 元素實(shí)例化 const input = new HTMLInputElement() // 或者 document.createElement("INPUT") input.type = "text" // 添加到DOM樹 document.querySelector("#mount-node").appendChild(input)
?由于聲明式注重What to do,而命令式注重How to do,并且我們操作的是DOM,所以采用聲明式的HTML標(biāo)簽比命令式的JavaScript會(huì)來得簡(jiǎn)潔平滑。但當(dāng)我們需要?jiǎng)討B(tài)實(shí)例化元素時(shí),命令式則是最佳的選擇。于是我們勉強(qiáng)可以這樣
// 元素實(shí)例化 const myAlert = new Alert() // 添加到DOM樹 document.querySelector("#mount-node").appendChild(myAlert.el) /* 由于Alert無法正常實(shí)現(xiàn)HTMLElement和Node接口,因此無法實(shí)現(xiàn) document.querySelector("#mount-node").appendChild(myAlert) myAlert和myAlert.el的差別在于前者的myAlert是元素本身,而后者則是元素句柄,其實(shí)沒有明確哪種更好,只是原生方法都是支持操作元素本身,一下來個(gè)不一致的句柄不蒙才怪了 */
?即使你能忍受上述的代碼,那通過innerHTML實(shí)現(xiàn)半聲明式的動(dòng)態(tài)元素實(shí)例化,那又怎么玩呢?是再手動(dòng)調(diào)用一下registerElement("alert", el => new Alert(el))嗎?
?更別想通過document.createElement來創(chuàng)建自定義元素了。
有生命無周期
?元素的生命從實(shí)例化那刻開始,然后經(jīng)歷如添加到DOM樹、從DOM樹移除等階段,而想要更全面有效地管理元素的話,那么捕獲各階段并完成相應(yīng)的處理則是唯一有效的途徑了。
?當(dāng)定義一個(gè)新元素時(shí),有3件事件是必須考慮的:
元素自閉合: 元素自身信息的自包含,并且不受外部上下文環(huán)境的影響;
元素的生命周期: 通過監(jiān)控元素的生命周期,從而實(shí)現(xiàn)不同階段完成不同任務(wù)的目錄;
元素間的數(shù)據(jù)交換: 采用property in, event out的方式與外部上下文環(huán)境通信,從而與其他元素進(jìn)行通信。
?元素自閉合貌似無望了,下面我們?cè)囋嚤O(jiān)聽元素的生命周期吧!
?通過constructor我們能監(jiān)聽元素的創(chuàng)建階段,但后續(xù)的各個(gè)階段呢?可幸的是可以通過MutationObserver監(jiān)聽document.body來實(shí)現(xiàn):)
最終得到的如下版本:
"use strict" class Alert{ constructor(el = document.createElement("ALERT")){ this.el = el this.el.fireConnected = () => { this.connectedCallback && this.connectedCallback() } this.el.fireDisconnected = () => { this.disconnectedCallback && this.disconnectedCallback() } this.el.fireAttributeChanged = (attrName, oldVal, newVal) => { this.attributeChangedCallback && this.attributeChangedCallback(attrName, oldVal, newVal) } const raw = el.innerHTML el.dataset.resolved = "" el.innerHTML = `總結(jié)${raw}` el.querySelector("button.close").addEventListener("click", _ => this.close()) } close(){ this.el.style.display = "none" } show(){ this.el.style.display = "block" } connectedCallback(){ console.log("connectedCallback") } disconnectedCallback(){ console.log("disconnectedCallback") } attributeChangedCallback(attrName, oldVal, newVal){ console.log("attributeChangedCallback") } } function registerElement(tagName, ctorFactory){ [...document.querySelectorAll(`${tagName}:not([data-resolved])`)].forEach(ctorFactory) } function registerElements(ctorFactories){ for(let k in ctorFactories){ registerElement(k, ctorFactories[k]) } } const observer = new MutationObserver(records => { records.forEach(record => { if (record.addedNodes.length && record.target.hasAttribute("data-resolved")){ // connected record.target.fireConnected() } else if (record.removedNodes.length){ // disconnected const node = [...record.removedNodes].find(node => node.hasAttribute("data-resolved")) node && node.fireDisconnected() } else if ("attributes" === record.type && record.target.hasAttribute("data-resolved")){ // attribute changed record.target.fireAttributeChanged(record.attributeName, record.oldValue, record.target.getAttribute(record.attributeName)) } }) }) observer.observe(document.body, {attributes: true, childList: true, subtree: true}) registerElement("alert", el => new Alert(el))
?千辛萬苦擼了個(gè)基本不可用的自定義元素模式,但通過代碼我們進(jìn)一步了解到對(duì)于自定義元素我們需要以下基本特性:
自定義元素可通過原有的方式實(shí)例化(
可通過原有的方法操作自定義元素實(shí)例(如document.body.appendChild等)
能監(jiān)聽元素的生命周期
下一篇《WebComponent魔法堂:深究Custom Element 之 標(biāo)準(zhǔn)構(gòu)建》中,我們將一同探究H5標(biāo)準(zhǔn)中Custom Element API,并利用它來實(shí)現(xiàn)滿足上述特性的自定義元素:)
?尊重原創(chuàng),轉(zhuǎn)載請(qǐng)注明來自: http://www.cnblogs.com/fsjohn... ^_^肥仔John
感謝Custom ELement
Custom ELement v1
MutationObserver
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/80535.html
摘要:明確各階段適合的操作用于初始化元素的狀態(tài)和設(shè)置事件監(jiān)聽,或者創(chuàng)建。事件類型轉(zhuǎn)換通過捕獲事件,然后通過發(fā)起事件來對(duì)事件類型進(jìn)行轉(zhuǎn)換,從而觸發(fā)更符合元素特征的事件類型。 前言 ?通過《WebComponent魔法堂:深究Custom Element 之 面向痛點(diǎn)編程》,我們明白到其實(shí)Custom Element并不是什么新東西,我們甚至可以在IE5.5上定義自己的alert元素。但這種簡(jiǎn)單...
摘要:而同步和異步則是描述另一個(gè)方面。異步將數(shù)據(jù)從內(nèi)核空間拷貝到用戶空間的操作由系統(tǒng)自動(dòng)處理,然后通知應(yīng)用程序直接使用數(shù)據(jù)即可。 前言 ?上周5在公司作了關(guān)于JS異步編程模型的技術(shù)分享,可能是內(nèi)容太干的緣故吧,最后從大家的表情看出這條粉腸到底在說啥?的結(jié)果:(下面是PPT的講義,具體的PPT和示例代碼在https://github.com/fsjohnhuan...上,有興趣就上去看看吧! ...
摘要:魔法堂重新認(rèn)識(shí)和魔法堂你一定誤解過的魔法堂就這個(gè)樣魔法堂說說那個(gè)被埋沒的志向深入細(xì)節(jié)后會(huì)發(fā)現(xiàn)中定位模式之間,和之間存在千絲萬縷的關(guān)系,必須以俯瞰的角度捋一下。當(dāng)采用時(shí),屬性的實(shí)際值會(huì)被重置為。由于和則需要通過來引入來提供盒子定位微調(diào)的功能。 前言 ?對(duì)于Box Model和Positioning Scheme中3種定位模式的細(xì)節(jié),已經(jīng)通過以下幾篇文章記錄了我對(duì)其的理解和思考。?《CSS...
摘要:與的映射關(guān)系為。與根對(duì)應(yīng)的對(duì)應(yīng)的層疊上下文,是其他的祖先,的范圍覆蓋整條。注意的默認(rèn)值為,自動(dòng)賦值為。對(duì)于,它會(huì)將賦予給對(duì)應(yīng)的,而則不會(huì)。 一、前言 ?假如只是開發(fā)簡(jiǎn)單的彈窗效果,懂得通過z-index來調(diào)整元素間的層疊關(guān)系就夠了。但要將多個(gè)彈窗間層疊關(guān)系給處理好,那么充分理解z-index背后的原理及兼容性問題就是必要的知識(shí)...
摘要:不耽誤表單提交數(shù)據(jù)雖然我們無法看到的元素,但當(dāng)表單提交時(shí)依然會(huì)將隱藏的元素的值提交上去。讓元素在見面上不可視,但保留元素原來占有的位置。不過由于各瀏覽器實(shí)現(xiàn)效果均有出入,因此一般不會(huì)使用這個(gè)值。繼承父元素的值。 前言 ?還記得面試時(shí)被問起請(qǐng)說說display:none和visibility:hidden的區(qū)別嗎?是不是回答完display:none不占用原來的位置,而visibilit...
閱讀 1424·2021-10-08 10:04
閱讀 747·2021-09-07 09:58
閱讀 2928·2019-08-30 15:55
閱讀 2481·2019-08-29 17:21
閱讀 2182·2019-08-28 18:04
閱讀 3087·2019-08-28 17:57
閱讀 732·2019-08-26 11:46
閱讀 2270·2019-08-23 17:20