簡體   English   中英

JavaScript - 將HTML標記插入到給定樣式索引的字符串中

[英]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()將字符串轉換為包含字母的數組,並循環遍歷結果數組。 在循環中查找字母索引等於其startend的對象。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM