Web componentd組件內(nèi)部事件回調(diào)及痛點(diǎn)剖析
寫在前面
最近致力于研究 Web components(以下簡稱WC),并且也初有成效的拿到了一定的結(jié)果,但今天想回過頭來重新審視一下 WC。
WC 到底是什么?
簡單的講,Web Component 就是把組件封裝成 html 標(biāo)簽的形式,并且在使用時(shí)不需要寫額外的 js 代碼。
組件是前端的發(fā)展方向,拋開周邊技術(shù)生態(tài),單純看 React 和 Vue 都是組件框架。因此,WC 可以視為原生標(biāo)簽的拓展/延伸,說到底,它依舊是一個(gè)標(biāo)簽!
類似?<video></video>
?標(biāo)簽,相比于原生標(biāo)簽,它多了更為豐富的樣式和可操作屬性。
谷歌公司由于掌握了 Chrome 瀏覽器,一直在推動(dòng)瀏覽器的原生組件,即 Web Components API。
相比第三方框架,原生組件簡單直接,符合直覺,不用加載任何外部模塊,代碼量小。貌似一切完美,似乎大有可以用來替換React、Vue之類的趨勢。
目前存在的缺陷
與其它 web 框架一起使用存在一些小問題,會(huì)給開發(fā)體驗(yàn)上造成一些困擾。
1、組件內(nèi)部事件的回調(diào)
比如,一個(gè)彈窗組件(<my-dialog></my-dialog>
)中的確定按鈕,那么它的事件是如何觸發(fā)的呢?
class myDialog extends HTMLElement { // ... connectedCallback() { const shadowRoot = this.attachShadow({ mode: 'open' }); shadowRoot.innerHTML = ` <div class="dialog"> <div class="dialog-content"> <div class="dialog-body"> 彈窗內(nèi)容 </div> <button id="okBtn">確定</button> </div> </div> `; shadowRoot.querySelector('#okBtn').addEventListener('click', () => { // 組件內(nèi)部定義事件 this.dispatchEvent(new CustomEvent('okBtnFn')); }); } } customElements.define('my-dialog', myDialog);
現(xiàn)在方案是 custom element 內(nèi)部自定義事件?new CustomEvent()
,外部用?addEventListener
監(jiān)聽。這樣的寫法是很丑陋的,仿佛又回到了原生 JS 寫應(yīng)用的時(shí)代。
<my-dialog></my-dialog> <script> export default { created() { document.addEventListener('okBtnFn', function(){ // 點(diǎn)擊彈窗按鈕,觸發(fā)回調(diào)事件 }); } } </script>
2、組件樣式覆蓋
對于開發(fā)者來說,難免會(huì)遇到需要調(diào)整組件內(nèi)部樣式的時(shí)候。無論你是使用antd
、vant
還是使用其它組件庫,但 WC 的 CSS 防污染機(jī)制導(dǎo)致你很難修改內(nèi)部樣式。這需要你付出一些代價(jià)來變相的修改內(nèi)部樣式
3、組件內(nèi)部資源相對路徑問題
就目前來說,任何直接基于 Custom Element v1, Template 和 HTML Import 的組件都無法做到完全資源獨(dú)立 —— 在不知道使用方環(huán)境且不給使用方增加額外限制的情況下使用內(nèi)部封裝的任何資源文件。比如如果你有一個(gè)自定義 icon 組件:
class MyIcon extends HTMLElement { static get observedAttributes() { return ['name','size','color'] } constructor() { super(); const shadowRoot = this.attachShadow({ mode: 'open' }); shadowRoot.innerHTML = ` <svg class="icon" id="icon" aria-hidden="true" viewBox="0 0 1024 1024"> <use id="use"></use> </svg> } attributeChangedCallback (name, oldValue, newValue) { if( name == 'name' && this.shadowRoot){ // 如果使用的項(xiàng)目中,根目錄沒有 icon.svg 文件,那就 gg this.use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', `./icon.svg#icon-${newValue}`); } } } customElements.define('my-icon', MyIcon);
如果使用的項(xiàng)目中,根目錄沒有 icon.svg 文件,那就 gg。如果你在這里使用 cdn 路徑,就會(huì)出現(xiàn)跨域問題。
4、form表單類組件 value 獲取問題
Shadow DOM 中包含有 <input>、<textarea> 或 <select> 等標(biāo)簽的 value 不會(huì)在 form 表單中自動(dòng)關(guān)聯(lián)。
示例代碼:
// web component class InputAge extends HTMLElement { constructor() { super(); } // connect component connectedCallback() { const shadow = this.attachShadow({ mode: 'closed' }); shadow.innerHTML = `<input type="number" placeholder="age" min="18" max="120" />`; } } // register component customElements.define( 'input-age', InputAge );
WC 組件被使用后
<form id="myform"> <input type="text" name="your-name" placeholder="name" /> <input-age name="your-age"></input-age> <button>submit</button> </form> <script> const form = document.getElementById('myform'); form.addEventListener('submit', e => { e.preventDefault(); console.log('Submitted data:'); const data = new FormData(form); for (let nv of data.entries()) { console.log(` ${ nv[0] }: ${ nv[1] }`); } }); </script>
提交的時(shí)候無法獲取?input-age
?的?value
。當(dāng)然會(huì)有解決方案,但會(huì)很復(fù)雜。
5、其它
此外,缺少數(shù)據(jù)綁定和狀態(tài)管理也是 WC 存在的缺陷,此處不再贅述。
寫在后面
WC 指在豐富 HTML 的 DOM 特性,讓 HTML 擁有更強(qiáng)大的復(fù)用能力
WC 可以直接當(dāng)做原生標(biāo)簽,在任何前端框架和無框架中運(yùn)行
結(jié)合當(dāng)下的主流技術(shù)棧來說,WC 當(dāng)前主要問題在于復(fù)雜的組件中,數(shù)據(jù)通信和事件傳遞存在一定使用成本
兼容問題,比如可以覆蓋內(nèi)部樣式的?:part
?方法
以上就是Web componentd組件內(nèi)部事件回調(diào)及痛點(diǎn)剖析的詳細(xì)內(nèi)容,更多關(guān)于Web componentd事件回調(diào)及痛點(diǎn)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
js/jquery解析json和數(shù)組格式的方法詳解
本篇文章主要是對js/jquery解析json和數(shù)組格式的方法進(jìn)行了詳細(xì)的介紹,需要的朋友可以過來參考下,希望對大家有所幫助2014-01-01javascript中動(dòng)態(tài)加載js文件多種解決辦法總結(jié)
這篇文章主要介紹了javascript中動(dòng)態(tài)加載js文件多種解決辦法,有需要的朋友可以參考一下2013-11-11javascript替換已有元素replaceChild()使用介紹
這篇文章主要介紹了javascript替換已有元素replaceChild()使用,需要的朋友可以參考下2014-04-04JavaScript常用數(shù)組去重實(shí)戰(zhàn)源碼
本文給大家分享js常用8種數(shù)組去重實(shí)戰(zhàn)源碼,針對每種方法通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2021-07-07JavaScript實(shí)現(xiàn)簡易購物車最全代碼解析(ES6面向?qū)ο?
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)簡易購物車最全代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09