子孫テキストノードを取得してテキストを1文字ずつ分割しタグで囲う
子孫テキストノードを取得して、テキストを1文字ずつ分割しタグで囲うには、次のような方法で実装できます。
関数定義
JavaScriptt (ES6以降)
/**
* テキストを1文字ずつ分割しタグで囲う
* @param {Node} baseElem 基準となる親要素
* @param {string} [wrapTagName="span"] 囲う要素のタグ名
*/
const splitTextCharWrapEachTag = (baseElem, wrapTagName = 'span') => {
/**
* 子孫テキストノードを取得
* @param {Node} parentNode 親要素
* @returns {Node[]} 取得したテキストノードを返す
*/
const getDescendantTextNodes = (parentNode, childNodes = []) => {
parentNode.childNodes.forEach(childNode => {
if (childNode.nodeType === 3) {
childNodes.push(childNode);
} else if (childNode.nodeType === 1) {
getDescendantTextNodes(childNode, childNodes);
}
});
return childNodes;
};
const textLineNodes = getDescendantTextNodes(baseElem);
textLineNodes.forEach(textLineNode => {
const chars = textLineNode.textContent.split('');
if (!chars.length) return true;
chars.forEach(char => {
let charNode;
if (char.match(/^\s+$/)) {
charNode = document.createTextNode(char);
} else {
charNode = document.createElement(wrapTagName);
charNode.textContent = char;
}
textLineNode.parentNode.insertBefore(charNode, textLineNode);
});
textLineNode.remove();
});
};
ポイント
12行目~22行目:childNodesプロパティで子テキストノードを取得します。
ノードの種類が要素の場合はさらにその子テキストノードを取得しています。
26行目~45行目:取得したテキストノードから文字列を取得し、splitメソッドで1文字ずつ分割します。
分割した文字列はインデントや改行はそのままにし、それ以外の文字列はspan要素で囲います。
使い方
引数
| 引数名 | 型 | 初期値 | 説明 | |
|---|---|---|---|---|
| 第一引数 必須 |
baseElem | Node | 基準となる親要素 | |
| 第二引数 | wrapTagName | string | 'span' | 囲う要素のタグ名 |
サンプルコード
JavaScript
splitTextCharWrapEachTag(document.querySelector('.code-block code'));