| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- <template>
- <view class="nana-Parse-container" :style="contentStyle">
- <ParseNodeRender v-for="(node, index) in nodes" :key="index" :node="node" />
- </view>
- </template>
- <script setup lang="ts">
- import ParseNodeRender from './ParseNodeRender.vue'
- import { parse, type DefaultTreeAdapterTypes } from 'parse5'
- import { computed, provide, ref, toRef } from 'vue';
- import type { ParseNode } from './Parse'
- export interface ParseProps {
- /**
- * HTML解析内容
- */
- content?: string|null|undefined;
- /**
- * 标签样式。键为标签名,值为样式
- */
- tagStyle?: Record<string, string>;
- /**
- * 类样式。键为类名,值为样式
- */
- classStyle?: Record<string, string>;
- /**
- * 容器样式
- */
- contentStyle?: any;
- }
- const props = withDefaults(defineProps<ParseProps>(), {
- tagStyle: () => ({}),
- classStyle: () => ({}),
- contentStyle: () => ({})
- });
- const praseImages = ref<string[]>([]);
- provide('tagStyle', toRef(props, 'tagStyle'));
- provide('classStyle', toRef(props, 'classStyle'));
- provide('praseImages', praseImages);
- const toObj = (attrs: DefaultTreeAdapterTypes.Element['attrs']) => {
- const obj: Record<string, string> = {};
- for (const attr of attrs) {
- obj[attr.name] = attr.value;
- }
- return obj;
- }
- // 解析HTML为节点树
- const parseHtml = (html: string): ParseNode[] => {
- const nodes: ParseNode[] = [];
- const doc = parse(html);
- praseImages.value = [];
-
- const solveTextNode = (child: DefaultTreeAdapterTypes.TextNode, nodes: ParseNode[], parentTag?: string) => {
- const value = child.value;
- if (value.trim() === '') {
- return null;
- }
- if (value.trim() === '\n') {
- const node: ParseNode = {
- tag: 'br',
- };
- nodes.push(node);
- return node;
- }
- const node: ParseNode = {
- tag: 'text',
- attrs: {
- content: value
- },
- parentTag,
- index: 0
- };
- nodes.push(node);
- return node;
- }
- const traverse = (element: DefaultTreeAdapterTypes.Element, parentTag?: string): ParseNode => {
- const node: ParseNode = {
- tag: element.tagName,
- attrs: toObj(element.attrs),
- children: [],
- parentTag,
- index: 0
- };
-
- // 解析子节点
- if (element.childNodes) {
- let index = 0;
- for (const child of element.childNodes) {
- if (child.nodeName === '#text') {
- const textNode = solveTextNode(child as DefaultTreeAdapterTypes.TextNode, node.children || [], element.tagName);
- if (textNode)
- textNode.index = index++;
- } else if (child.nodeName !== '#comment' && child.nodeName !== '#documentType') {
- const childNode = traverse(child as DefaultTreeAdapterTypes.Element, element.tagName);
- childNode.index = index++;
- node.children?.push(childNode);
- if (childNode.tag === 'img') {
- praseImages.value.push(childNode.attrs?.src as string);
- }
- }
- }
- }
-
- return node;
- };
- let index = 0;
- for (const child of doc.childNodes) {
- if (child.nodeName === '#text') {
- const textNode = solveTextNode(child as DefaultTreeAdapterTypes.TextNode, nodes, 'body');
- if (textNode)
- textNode.index = index++;
- } else if (child.nodeName !== '#documentType') {
- const childNode = traverse(child as DefaultTreeAdapterTypes.Element, 'body');
- childNode.index = index++;
- nodes.push(childNode);
- }
- }
- console.log(doc);
-
- return nodes;
- };
- // 计算属性,获取解析后的节点树
- const nodes = computed(() => parseHtml(props.content || ''));
- </script>
- <style scoped>
- .nana-Parse-container {
- width: 100%;
- }
- </style>
|