抱歉,這篇文章寫的錯誤百出,請各位無視這篇文章,我再找時間更新。
在使用web component建構組件庫的時侯,有一個很常見的問題,那就是web component要切的多細。
以客製化表格組件為例子,在html中最常使用的就有table,thead,tbody,tr,th,td等元素,想要做一個web component,光是CSS就是大工程了。
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)
<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>
如果各位有使用過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)
因為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>`);