[英]JavaScript - Insert HTML markup into string given styling indexes
我有一段文字。
"This is a test to see whether nested style spans work properly."
我將樣式信息作為JSON對象,例如
0: {start: 22, end: 54, type: "strong"}
1: {start: 30, end: 36, type: "hyperlink", data: {…}}
2: {start: 37, end: 48, type: "em"}
3: {start: 43, end: 48, type: "hyperlink", data: {…}}
該文本看起來像
<p>This is a test to see <strong>whether <a href="https://www.google.co.za">nested</a> <em>style <a href="https://www.google.co.za">spans</a></em> work </strong>properly.</p>
什么應該是算法的一般方法? 問題是,一旦我開始將標記插入文本來設置樣式,樣式信息中包含的索引顯然已經過時了。
我試着跟蹤我通過緩沖區插入的字符的長度(以便可以使用緩沖區長度調整索引),但這成為嵌套標記的問題。 我的整個'解決方案'感覺非常笨拙和笨拙,我敢肯定必須有更好的方法。
這是我嘗試過的代碼。
NewsUtils.styleSpanCSS = span => {
let styledSpan = {};
switch (span.type) {
case "em":
styledSpan.opening = "<span";
styledSpan.style = ' class="italic">';
styledSpan.closing = "</span>";
break;
case "hyperlink":
styledSpan.opening = `<a href="${span.data.url}">`;
styledSpan.style = "";
styledSpan.closing = "</a>";
break;
case "strong":
styledSpan.opening = "<span";
styledSpan.style = ' class="bold">';
styledSpan.closing = "</span>";
break;
default:
styledSpan.opening = "";
styledSpan.style = "";
styledSpan.closing = "";
}
styledSpan.length =
styledSpan.opening.length +
styledSpan.style.length +
styledSpan.closing.length;
return styledSpan;
};
NewsUtils.styleParagraph = elem => {
if (elem.spans.length > 0) {
let buffer = 0;
elem.spans.map(span => {
let elementToInsert = NewsUtils.styleSpanCSS(span);
let spanLength =
elementToInsert.opening.length +
elementToInsert.style.length +
elementToInsert.closing.length;
elem.text =
elem.text.substring(0, span.start + buffer) +
elementToInsert.opening +
elementToInsert.style +
elem.text.substring(span.start + buffer, span.end + buffer) +
elementToInsert.closing +
elem.text.substring(span.end + buffer, elem.text.length + buffer);
buffer += spanLength;);
});
return <p dangerouslySetInnerHTML={{ __html: elem.text }} />;
}
return <p dangerouslySetInnerHTML={{ __html: elem.text }} />;
};
NewsUtils.markupParagraphs = post => {
const postDetails = post.data.text.map(elem => {
switch (elem.type) {
case "paragraph":
return NewsUtils.styleParagraph(elem);
case "image":
return (
<img
src={elem.url}
width={elem.dimensions.width}
height={elem.dimensions.height}
/>
);
case "embed":
let url = elem.oembed.embed_url;
url = url.substring(0, url.indexOf("&"));
url = url.replace("watch?v=", "embed/");
url = url.replace("vimeo.com", "player.vimeo.com/video");
return <iframe src={url} frameBorder="0" allowFullScreen />;
default:
return null;
}
});
return postDetails;
};
};
這是一個基本的實現。 我擺脫了超鏈接特殊處理來演示算法本身,但是應該很容易將該邏輯添加回來:
const text = 'This is a test to see whether nested style spans work properly.' const styling = [ {start: 22, end: 54, type: "strong"}, {start: 30, end: 36, type: "a"}, {start: 37, end: 48, type: "em"}, {start: 43, end: 48, type: "a"} ]; const result = [...text].reduce((a, v, i) => { styling.filter(s => s.start === i).forEach(s => a += `<${s.type}>`); styling.filter(s => s.end === i).forEach(s => a += `</${s.type}>`); return a + v; }, ''); document.body.innerHTML = result;
輸出:
This is a test to see <strong>whether <a>nested</a> <em>style <a>spans</em></a> work </strong>properly.
如果輸入和樣式數組很大,則可能需要創建臨時查找對象以提高性能。
您需要使用.split()
將字符串轉換為包含字母的數組,並循環遍歷結果數組。 在循環中查找字母索引等於其start
或end
的對象。
var newStr = "";
// Loop through letters
str.split('').forEach(function(letter, i){
// Loop through object
for (key in obj){
// If letter index is equal to key start
if (obj[key].start == i)
newStr += obj[key].type == "hyperlink" ?
'<a href="https://www.google.co.za">' :
'<'+obj[key].type+'>';
// If letter index is equal to key end
if (obj[key].end == i)
newStr += obj[key].type == "hyperlink" ?
'</a>' :
'</'+obj[key].type+'>';
}
newStr += letter;
});
// Wrap result in <p></p>
newStr = "<p>"+newStr+"</p>";
document.write(newStr);
var str = "This is a test to see whether nested style spans work properly."; var obj = { 0: {start: 22, end: 54, type: "strong"}, 1: {start: 30, end: 36, type: "hyperlink", data: {}}, 2: {start: 37, end: 48, type: "em"}, 3: {start: 43, end: 48, type: "hyperlink", data: {}} }; var newStr = ""; str.split('').forEach(function(letter, i){ for (key in obj){ if (obj[key].start == i) newStr += obj[key].type == "hyperlink" ? '<a href="https://www.google.co.za">' : '<'+obj[key].type+'>'; if (obj[key].end == i) newStr += obj[key].type == "hyperlink" ? '</a>' : '</'+obj[key].type+'>'; } newStr += letter; }); newStr = "<p>"+newStr+"</p>";
這種方法首先將給定位置排序到最內部范圍,然后采用外部樣式。
var string = 'This is a test to see whether nested style spans work properly.', makeup = [{ start: 0, end: 63, type: "p" }, { start: 22, end: 54, type: "strong" }, { start: 30, end: 36, type: "hyperlink", data: { link: 'http://example.com/#1' } }, { start: 37, end: 48, type: "em" }, { start: 43, end: 48, type: "hyperlink", data: { link: 'http://example.com/#2' } }], sorted = [], positions = Array.from(string), i, j, result; while (makeup.length > 1) { i = 0; j = 1; while (j < makeup.length) { if (makeup[j].start >= makeup[i].start && makeup[j].end <= makeup[i].end) { i = j; } j++; } sorted.push(makeup.splice(i, 1)[0]); } sorted.push(makeup.splice(0, 1)[0]); sorted.forEach(({ start, end, type, data }) => { var [header, footer] = type === 'hyperlink' ? [`<a href="${ data.link }">`, '</a>'] : [`<${ type }>`, `</${ type }>`]; positions[start] = header + positions[start]; positions[end - 1] += footer; }); result = positions.join(''); console.log(result); document.body.innerHTML += result;
拆分為字符數組允許在特定索引處插入而不影響其余索引:
const text = 'This is a test to see whether nested style spans work properly.' const json = `{ "0": {"start": 22, "end": 54, "type": "strong"}, "1": {"start": 30, "end": 36, "type": "hyperlink"}, "2": {"start": 37, "end": 48, "type": "em"}, "3": {"start": 43, "end": 48, "type": "hyperlink"} }` const letters = text.split('') JSON.parse(json, (k, v) => v.type ? (letters[v.start] = '<' + v.type + '>' + letters[v.start], letters[v.end] = '</' + v.type + '>' + letters[v.end] ) : v) console.log( letters.join('') ) console.log( letters )
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.