Initial commit

This commit is contained in:
admin
2025-12-08 14:39:07 +08:00
commit 9d4f78656b
782 changed files with 66418 additions and 0 deletions

View File

@@ -0,0 +1,396 @@
/*!
* mp-html v2.5.1
* https://github.com/jin-yufeng/mp-html
*
* Released under the MIT license
* Author: Jin Yufeng
*/
const Parser = require('./parser')
const plugins = []
Component({
data: {
nodes: []
},
properties: {
/**
* @description 容器的样式
* @type {String}
*/
containerStyle: String,
/**
* @description 用于渲染的 html 字符串
* @type {String}
*/
content: {
type: String,
value: '',
observer (content) {
this.setContent(content)
}
},
/**
* @description 是否允许外部链接被点击时自动复制
* @type {Boolean}
* @default true
*/
copyLink: {
type: Boolean,
value: true
},
/**
* @description 主域名,用于拼接链接
* @type {String}
*/
domain: String,
/**
* @description 图片出错时的占位图链接
* @type {String}
*/
errorImg: String,
/**
* @description 是否开启图片懒加载
* @type {Boolean}
* @default false
*/
lazyLoad: Boolean,
/**
* @description 图片加载过程中的占位图链接
* @type {String}
*/
loadingImg: String,
/**
* @description 是否在播放一个视频时自动暂停其他视频
* @type {Boolean}
* @default true
*/
pauseVideo: {
type: Boolean,
value: true
},
/**
* @description 是否允许图片被点击时自动预览
* @type {Boolean | String}
* @default true
*/
previewImg: {
type: null,
value: true
},
/**
* @description 是否给每个表格添加一个滚动层使其能单独横向滚动
* @type {Boolean}
* @default false
*/
scrollTable: Boolean,
/**
* @description 是否开启长按复制
* @type {Boolean | String}
* @default false
*/
selectable: null,
/**
* @description 是否将 title 标签的内容设置到页面标题
* @type {Boolean}
* @default true
*/
setTitle: {
type: Boolean,
value: true
},
/**
* @description 是否允许图片被长按时显示菜单
* @type {Boolean}
* @default true
*/
showImgMenu: {
type: Boolean,
value: true
},
/**
* @description 标签的默认样式
* @type {Object}
*/
tagStyle: Object,
/**
* @description 是否使用锚点链接
* @type {Boolean | Number}
* @default false
*/
useAnchor: null
},
created () {
this.plugins = []
for (let i = plugins.length; i--;) {
this.plugins.push(new plugins[i](this))
}
// #ifdef MP-ALIPAY
if (this.properties.content) {
this.setContent(this.properties.content)
}
// #endif
},
// #ifdef MP-ALIPAY
didUpdate (e) {
if (e.content !== this.properties.content) {
this.setContent(this.properties.content)
}
},
// #endif
detached () {
// 注销插件
this._hook('onDetached')
},
methods: {
/**
* @description 将锚点跳转的范围限定在一个 scroll-view 内
* @param {Object} page scroll-view 所在页面的示例
* @param {String} selector scroll-view 的选择器
* @param {String} scrollTop scroll-view scroll-top 属性绑定的变量名
*/
in (page, selector, scrollTop) {
if (page && selector && scrollTop) {
this._in = {
page,
selector,
scrollTop
}
}
},
/**
* @description 锚点跳转
* @param {String} id 要跳转的锚点 id
* @param {Number} offset 跳转位置的偏移量
* @returns {Promise}
*/
navigateTo (id, offset) {
return new Promise((resolve, reject) => {
if (!this.properties.useAnchor) {
reject(Error('Anchor is disabled'))
return
}
// 跨组件选择器
const deep =
// #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO
'>>>'
// #endif
// #ifdef MP-BAIDU || MP-ALIPAY
' ' // eslint-disable-line
// #endif
const selector = wx.createSelectorQuery()
// #ifndef MP-ALIPAY
.in(this._in ? this._in.page : this)
// #endif
.select((this._in ? this._in.selector : '._root') + (id ? `${deep}#${id}` : '')).boundingClientRect()
if (this._in) {
selector.select(this._in.selector).scrollOffset()
.select(this._in.selector).boundingClientRect()
} else {
// 获取 scroll-view 的位置和滚动距离
selector.selectViewport().scrollOffset() // 获取窗口的滚动距离
}
selector.exec(res => {
if (!res[0]) {
reject(Error('Label not found'))
return
}
const scrollTop = res[1].scrollTop + res[0].top - (res[2] ? res[2].top : 0) + (offset || parseInt(this.properties.useAnchor) || 0)
if (this._in) {
// scroll-view 跳转
this._in.page.setData({
[this._in.scrollTop]: scrollTop
})
} else {
// 页面跳转
wx.pageScrollTo({
scrollTop,
duration: 300
})
}
resolve()
})
})
},
/**
* @description 获取文本内容
* @returns {String}
*/
getText (nodes) {
let text = '';
(function traversal (nodes) {
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i]
if (node.type === 'text') {
text += node.text.replace(/&amp;/g, '&')
} else if (node.name === 'br') {
text += '\n'
} else {
// 块级标签前后加换行
const isBlock = node.name === 'p' || node.name === 'div' || node.name === 'tr' || node.name === 'li' || (node.name[0] === 'h' && node.name[1] > '0' && node.name[1] < '7')
if (isBlock && text && text[text.length - 1] !== '\n') {
text += '\n'
}
// 递归获取子节点的文本
if (node.children) {
traversal(node.children)
}
if (isBlock && text[text.length - 1] !== '\n') {
text += '\n'
} else if (node.name === 'td' || node.name === 'th') {
text += '\t'
}
}
}
})(nodes || this.data.nodes)
return text
},
/**
* @description 获取内容大小
* @returns {Promise}
*/
getRect () {
return new Promise((resolve, reject) => {
wx.createSelectorQuery()
// #ifndef MP-ALIPAY
.in(this)
// #endif
.select('._root').boundingClientRect().exec(res => res[0] ? resolve(res[0]) : reject(Error('Root label not found')))
})
},
/**
* @description 暂停播放媒体
*/
pauseMedia () {
for (let i = (this._videos || []).length; i--;) {
this._videos[i].pause()
}
},
/**
* @description 设置媒体播放速率
* @param {Number} rate 播放速率
*/
setPlaybackRate (rate) {
this.playbackRate = rate
for (let i = (this._videos || []).length; i--;) {
this._videos[i].playbackRate(rate)
}
},
/**
* @description 设置富文本内容
* @param {string} content 要渲染的 html 字符串
* @param {boolean} append 是否在尾部追加
*/
setContent (content, append) {
if (!this.imgList || !append) {
this.imgList = []
}
this._videos = []
const data = {}
const nodes = new Parser(this).parse(content)
// 尾部追加内容
if (append) {
for (let i = this.data.nodes.length, j = nodes.length; j--;) {
data[`nodes[${i + j}]`] = nodes[j]
}
} else {
data.nodes = nodes
}
this.setData(data,
// #ifndef MP-TOUTIAO
() => {
this._hook('onLoad')
this.triggerEvent('load')
}
// #endif
)
// #ifdef MP-TOUTIAO
this.selectComponent('#_root', child => {
child.root = this
this._hook('onLoad')
this.triggerEvent('load')
})
// #endif
if (this.properties.lazyLoad || this.imgList._unloadimgs < this.imgList.length / 2) {
// 设置懒加载,每 350ms 获取高度,不变则认为加载完毕
let height = 0
const callback = rect => {
if (!rect || !rect.height) rect = {}
// 350ms 总高度无变化就触发 ready 事件
if (rect.height === height) {
this.triggerEvent('ready', rect)
} else {
height = rect.height
setTimeout(() => {
this.getRect().then(callback).catch(callback)
}, 350)
}
}
this.getRect().then(callback).catch(callback)
} else {
// 未设置懒加载,等待所有图片加载完毕
if (!this.imgList._unloadimgs) {
this.getRect().then(rect => {
this.triggerEvent('ready', rect)
}).catch(() => {
this.triggerEvent('ready', {})
})
}
}
},
/**
* @description 调用插件的钩子函数
* @private
*/
_hook (name) {
for (let i = plugins.length; i--;) {
if (this.plugins[i][name]) {
this.plugins[i][name]()
}
}
},
// #ifndef MP-TOUTIAO
/**
* @description 添加子组件
* @private
*/
_add (e) {
e
// #ifndef MP-ALIPAY
.detail
// #endif
.root = this
}
// #endif
}
})

View File

@@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"node": "./node/node"
}
}

View File

@@ -0,0 +1,7 @@
<!-- 主组件 -->
<view class="_root {{selectable?'_select':''}}" style="{{containerStyle}}">
<!-- 加载完成前显示自定义 loading -->
<slot wx:if="{{!nodes[0]}}" />
<!-- 节点树 -->
<node id="_root" childs="{{nodes}}" opts="{{[lazyLoad,loadingImg,errorImg,showImgMenu,selectable]}}" mp-weixin:mp-qq:mp-baidu:catchadd="_add" mp-alipay:onAdd="_add" />
</view>

View File

@@ -0,0 +1,13 @@
/* 根节点样式 */
._root {
padding: 1px 0;
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
}
/* 长按复制 */
._select {
-webkit-user-select: text;
user-select: text;
}

View File

@@ -0,0 +1,247 @@
/**
* @fileoverview 递归子组件,用于显示节点树
*/
Component({
data: {
ctrl: {}, // 控制信号
// #ifdef MP-WEIXIN
isiOS: wx.getSystemInfoSync().system.includes('iOS')
// #endif
},
properties: {
childs: Array, // 子节点列表
opts: Array // 设置 [是否开启懒加载, 加载中占位图, 错误占位图, 是否使用长按菜单]
},
options: {
addGlobalClass: true
},
// #ifndef MP-TOUTIAO
attached () {
// #ifndef MP-ALIPAY
this.triggerEvent('add', this, {
bubbles: true,
composed: true
})
// #endif
// #ifdef MP-ALIPAY
this.props.onAdd(this)
// #endif
},
// #endif
methods: {
noop () { },
/**
* @description 获取标签
* @param {String} path 路径
*/
getNode (path) {
try {
const nums = path.split('_')
let node = this.properties.childs[nums[0]]
for (let i = 1; i < nums.length; i++) {
node = node.children[nums[i]]
}
return node
} catch {
return {
text: '',
attrs: {},
children: []
}
}
},
/**
* @description 播放视频事件
* @param {Event} e
*/
play (e) {
const i = e.target.dataset.i
const node = this.getNode(i)
this.root.triggerEvent('play', {
source: node.name,
attrs: {
...node.attrs,
src: node.src[this.data.ctrl[i] || 0]
}
})
if (this.root.properties.pauseVideo) {
let flag = false
const id = e.target.id
for (let i = this.root._videos.length; i--;) {
if (this.root._videos[i].id === id) {
flag = true
} else {
this.root._videos[i].pause() // 自动暂停其他视频
}
}
// 将自己加入列表
if (!flag) {
const ctx = wx.createVideoContext(id
// #ifndef MP-BAIDU
, this
// #endif
)
ctx.id = id
if (this.root.playbackRate) {
ctx.playbackRate(this.root.playbackRate)
}
this.root._videos.push(ctx)
}
}
},
/**
* @description 图片点击事件
* @param {Event} e
*/
imgTap (e) {
const node = this.getNode(e.target.dataset.i)
// 父级中有链接
if (node.a) return this.linkTap(node.a)
if (node.attrs.ignore) return
this.root.triggerEvent('imgtap', node.attrs)
if (this.root.properties.previewImg) {
const current =
// #ifndef MP-ALIPAY
this.root.imgList[node.i]
// #endif
// #ifdef MP-ALIPAY
node.i // eslint-disable-line
// #endif
// 自动预览图片
wx.previewImage({
// #ifdef MP-WEIXIN
showmenu: this.root.properties.showImgMenu,
// #endif
// #ifdef MP-ALIPAY
enablesavephoto: this.root.properties.showImgMenu,
enableShowPhotoDownload: this.root.properties.showImgMenu,
// #endif
current,
urls: this.root.imgList
})
}
},
/**
* @description 图片加载完成事件
* @param {Event} e
*/
imgLoad (e) {
const i = e.target.dataset.i
const node = this.getNode(i)
let val
if (!node.w) {
val = e.detail.width
} else if ((this.properties.opts[1] && !this.data.ctrl[i]) || this.data.ctrl[i] === -1) {
// 加载完毕,取消加载中占位图
val = 1
}
if (val
// #ifdef MP-TOUTIAO
&& val !== this.data.ctrl[i] // eslint-disable-line
// #endif
) {
this.setData({
['ctrl.' + i]: val
})
}
this.checkReady()
},
/**
* @description 检查是否所有图片加载完毕
*/
checkReady () {
if (!this.root.properties.lazyLoad) {
this.root.imgList._unloadimgs -= 1
if (!this.root.imgList._unloadimgs) {
setTimeout(() => {
this.root.getRect().then(rect => {
this.root.triggerEvent('ready', rect)
}).catch(() => {
this.root.triggerEvent('ready', {})
})
}, 350)
}
}
},
/**
* @description 链接点击事件
* @param {Event} e
*/
linkTap (e) {
const node = e.currentTarget ? this.getNode(e.currentTarget.dataset.i) : {}
const attrs = node.attrs || e
const href = attrs.href
this.root.triggerEvent('linktap', Object.assign({
innerText: this.root.getText(node.children || []) // 链接内的文本内容
}, attrs))
if (href) {
if (href[0] === '#') {
// 跳转锚点
this.root.navigateTo(href.substring(1)).catch(() => { })
} else if (href.split('?')[0].includes('://')) {
// 复制外部链接
if (this.root.properties.copyLink) {
wx.setClipboardData({
data: href,
success: () =>
wx.showToast({
title: '链接已复制'
})
})
}
} else {
// 跳转页面
wx.navigateTo({
url: href,
fail () {
wx.switchTab({
url: href,
fail () { }
})
}
})
}
}
},
/**
* @description 错误事件
* @param {Event} e
*/
mediaError (e) {
const i = e.target.dataset.i
const node = this.getNode(i)
if (node.name === 'video' || node.name === 'audio') {
// 加载其他源
let index = (this.data.ctrl[i] || 0) + 1
if (index > node.src.length) {
index = 0
}
if (index < node.src.length) {
return this.setData({
['ctrl.' + i]: index
})
}
} else if (node.name === 'img') {
// 显示错误占位图
if (this.properties.opts[2]) {
this.setData({
['ctrl.' + i]: -1
})
}
this.checkReady()
}
if (this.root) {
this.root.triggerEvent('error', {
source: node.name,
attrs: node.attrs,
errMsg: e.detail.errMsg
})
}
}
}
})

