小弟我查的資料不多,對於未來web component可能會出現的新技術只有查到Declarative Shadow DOM。
SPA技術很好用,因為用Javascript來建構頁面時,開發和使用者互動的功能很簡單。可是因為SPA是完全由javascript生成頁面,對SEO非常不友好,所謂的Isomorphic JavaScript技術也相應而生。而web component也因為是使用javascript來建構custom element和shadow DOM,基本上SPA會有的問題web component都會有,所以在SEO的問題上,也可以使用相同的思路來處理。
Isomorphic JavaScript的核心我認為有二部分,第一部分是在伺服端就做出HTML,第二部分則是在前端載入JS後的hydration(注水)。
Declarative Shadow DOM現在只能在Chrome系列的瀏覧器上使用,其他瀏覧器不會生成DOM
Can i use 支援表 https://caniuse.com/declarative-shadow-dom
shadowroot這個屬性可以告訴瀏覧器,template元素和內容在生成DOM時是要渲染成Shadow DOM;當然,對那些不支援shadowroot屬性的瀏覧器來說,template元素還是會跳過不渲染。
shadowroot="open"就像是使用this.attachShadow({mode: 'open'})一樣
<my-com id="my-com" card-content="ha! you~" content-color="yellow">
    <template shadowroot="open">
        <style>
            ...
        </style>
        <div class='card'>
            <h2 id='card-title' class='card-title'>title</h2>
            <div id='card-content' class='card-content'>content</div>
            <slot id='card-slot'></slot>
            <div id='card-content2' class='card-content2'>content2</div>
        </div>
    </template>
    <div id="slot">click</div>
</my-com>
如果有支援Declarative Shadow DOM,在使用class時可以不用使用attachShadow方法生成SHadow DOM(因為己經在解析HTML時生成了),但事件的綁定之類的還是要宣告。
class MyComponent extends HTMLElement {
    constructor() {
        super();
        this.render = this.render.bind(this);
        this.ClickEvent = this.ClickEvent.bind(this);
        this.ClickEvent2 = this.ClickEvent2.bind(this);
        // 如果在不支援Declarative Shadow DOM的瀏覧器中使用要加這一段
        // 因為有支援的話this.shadowRoot就不會是null
        if (!this.shadowRoot) {
            this.attachShadow({mode: 'open'});
            this.shadowRoot.appendChild(this.render())
        }
    }
    connectedCallback() {
        // 不管有沒有支援Declarative Shadow DOM都要加這一段,因為事件綁定只能由JS來做
        // javascript 的 hydration
        this.root.getElementById('card-title').addEventListener('click', this.ClickEvent)
        this.root.getElementById('card-slot').addEventListener('click', this.ClickEvent2)
    }
    disconnectedCallback() {
        // 不管有沒有支援Declarative Shadow DOM都要加這一段,因為事件綁定只能由JS來做
        // javascript 的 hydration
        this.root.getElementById('card-title').removeEventListener('click', this.ClickEvent)
        this.root.getElementById('card-slot').removeEventListener('click', this.ClickEvent2)
    }
    ...
    // 如果有支援Declarative Shadow DOM,就可以不需要這個函式
    render() {
        const template = document.createElement('template');
        template.innerHTML = `
            <style>${this.style}</style>
            <div class='card'>
                <h2 id='card-title' class='card-title'>title</h2>
                <div id='card-content' class='card-content'>content</div>
                <slot id='card-slot'></slot>
                <div id='card-content2' class='card-content2'>content2</div>
            </div>
        `;
        return template.content;
    }
    ClickEvent() {
        console.log('click')
    }
    ClickEvent2() {
        const newEvevt = new CustomEvent('clickSlot', {
            bubbles: true,
            composed: true,
            detail: {
                name: 'click'
            }
        })
        this.dispatchEvent(newEvevt)
    }
}
customElements.define('my-com', MyComponent);