為什麼需要Web Component?
tags: Web
HTML5
JavaScript
category: Front-End
description: 為什麼需要web component?
created_at: 2021/06/29 20:00:00
假設我們先做個小練習
做兩個按鈕分別可以遞增遞減數字,像是下面這樣
See the Pen Button-Counter by 賴俊賓 (@laijunbin) on CodePen.
你會發現功能很簡單但光做一個程式碼就很長了,像是下面這樣
HTML相對單純
<div class="button-counter">
<button class="decrement-button">-</button>
<span class="number-span">0</span>
<button class="increment-button">+</button>
</div>
但 javascript 就長非常多
const buttonCounter = document.querySelector('.button-counter')
const decrementButton = buttonCounter.querySelector('.decrement-button')
const incrementButton = buttonCounter.querySelector('.increment-button')
const numberSpan = buttonCounter.querySelector('.number-span')
incrementButton.addEventListener('click', () => {
const number = parseInt(numberSpan.textContent)
const newNumber = number + 1
numberSpan.textContent = newNumber
})
decrementButton.addEventListener('click', () => {
const number = parseInt(numberSpan.textContent)
const newNumber = number - 1
numberSpan.textContent = newNumber
})
假設我要做兩個呢?
See the Pen Single-Button-Counter-Vanilla by 賴俊賓 (@laijunbin) on CodePen.
以我的寫法來說 javacsript 的長度沒有增加很多,但是 html 的部分免不了的還是只能乖乖複製貼上
<div class="button-counter">
<button class="decrement-button">-</button>
<span class="number-span">0</span>
<button class="increment-button">+</button>
</div>
<hr>
<div class="button-counter">
<button class="decrement-button">-</button>
<span class="number-span">0</span>
<button class="increment-button">+</button>
</div>
JavaScript 的部分採用迴圈解決
const buttonCounters = document.querySelectorAll('.button-counter')
buttonCounters.forEach(buttonCounter => {
const decrementButton = buttonCounter.querySelector('.decrement-button')
const incrementButton = buttonCounter.querySelector('.increment-button')
const numberSpan = buttonCounter.querySelector('.number-span')
incrementButton.addEventListener('click', () => {
const number = parseInt(numberSpan.textContent)
const newNumber = number + 1
numberSpan.textContent = newNumber
})
decrementButton.addEventListener('click', () => {
const number = parseInt(numberSpan.textContent)
const newNumber = number - 1
numberSpan.textContent = newNumber
})
})
那有沒有可能都用 JavaScript 來操縱,讓HTML短一些呢?
這時可能就希望可以寫個 <app-counter></app-counter>
之類的東西代表一組元件(component)
你的程式可能就變成下面這樣
<app-counter></app-counter>
<app-counter></app-counter>
<app-counter></app-counter>
這時的 JavaScript 變得必須要熟悉 DOM 的操作
const counters = document.querySelectorAll('app-counter')
counters.forEach(counter => {
const buttonCounter = document.createElement('div')
const decrementButton = Object.assign(document.createElement('button'), { textContent: '-' })
const incrementButton = Object.assign(document.createElement('button'), { textContent: '+' })
const numberSpan = Object.assign(document.createElement('span'), { textContent: '0' })
incrementButton.addEventListener('click', () => {
const number = parseInt(numberSpan.textContent)
const newNumber = number + 1
numberSpan.textContent = newNumber
})
decrementButton.addEventListener('click', () => {
const number = parseInt(numberSpan.textContent)
const newNumber = number - 1
numberSpan.textContent = newNumber
})
buttonCounter.appendChild(decrementButton)
buttonCounter.appendChild(numberSpan)
buttonCounter.appendChild(incrementButton)
counter.replaceWith(buttonCounter)
})
這時已經有 component 的概念了,只是在 HTML5 加入了一些語法糖(?)
JavaScript:
class Counter extends HTMLElement{
constructor(){
super()
const decrementButton = Object.assign(document.createElement('button'), { textContent: '-' })
const incrementButton = Object.assign(document.createElement('button'), { textContent: '+' })
const numberSpan = Object.assign(document.createElement('span'), { textContent: '0' })
incrementButton.addEventListener('click', () => {
const number = parseInt(numberSpan.textContent)
const newNumber = number + 1
numberSpan.textContent = newNumber
})
decrementButton.addEventListener('click', () => {
const number = parseInt(numberSpan.textContent)
const newNumber = number - 1
numberSpan.textContent = newNumber
})
this.appendChild(decrementButton)
this.appendChild(numberSpan)
this.appendChild(incrementButton)
}
}
customElements.define('app-counter', Counter) // 註冊<app-counter>標籤
上面就是 HTML5 當中 Web Component 的基本使用方式了
前端框架都有 Component 的概念,但是不是使用這個方式實作的,因為這種方式瀏覽器支援度不是很好。但是自己玩玩也夠了
稍微利用一下也可以做出屬於自己的 Component 工具,可以帶屬性、綁事件,更不用寫那麼多 DOM 操作的語法。
我在今年寒假稍微包裝一下的範例
可以像下面這樣使用他 (基本上就跟前端框架做的事差不多)
index.html
<app-root></app-root>
<script src="./main.js"></script>
template.html
<div>hello {{ count }}</div>
<button (click)="counting()">Counting!</button>
main.js
Component.create({
selector: 'app-root',
template: 'template.html'
})(class {
constructor() {
this.count = 0;
}
counting() {
this.count++;
}
});
這樣就可以達到一個按鈕點下去後 count + 1 並渲染到畫面上了
下一篇會使用 Vue 與 React 當範例