View File

@@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"node": "./node"
}
}

View File

@@ -0,0 +1,112 @@
<!-- node 递归子组件 -->
<!-- #ifdef MP-WEIXIN || MP-QQ -->
<wxs module="isInline">
// 行内标签列表
var inlineTags = {
abbr: true,
b: true,
big: true,
code: true,
del: true,
em: true,
i: true,
ins: true,
label: true,
q: true,
small: true,
span: true,
strong: true,
sub: true,
sup: true
}
/**
* @description 判断是否为行内标签
*/
module.exports = function (tagName, style) {
return inlineTags[tagName] || (style || '').indexOf('inline') !== -1
}
</wxs>
<!-- #endif -->
<template name="el">
<!-- 图片 -->
<block wx:if="{{n.name==='img'}}">
<!-- 表格中的图片,使用 rich-text 防止大小不正确 -->
<rich-text wx:if="{{n.t}}" style="display:{{n.t}}" nodes="<img class='_img' style='{{n.attrs.style}}' src='{{n.attrs.src}}'>" data-i="{{i}}" catchtap="imgTap" />
<block wx:else>
<!-- 占位图 -->
<image wx:if="{{(opts[1]&&!ctrl[i])||ctrl[i]<0}}" class="_img" style="{{n.attrs.style}}" src="{{ctrl[i]<0?opts[2]:opts[1]}}" mode="widthFix" />
<!-- 显示图片 -->
<image id="{{n.attrs.id}}" class="_img {{n.attrs.class}}" style="{{ctrl[i]===-1?'display:none;':''}}width:{{ctrl[i]||1}}px;height:1px;{{n.attrs.style}}" src="{{n.attrs.src}}" mode="{{!n.h?'widthFix':(!n.w?'heightFix':(n.m||'scaleToFill'))}}" lazy-load="{{opts[0]}}" mp-weixin:mp-baidu:webp="{{n.webp}}" mp-weixin:show-menu-by-longpress="{{opts[3]&&!n.attrs.ignore}}" mp-baidu:image-menu-prevent="{{!opts[3]||n.attrs.ignore}}" data-i="{{i}}" bindload="imgLoad" binderror="mediaError" catchtap="imgTap" bindlongpress="noop" />
</block>
</block>
<!-- 文本 -->
<!-- #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO -->
<text wx:elif="{{n.text}}" mp-weixin:user-select="{{opts[4]=='force'&&isiOS}}" decode>{{n.text}}</text>
<!-- #endif -->
<text wx:elif="{{n.name==='br'}}">{{'\n'}}</text>
<!-- 链接 -->
<view wx:elif="{{n.name==='a'}}" id="{{n.attrs.id}}" class="{{n.attrs.href?'_a ':''}}{{n.attrs.class}}" hover-class="_hover" style="display:inline;{{n.attrs.style}}" data-i="{{i}}" catchtap="linkTap">
<!-- #ifdef MP-WEIXIN || MP-QQ -->
<node childs="{{n.children}}" opts="{{opts}}" style="display:inherit" />
<!-- #endif -->
<!-- #ifdef MP-BAIDU -->
<block wx:for="{{n.children}}" wx:key="index">
<template is="el" data="{{n:item,i:i+'_'+index,opts:opts,ctrl:ctrl}}"></template>
</block>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY || MP-TOUTIAO -->
<template is="node" data="{{childs:n.children,path:i+'_',opts:opts,ctrl:ctrl}}"></template>
<!-- #endif -->
</view>
<!-- 视频 -->
<video wx:elif="{{n.name==='video'}}" id="{{n.attrs.id}}" class="{{n.attrs.class}}" style="{{n.attrs.style}}" autoplay="{{n.attrs.autoplay}}" controls="{{n.attrs.controls}}" loop="{{n.attrs.loop}}" muted="{{n.attrs.muted}}" object-fit="{{n.attrs['object-fit']}}" poster="{{n.attrs.poster}}" src="{{n.src[ctrl[i]||0]}}" data-i="{{i}}" bindplay="play" binderror="mediaError" />
<!-- #ifndef MP-TOUTIAO -->
<!-- 音频 -->
<audio wx:elif="{{n.name==='audio'}}" id="{{n.attrs.id}}" class="{{n.attrs.class}}" style="{{n.attrs.style}}" author="{{n.attrs.author}}" controls="{{n.attrs.controls}}" loop="{{n.attrs.loop}}" name="{{n.attrs.name}}" poster="{{n.attrs.poster}}" src="{{n.src[ctrl[i]||0]}}" data-i="{{i}}" bindplay="play" binderror="mediaError" />
<!-- #endif -->
<!-- insert -->
<!-- 富文本 -->
<rich-text wx:else id="{{n.attrs.id}}" mp-weixin:mp-qq:mp-baidu:mp-toutiao:style="{{n.f}}" mp-alipay:style="display:inline;{{n.f}}" mp-baidu:selectable="{{opts[4]}}" mp-weixin:user-select="{{opts[4]}}" nodes="{{[n]}}" />
</template>
<!-- #ifdef MP-ALIPAY || MP-TOUTIAO -->
<template name="node">
<block wx:for="{{childs}}" wx:for-item="n" wx:for-index="i" wx:key="i">
<template wx:if="{{!n.c}}" is="el" data="{{n:n,i:path+i,opts:opts,ctrl:ctrl}}" />
<view wx:else id="{{n.attrs.id}}" class="_{{n.name}} {{n.attrs.class}}" style="{{n.attrs.style}}">
<template is="node" data="{{childs:n.children,path:path+i+'_',opts:opts,ctrl:ctrl}}"></template>
</view>
</block>
</template>
<template is="node" data="{{childs:childs,path:'',opts:opts,ctrl:ctrl}}"></template>
<!-- #endif -->
<!-- #ifndef MP-ALIPAY || MP-TOUTIAO -->
<!-- 第 1 层 -->
<block wx:for="{{childs}}" wx:for-item="n1" wx:for-index="i1" wx:key="i1">
<template mp-weixin:mp-qq:wx:if="{{!n1.c&&(!n1.children||n1.name==='a'||!isInline(n1.name,n1.attrs.style))}}" mp-baidu:wx:if="{{!n1.c}}" is="el" data="{{n:n1,i:''+i1,opts:opts,ctrl:ctrl}}" />
<view wx:else id="{{n1.attrs.id}}" class="_{{n1.name}} {{n1.attrs.class}}" style="{{n1.attrs.style}}">
<!-- 第 2 层 -->
<block wx:for="{{n1.children}}" wx:for-item="n2" wx:for-index="i2" wx:key="i2">
<template mp-weixin:mp-qq:wx:if="{{!n2.c&&(!n2.children||n2.name==='a'||!isInline(n2.name,n2.attrs.style))}}" mp-baidu:wx:if="{{!n2.c}}" is="el" data="{{n:n2,i:i1+'_'+i2,opts:opts,ctrl:ctrl}}" />
<view wx:else id="{{n2.attrs.id}}" class="_{{n2.name}} {{n2.attrs.class}}" style="{{n2.attrs.style}}">
<!-- 第 3 层 -->
<block wx:for="{{n2.children}}" wx:for-item="n3" wx:for-index="i3" wx:key="i3">
<template mp-weixin:mp-qq:wx:if="{{!n3.c&&(!n3.children||n3.name==='a'||!isInline(n3.name,n3.attrs.style))}}" mp-baidu:wx:if="{{!n3.c}}" is="el" data="{{n:n3,i:i1+'_'+i2+'_'+i3,opts:opts,ctrl:ctrl}}" />
<view wx:else id="{{n3.attrs.id}}" class="_{{n3.name}} {{n3.attrs.class}}" style="{{n3.attrs.style}}">
<!-- 第 4 层 -->
<block wx:for="{{n3.children}}" wx:for-item="n4" wx:for-index="i4" wx:key="i4">
<template mp-weixin:mp-qq:wx:if="{{!n4.c&&(!n4.children||n4.name==='a'||!isInline(n4.name,n4.attrs.style))}}" mp-baidu:wx:if="{{!n4.c}}" is="el" data="{{n:n4,i:i1+'_'+i2+'_'+i3+'_'+i4,opts:opts,ctrl:ctrl}}" />
<view wx:else id="{{n4.attrs.id}}" class="_{{n4.name}} {{n4.attrs.class}}" style="{{n4.attrs.style}}">
<!-- 第 5 层 -->
<block wx:for="{{n4.children}}" wx:for-item="n5" wx:for-index="i5" wx:key="i5">
<template mp-weixin:mp-qq:wx:if="{{!n5.c&&(!n5.children||n5.name==='a'||!isInline(n5.name,n5.attrs.style))}}" mp-baidu:wx:if="{{!n5.c}}" is="el" data="{{n:n5,i:i1+'_'+i2+'_'+i3+'_'+i4+'_'+i5,opts:opts,ctrl:ctrl}}" />
<node wx:else id="{{n5.attrs.id}}" class="_{{n5.name}} {{n5.attrs.class}}" style="{{n5.attrs.style}}" childs="{{n5.children}}" opts="{{opts}}" />
</block>
</view>
</block>
</view>
</block>
</view>
</block>
</view>
</block>
<!-- #endif -->

