工作中需要使用富文本,出于簡(jiǎn)潔的考慮,我選擇了wangeditor昔善,可是PM突然說(shuō)要加一個(gè)格式刷功能,所以去找插件畔乙,然后我就看到了下面這張圖君仆。
同時(shí)也在其他地方看到了類(lèi)似的文章,不過(guò)他使用的editor版本貌似和我的不一致牲距,所以決定自己寫(xiě)一個(gè)返咱。
首先要判斷格式刷的邊界問(wèn)題,range獲取到的節(jié)點(diǎn)是當(dāng)前選中區(qū)域所在節(jié)點(diǎn)的父節(jié)點(diǎn)牍鞠,而不是你選擇的文字部分咖摹。所以,實(shí)際上需要復(fù)制的樣式是獲取到的節(jié)點(diǎn)一層一層往里找难述,直到找到文本節(jié)點(diǎn)為止萤晴,如果該節(jié)點(diǎn)沒(méi)有,就找它的第一個(gè)子節(jié)點(diǎn)胁后。
function getTargetDom(dom) {
for (let i of dom.childNodes) {
if (i.nodeType === 3 && i.nodeValue && i.nodeValue.trim() !== '') {
targetDom = dom;
return;
}
}
getTargetDom(dom.children[0]);
}
然后我們要從這個(gè)目標(biāo)節(jié)點(diǎn)開(kāi)始一層一層往上找店读,直到找到p
標(biāo)簽為止,因?yàn)閜標(biāo)簽在富文本里面代表一行攀芯,同時(shí)屯断,因?yàn)槟0鍥](méi)有嚴(yán)格按照編輯器里面來(lái),我們需要把p
標(biāo)簽里面的樣式也做一個(gè)處理侣诺,這里我換成了span
標(biāo)簽殖演。
function getAllStyle(dom) {
if (!dom) return;
const tagName = dom.tagName.toLowerCase();
if (tagName === 'p') {
nodeArray.push({
tagName: 'span',
attributes: Array.from(dom.attributes).map((i) => {
return {
name: i.name,
value: i.value,
};
}),
});
return;
} else {
nodeArray.push({
tagName: tagName,
attributes: Array.from(dom.attributes).map((i) => {
return {
name: i.name,
value: i.value,
};
}),
});
getAllStyle(dom.parentNode);
}
}
return nodeArray;
}
最后一步,就是把從內(nèi)到外獲取到的節(jié)點(diǎn)和屬性紧武,按原樣套接上去得到最后的節(jié)點(diǎn)
function addStyle(text, nodeArray) {
let currentNode = null;
nodeArray.forEach((ele, index) => {
let node = document.createElement(ele.tagName);
for (const attr of ele.attributes) {
node.setAttribute(attr.name, attr.value);
}
if (index === 0) {
node.innerText = text;
currentNode = node;
} else {
node.appendChild(currentNode);
currentNode = node;
}
});
return currentNode;
}
接下來(lái)是和編輯器相關(guān)的操作就不在贅述了剃氧,結(jié)合編輯器以及MDN的文檔,可以實(shí)現(xiàn)大部分功能阻星。
值得一提的是,我這里判斷文字選擇用的是mouseup
的事件,因?yàn)闀簳r(shí)也沒(méi)想到其他的辦法妥箕,如果有更好的辦法滥酥,希望不吝賜教。
預(yù)覽地址:https://snjiang1992.github.io/format-painter/
源碼地址:https://github.com/SNJiang1992/format-painter