提交 5a65b4bd 编写于 作者: D DCloud_LXH

fix(h5): rich-text ssr

上级 1ec26b08
import { onMounted, ref, watch, getCurrentInstance } from 'vue' import { onMounted, ref, watch, getCurrentInstance, h, VNode } from 'vue'
import { hasOwn } from '@vue/shared'
import { import {
defineBuiltInComponent, defineBuiltInComponent,
useCustomEvent, useCustomEvent,
EmitEvent, EmitEvent,
} from '@dcloudio/uni-components' } from '@dcloudio/uni-components'
import parseNodes from './nodes-parser' import parseNodes, { TAGS, decodeEntities } from './nodes-parser'
import { props, parseHtml } from '../../components/rich-text' import { props, parseHtml } from '../../components/rich-text'
import { ssrRef } from '@dcloudio/uni-app'
interface Node {
type: string
text?: string
name: string
attrs: Object
children: Node[]
}
function _createVNode(nodeList: Node[]): Array<VNode | undefined> {
if (!nodeList) return []
return nodeList.map((node) => {
if (node.name) {
const tagName = node.name.toLowerCase()
if (!hasOwn(TAGS, tagName)) {
return
}
}
const isNode = !hasOwn(node, 'type') || node.type === 'node'
return h(
isNode ? node.name : 'span',
node.attrs,
isNode ? _createVNode(node.children) : decodeEntities(node.text)
)
})
}
export default /*#__PURE__*/ defineBuiltInComponent({ export default /*#__PURE__*/ defineBuiltInComponent({
name: 'RichText', name: 'RichText',
...@@ -23,7 +52,9 @@ export default /*#__PURE__*/ defineBuiltInComponent({ ...@@ -23,7 +52,9 @@ export default /*#__PURE__*/ defineBuiltInComponent({
], ],
setup(props, { emit, attrs }) { setup(props, { emit, attrs }) {
const vm = getCurrentInstance() const vm = getCurrentInstance()
const scopeId = (vm && vm.vnode.scopeId) || ''
const rootRef = ref<HTMLElement | null>(null) const rootRef = ref<HTMLElement | null>(null)
const nodelist = ssrRef(props.nodes, 'nodelist')
const trigger = useCustomEvent<EmitEvent<typeof emit>>(rootRef, emit) const trigger = useCustomEvent<EmitEvent<typeof emit>>(rootRef, emit)
const hasItemClick = !!attrs.onItemclick const hasItemClick = !!attrs.onItemclick
...@@ -31,14 +62,21 @@ export default /*#__PURE__*/ defineBuiltInComponent({ ...@@ -31,14 +62,21 @@ export default /*#__PURE__*/ defineBuiltInComponent({
trigger('itemclick', e, detail) trigger('itemclick', e, detail)
} }
// ssr 处理
if (__NODE_JS__) {
if (typeof props.nodes === 'string') {
nodelist.value = parseHtml(props.nodes)
}
}
function _renderNodes(nodes: string | unknown[]) { function _renderNodes(nodes: string | unknown[]) {
if (typeof nodes === 'string') { if (typeof nodes === 'string') {
nodes = parseHtml(nodes) nodelist.value = parseHtml(nodes)
} }
const nodeList = parseNodes( const nodeList = parseNodes(
nodes, nodelist.value,
document.createDocumentFragment(), document.createDocumentFragment(),
(vm && vm.vnode.scopeId) || '', scopeId,
hasItemClick && triggerItemClick hasItemClick && triggerItemClick
) )
rootRef.value!.firstElementChild!.innerHTML = '' rootRef.value!.firstElementChild!.innerHTML = ''
...@@ -53,15 +91,22 @@ export default /*#__PURE__*/ defineBuiltInComponent({ ...@@ -53,15 +91,22 @@ export default /*#__PURE__*/ defineBuiltInComponent({
) )
onMounted(() => { onMounted(() => {
_renderNodes(props.nodes) _renderNodes(nodelist.value as [])
}) })
return () => { return () =>
return ( h(
<uni-rich-text ref={rootRef}> 'uni-rich-text',
<div /> {
</uni-rich-text> ref: rootRef,
},
[
h(
'div',
{},
__NODE_JS__ ? _createVNode(nodelist.value as Node[]) : []
),
]
) )
}
}, },
}) })
import { hasOwn, isPlainObject } from '@vue/shared' import { hasOwn, isPlainObject } from '@vue/shared'
import { getRealPath } from '@dcloudio/uni-platform' import { getRealPath } from '@dcloudio/uni-platform'
const TAGS = { export const TAGS = {
a: '', a: '',
abbr: '', abbr: '',
address: '', address: '',
...@@ -77,7 +77,7 @@ const CHARS = { ...@@ -77,7 +77,7 @@ const CHARS = {
apos: "'", apos: "'",
} }
function decodeEntities(htmlString) { export function decodeEntities(htmlString) {
return htmlString.replace( return htmlString.replace(
/&(([a-zA-Z]+)|(#x{0,1}[\da-zA-Z]+));/gi, /&(([a-zA-Z]+)|(#x{0,1}[\da-zA-Z]+));/gi,
function (match, stage) { function (match, stage) {
...@@ -90,9 +90,13 @@ function decodeEntities(htmlString) { ...@@ -90,9 +90,13 @@ function decodeEntities(htmlString) {
if (/^#x[0-9a-f]{1,4}$/i.test(stage)) { if (/^#x[0-9a-f]{1,4}$/i.test(stage)) {
return String.fromCharCode('0' + stage.slice(1)) return String.fromCharCode('0' + stage.slice(1))
} }
const wrap = document.createElement('div') if (!__NODE_JS__) {
wrap.innerHTML = match const wrap = document.createElement('div')
return wrap.innerText || wrap.textContent wrap.innerHTML = match
return wrap.innerText || wrap.textContent
} else {
return match
}
} }
) )
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册