优化组件/更新
This commit is contained in:
@@ -1,8 +1,4 @@
|
||||
## news
|
||||
1. 欢迎加入 `QQ` 交流群:`699734691`
|
||||

|
||||
2. 示例微信小程序 `富文本插件` 添加 `获取组件包` 功能 [详细](https://jin-yufeng.gitee.io/mp-html/#/overview/quickstart?id=mp)
|
||||

|
||||
## 为减小组件包的大小,默认组件包中不包含编辑、latex 公式等扩展功能,需要使用扩展功能的请参考下方的 插件扩展 栏的说明
|
||||
|
||||
## 功能介绍
|
||||
- 全端支持(含 `v3、NVUE`)
|
||||
@@ -11,10 +7,10 @@
|
||||
- 支持设置占位图(加载中、出错时、预览时)
|
||||
- 支持锚点跳转、长按复制等丰富功能
|
||||
- 支持大部分 *html* 实体
|
||||
- 丰富的插件(关键词搜索、内容 **编辑** 等)
|
||||
- 丰富的插件(关键词搜索、内容编辑、`latex` 公式等)
|
||||
- 效率高、容错性强且轻量化
|
||||
|
||||
查看 [功能介绍](https://jin-yufeng.gitee.io/mp-html/#/overview/feature) 了解更多
|
||||
查看 [功能介绍](https://jin-yufeng.github.io/mp-html/#/overview/feature) 了解更多
|
||||
|
||||
## 使用方法
|
||||
- `uni_modules` 方式
|
||||
@@ -88,13 +84,13 @@
|
||||
使用 *cli* 方式运行的项目,通过 *npm* 方式引入时,需要在 *vue.config.js* 中配置 *transpileDependencies*,详情可见 [#330](https://github.com/jin-yufeng/mp-html/issues/330#issuecomment-913617687)
|
||||
如果在 **nvue** 中使用还要将 `dist/uni-app/static` 目录下的内容拷贝到项目的 `static` 目录下,否则无法运行
|
||||
|
||||
查看 [快速开始](https://jin-yufeng.gitee.io/mp-html/#/overview/quickstart) 了解更多
|
||||
查看 [快速开始](https://jin-yufeng.github.io/mp-html/#/overview/quickstart) 了解更多
|
||||
|
||||
## 组件属性
|
||||
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|:---:|:---:|:---:|---|
|
||||
| container-style | String | | 容器的样式([2.1.0+](https://jin-yufeng.gitee.io/mp-html/#/changelog/changelog#v210)) |
|
||||
| container-style | String | | 容器的样式([2.1.0+](https://jin-yufeng.github.io/mp-html/#/changelog/changelog#v210)) |
|
||||
| content | String | | 用于渲染的 html 字符串 |
|
||||
| copy-link | Boolean | true | 是否允许外部链接被点击时自动复制 |
|
||||
| domain | String | | 主域名(用于链接拼接) |
|
||||
@@ -110,7 +106,7 @@
|
||||
| tag-style | Object | | 设置标签的默认样式 |
|
||||
| use-anchor | Boolean | false | 是否使用锚点链接 |
|
||||
|
||||
查看 [属性](https://jin-yufeng.gitee.io/mp-html/#/basic/prop) 了解更多
|
||||
查看 [属性](https://jin-yufeng.github.io/mp-html/#/basic/prop) 了解更多
|
||||
|
||||
## 组件事件
|
||||
|
||||
@@ -121,8 +117,9 @@
|
||||
| error | 发生渲染错误时 |
|
||||
| imgtap | 图片被点击时 |
|
||||
| linktap | 链接被点击时 |
|
||||
| play | 音视频播放时 |
|
||||
|
||||
查看 [事件](https://jin-yufeng.gitee.io/mp-html/#/basic/event) 了解更多
|
||||
查看 [事件](https://jin-yufeng.github.io/mp-html/#/basic/event) 了解更多
|
||||
|
||||
## api
|
||||
组件实例上提供了一些 `api` 方法可供调用
|
||||
@@ -135,8 +132,10 @@
|
||||
| getRect | 获取富文本内容的位置和大小 |
|
||||
| setContent | 设置富文本内容 |
|
||||
| imgList | 获取所有图片的数组 |
|
||||
| pauseMedia | 暂停播放音视频([2.2.2+](https://jin-yufeng.github.io/mp-html/#/changelog/changelog#v222)) |
|
||||
| setPlaybackRate | 设置音视频播放速率([2.4.0+](https://jin-yufeng.github.io/mp-html/#/changelog/changelog#v240)) |
|
||||
|
||||
查看 [api](https://jin-yufeng.gitee.io/mp-html/#/advanced/api) 了解更多
|
||||
查看 [api](https://jin-yufeng.github.io/mp-html/#/advanced/api) 了解更多
|
||||
|
||||
## 插件扩展
|
||||
除基本功能外,本组件还提供了丰富的扩展,可按照需要选用
|
||||
@@ -144,7 +143,7 @@
|
||||
| 名称 | 作用 |
|
||||
|:---:|---|
|
||||
| audio | 音乐播放器 |
|
||||
| editable | 富文本 **编辑**([示例项目](https://6874-html-foe72-1259071903.tcb.qcloud.la/editable.zip?sign=cc0017be203fb3dbca62d33a0c15792e&t=1608447445)) |
|
||||
| editable | 富文本 **编辑**([示例项目](https://mp-html.oss-cn-hangzhou.aliyuncs.com/editable.zip)) |
|
||||
| emoji | 解析 emoji |
|
||||
| highlight | 代码块高亮显示 |
|
||||
| markdown | 渲染 markdown |
|
||||
@@ -152,8 +151,9 @@
|
||||
| style | 匹配 style 标签中的样式 |
|
||||
| txv-video | 使用腾讯视频 |
|
||||
| img-cache | 图片缓存 by [@PentaTea](https://github.com/PentaTea) |
|
||||
| latex | 渲染 latex 公式 by [@Zeng-J](https://github.com/Zeng-J) |
|
||||
|
||||
从插件市场导入的包中 **不含有** 扩展插件,需要使用插件参考以下方法:
|
||||
从插件市场导入的包中 **不含有** 扩展插件,使用插件需通过微信小程序 `富文本插件` 获取或参考以下方法进行打包:
|
||||
1. 获取完整组件包
|
||||
```bash
|
||||
npm install mp-html
|
||||
@@ -167,19 +167,26 @@
|
||||
```
|
||||
4. 拷贝 `dist/uni-app` 中的内容到项目根目录
|
||||
|
||||
查看 [插件](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin) 了解更多
|
||||
查看 [插件](https://jin-yufeng.github.io/mp-html/#/advanced/plugin) 了解更多
|
||||
|
||||
## 关于 nvue
|
||||
`nvue` 使用原生渲染,不支持部分 `css` 样式,为实现和 `html` 相同的效果,组件内部通过 `web-view` 进行渲染,性能上差于原生,根据 `weex` 官方建议,`web` 标签仅应用在非常规的降级场景。因此,如果通过原生的方式(如 `richtext`)能够满足需要,则不建议使用本组件,如果有较多的富文本内容,则可以直接使用 `vue` 页面
|
||||
由于渲染方式与其他端不同,有以下限制:
|
||||
1. 不支持 `lazy-load` 属性
|
||||
2. 视频不支持全屏播放
|
||||
3. 如果在 `flex-direction: row` 的容器中使用,需要给组件设置宽度或设置 `flex: 1` 占满剩余宽度
|
||||
|
||||
纯 `nvue` 模式下,[此问题](https://ask.dcloud.net.cn/question/119678) 修复前,不支持通过 `uni_modules` 引入,需要本地引入(将 [dist/uni-app](https://github.com/jin-yufeng/mp-html/tree/master/dist/uni-app) 中的内容拷贝到项目根目录下)
|
||||
|
||||
|
||||
## 问题反馈
|
||||
遇到问题时,请先查阅 [常见问题](https://jin-yufeng.gitee.io/mp-html/#/question/faq) 和 [issue](https://github.com/jin-yufeng/mp-html/issues) 中是否已有相同的问题
|
||||
遇到问题时,请先查阅 [常见问题](https://jin-yufeng.github.io/mp-html/#/question/faq) 和 [issue](https://github.com/jin-yufeng/mp-html/issues) 中是否已有相同的问题
|
||||
可通过 [issue](https://github.com/jin-yufeng/mp-html/issues/new/choose) 、插件问答或发送邮件到 [mp_html@126.com](mailto:mp_html@126.com) 提问,不建议在评论区提问(不方便回复)
|
||||
提问请严格按照 [issue 模板](https://github.com/jin-yufeng/mp-html/issues/new/choose) ,描述清楚使用环境、`html` 内容或可复现的 `demo` 项目以及复现方式,对于 **描述不清**、**无法复现** 或重复的问题将不予回复
|
||||
|
||||
查看 [问题反馈](https://jin-yufeng.gitee.io/mp-html/#/question/feedback) 了解更多
|
||||
欢迎加入 `QQ` 交流群:
|
||||
群1(已满):`699734691`
|
||||
群2(已满):`778239129`
|
||||
群3:`960265313`
|
||||
|
||||
查看 [问题反馈](https://jin-yufeng.github.io/mp-html/#/question/feedback) 了解更多
|
||||
|
||||
@@ -1,3 +1,71 @@
|
||||
## v2.5.1(2025-04-20)
|
||||
1. `U` 适配鸿蒙 `APP` [详细](https://github.com/jin-yufeng/mp-html/issues/615)
|
||||
2. `U` 微信小程序替换废弃 `api` `getSystemInfoSync` [详细](https://github.com/jin-yufeng/mp-html/issues/613)
|
||||
3. `F` 修复了 `app` 端播放视频可能报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/617)
|
||||
4. `F` 修复了 `latex` 插件可能出现 `xxx can be used only in display mode` 的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/632)
|
||||
5. `F` 修复了 `uni-app` 包 `latex` 公式可能不显示的问题 [#599](https://github.com/jin-yufeng/mp-html/issues/599)、[#627](https://github.com/jin-yufeng/mp-html/issues/627)
|
||||
## v2.5.0(2024-04-22)
|
||||
1. `U` `play` 事件增加返回 `src` 等信息 [详细](https://github.com/jin-yufeng/mp-html/issues/526)
|
||||
2. `U` `preview-img` 属性支持设置为 `all` 开启 `base64` 图片预览 [详细](https://github.com/jin-yufeng/mp-html/issues/536)
|
||||
3. `U` `editable` 插件增加简易模式(点击文字直接编辑)
|
||||
4. `U` `latex` 插件支持块级公式 [详细](https://github.com/jin-yufeng/mp-html/issues/582)
|
||||
5. `F` 修复了表格部分情况下背景丢失的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/587)
|
||||
6. `F` 修复了部分 `svg` 无法显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/591)
|
||||
7. `F` 修复了 `h5` 和 `app` 端部分情况下样式无法识别的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/518)
|
||||
8. `F` 修复了 `latex` 插件部分情况下显示不正确的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/580)
|
||||
9. `F` 修复了 `editable` 插件表格无法删除的问题
|
||||
10. `F` 修复了 `editable` 插件 `vue3` `h5` 端点击图片报错的问题
|
||||
11. `F` 修复了 `editable` 插件点击表格没有菜单栏的问题
|
||||
## v2.4.3(2024-01-21)
|
||||
1. `A` 增加 [card](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#card) 插件 [详细](https://github.com/jin-yufeng/mp-html/pull/533) by [@whoooami](https://github.com/whoooami)
|
||||
2. `F` 修复了 `svg` 中包含 `foreignobject` 可能不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/523)
|
||||
3. `F` 修复了合并单元格的表格部分情况下显示不正确的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/561)
|
||||
4. `F` 修复了 `img` 标签设置 `object-fit` 无效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/567)
|
||||
5. `F` 修复了 `latex` 插件公式会换行的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/540)
|
||||
6. `F` 修复了 `editable` 和 `audio` 插件共用时点击 `audio` 无法编辑的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/529) by [@whoooami](https://github.com/whoooami)
|
||||
7. `F` 修复了微信小程序部分情况下图片会报错 `replace of undefined` 的问题
|
||||
8. `F` 修复了快手小程序图片不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/571)
|
||||
## v2.4.2(2023-05-14)
|
||||
1. `A` `editable` 插件支持修改文字颜色 [详细](https://github.com/jin-yufeng/mp-html/issues/254)
|
||||
2. `F` 修复了 `svg` 中有 `style` 不生效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/505)
|
||||
3. `F` 修复了使用旧版编译器可能报错 `Bad attr nodes` 的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/472)
|
||||
4. `F` 修复了 `app` 端可能出现无法读取 `lazyLoad` 的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/513)
|
||||
5. `F` 修复了 `editable` 插件在点击换图时未拼接 `domain` 的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/497) by [@TwoKe945](https://github.com/TwoKe945)
|
||||
6. `F` 修复了 `latex` 插件部分情况下不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/515)
|
||||
7. `F` 修复了 `editable` 插件点击音视频时其他标签框不消失的问题
|
||||
## v2.4.1(2022-12-25)
|
||||
1. `F` 修复了没有图片时 `ready` 事件可能不触发的问题
|
||||
2. `F` 修复了加载过程中可能出现 `Root label not found` 错误的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/470)
|
||||
3. `F` 修复了 `audio` 插件退出页面可能会报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/457)
|
||||
4. `F` 修复了 `vue3` 运行到 `app` 在 `HBuilder X 3.6.10` 以上报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/480)
|
||||
5. `F` 修复了 `nvue` 端链接中包含 `%22` 时可能无法显示的问题
|
||||
6. `F` 修复了 `vue3` 使用 `highlight` 插件可能报错的问题
|
||||
## v2.4.0(2022-08-27)
|
||||
1. `A` 增加了 [setPlaybackRate](https://jin-yufeng.gitee.io/mp-html/#/advanced/api#setPlaybackRate) 的 `api`,可以设置音视频的播放速率 [详细](https://github.com/jin-yufeng/mp-html/issues/452)
|
||||
2. `A` 示例小程序代码开源 [详细](https://github.com/jin-yufeng/mp-html-demo)
|
||||
3. `U` 优化 `ready` 事件触发时机,未设置懒加载的情况下基本可以准确触发 [详细](https://github.com/jin-yufeng/mp-html/issues/195)
|
||||
4. `U` `highlight` 插件在编辑状态下不进行高亮处理,便于编辑
|
||||
5. `F` 修复了 `flex` 布局下图片大小可能不正确的问题
|
||||
6. `F` 修复了 `selectable` 属性没有设置 `force` 也可能出现渲染异常的问题
|
||||
7. `F` 修复了表格中的图片大小可能不正确的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/448)
|
||||
8. `F` 修复了含有合并单元格的表格可能无法设置竖直对齐的问题
|
||||
9. `F` 修复了 `editable` 插件在 `scroll-view` 中使用时工具条位置可能不正确的问题
|
||||
10. `F` 修复了 `vue3` 使用 [search](advanced/plugin#search) 插件可能导致错误换行的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/449)
|
||||
## v2.3.2(2022-08-13)
|
||||
1. `A` 增加 [latex](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#latex) 插件,可以渲染数学公式 [详细](https://github.com/jin-yufeng/mp-html/pull/447) by [@Zeng-J](https://github.com/Zeng-J)
|
||||
2. `U` 优化根节点下有很多标签的长内容渲染速度
|
||||
3. `U` `highlight` 插件适配 `lang-xxx` 格式
|
||||
4. `F` 修复了 `table` 标签设置 `border` 属性后可能无法修改边框样式的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/439) by [@zouxingjie](https://github.com/zouxingjie)
|
||||
5. `F` 修复了 `editable` 插件输入连续空格无效的问题
|
||||
6. `F` 修复了 `vue3` 图片设置 `inline` 会报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/438)
|
||||
7. `F` 修复了 `vue3` 使用 `table` 可能报错的问题
|
||||
## v2.3.1(2022-05-20)
|
||||
1. `U` `app` 端支持使用本地图片
|
||||
2. `U` 优化了微信小程序 `selectable` 属性在 `ios` 端的处理 [详细](https://jin-yufeng.gitee.io/mp-html/#/basic/prop#selectable)
|
||||
3. `F` 修复了 `editable` 插件不在顶部时 `tooltip` 位置可能错误的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/430)
|
||||
4. `F` 修复了 `vue3` 运行到微信小程序可能报错丢失内容的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/414)
|
||||
5. `F` 修复了 `vue3` 部分标签可能被错误换行的问题
|
||||
6. `F` 修复了 `editable` 插件 `app` 端插入视频无法预览的问题
|
||||
## v2.3.0(2022-04-01)
|
||||
1. `A` 增加了 `play` 事件,音视频播放时触发,可用于与页面其他音视频进行互斥播放 [详细](basic/event#play)
|
||||
2. `U` `show-img-menu` 属性支持控制预览时是否长按弹出菜单
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<view id="_root" :class="(selectable?'_select ':'')+'_root'" :style="containerStyle">
|
||||
<slot v-if="!nodes[0]" />
|
||||
<!-- #ifndef APP-PLUS-NVUE -->
|
||||
<node v-else :childs="nodes" :opts="[lazyLoad,loadingImg,errorImg,showImgMenu]" name="span" />
|
||||
<node v-else :childs="nodes" :opts="[lazyLoad,loadingImg,errorImg,showImgMenu,selectable]" name="span" />
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP-PLUS-NVUE -->
|
||||
<web-view ref="web" src="/uni_modules/mp-html/static/app-plus/mp-html/local.html" :style="'margin-top:-2px;height:' + height + 'px'" @onPostMessage="_onMessage" />
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
<script>
|
||||
/**
|
||||
* mp-html v2.3.0
|
||||
* mp-html v2.5.1
|
||||
* @description 富文本组件
|
||||
* @tutorial https://github.com/jin-yufeng/mp-html
|
||||
* @property {String} container-style 容器的样式
|
||||
@@ -128,7 +128,6 @@ export default {
|
||||
},
|
||||
beforeDestroy () {
|
||||
this._hook('onDetached')
|
||||
clearInterval(this._timer)
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
@@ -284,6 +283,28 @@ export default {
|
||||
// #endif
|
||||
},
|
||||
|
||||
/**
|
||||
* @description 设置媒体播放速率
|
||||
* @param {Number} rate 播放速率
|
||||
*/
|
||||
setPlaybackRate (rate) {
|
||||
this.playbackRate = rate
|
||||
for (let i = (this._videos || []).length; i--;) {
|
||||
this._videos[i].playbackRate(rate)
|
||||
}
|
||||
// #ifdef APP-PLUS
|
||||
const command = 'for(var e=document.getElementsByTagName("video"),i=e.length;i--;)e[i].playbackRate=' + rate
|
||||
// #ifndef APP-PLUS-NVUE
|
||||
let page = this.$parent
|
||||
while (!page.$scope) page = page.$parent
|
||||
page.$scope.$getAppWebview().evalJS(command)
|
||||
// #endif
|
||||
// #ifdef APP-PLUS-NVUE
|
||||
this.$refs.web.evalJs(command)
|
||||
// #endif
|
||||
// #endif
|
||||
},
|
||||
|
||||
/**
|
||||
* @description 设置内容
|
||||
* @param {String} content html 内容
|
||||
@@ -308,19 +329,32 @@ export default {
|
||||
this.$emit('load')
|
||||
})
|
||||
|
||||
// 等待图片加载完毕
|
||||
let height
|
||||
clearInterval(this._timer)
|
||||
this._timer = setInterval(() => {
|
||||
this.getRect().then(rect => {
|
||||
if (this.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.$emit('ready', rect)
|
||||
clearInterval(this._timer)
|
||||
} else {
|
||||
height = rect.height
|
||||
setTimeout(() => {
|
||||
this.getRect().then(callback).catch(callback)
|
||||
}, 350)
|
||||
}
|
||||
height = rect.height
|
||||
}).catch(() => { })
|
||||
}, 350)
|
||||
}
|
||||
this.getRect().then(callback).catch(callback)
|
||||
} else {
|
||||
// 未设置懒加载,等待所有图片加载完毕
|
||||
if (!this.imgList._unloadimgs) {
|
||||
this.getRect().then(rect => {
|
||||
this.$emit('ready', rect)
|
||||
}).catch(() => {
|
||||
this.$emit('ready', {})
|
||||
})
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
|
||||
@@ -340,7 +374,7 @@ export default {
|
||||
* @description 设置内容
|
||||
*/
|
||||
_set (nodes, append) {
|
||||
this.$refs.web.evalJs('setContent(' + JSON.stringify(nodes) + ',' + JSON.stringify([this.containerStyle.replace(/(?:margin|padding)[^;]+/g, ''), this.errorImg, this.loadingImg, this.pauseVideo, this.scrollTable, this.selectable]) + ',' + append + ')')
|
||||
this.$refs.web.evalJs('setContent(' + JSON.stringify(nodes).replace(/%22/g, '') + ',' + JSON.stringify([this.containerStyle.replace(/(?:margin|padding)[^;]+/g, ''), this.errorImg, this.loadingImg, this.pauseVideo, this.scrollTable, this.selectable]) + ',' + append + ')')
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -366,7 +400,9 @@ export default {
|
||||
case 'onReady':
|
||||
this.getRect().then(res => {
|
||||
this.$emit('ready', res)
|
||||
}).catch(() => { })
|
||||
}).catch(() => {
|
||||
this.$emit('ready', {})
|
||||
})
|
||||
break
|
||||
// 总高度发生变化
|
||||
case 'onHeightChange':
|
||||
|
||||
@@ -3,20 +3,33 @@
|
||||
<block v-for="(n, i) in childs" v-bind:key="i">
|
||||
<!-- 图片 -->
|
||||
<!-- 占位图 -->
|
||||
<image v-if="n.name==='img'&&((opts[1]&&!ctrl[i])||ctrl[i]<0)" class="_img" :style="n.attrs.style" :src="ctrl[i]<0?opts[2]:opts[1]" mode="widthFix" />
|
||||
<image v-if="n.name==='img'&&!n.t&&((opts[1]&&!ctrl[i])||ctrl[i]<0)" class="_img" :style="n.attrs.style" :src="ctrl[i]<0?opts[2]:opts[1]" mode="widthFix" />
|
||||
<!-- 显示图片 -->
|
||||
<!-- #ifdef H5 || (APP-PLUS && VUE2) -->
|
||||
<img v-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 || APP-PLUS -->
|
||||
<image v-if="n.name==='img'" :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':'')" :lazy-load="opts[0]" :webp="n.webp" :show-menu-by-longpress="opts[3]&&!n.attrs.ignore" :image-menu-prevent="!opts[3]||n.attrs.ignore" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
|
||||
<!-- #ifndef H5 || (APP-PLUS && VUE2) -->
|
||||
<!-- 表格中的图片,使用 rich-text 防止大小不正确 -->
|
||||
<rich-text v-if="n.name==='img'&&n.t" :style="'display:'+n.t" :nodes="[{attrs:{style:n.attrs.style||'',src:n.attrs.src},name:'img'}]" :data-i="i" @tap.stop="imgTap" />
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP-HARMONY -->
|
||||
<image v-else-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+ctrl[i]+'px;'+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :mode="!n.h?'widthFix':(!n.w?'heightFix':(n.m||'scaleToFill'))" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 || APP-PLUS || MP-KUAISHOU -->
|
||||
<image v-else-if="n.name==='img'" :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]" :webp="n.webp" :show-menu-by-longpress="opts[3]&&!n.attrs.ignore" :image-menu-prevent="!opts[3]||n.attrs.ignore" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP-KUAISHOU -->
|
||||
<image v-else-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+n.attrs.style" :src="n.attrs.src" :lazy-load="opts[0]" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap"></image>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP-PLUS && VUE3 -->
|
||||
<image v-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;'+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :mode="!n.h?'widthFix':(!n.w?'heightFix':'')" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
|
||||
<image v-else-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;'+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :mode="!n.h?'widthFix':(!n.w?'heightFix':(n.m||''))" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
|
||||
<!-- #endif -->
|
||||
<!-- 文本 -->
|
||||
<!-- #ifndef MP-BAIDU || MP-ALIPAY || MP-TOUTIAO -->
|
||||
<text v-else-if="n.text" :user-select="n.us" decode>{{n.text}}</text>
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<text v-else-if="n.text" :user-select="opts[4]=='force'&&isiOS" decode>{{n.text}}</text>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef MP-WEIXIN || MP-BAIDU || MP-ALIPAY || MP-TOUTIAO -->
|
||||
<text v-else-if="n.text" decode>{{n.text}}</text>
|
||||
<!-- #endif -->
|
||||
<text v-else-if="n.name==='br'">\n</text>
|
||||
<!-- 链接 -->
|
||||
@@ -25,7 +38,7 @@
|
||||
</view>
|
||||
<!-- 视频 -->
|
||||
<!-- #ifdef APP-PLUS -->
|
||||
<view v-else-if="n.html" :id="n.attrs.id" :class="'_video '+n.attrs.class" :style="n.attrs.style" v-html="n.html" @vplay.stop="play" />
|
||||
<view v-else-if="n.html" :id="n.attrs.id" :class="'_video '+n.attrs.class" :style="n.attrs.style" v-html="n.html" :data-i="i" @vplay.stop="play" />
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef APP-PLUS -->
|
||||
<video v-else-if="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" @play="play" @error="mediaError" />
|
||||
@@ -57,10 +70,10 @@
|
||||
|
||||
<!-- 富文本 -->
|
||||
<!-- #ifdef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
|
||||
<rich-text v-else-if="!n.c&&!handler.isInline(n.name, n.attrs.style)" :id="n.attrs.id" :style="n.f" :nodes="[n]" />
|
||||
<rich-text v-else-if="!n.c&&!handler.isInline(n.name, n.attrs.style)" :id="n.attrs.id" :style="n.f" :user-select="opts[4]" :nodes="[n]" />
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
|
||||
<rich-text v-else-if="!n.c" :id="n.attrs.id" :style="n.f+';display:inline'" :preview="false" :nodes="[n]" />
|
||||
<rich-text v-else-if="!n.c" :id="n.attrs.id" :style="'display:inline;'+n.f" :preview="false" :selectable="opts[4]" :user-select="opts[4]" :nodes="[n]" />
|
||||
<!-- #endif -->
|
||||
<!-- 继续递归 -->
|
||||
<view v-else-if="n.c===2" :id="n.attrs.id" :class="'_block _'+n.name+' '+n.attrs.class" :style="n.f+';'+n.attrs.style">
|
||||
@@ -113,7 +126,10 @@ export default {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
ctrl: {}
|
||||
ctrl: {},
|
||||
// #ifdef MP-WEIXIN
|
||||
isiOS: uni.getSystemInfoSync().system.includes('iOS')
|
||||
// #endif
|
||||
}
|
||||
},
|
||||
props: {
|
||||
@@ -129,7 +145,7 @@ export default {
|
||||
},
|
||||
components: {
|
||||
|
||||
// #ifndef H5 && VUE3
|
||||
// #ifndef ((H5 || APP-PLUS) && VUE3) || APP-HARMONY
|
||||
node
|
||||
// #endif
|
||||
},
|
||||
@@ -167,14 +183,22 @@ export default {
|
||||
},
|
||||
methods:{
|
||||
// #ifdef MP-WEIXIN
|
||||
toJSON () { },
|
||||
toJSON () { return this },
|
||||
// #endif
|
||||
/**
|
||||
* @description 播放视频事件
|
||||
* @param {Event} e
|
||||
*/
|
||||
play (e) {
|
||||
this.root.$emit('play')
|
||||
const i = e.currentTarget.dataset.i
|
||||
const node = this.childs[i]
|
||||
this.root.$emit('play', {
|
||||
source: node.name,
|
||||
attrs: {
|
||||
...node.attrs,
|
||||
src: node.src[this.ctrl[i] || 0]
|
||||
}
|
||||
})
|
||||
// #ifndef APP-PLUS
|
||||
if (this.root.pauseVideo) {
|
||||
let flag = false
|
||||
@@ -194,6 +218,9 @@ export default {
|
||||
// #endif
|
||||
)
|
||||
ctx.id = id
|
||||
if (this.root.playbackRate) {
|
||||
ctx.playbackRate(this.root.playbackRate)
|
||||
}
|
||||
this.root._videos.push(ctx)
|
||||
}
|
||||
}
|
||||
@@ -214,7 +241,14 @@ export default {
|
||||
// #ifdef H5 || APP-PLUS
|
||||
node.attrs.src = node.attrs.src || node.attrs['data-src']
|
||||
// #endif
|
||||
// #ifndef APP-HARMONY
|
||||
this.root.$emit('imgtap', node.attrs)
|
||||
// #endif
|
||||
// #ifdef APP-HARMONY
|
||||
this.root.$emit('imgtap', {
|
||||
...node.attrs
|
||||
})
|
||||
// #endif
|
||||
// 自动预览图片
|
||||
if (this.root.previewImg) {
|
||||
uni.previewImage({
|
||||
@@ -279,6 +313,25 @@ export default {
|
||||
// 加载完毕,取消加载中占位图
|
||||
this.$set(this.ctrl, i, 1)
|
||||
}
|
||||
this.checkReady()
|
||||
},
|
||||
|
||||
/**
|
||||
* @description 检查是否所有图片加载完毕
|
||||
*/
|
||||
checkReady () {
|
||||
if (this.root && !this.root.lazyLoad) {
|
||||
this.root._unloadimgs -= 1
|
||||
if (!this.root._unloadimgs) {
|
||||
setTimeout(() => {
|
||||
this.root.getRect().then(rect => {
|
||||
this.root.$emit('ready', rect)
|
||||
}).catch(() => {
|
||||
this.root.$emit('ready', {})
|
||||
})
|
||||
}, 350)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -355,6 +408,7 @@ export default {
|
||||
if (this.opts[2]) {
|
||||
this.$set(this.ctrl, i, -1)
|
||||
}
|
||||
this.checkReady()
|
||||
}
|
||||
if (this.root) {
|
||||
this.root.$emit('error', {
|
||||
|
||||
@@ -71,16 +71,24 @@ const config = {
|
||||
viewbox: 'viewBox',
|
||||
attributename: 'attributeName',
|
||||
repeatcount: 'repeatCount',
|
||||
repeatdur: 'repeatDur'
|
||||
repeatdur: 'repeatDur',
|
||||
foreignobject: 'foreignObject'
|
||||
}
|
||||
}
|
||||
const tagSelector={}
|
||||
const {
|
||||
windowWidth,
|
||||
let windowWidth, system
|
||||
// #ifdef MP-WEIXIN
|
||||
if (uni.canIUse('getWindowInfo')) {
|
||||
windowWidth = uni.getWindowInfo().windowWidth
|
||||
system = uni.getDeviceInfo().system
|
||||
} else {
|
||||
// #endif
|
||||
const systemInfo = uni.getSystemInfoSync()
|
||||
windowWidth = systemInfo.windowWidth
|
||||
// #ifdef MP-WEIXIN
|
||||
system
|
||||
// #endif
|
||||
} = uni.getSystemInfoSync()
|
||||
system = systemInfo.system
|
||||
}
|
||||
// #endif
|
||||
const blankChar = makeMap(' ,\r,\n,\t,\f')
|
||||
let idIndex = 0
|
||||
|
||||
@@ -138,6 +146,26 @@ function decodeEntity (str, amp) {
|
||||
return str
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 合并多个块级标签,加快长内容渲染
|
||||
* @param {Array} nodes 要合并的标签数组
|
||||
*/
|
||||
function mergeNodes (nodes) {
|
||||
let i = nodes.length - 1
|
||||
for (let j = i; j >= -1; j--) {
|
||||
if (j === -1 || nodes[j].c || !nodes[j].name || (nodes[j].name !== 'div' && nodes[j].name !== 'p' && nodes[j].name[0] !== 'h') || (nodes[j].attrs.style || '').includes('inline')) {
|
||||
if (i - j >= 5) {
|
||||
nodes.splice(j + 1, i - j, {
|
||||
name: 'div',
|
||||
attrs: {},
|
||||
children: nodes.slice(j + 1, i + 1)
|
||||
})
|
||||
}
|
||||
i = j - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description html 解析器
|
||||
* @param {Object} vm 组件实例
|
||||
@@ -146,6 +174,7 @@ function Parser (vm) {
|
||||
this.options = vm || {}
|
||||
this.tagStyle = Object.assign({}, config.tagStyle, this.options.tagStyle)
|
||||
this.imgList = vm.imgList || []
|
||||
this.imgList._unloadimgs = 0
|
||||
this.plugins = vm.plugins || []
|
||||
this.attrs = Object.create(null)
|
||||
this.stack = []
|
||||
@@ -170,6 +199,9 @@ Parser.prototype.parse = function (content) {
|
||||
while (this.stack.length) {
|
||||
this.popNode()
|
||||
}
|
||||
if (this.nodes.length > 50) {
|
||||
mergeNodes(this.nodes)
|
||||
}
|
||||
return this.nodes
|
||||
}
|
||||
|
||||
@@ -214,9 +246,15 @@ Parser.prototype.getUrl = function (url) {
|
||||
} else if (domain) {
|
||||
// 否则补充整个域名
|
||||
url = domain + url
|
||||
}
|
||||
} else if (domain && !url.includes('data:') && !url.includes('://')) {
|
||||
url = domain + '/' + url
|
||||
} /* #ifdef APP-PLUS */ else {
|
||||
url = plus.io.convertLocalFileSystemURL(url)
|
||||
} /* #endif */
|
||||
} else if (!url.includes('data:') && !url.includes('://')) {
|
||||
if (domain) {
|
||||
url = domain + '/' + url
|
||||
} /* #ifdef APP-PLUS */ else {
|
||||
url = plus.io.convertLocalFileSystemURL(url)
|
||||
} /* #endif */
|
||||
}
|
||||
return url
|
||||
}
|
||||
@@ -291,6 +329,7 @@ Parser.prototype.onTagName = function (name) {
|
||||
this.tagName = this.xml ? name : name.toLowerCase()
|
||||
if (this.tagName === 'svg') {
|
||||
this.xml = (this.xml || 0) + 1 // svg 标签内大小写敏感
|
||||
config.ignoreTags.style = undefined // svg 标签内 style 可用
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,6 +340,12 @@ Parser.prototype.onTagName = function (name) {
|
||||
*/
|
||||
Parser.prototype.onAttrName = function (name) {
|
||||
name = this.xml ? name : name.toLowerCase()
|
||||
// #ifdef (VUE3 && (H5 || APP-PLUS)) || APP-PLUS-NVUE
|
||||
if (name.includes('?') || name.includes(';')) {
|
||||
this.attrName = undefined
|
||||
return
|
||||
}
|
||||
// #endif
|
||||
if (name.substr(0, 5) === 'data-') {
|
||||
if (name === 'data-src' && !this.attrs.src) {
|
||||
// data-src 自动转为 src
|
||||
@@ -427,7 +472,7 @@ Parser.prototype.onOpenTag = function (selfClose) {
|
||||
node.webp = 'T'
|
||||
}
|
||||
// data url 图片如果没有设置 original-src 默认为不可预览的小图片
|
||||
if (attrs.src.includes('data:') && !attrs['original-src']) {
|
||||
if (attrs.src.includes('data:') && this.options.previewImg !== 'all' && !attrs['original-src']) {
|
||||
attrs.ignore = 'T'
|
||||
}
|
||||
if (!attrs.ignore || node.webp || attrs.src.includes('cloud://')) {
|
||||
@@ -435,11 +480,18 @@ Parser.prototype.onOpenTag = function (selfClose) {
|
||||
const item = this.stack[i]
|
||||
if (item.name === 'a') {
|
||||
node.a = item.attrs
|
||||
break
|
||||
}
|
||||
if (item.name === 'table' && !node.webp && !attrs.src.includes('cloud://')) {
|
||||
if (!styleObj.display || styleObj.display.includes('inline')) {
|
||||
node.t = 'inline-block'
|
||||
} else {
|
||||
node.t = styleObj.display
|
||||
}
|
||||
styleObj.display = undefined
|
||||
}
|
||||
// #ifndef H5 || APP-PLUS
|
||||
const style = item.attrs.style || ''
|
||||
if (style.includes('flex:') && !style.includes('flex:0') && !style.includes('flex: 0') && (!styleObj.width || !styleObj.width.includes('%'))) {
|
||||
if (style.includes('flex:') && !style.includes('flex:0') && !style.includes('flex: 0') && (!styleObj.width || parseInt(styleObj.width) > 100)) {
|
||||
styleObj.width = '100% !important'
|
||||
styleObj.height = ''
|
||||
for (let j = i + 1; j < this.stack.length; j++) {
|
||||
@@ -483,6 +535,9 @@ Parser.prototype.onOpenTag = function (selfClose) {
|
||||
}
|
||||
// #endif
|
||||
this.imgList.push(src)
|
||||
if (!node.t) {
|
||||
this.imgList._unloadimgs += 1
|
||||
}
|
||||
// #ifdef H5 || APP-PLUS
|
||||
if (this.options.lazyLoad) {
|
||||
attrs['data-src'] = attrs.src
|
||||
@@ -511,6 +566,13 @@ Parser.prototype.onOpenTag = function (selfClose) {
|
||||
if (!isNaN(parseInt(styleObj.height)) && (!styleObj.height.includes('%') || (parent && (parent.attrs.style || '').includes('height')))) {
|
||||
node.h = 'T'
|
||||
}
|
||||
if (node.w && node.h && styleObj['object-fit']) {
|
||||
if (styleObj['object-fit'] === 'contain') {
|
||||
node.m = 'aspectFit'
|
||||
} else if (styleObj['object-fit'] === 'cover') {
|
||||
node.m = 'aspectFill'
|
||||
}
|
||||
}
|
||||
} else if (node.name === 'svg') {
|
||||
siblings.push(node)
|
||||
this.stack.push(node)
|
||||
@@ -523,6 +585,11 @@ Parser.prototype.onOpenTag = function (selfClose) {
|
||||
}
|
||||
}
|
||||
attrs.style = attrs.style.substr(1) || undefined
|
||||
// #ifdef (MP-WEIXIN || MP-QQ) && VUE3
|
||||
if (!attrs.style) {
|
||||
delete attrs.style
|
||||
}
|
||||
// #endif
|
||||
} else {
|
||||
if ((node.name === 'pre' || ((attrs.style || '').includes('white-space') && attrs.style.includes('pre'))) && this.pre !== 2) {
|
||||
this.pre = node.pre = 1
|
||||
@@ -556,8 +623,8 @@ Parser.prototype.onCloseTag = function (name) {
|
||||
siblings.push({
|
||||
name,
|
||||
attrs: {
|
||||
class: tagSelector[name],
|
||||
style: this.tagStyle[name]
|
||||
class: tagSelector[name] || '',
|
||||
style: this.tagStyle[name] || ''
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -632,11 +699,19 @@ Parser.prototype.popNode = function () {
|
||||
return
|
||||
}
|
||||
const name = config.svgDict[node.name] || node.name
|
||||
if (name === 'foreignObject') {
|
||||
for (const child of (node.children || [])) {
|
||||
if (child.attrs && !child.attrs.xmlns) {
|
||||
child.attrs.xmlns = 'http://www.w3.org/1999/xhtml'
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
src += '<' + name
|
||||
for (const item in node.attrs) {
|
||||
const val = node.attrs[item]
|
||||
if (val) {
|
||||
src += ` ${config.svgDict[item] || item}="${val}"`
|
||||
src += ` ${config.svgDict[item] || item}="${val.replace(/"/g, '')}"`
|
||||
}
|
||||
}
|
||||
if (!node.children) {
|
||||
@@ -658,6 +733,7 @@ Parser.prototype.popNode = function () {
|
||||
node.children = undefined
|
||||
// #endif
|
||||
this.xml = false
|
||||
config.ignoreTags.style = true
|
||||
return
|
||||
}
|
||||
|
||||
@@ -777,6 +853,8 @@ Parser.prototype.popNode = function () {
|
||||
let padding = parseFloat(attrs.cellpadding)
|
||||
let spacing = parseFloat(attrs.cellspacing)
|
||||
const border = parseFloat(attrs.border)
|
||||
const bordercolor = styleObj['border-color']
|
||||
const borderstyle = styleObj['border-style']
|
||||
if (node.c) {
|
||||
// padding 和 spacing 默认 2
|
||||
if (isNaN(padding)) {
|
||||
@@ -787,11 +865,15 @@ Parser.prototype.popNode = function () {
|
||||
}
|
||||
}
|
||||
if (border) {
|
||||
attrs.style += ';border:' + border + 'px solid gray'
|
||||
attrs.style += `;border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'}`
|
||||
}
|
||||
if (node.flag && node.c) {
|
||||
// 有 colspan 或 rowspan 且含有链接的表格通过 grid 布局实现
|
||||
styleObj.display = 'grid'
|
||||
if (styleObj['border-collapse'] === 'collapse') {
|
||||
styleObj['border-collapse'] = undefined
|
||||
spacing = 0
|
||||
}
|
||||
if (spacing) {
|
||||
styleObj['grid-gap'] = spacing + 'px'
|
||||
styleObj.padding = spacing + 'px'
|
||||
@@ -809,6 +891,23 @@ Parser.prototype.popNode = function () {
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
if (nodes[i].name === 'tr') {
|
||||
trList.push(nodes[i])
|
||||
} else if (nodes[i].name === 'colgroup') {
|
||||
let colI = 1
|
||||
for (const col of (nodes[i].children || [])) {
|
||||
if (col.name === 'col') {
|
||||
const style = col.attrs.style || ''
|
||||
const start = style.indexOf('width') ? style.indexOf(';width') : 0
|
||||
// 提取出宽度
|
||||
if (start !== -1) {
|
||||
let end = style.indexOf(';', start + 6)
|
||||
if (end === -1) {
|
||||
end = style.length
|
||||
}
|
||||
width[colI] = style.substring(start ? start + 7 : 6, end)
|
||||
}
|
||||
colI += 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
traversal(nodes[i].children || [])
|
||||
}
|
||||
@@ -825,7 +924,7 @@ Parser.prototype.popNode = function () {
|
||||
col++
|
||||
}
|
||||
let style = td.attrs.style || ''
|
||||
const start = style.indexOf('width') ? style.indexOf(';width') : 0
|
||||
let start = style.indexOf('width') ? style.indexOf(';width') : 0
|
||||
// 提取出 td 的宽度
|
||||
if (start !== -1) {
|
||||
let end = style.indexOf(';', start + 6)
|
||||
@@ -837,7 +936,30 @@ Parser.prototype.popNode = function () {
|
||||
}
|
||||
style = style.substr(0, start) + style.substr(end)
|
||||
}
|
||||
style += (border ? `;border:${border}px solid gray` + (spacing ? '' : ';border-right:0;border-bottom:0') : '') + (padding ? `;padding:${padding}px` : '')
|
||||
// 设置竖直对齐
|
||||
style += ';display:flex'
|
||||
start = style.indexOf('vertical-align')
|
||||
if (start !== -1) {
|
||||
const val = style.substr(start + 15, 10)
|
||||
if (val.includes('middle')) {
|
||||
style += ';align-items:center'
|
||||
} else if (val.includes('bottom')) {
|
||||
style += ';align-items:flex-end'
|
||||
}
|
||||
} else {
|
||||
style += ';align-items:center'
|
||||
}
|
||||
// 设置水平对齐
|
||||
start = style.indexOf('text-align')
|
||||
if (start !== -1) {
|
||||
const val = style.substr(start + 11, 10)
|
||||
if (val.includes('center')) {
|
||||
style += ';justify-content: center'
|
||||
} else if (val.includes('right')) {
|
||||
style += ';justify-content: right'
|
||||
}
|
||||
}
|
||||
style = (border ? `;border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'}` + (spacing ? '' : ';border-right:0;border-bottom:0') : '') + (padding ? `;padding:${padding}px` : '') + ';' + style
|
||||
// 处理列合并
|
||||
if (td.attrs.colspan) {
|
||||
style += `;grid-column-start:${col};grid-column-end:${col + parseInt(td.attrs.colspan)}`
|
||||
@@ -890,7 +1012,7 @@ Parser.prototype.popNode = function () {
|
||||
const td = nodes[i]
|
||||
if (td.name === 'th' || td.name === 'td') {
|
||||
if (border) {
|
||||
td.attrs.style = `border:${border}px solid gray;${td.attrs.style || ''}`
|
||||
td.attrs.style = `border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'};${td.attrs.style || ''}`
|
||||
}
|
||||
if (padding) {
|
||||
td.attrs.style = `padding:${padding}px;${td.attrs.style || ''}`
|
||||
@@ -912,11 +1034,26 @@ Parser.prototype.popNode = function () {
|
||||
node.children = [table]
|
||||
attrs = table.attrs
|
||||
}
|
||||
} else if ((node.name === 'tbody' || node.name === 'tr') && node.flag && node.c) {
|
||||
node.flag = undefined;
|
||||
(function traversal (nodes) {
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
if (nodes[i].name === 'td') {
|
||||
// 颜色样式设置给单元格避免丢失
|
||||
for (const style of ['color', 'background', 'background-color']) {
|
||||
if (styleObj[style]) {
|
||||
nodes[i].attrs.style = style + ':' + styleObj[style] + ';' + (nodes[i].attrs.style || '')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
traversal(nodes[i].children || [])
|
||||
}
|
||||
}
|
||||
})(children)
|
||||
} else if ((node.name === 'td' || node.name === 'th') && (attrs.colspan || attrs.rowspan)) {
|
||||
for (let i = this.stack.length; i--;) {
|
||||
if (this.stack[i].name === 'table') {
|
||||
if (this.stack[i].name === 'table' || this.stack[i].name === 'tbody' || this.stack[i].name === 'tr') {
|
||||
this.stack[i].flag = 1 // 指示含有合并单元格
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if (node.name === 'ruby') {
|
||||
@@ -941,18 +1078,20 @@ Parser.prototype.popNode = function () {
|
||||
}
|
||||
}
|
||||
} else if (node.c) {
|
||||
node.c = 2
|
||||
for (let i = node.children.length; i--;) {
|
||||
const child = node.children[i]
|
||||
// #ifdef (MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE3
|
||||
if (child.name && (config.inlineTags[child.name] || (child.attrs.style || '').includes('inline'))) {
|
||||
child.c = 1
|
||||
(function traversal (node) {
|
||||
node.c = 2
|
||||
for (let i = node.children.length; i--;) {
|
||||
const child = node.children[i]
|
||||
// #ifdef (MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE3
|
||||
if (child.name && (config.inlineTags[child.name] || ((child.attrs.style || '').includes('inline') && child.children)) && !child.c) {
|
||||
traversal(child)
|
||||
}
|
||||
// #endif
|
||||
if (!child.c || child.name === 'table') {
|
||||
node.c = 1
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
if (!child.c || child.name === 'table') {
|
||||
node.c = 1
|
||||
}
|
||||
}
|
||||
})(node)
|
||||
}
|
||||
|
||||
if ((styleObj.display || '').includes('flex') && !node.c) {
|
||||
@@ -977,22 +1116,8 @@ Parser.prototype.popNode = function () {
|
||||
node.f = ';max-width:100%'
|
||||
}
|
||||
|
||||
// 优化长内容加载速度
|
||||
if (children.length >= 50 && node.c && !(styleObj.display || '').includes('flex')) {
|
||||
let i = children.length - 1
|
||||
for (let j = i; j >= -1; j--) {
|
||||
// 合并多个块级标签
|
||||
if (j === -1 || children[j].c || !children[j].name || (children[j].name !== 'div' && children[j].name !== 'p' && children[j].name[0] !== 'h') || (children[j].attrs.style || '').includes('inline')) {
|
||||
if (i - j >= 5) {
|
||||
children.splice(j + 1, i - j, {
|
||||
name: 'div',
|
||||
attrs: {},
|
||||
children: node.children.slice(j + 1, i + 1)
|
||||
})
|
||||
}
|
||||
i = j - 1
|
||||
}
|
||||
}
|
||||
mergeNodes(children)
|
||||
}
|
||||
// #endif
|
||||
|
||||
@@ -1012,8 +1137,10 @@ Parser.prototype.popNode = function () {
|
||||
}
|
||||
attrs.style = attrs.style.substr(1) || undefined
|
||||
// #ifdef (MP-WEIXIN || MP-QQ) && VUE3
|
||||
if (!attrs.style) {
|
||||
delete attrs.style
|
||||
for (const key in attrs) {
|
||||
if (!attrs[key]) {
|
||||
delete attrs[key]
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
@@ -1040,7 +1167,15 @@ Parser.prototype.onText = function (text) {
|
||||
}
|
||||
}
|
||||
// 去除含有换行符的空串
|
||||
if (trim === ' ' && flag) return
|
||||
if (trim === ' ') {
|
||||
if (flag) return
|
||||
// #ifdef VUE3
|
||||
else {
|
||||
const parent = this.stack[this.stack.length - 1]
|
||||
if (parent && parent.name[0] === 't') return
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
text = trim
|
||||
}
|
||||
const node = Object.create(null)
|
||||
@@ -1051,9 +1186,8 @@ Parser.prototype.onText = function (text) {
|
||||
node.text = decodeEntity(text)
|
||||
if (this.hook(node)) {
|
||||
// #ifdef MP-WEIXIN
|
||||
if (this.options.selectable === 'force' && system.includes('iOS')) {
|
||||
if (this.options.selectable === 'force' && system.includes('iOS') && !uni.canIUse('rich-text.user-select')) {
|
||||
this.expose()
|
||||
node.us = 'T'
|
||||
}
|
||||
// #endif
|
||||
const siblings = this.stack.length ? this.stack[this.stack.length - 1].children : this.nodes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "mp-html",
|
||||
"displayName": "mp-html 富文本组件【全端支持,可编辑】",
|
||||
"version": "v2.3.0",
|
||||
"displayName": "mp-html 富文本组件【全端支持,支持编辑、latex等扩展】",
|
||||
"version": "v2.5.1",
|
||||
"description": "一个强大的富文本组件,高效轻量,功能丰富",
|
||||
"keywords": [
|
||||
"富文本",
|
||||
@@ -12,10 +12,6 @@
|
||||
],
|
||||
"repository": "https://github.com/jin-yufeng/mp-html",
|
||||
"dcloudext": {
|
||||
"category": [
|
||||
"前端组件",
|
||||
"通用组件"
|
||||
],
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
@@ -32,18 +28,22 @@
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/mp-html"
|
||||
"npmurl": "https://www.npmjs.com/package/mp-html",
|
||||
"type": "component-vue"
|
||||
},
|
||||
"uni_modules": {
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
"aliyun": "y",
|
||||
"alipay": "n"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y"
|
||||
"app-nvue": "y",
|
||||
"app-harmony": "u",
|
||||
"app-uvue": "u"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
|
||||
@@ -1 +1 @@
|
||||
"use strict";function t(t){for(var e=Object.create(null),n=t.attributes.length;n--;)e[t.attributes[n].name]=t.attributes[n].value;return e}function e(){o[1]&&(this.src=o[1],this.onerror=null),this.onclick=null,this.ontouchstart=null,uni.postMessage({data:{action:"onError",source:"img",attrs:t(this)}})}function n(r,i,s){for(var c=0;c<r.length;c++)!function(c){var u=r[c],l=void 0;if(u.type&&"node"!==u.type)l=document.createTextNode(u.text.replace(/&/g,"&"));else{var d=u.name;"svg"===d&&(s="http://www.w3.org/2000/svg"),"html"!==d&&"body"!==d||(d="div"),l=s?document.createElementNS(s,d):document.createElement(d);for(var g in u.attrs)l.setAttribute(g,u.attrs[g]);if(u.children&&n(u.children,l,s),"img"===d){if(!l.src&&l.getAttribute("data-src")&&(l.src=l.getAttribute("data-src")),u.attrs.ignore||(l.onclick=function(e){e.stopPropagation(),uni.postMessage({data:{action:"onImgTap",attrs:t(this)}})}),o[2]){var p=new Image;p.src=l.src,l.src=o[2],p.onload=function(){l.src=this.src},p.onerror=function(){l.onerror()}}l.onerror=e}else if("a"===d)l.addEventListener("click",function(e){e.stopPropagation(),e.preventDefault();var n,o=this.getAttribute("href");o&&"#"===o[0]&&(n=(document.getElementById(o.substr(1))||{}).offsetTop),uni.postMessage({data:{action:"onLinkTap",attrs:t(this),offset:n}})},!0);else if("video"===d||"audio"===d)a.push(l),u.attrs.autoplay||u.attrs.controls||l.setAttribute("controls","true"),l.onplay=function(){if(uni.postMessage({data:{action:"onPlay"}}),o[3])for(var t=0;t<a.length;t++)a[t]!==this&&a[t].pause()},l.onerror=function(){uni.postMessage({data:{action:"onError",source:d,attrs:t(this)}})};else if("table"===d&&o[4]&&!l.style.cssText.includes("inline")){var f=document.createElement("div");f.style.overflow="auto",f.appendChild(l),l=f}else"svg"===d&&(s=void 0)}i.appendChild(l)}(c)}document.addEventListener("UniAppJSBridgeReady",function(){document.body.onclick=function(){return uni.postMessage({data:{action:"onClick"}})},uni.postMessage({data:{action:"onJSBridgeReady"}})});var o,a=[];window.setContent=function(t,e,r){var i=document.getElementById("content");e[0]&&(document.body.style.cssText=e[0]),e[5]||(i.style.userSelect="none"),r||(i.innerHTML="",a=[]),o=e;var s=document.createDocumentFragment();n(t,s),i.appendChild(s);var c=i.scrollHeight;uni.postMessage({data:{action:"onLoad",height:c}}),clearInterval(window.timer);var u=!1;window.timer=setInterval(function(){i.scrollHeight!==c?(c=i.scrollHeight,uni.postMessage({data:{action:"onHeightChange",height:c}})):u||(u=!0,uni.postMessage({data:{action:"onReady"}}))},350)},window.onunload=function(){clearInterval(window.timer)};
|
||||
"use strict";function t(t){for(var e=Object.create(null),n=t.attributes.length;n--;)e[t.attributes[n].name]=t.attributes[n].value;return e}function e(){a[1]&&(this.src=a[1],this.onerror=null),this.onclick=null,this.ontouchstart=null,uni.postMessage({data:{action:"onError",source:"img",attrs:t(this)}})}function n(){window.unloadimgs-=1,0===window.unloadimgs&&uni.postMessage({data:{action:"onReady"}})}function o(r,s,c){for(var d=0;d<r.length;d++)!function(d){var u=r[d],l=void 0;if(u.type&&"node"!==u.type)l=document.createTextNode(u.text.replace(/&/g,"&"));else{var g=u.name;"svg"===g&&(c="http://www.w3.org/2000/svg"),"html"!==g&&"body"!==g||(g="div"),l=c?document.createElementNS(c,g):document.createElement(g);for(var p in u.attrs)l.setAttribute(p,u.attrs[p]);if(u.children&&o(u.children,l,c),"img"===g){if(window.unloadimgs+=1,l.onload=n,l.onerror=n,!l.src&&l.getAttribute("data-src")&&(l.src=l.getAttribute("data-src")),u.attrs.ignore||(l.onclick=function(e){e.stopPropagation(),uni.postMessage({data:{action:"onImgTap",attrs:t(this)}})}),a[2]){var h=new Image;h.src=l.src,l.src=a[2],h.onload=function(){l.src=this.src},h.onerror=function(){l.onerror()}}l.onerror=e}else if("a"===g)l.addEventListener("click",function(e){e.stopPropagation(),e.preventDefault();var n,o=this.getAttribute("href");o&&"#"===o[0]&&(n=(document.getElementById(o.substr(1))||{}).offsetTop),uni.postMessage({data:{action:"onLinkTap",attrs:t(this),offset:n}})},!0);else if("video"===g||"audio"===g)i.push(l),u.attrs.autoplay||u.attrs.controls||l.setAttribute("controls","true"),l.onplay=function(){if(uni.postMessage({data:{action:"onPlay"}}),a[3])for(var t=0;t<i.length;t++)i[t]!==this&&i[t].pause()},l.onerror=function(){uni.postMessage({data:{action:"onError",source:g,attrs:t(this)}})};else if("table"===g&&a[4]&&!l.style.cssText.includes("inline")){var f=document.createElement("div");f.style.overflow="auto",f.appendChild(l),l=f}else"svg"===g&&(c=void 0)}s.appendChild(l)}(d)}document.addEventListener("UniAppJSBridgeReady",function(){document.body.onclick=function(){return uni.postMessage({data:{action:"onClick"}})},uni.postMessage({data:{action:"onJSBridgeReady"}})});var a,i=[];window.setContent=function(t,e,n){var r=document.getElementById("content");e[0]&&(document.body.style.cssText=e[0]),e[5]||(r.style.userSelect="none"),n||(r.innerHTML="",i=[]),a=e,window.unloadimgs=0;var s=document.createDocumentFragment();o(t,s),r.appendChild(s);var c=r.scrollHeight;uni.postMessage({data:{action:"onLoad",height:c}}),window.unloadimgs||uni.postMessage({data:{action:"onReady",height:c}}),clearInterval(window.timer),window.timer=setInterval(function(){r.scrollHeight!==c&&(c=r.scrollHeight,uni.postMessage({data:{action:"onHeightChange",height:c}}))},350)},window.onunload=function(){clearInterval(window.timer)};
|
||||
Reference in New Issue
Block a user