renderJSON.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. // const _text_styles_ = ["bold", "underline", "italic", "sup", "sub"];
  2. import { RichTextBlockJSON, RichTextJSON, RichTextSectionJSON } from "@/types";
  3. let _container = document.createElement("div");
  4. /**
  5. * 将富文本 JSON 渲染到指定的元素中
  6. *
  7. * @param {RichTextJSON} body
  8. * @param {HTMLDivElement} container
  9. */
  10. export function renderRichText(body: RichTextJSON, container?: HTMLDivElement) {
  11. _container = container || document.createElement("div");
  12. let sections = body?.sections || [];
  13. let nodes = [] as Array<Node>;
  14. sections.forEach((section) => {
  15. nodes.push(renderSection(section));
  16. });
  17. if (_container != undefined) {
  18. // container.classList.add("rich-text");
  19. while (_container.hasChildNodes()) {
  20. _container.removeChild(_container.lastChild as Node);
  21. }
  22. nodes.forEach((node) => {
  23. _container.appendChild(node);
  24. });
  25. }
  26. return _container;
  27. }
  28. /**
  29. * @param {RichTextSectionJSON} section
  30. * @returns {HTMLDivElement} 返回根据 section 渲染好的 HTMLDivElement
  31. */
  32. function renderSection(section: RichTextSectionJSON) {
  33. let blocks = section.blocks || [];
  34. let inline = blocks.length > 1;
  35. let node = document.createElement("div");
  36. // node.style = "display: flex;";
  37. blocks.forEach((block) => {
  38. node.appendChild(renderBlock(block, inline));
  39. });
  40. return node;
  41. }
  42. /**
  43. * @param {RichTextBlockJSON} block
  44. * @param {Boolean} inline 图片是否以 inline 的样式展示
  45. * @returns {HTMLElement} 返回根据 block 渲染好的 HTMLElement
  46. */
  47. function renderBlock(block: RichTextBlockJSON, inline: boolean) {
  48. // let node = document.createElement('span')
  49. // let classList = node.classList
  50. let node;
  51. if (block.type === "text") {
  52. // classList.add('text')
  53. // if (block.param != undefined) {
  54. // _text_styles_.forEach(style => {
  55. // if (block.param[style] === true) {
  56. // classList.add(style)
  57. // }
  58. // })
  59. // }
  60. if (
  61. block.param &&
  62. (block.param.underline || block.param.bold || block.param.italic)
  63. ) {
  64. let uNode: Node | null = null,
  65. bNode: Node | null = null,
  66. iNode: Node | null = null;
  67. if (block.param.underline) {
  68. uNode = document.createElement("u");
  69. }
  70. if (block.param.bold) {
  71. bNode = document.createElement("b");
  72. }
  73. if (block.param.italic) {
  74. iNode = document.createElement("i");
  75. }
  76. // 将不为空的元素依次append
  77. node = ([uNode, bNode, iNode] as Array<Node>)
  78. .filter((v) => v)
  79. .reduceRight((p, c) => {
  80. c.appendChild(p);
  81. return c;
  82. });
  83. let childNode = node;
  84. for (let i = 0; i < 3; i++) {
  85. if (childNode && childNode.hasChildNodes()) {
  86. childNode = childNode.childNodes[0];
  87. }
  88. }
  89. childNode.textContent = block.value;
  90. } else {
  91. node = document.createTextNode(block.value);
  92. }
  93. } else if (block.type === "image") {
  94. node = document.createElement("img");
  95. if (inline === true) {
  96. node.classList.add("inline");
  97. }
  98. node.src = block.value;
  99. // param
  100. if (block.param) {
  101. const { width, height } = block.param;
  102. width && (node.style.width = width + "px");
  103. height && (node.style.height = height + "px");
  104. }
  105. } else if (block.type === "audio") {
  106. node = document.createElement("audio");
  107. node.className = "audio";
  108. node.src = block.value;
  109. node.controls = true;
  110. }
  111. return node as Node;
  112. }