My avatar

北雁云依的博客

My avatar

北雁云依的博客

把信拿去吧,你可以假戏真做

RSS
· 浏览

Vue 对 HTML 自定义渲染

import { defineComponent, h } from 'vue';
import { NH1, NH2, NH3, NH4, NH5, NH6, NBlockquote, NP, NText, NScrollbar, NA } from 'naive-ui';
import TextSlot from '../components/TextSlot.vue';

const render: (nodeList: Node) => any = (nodeList) => {
  //@ts-ignore
  if (nodeList.nodeName === '#text') return h(TextSlot, null, () => nodeList.nodeValue);
  const childs = () => Array.from(nodeList.childNodes).map((node) => render(node));
  switch (nodeList.nodeName) {
    case 'H1':
      return h(NH1, null, childs);
    case 'H2':
      return h(NH2, null, childs);
    case 'H3':
      return h(NH3, null, childs);
    case 'H4':
      return h(NH4, null, childs);
    case 'H5':
      return h(NH5, null, childs);
    case 'H6':
      return h(NH6, null, childs);
    case 'P':
      return h(NP, null, childs);
    case 'BLOCKQUOTE':
      return h(NBlockquote, null, childs);
    case 'PRE':
      return h(NScrollbar, { xScrollable: true, style: { maxWidth: '90vw' } }, () =>
        h('pre', {
          innerHTML: (nodeList as HTMLPreElement).innerHTML,
        }),
      );
    case 'A':
      return h(
        NA,
        { href: (nodeList as HTMLAnchorElement).href },
        () => (nodeList as HTMLAnchorElement).innerText,
      );
    case 'OL':
      return h('ol', { innerHTML: (nodeList as Element).innerHTML }, childs);
    case 'UL':
      return h('ul', { innerHTML: (nodeList as Element).innerHTML }, childs);
    case 'BR':
      return h('br', null, childs);
    case 'CODE':
      return h('code', null, (nodeList as any).innerText);
    default:
      console.log(nodeList);
      return Array.from(nodeList.childNodes).map((node) => render(node));
  }
};

const parseHtml = (htmlStr: string) => {
  if (!htmlStr) return null;
  const parser = new DOMParser();
  const dom = parser.parseFromString(htmlStr, 'text/html');
  const renderedChilds = Array.from(dom.childNodes).map((node) => render(node));
  const ret = h(
    'div',
    {
      style: {
        marginLeft: '0.5rem',
        marginRight: '0.5rem',
      },
    },
    renderedChilds,
  );
  console.log(ret);
  return ret;
};

const PPPPPP = defineComponent({
  props: { htmlStr: String },
  setup() {},
  render() {
    return parseHtml(this.$props.htmlStr!) || h('div');
  },
});

export default PPPPPP;

上面的代码来自我废弃的博客系统。简简单单遍历个 DOM 树然后渲染就行了,没啥好说的。

实际上也可以用querySelectorAll来做,把特定元素替换成自定义元素,然后注册Web Components解决之。

博客系统写到一半,这边 vuepress-theme-hope 的 bug 已经被解决掉了,所以直接上 vuepress 摆烂。看看回头开发 HexoSharp 怎么样。

分享

复制此页面地址到邦联宇宙搜索框以在邦联宇宙分享本文:https://blog.yunyi.beiyan.us/posts/htmlRender