iT邦幫忙

2022 iThome 鐵人賽

DAY 27
0
Modern Web

web component - 次世代網頁技術的重要拼圖系列 第 27

web component 組件庫實做建議-大型複合組件

  • 分享至 

  • xImage
  •  

抱歉,這篇文章寫的錯誤百出,請各位無視這篇文章,我再找時間更新。

在使用web component建構組件庫的時侯,有一個很常見的問題,那就是web component要切的多細。

以客製化表格組件為例子,在html中最常使用的就有table,thead,tbody,tr,th,td等元素,想要做一個web component,光是CSS就是大工程了。

slot的限制

  1. slot沒辦法包其他節點
class MyDiv2 extends HTMLElement {
    constructor() {
        super();
        const shadow = this.attachShadow({mode: 'open'});
        // slot還是能放子節點,但裡面的'<div>world</div>'不會顯示
        shadow.innerHTML = `<div>
            <div>hallo</div>
            <slot>
                <div>world</div>
            </slot>
        </div>`;
    }
}
window.customElements.define('my-div2', MyDiv2)
  1. 只有直屬的子節點能設定slot,孫節點不能設定slot
<body>
    <my-div>
        <!-- 因為是my-div的子節點,可以被放到正確的slot上  -->
        <div slot='text1'>hallo</div>
        <div>
            <!-- 因為不是my-div的子節點,沒辦法放到正確的slot上  -->
            <div slot='text2'>world</div>
        </div>
    </my-div>
</body>

其他框架的解法

以react來說,要實做這種複合的組件非常簡單,使用render props技術就能簡單的客製化所有東西,當然也包含子組件(這也是我喜歡react的理由)。以vue來說,雖然沒有萬能的render prop能使用,只能使用slot,但因為可以使用v-for,上層的prop也能使用object,CSS的限制也沒有Shadow DOM的多,還是能在一定程度上做客製化。

目標是有限度的客製化

大部分的人在使用組件庫時的需求其實都差不多,如果不追求太多的客製化,可以使用一些簡單的方法來客製化

只有屬性來做少量的客製化

<my-table tdColor='red' trColor='blue' ...>
</my-table>

目標是完全的客製化

如果各位和小弟我一樣想要追求完全的客製化,我這裡提供了數個方法。

層層包起來

就像套娃一樣一層層的包各種組件,能客製化的程度最高,但如果需要的客製化需求不高時,程式寫起來也很麻煩。

    <my-table>
        <my-thead>
            <my-tr>
                <my-th>...</my-th>
                ...
                <my-th>...</my-th>
            </my-tr>
        </my-thead>
        <my-tbody>
            <my-tr>
                <my-td>...</my-td>
                ...
                <my-td></my-td>
            </my-tr>
        </my-tbody>
    </my-table>

傳送custom element的名稱

如果各位有使用過mui.js的話,mui.js的所有組件都有一個名為'component'的屬性,只要設定組件的名稱,就能把組件底層使用的組件換掉。web component也可以做一樣的事情。

<body>
    <my-div>
    </my-div>
    <my-div2 component="my-div"></my-div2>
</body>

javascript

class MyDiv extends HTMLElement {
    constructor() {
        super();
        const shadow = this.attachShadow({mode: 'open'});
        const div1 = document.createElement('div');
        div1.style = 'width: 100px; height: 100px; border: 1px solid black; background-color: aqua;';
        shadow.appendChild(div1);
    }
}
window.customElements.define('my-div', MyDiv)
class MyDiv2 extends HTMLElement {
    constructor() {
        super();
        const shadow = this.attachShadow({mode: 'open'});
        const component = this.getAttribute('component');
        const div1 = document.createElement(component);
        shadow.innerHTML = `<${component}></${component}>`;
    }
}
window.customElements.define('my-div2', MyDiv2)

利用javascript的方法來客製化

因為web component是使用javascript來建構的,所以也可以使用javascript的方法來客製化

<body>
    <my-div3 id='div3'></my-div>
</body>

Javascript

class MyDiv extends HTMLElement {
    constructor() {
        super();
        const shadow = this.attachShadow({mode: 'open'});
        const div1 = document.createElement('div');
        div1.style = 'width: 100px; height: 100px; border: 1px solid black; background-color: aqua;';
        shadow.appendChild(div1);
    }
}
window.customElements.define('my-div', MyDiv)
class MyDiv3 extends HTMLElement {
    constructor() {
        super();
        const shadow = this.attachShadow({mode: 'open'});
    }
    setInnerHTML(html) {
        this.shadowRoot.innerHTML = html;
    }
}
window.customElements.define('my-div3', MyDiv3)
const div3 = document.getElementById('div3');
div3.setInnerHTML(`<my-div></my-div>`);

上一篇
web component 組件庫實做建議-CSS篇
下一篇
web component 組件庫實做-介紹造輪子的工具庫
系列文
web component - 次世代網頁技術的重要拼圖30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言