View File

@@ -0,0 +1,164 @@
/* a 标签默认效果 */
._a {
padding: 1.5px 0 1.5px 0;
color: #366092;
word-break: break-all;
}
/* a 标签点击态效果 */
._hover {
text-decoration: underline;
opacity: 0.7;
}
/* 图片默认效果 */
._img {
max-width: 100%;
-webkit-touch-callout: none;
}
/* 内部样式 */
._b,
._strong {
font-weight: bold;
}
._code {
font-family: monospace;
}
._del {
text-decoration: line-through;
}
._em,
._i {
font-style: italic;
}
._h1 {
font-size: 2em;
}
._h2 {
font-size: 1.5em;
}
._h3 {
font-size: 1.17em;
}
._h5 {
font-size: 0.83em;
}
._h6 {
font-size: 0.67em;
}
._h1,
._h2,
._h3,
._h4,
._h5,
._h6 {
display: block;
font-weight: bold;
}
._ins {
text-decoration: underline;
}
._li {
display: list-item;
}
._ol {
list-style-type: decimal;
}
._ol,
._ul {
display: block;
padding-left: 40px;
margin: 1em 0;
}
._q::before {
content: '"';
}
._q::after {
content: '"';
}
._sub {
font-size: smaller;
vertical-align: sub;
}
._sup {
font-size: smaller;
vertical-align: super;
}
._thead,
._tbody,
._tfoot {
display: table-row-group;
}
._tr {
display: table-row;
}
._td,
._th {
display: table-cell;
vertical-align: middle;
}
._th {
font-weight: bold;
text-align: center;
}
._ul {
list-style-type: disc;
}
._ul ._ul {
margin: 0;
list-style-type: circle;
}
._ul ._ul ._ul {
list-style-type: square;
}
._abbr,
._b,
._code,
._del,
._em,
._i,
._ins,
._label,
._q,
._span,
._strong,
._sub,
._sup {
display: inline;
}
/* #ifndef MP-ALIPAY || MP-TOUTIAO */
._blockquote,
._div,
._p {
display: block;
}
/* #endif */

File diff suppressed because it is too large Load Diff