一忽肛、什么是Web Components?
Web Components是一個(gè)瀏覽器的新功能保屯,它允許開發(fā)者創(chuàng)建可重用的定制元素秉版,該定制元素的功能封裝在代碼之外贤重,定制元素的功能部分由自身的html結(jié)構(gòu)、css樣式以及javascript代碼組成清焕,并且不會干擾到代碼中其他元素并蝗,該元素被定義之后可以在任何web應(yīng)用中使用,使用方式同原生標(biāo)簽元素秸妥。它不依賴于任何框架滚停,可實(shí)現(xiàn)跨框架使用,這也解決了項(xiàng)目重構(gòu)時(shí)換框架即需要重新開發(fā)組件的痛點(diǎn)粥惧。
瀏覽器兼容性可參考:Web Components的瀏覽器兼容性
二键畴、為什么使用Web Components?
相比于其他組件突雪,使用Web Components技術(shù)開發(fā)的組件擁有以下幾個(gè)顯著優(yōu)點(diǎn):
1起惕、一勞永逸
組件擁有更長的壽命,它不需要適應(yīng)新的技術(shù)而重寫咏删。雖然我們團(tuán)隊(duì)目前的主要技術(shù)棧是vue惹想,但是也要考慮到將來項(xiàng)目重構(gòu)時(shí)會面臨技術(shù)棧升級或者更換的一個(gè)情況。
2督函、語法簡單易學(xué)
組件僅由html嘀粱、css激挪、javascript三部分組成,使用它可以不像使用依賴庫或者框架的組件一樣去額外學(xué)習(xí)一些框架的特定語言锋叨。
3垄分、可移植性強(qiáng)
組件可以在任何web應(yīng)用中使用,因?yàn)楹苌偕踔翛]有依賴娃磺,組件的使用障礙要明顯低于依賴庫或者框架的組件锋喜。
但同時(shí),Web Components還存在一些弊端豌鸡,由于目前瀏覽器支持性還不太高,而且官方教程寫的也不是非常清晰易懂段标,使用起來還是有一定難度的涯冠。
由于我們團(tuán)隊(duì)開發(fā)的項(xiàng)目的只需要兼容google瀏覽器,而且團(tuán)隊(duì)技術(shù)棧又比較廣泛逼庞,涉及vue蛇更、react、angluar赛糟,考慮到業(yè)務(wù)組件的可移植性派任,我選擇使用Web components。
三璧南、怎么使用Web Components掌逛?
使用部分的介紹以vue框架下我開發(fā)的一個(gè)業(yè)務(wù)組件為例,該組件主要實(shí)現(xiàn)兩個(gè)功能:1司倚、在瀏覽器展示一段文字豆混;2、所展示的這段文字中的關(guān)鍵字要標(biāo)紅动知。接下來正式進(jìn)入使用步驟的介紹皿伺。
2.1 使用customElements.define()創(chuàng)建一個(gè)自定義元素
window.customElements 是 CustomElementRegistry 的實(shí)例,CustomElementRegistry提供注冊自定義元素和查詢已注冊元素的方法盒粮。
customElements.define()在創(chuàng)建一個(gè)類后定義自定義元素鸵鸥,它接受三個(gè)參數(shù):
- 第一個(gè)參數(shù)為所創(chuàng)建元素的名稱 (注:為了和原生的元素區(qū)分開,元素的名稱不能是單個(gè)單詞丹皱,且其中必須要有短橫線妒穴,eg: emphasize-words)
- 第二個(gè)參數(shù)為定義元素行為的類
- 第三個(gè)參數(shù)為可選參數(shù),是一個(gè)包含extends屬性的配置對象种呐,它指定所創(chuàng)建的元素繼承自哪個(gè)內(nèi)置元素宰翅,可以繼承任何內(nèi)置元素
(function() {
let target_template = document.createElement("template");
target_template.setAttribute("id", "emphasizeWordsTemplate");
//引號內(nèi)填寫的HTML代碼
target_template.innerHTML = `
<style>
</style>
<span id="words"></span>
`;
document.body.append(target_template);
// 將父組件傳來的純文本變成帶樣式(將關(guān)鍵詞標(biāo)紅)的html
class EmphasizeWords extends HTMLElement {
constructor() {
super();
var shadow = this.attachShadow( { mode: 'closed' } );
var templateElem = document.getElementById('emphasizeWordsTemplate');
var content = templateElem.content.cloneNode(true);
// 文本
let text = this.getAttribute('text');
// 關(guān)鍵詞
let keyWords = String(this.getAttribute('keyWords')).split(',');
// 標(biāo)記顏色
let color = this.getAttribute('markColor');
// 將文本中關(guān)鍵詞替換
for (let i = 0; i < keyWords.length; i++) {
let r = new RegExp(keyWords[i], "ig");
if(r.test(text)) {
text = text.replace(r, `<font color="${color}">${keyWords[i]}</font>`)
}
}
content.getElementById('words').innerHTML = text
shadow.appendChild(content);
}
}
window.customElements.define('emphasize-words', EmphasizeWords);
})();
2.2 引入自定義元素
Web components有兩種引入方式,以vue框架下引入方式為例:
方法1爽室、在vue的主渲染文件index.html使用script
標(biāo)簽將剛剛創(chuàng)建的Web components的js文件引入
<script src="./emphasize-words" defer></script>
方法2汁讼、在vue的入口文件main.js或某個(gè)獨(dú)立vue組件中使用ES module的形式引入
import './emphasize-words'
2.3 使用Web components
Web components通過向?yàn)g覽器注冊自定義元素實(shí)現(xiàn)淆攻,注冊后的自定義元素,使用方法上和原生標(biāo)簽元素相比沒有什么區(qū)別嘿架,你只需要傳入自定義元素要求的屬性即可瓶珊,例如:
<emphasize-words text="關(guān)鍵詞標(biāo)紅" keyWords="關(guān)鍵詞" markColor="red"></emphasize-words>
在vue、react等框架中使用則需要遵守框架特定的語法耸彪,例如在vue中你可以這樣使用它:
<template>
<div>
<emphasize-words :text="text" :keyWords="keyWords" markColor="red"></emphasize-words>
</div>
</template>
<script>
export default {
data() {
return {
text: '文案本意是指放書的桌子伞芹,后來指在桌子上寫字的人。現(xiàn)在指的是公司或企業(yè)中從事文字工作的職位蝉娜,就是以文字來表現(xiàn)已經(jīng)制定的創(chuàng)意策略唱较。文案是一個(gè)與廣告創(chuàng)意先后相繼呈現(xiàn)的表現(xiàn)過程、發(fā)展過程與深化過程召川, 多存在于廣告公司南缓,企業(yè)宣傳與新聞策劃工作等。',
keyWords: ['文案', '新聞策劃', '廣告'],
}
},
}
</script>
2.4 用生命周期解決自定義元素使用時(shí)報(bào)錯(cuò)問題
如上2.1的示例可能會產(chǎn)生一個(gè)問題——若這個(gè)組件還未加載完就被調(diào)用荧呐,會導(dǎo)致組件報(bào)錯(cuò)汉形。這時(shí),就要用到生命周期函數(shù)倍阐。
在custom element的構(gòu)造函數(shù)中概疆,可以指定多個(gè)不同的回調(diào)函數(shù),它們將會在元素的不同生命時(shí)期被調(diào)用:
connectedCallback:當(dāng) custom element首次被插入文檔DOM時(shí)峰搪,被調(diào)用岔冀。
disconnectedCallback:當(dāng) custom element從文檔DOM中刪除時(shí),被調(diào)用罢艾。
adoptedCallback:當(dāng) custom element被移動到新的文檔時(shí)楣颠,被調(diào)用。
attributeChangedCallback: 當(dāng) custom element增加咐蚯、刪除童漩、修改自身屬性時(shí),被調(diào)用春锋。
將上述功能代碼的調(diào)用位置稍作修改即可(等組件加載完畢再執(zhí)行功能代碼)
let target_template = document.createElement("template");
target_template.setAttribute("id", "emphasizeWordsTemplate");
//引號內(nèi)填寫的HTML代碼
target_template.innerHTML = `
<style>
</style>
<span id="words"></span>
`;
document.body.append(target_template);
class EmphasizeWords extends HTMLElement {
constructor() {
super();
}
init(){
let shadow = this.attachShadow( { mode: 'open' } );
let templateElem = document.getElementById('emphasizeWordsTemplate');
let content = templateElem.content.cloneNode(true);
// 將父組件傳來的文本變成帶樣式的的html
console.log(this, this.getAttribute('text'));
// 文本
let text = this.getAttribute('text');
console.log(text);
// 關(guān)鍵詞
let keyWords = String(this.getAttribute('keyWords')).split(',');
// 標(biāo)記顏色
let color = this.getAttribute('markColor');
// 將文本中關(guān)鍵詞替換
for (let i = 0; i < keyWords.length; i++) {
let r = new RegExp(keyWords[i], "ig");
if(r.test(text)) {
text = text?.replace(r, `<font color="${color}">${keyWords[i]}</font>`)
}
}
content.getElementById('words').innerHTML = text
shadow.appendChild(content);
}
connectedCallback() {
console.log('被加載')
this.init();
}
disconnectedCallback() {
console.log('被刪除')
}
adoptedCallback() {
console.log('被移動到新的文檔')
}
attributeChangedCallback() {
console.log('增加矫膨、刪除、修改自身屬性')
}
}
window.customElements.define('emphasize-words', EmphasizeWords);
四期奔、展示結(jié)果
瀏覽器展示結(jié)果:
控制臺打印傳值后的emphasize-words標(biāo)簽及其text屬性內(nèi)容:
五侧馅、總結(jié)
Web components 的出現(xiàn)讓組件可以快速適應(yīng)變化,讓組件擁有更長的壽命呐萌,但其瀏覽器的支持性不高的缺點(diǎn)也使它目前沒有成為主流的選擇馁痴。本篇文章只簡單介紹了Web components在vue項(xiàng)目中的使用,關(guān)于Web components的知識點(diǎn)還有非常多肺孤,比如插槽的使用罗晕、現(xiàn)有的Web components庫等济欢,之后也會根據(jù)使用和調(diào)研情況慢慢完善該系列文章。