移动端更新

This commit is contained in:
molong committed 2026-02-21 14:47:54 +08:00
1 parent 7f8e68bb0a
commit c0d27be99b
432 files changed
+100843

No files matched your search

View File
Whitespace-only changes.
+56
View File
@@ -0,0 +1,56 @@
# mp-html
> 一个强大的小程序富文本组件
![star](https://img.shields.io/github/stars/jin-yufeng/mp-html)
![forks](https://img.shields.io/github/forks/jin-yufeng/mp-html)
[![npm](https://img.shields.io/npm/v/mp-html)](https://www.npmjs.com/package/mp-html)
![downloads](https://img.shields.io/npm/dt/mp-html)
[![Coverage Status](https://coveralls.io/repos/github/jin-yufeng/mp-html/badge.svg?branch=master)](https://coveralls.io/github/jin-yufeng/mp-html?branch=master)
![license](https://img.shields.io/github/license/jin-yufeng/mp-html)
[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
## 📢 概况 :id=overview
显示动态 *html* 富文本是很多应用必要的需求,小程序平台不支持 *dom* 操作使得这成为一个难题,其自带的 *rich-text* 组件支持的标签少且屏蔽所有事件,难以实际应用。因此就有了这样一个能够便捷的在小程序平台上处理富文本的组件,还支持丰富的扩展功能。
## 📋 特性 :id=feature
- 支持在多个主流的小程序平台和 *uni-app* 中使用
- 支持丰富的标签(包括 *table*、*video*、*svg* 等)
- 支持丰富的事件效果(自动预览图片、链接处理等)
- 支持设置占位图(加载中、出错时、预览时)
- 支持锚点跳转、长按复制等丰富功能
- 支持大部分 *html* 实体
- 丰富的插件(关键词搜索、内容编辑、*latex* 公式 等)
- 效率高、容错性强且轻量化(*≈25KB*,*9KB gzipped*)
查看 [功能介绍](overview/feature) 了解更多
## 🎉 使用案例 :id=case
| [官方示例](https://github.com/jin-yufeng/mp-html-demo) | 欢喜商城 | 多么生活 | 食法查 | 微慕 | 科学复习 |
|:---:|:---:|:---:|:---:|:---:|:---:|
| ![富文本插件](assets/case/富文本插件.jpg) | ![欢喜商城](assets/case/欢喜商城.png) | ![多么生活](assets/case/多么生活.jpg) | ![食法查](assets/case/食法查.png) | ![微慕](assets/case/微慕.jpg) | ![科学复习](assets/case/科学复习.png) |
| [程序员技术之旅](https://github.com/fendoudebb/z-blog-wx) | 典典博客 | 优秀笔记 | 同城共享书 | [技术源 share](https://github.com/wangsrGit119/mini-blog-halo) | 你的代码写的真棒 |
|:---:|:---:|:---:|:---:|:---:|:---:|
| ![程序员技术之旅](assets/case/程序员技术之旅.jpg) | ![典典博客](assets/case/典典博客.jpg) | ![优秀笔记](assets/case/优秀笔记.jpg) | ![同城共享书](assets/case/同城共享书.jpg) | ![技术源share](assets/case/技术源share.jpg) | ![你的代码写的真棒](assets/case/你的代码写的真棒.jpg) |
| 谛否 | 小莫唐尼 | [模版演示](https://github.com/zhihuifanqiechaodan/miniprogram-template) | AI瓦力 | 豆流便签 | 前端八股通 |
|:---:|:---:|:---:|:---:|:---:|:---:|
| ![谛否](assets/case/谛否.jpg) | ![小莫唐尼](assets/case/小莫唐尼.png) | ![MiniProgram模版演示](assets/case/MiniProgram模版演示.jpg) | ![AI瓦力](assets/case/AI瓦力.jpg) | ![豆流便签](assets/case/豆流便签.jpg) | ![前端八股通](assets/case/前端八股通.jpg) |
以上排名不分先后,更多可见 [使用案例收集](https://github.com/jin-yufeng/mp-html/issues/27)(欢迎添加)
## 🎈 联系与支持 :id=sponsor
![group](assets/group.jpg)
![支持](assets/sponsor.png)
## 📃 许可 :id=license
[MIT License](https://github.com/jin-yufeng/mp-html/blob/master/LICENSE)
?> 您可以免费的使用(包括商用)、复制或修改本组件
!> 在用于生产环境前,务必进行仔细测试,由本组件 *bug* 带来的损失概不负责
---
Powered by docsify
+12
View File
@@ -0,0 +1,12 @@
![logo](assets/logo/logo.png)
# mp-html <small>2.5.2</small>
> 一个强大的小程序富文本组件
- 全面的标签支持
- 多平台使用支持
- 丰富的附加功能
[GitHub](https://github.com/jin-yufeng/mp-html)
[快速开始](/overview/quickstart)
+20
View File
@@ -0,0 +1,20 @@
- 概览
- [🚀 快速开始](overview/quickstart)
- [🎉 功能介绍](overview/feature)
- 基本使用
- [🔨 属性](basic/prop)
- [📫 事件](basic/event)
- 进阶使用
- [🔎 api](advanced/api)
- [📌 插件](advanced/plugin)
- [🔧 二次开发](advanced/develop)
- 疑问解答
- [📘 常见问题](question/faq)
- [📩 反馈](question/feedback)
- [📝 贡献指南](question/contribution)
- 更新日志
- [📖 更新日志](changelog/changelog)
+230
View File
@@ -0,0 +1,230 @@
# 🔎 api
组件的实例上挂载了一些实用的 *api* 方法可供调用
## 获取组件实例 :id=getCompent
- *uni-app*
```vue
<template>
<view>
<mp-html ref="article" />
</view>
</template>
<script>
export default {
onLoad () {
var ctx = this.$refs.article
}
}
</script>
```
- 支付宝小程序
需开启 [component2](https://opendocs.alipay.com/mini/framework/component-ref) 模式
```axml
<mp-html ref="article">
```
```javascript
Page({
article (ctx) {
// 获得组件实例
}
})
```
- 其他小程序平台
```wxml
<mp-html id="article" />
```
```javascript
Page({
onLoad () {
// 微信、QQ、百度
var ctx = this.selectComponent('#article')
// 头条
this.selectComponent('#article', ctx => {
})
}
})
```
## in
功能:将锚点跳转的范围限定在一个 *scroll-view*(需要开启纵向滚动)内
输入值:
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|:---:|:---:|:---:|:---:|---|
| page | object | 是 | - | scroll-view 标签所在页面实例 |
| selector | string | 是 | - | scroll-view 标签 的选择器 |
| scrollTop | string | 是 | - | scroll-view 标签 scrollTop 属性绑定的变量名 |
返回值:无
示例:
```wxml
<scroll-view id="scroll" style="height:300px" scroll-top="{{top}}" scroll-y scroll-with-animation>
<mp-html id="article" content="{{html}}" />
</scroll-view>
```
```javascript
Page({
onLoad () {
// ctx 为组件实例
ctx.in(this, '#scroll', 'top')
}
})
```
!> 在 *scroll-view* 中使用时需要注意如果使用了视频,需要保证该平台的 *video* 标签支持同层渲染
## navigateTo
功能:锚点跳转
前提是 [use-anchor](basic/prop#use-anchor) 属性的值为 *true*
必须在 [load](basic/event#load) 事件触发后使用,建议在 [ready](basic/event#ready) 事件触发后使用以保证跳转位置准确
输入值:
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|:---:|:---:|:---:|:---:|---|
| id | string | 否 | - | 要跳转的锚点 id,为空则跳转到开头 |
| offset | number | 否 | 0 | 跳转位置的偏移量 |
返回值:**Promise**
该方法中传入的 *offset* 优先级高于 [use-anchor](basic/prop#use-anchor) 属性
示例:
```javascript
Page({
ready () {
// ctx 为组件实例
ctx.navigateTo('anchor').then(() => {
console.log('跳转成功')
}).catch(err => {
console.log('跳转失败:', err)
})
}
})
```
## getText
功能:获取文本内容
必须在 [load](basic/event#load) 事件触发后使用
输入值:无
返回值:**String**
## getRect
功能:获取富文本内容的位置和大小
如果开启了 [lazy-load](basic/prop#lazy-load),[ready](basic/event#ready) 事件返回的不是最终大小,可通过此方法获得实时的大小和位置信息
输入值:无
返回值:**Promise**
示例:
```javascript
Page({
getRect () {
// ctx 为组件实例
ctx.getRect().then(rect => {
console.log(rect) // boundingClientRect 信息
}).catch(err => {
console.log('获取失败', err)
})
}
})
```
!> 该方法有小概率可能获取失败,需要做好错误处理
## setContent
功能:设置富文本内容
此方法的功能与 [content](basic/prop#content) 属性基本一致,但此方法的设置不需要经过视图层且可以从尾部追加
输入值:
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|:---:|:---:|:---:|:---:|---|
| content | string | 是 | - | 要渲染的 html 字符串 |
| append | boolean | 否 | false | 是否从尾部追加 |
返回值:无
!> 调用此方法会触发 [load](basic/event#load) 和 [ready](basic/event#ready) 事件,请勿在事件处理函数中调用,否则可能陷入死循环
## imgList
功能:获取所有图片的数组
该数组用于图片预览,对其进行修改可以在自动预览时生效(如修改为高清图链接或转存 *base64*)
!> 这是一个属性,不是一个函数
请不要增删此数组(可以修改),否则在自动预览时可能出现问题
```javascript
Page({
load () {
// ctx 为组件实例
var cover = ctx.imgList[0] // 首张图可以作为转发封面图
ctx.imgList.forEach((src, i, array) => {
console.log(src)
// 替换为高清图链接
array[i] = src.replace('thumb', '')
// 转存 base64 便于预览
var fs = wx.getFileSystemManager && wx.getFileSystemManager()
var info = src.match(/data:image\/(\S+?);(\S+?),(.+)/)
if (!info) return
var filePath = `${wx.env.USER_DATA_PATH}/${Date.now()}.${info[1]}`
fs && fs.writeFile({
filePath,
data: info[3],
encoding: info[2],
success: () => array[i] = filePath
})
})
}
})
```
## pauseMedia
?> [2.2.2](changelog/changelog#v222) 版本起支持
功能:暂停正在播放的视频或音频
?> 和 [play](basic/event#play) 事件配合可以实现与页面中其他音视频进行互斥播放
输入值:无
返回值:无
示例:
```javascript
Page({
onHide () {
// ctx 为组件实例
ctx.pauseMedia() // 页面跳转或隐藏时暂停播放
}
})
```
## setPlaybackRate
?> [2.4.0](changelog/changelog#v240) 版本起支持
功能:设置音视频的播放速率
输入值:
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|:---:|:---:|:---:|:---:|---|
| rate | number | 是 | - | 播放速率,一般支持 0.5~2.0 |
返回值:无
示例:
```javascript
Page({
// 点击设置速率按钮
setPlaybackRate () {
wx.showActionSheet({
itemList: ['0.5', '1.0', '1.25', '1.5', '2.0'],
success: res => {
const rate = [0.5, 1.0, 1.25, 1.5, 2.0][res.tapIndex]
// ctx 为组件实例
ctx.setPlaybackRate(rate)
}
})
}
})
```
+114
View File
@@ -0,0 +1,114 @@
# 二次开发 :id=develop
## 📣 说明 :id=notice
二次开发请在 *src* 目录下进行修改,修改完成后可通过下述方法自动生成各平台的代码包
为方便维护,本项目原生包多个平台共用一套源代码,在编写时直接按照微信端的写法进行编写即可,[生成代码包](#pack) 时会自动进行转换
自动转换已经抹平了大部分平台之间的差异(文件后缀名、*api* 格式等),需要注意的是 **访问组件的属性** 时,请通过 *this.properties* 访问而不是 *this.data*,因为在支付宝平台中两者不互通
个别问题可以自行修改 *tools/converter.js* 进行处理
附项目结构:
```
├─dev(生成的各平台示例项目)
├─dist(生成的各平台代码包)
│ ├─mp-alipay
│ ├─mp-baidu
│ ├─mp-qq
│ ├─mp-toutiao
│ ├─mp-weixin
│ └─uni-app
├─docs(文档,由 docsify 生成)
├─plugins(插件源代码)
├─src(组件源代码)
│ ├─miniprogram(原生包源代码)
│ └─uni-app(uni-app 包源代码)
├─test(测试代码)
├─tools(构建工具)
│ ├─demo(示例项目源代码)
│ │ ├─miniprogram(原生平台示例项目)
│ │ └─uni-app(uni-app 平台示例项目)
| ├─config.js(构建工具的配置项)
| ├─converter.js(将微信端的代码转换到各个平台)
| ├─ifdef.js(处理条件编译)
| ├─minifier.js(处理 json 和 wxs 的压缩)
| └─plugin.js(处理插件构建)
├─.eslintrc.json(eslint 配置)
├─.stylelintrc.json(stylelint 配置)
├─gulpfile.js(gulp 生成文件)
├─LICENSE(许可证 MIT)
└─package.json(项目配置)
```
?> 对于较复杂的修改,如果能通过 [编写插件](advanced/plugin#develop) 方式实现更推荐插件方式,这样在组件包升级的时候便于维护和管理
## 🎈 条件编译 :id=ifdef
不同平台之间一些差异的地方可能无法简单的通过替换解决,因此本项目中引入了一种条件编译机制解决平台差异,可在修改时加以利用(条件编译是指在生成包的过程中就仅保留本平台需要的代码,与运行过程中的 *if* 判断不同)
方式 *1*(适用于 *js*、*wxml*、*wxss* 文件)
仅在某平台下需要使用的代码放在两个注释(各种注释格式皆可)之间即可,示例:
```javascript
// #ifdef MP-WEIXIN
console.log('这是微信平台')
// #endif
// #ifndef MP-WEIXIN
console.log('这不是微信平台')
// #endif
```
方式 *2*(适用于 *wxml* 文件)
对于仅在某一平台使用的属性,可在属性名前加 *平台名:* ,示例:
```wxml
<!-- show-menu-by-longpress 属性将仅被生成到微信包中 -->
<image mp-weixin:show-menu-by-longpress="xxx" />
```
说明:
1. 可用的平台名称:*mp-weixin*, *mp-qq*, *mp-baidu*, *mp-alipay*, *mp-toutiao*(不区分大小写)
2. *#if(n)def* 和 *#endif* 必须成对出现,否则会报错(可以多层嵌套)
3. 如果编译过程中发现问题可以自行修改 *tools/ifdef.js* 进行处理
## 📦 生成组件包 :id=pack
修改完成后,可按以下步骤生成新的组件包
在 *mp-html* 文件夹下执行:
?> 以下命令需要在组件包根目录下执行,即包含 [package.json](https://github.com/jin-yufeng/mp-html/blob/master/package.json) 的目录(如果通过 *npm* 获取就是 *node_modules/mp-html*)
1. 安装依赖
```bash
# 通过 npm 安装
npm install
# 或通过 yarn 安装
yarn
```
2. 生成代码包到 *dist* 文件夹
```bash
# 生成微信包到 dist/mp-weixin
npm run build:weixin
# 生成 qq 包到 dist/mp-qq
npm run build:qq
# 生成百度包到 dist/mp-baidu
npm run build:baidu
# 生成支付宝包到 dist/mp-alipay
npm run build:alipay
# 生成头条包到 dist/mp-toutiao
npm run build:toutiao
# 生成 uni-app 包到 dist/uni-app
npm run build:uni-app
# 生成所有包
npm run build
```
?> 如需修改打包过程中的配置(*babel*, *uglifyJs* 等),可以对 *tools/config.js* 进行修改
## 🔦 检查和测试 :id=test
假设已安装好依赖
```bash
npm run lint # eslint 检查
npm run lintcss # stylelint 检查
npm run lintcss --fix # 检查并修复
npm run test # 执行 jest 测试
npm run coverage # 测试代码覆盖率
```
可以向 *test* 目录下添加新的测试用例进行测试
+488
View File
@@ -0,0 +1,488 @@
# 📌 插件 :id=plugin
> 可以在这里选择需要的插件以实现更加丰富的功能
## 使用插件 :id=use
!> 直接将插件文件夹拷贝到组件包中无法生效,请通过以下方式生成包含扩展的组件包
#### 小程序方式
!> 该方式暂不可用
?> 该方式适合不熟悉 *npm* 的用户
1. 通过 [小程序方式](overview/quickstart#mp) 获取包含扩展插件的组件包
2. 将下载的组件包解压,原生小程序复制到 *components* 目录下,*uni-app* 复制到项目根目录下,按照源码方式引入即可,详见 [引入方式](overview/quickstart#use)
#### npm 方式
1. 获取完整的组件包
通过 [npm](overview/quickstart#npm) 或 [git](overview/quickstart#git) 等方式获取 **包含完整项目** 的组件包(注意从 *uni-app* 的插件市场中导入的包中仅包含构建后的组件,**不包含** 构建工具和插件)
![step1](../assets/tutorials/01.png)
2. 选择需要的插件
参考下方插件使用说明,确定要使用的插件,将其名称填入 [tools/config.js](https://github.com/jin-yufeng/mp-html/blob/master/tools/config.js#L8) 中的 *plugins* 中
如果想仅在部分平台使用该插件,可以在该插件目录下的 *build.js* 的 *platform* 字段中填入需要的平台名称
![step2](../assets/tutorials/02.png)
3. 生成组件包
设置完成后,可通过项目提供的命令行工具生成新的组件包,具体见 [生成组件包](advanced/develop#pack)
![step3_1](../assets/tutorials/03.png)
![step3_2](../assets/tutorials/04.png)
4. 按照源码或 *npm* 方式引入构建后的组件包进行使用即可,详见 [引入方式](overview/quickstart#use)
## audio
功能:音乐播放器
大小:*≈4KB*
支持平台:
| 微信小程序 | QQ 小程序 | 百度小程序 | 支付宝小程序 | 头条小程序 | uni-app |
|:---:|:---:|:---:|:---:|:---:|:---:|
| √ | √ | √ | √ | √ | √(nvue 不支持) |
!> 百度小程序原生包在此 [问题](https://smartprogram.baidu.com/forum/topic/show/125787) 未解决前无法使用
说明:
在大多数小程序平台,*audio* 标签已被废弃或无法使用,本插件可以代替 *audio* 标签播放音乐,并实现以下优化:
1. [pause-video](basic/prop#pause-video) 属性也可以应用于音频,即播放一个音视频时可以自动暂停其他正在播放的音视频
2. 增加了一个可以拖动的进度条
3. 组件大小可以根据页面宽度自动调整
4. 支持 *autoplay* 属性
5. 播放被后台打断时,页面显示后自动继续播放
基础库要求:
支付宝 *1.23.4+* ,其余平台满足 [最低要求](question/faq#lib) 即可
第 *5* 条仅微信 *2.2.3+* 、*QQ*、百度支持
?> 如果希望页面上使用本组件,组件的路径为 *path/to/mp-html/audio/audio*
属性和事件基本同 *audio* 组件,组件实例上提供了 *setSrc*、*play*、*seek*、*pause*、*stop* 方法可供控制播放状态
## editable
功能:富文本编辑
下表列出了本插件与原生 *editor* 组件的功能差异,可按需选用
| 组件 | 优点 | 缺点 |
|:---:|:---:|:---:|
| 原生 *editor* | 底层通过 *contenteditable* 实现,编辑流畅 | 支持标签少(不支持音视频、表格以及 *section* 等常用标签)、部分小程序平台不支持或低版本不兼容 |
| 本插件 | 支持标签全面、支持平台全面 | 编辑灵活性不够强 |
大小:*≈17.5KB*
支持平台:
| 微信小程序 | QQ 小程序 | 百度小程序 | 支付宝小程序 | 头条小程序 | uni-app |
|:---:|:---:|:---:|:---:|:---:|:---:|
| √ | √ | √ | √ | √ | √(nvue 不支持) |
##### 示例项目 :id=editable_demo
微信小程序点击 [代码片段](https://developers.weixin.qq.com/s/S2ZpZDm87fQP) 即可在微信开发者工具中导入;*uni-app* 下载 [示例项目](https://mp-html.oss-cn-hangzhou.aliyuncs.com/editable.zip) 在 *HBuilder X* 中打开即可体验;注意示例项目中不一定包含最新版本,仅供参考使用方法
?> 也可以参考示例小程序 [源代码](https://github.com/jin-yufeng/mp-html-demo)
说明:
引入本插件后,会给组件添加以下属性:
| 属性名 | 类型 | 默认值 | 说明 |
|:---:|:---:|:---:|:---:|
| editable | Boolean | false | 是否开启内容编辑 |
| placeholder | String | 请输入 | 输入框为空时占位符([2.1.0+](changelog/changelog#v210)) |
?> [2.5.0](changelog/changelog#v250) 版本起支持将 *editable* 属性设置为 *"simple"* 来开启简易模式,简易模式下,点击文字内容直接进入编辑,不再弹出操作菜单栏和方框
添加以下事件:
| 事件名 | 触发时机 | 用途 |
|:---:|:---:|:---:|
| remove([2.2.0+](changelog/changelog#v220)) | 删除图片/视频/音频标签时 | 删除已上传的线上文件 |
支持以下操作:
| 类型 | 操作 |
|:---:|:---:|
| 文本 | 修改 |
| 图片 | 更换链接、调整宽度、设置成超链接([2.0.4+](changelog/changelog#v204))、设置预览图链接、禁用预览、删除 |
| 链接 | 更换链接、删除 |
| 音视频 | 设置封面、设置循环播放、设置自动播放([2.2.0+](changelog/changelog#v220))、删除 |
| 普通标签 | 设置字体大小、颜色([2.4.2+](changelog/changelog#v242))、斜体、粗体、下划线([2.0.4+](changelog/changelog#v204))、居中、缩进、删除 |
?> [2.2.1](changelog/changelog#v221) 版本起所有标签支持上下移动操作,但仅限同级标签间移动,即在有同级标签且非第一个(或最后一个)时可以上移(或下移)
?> 在支付宝小程序中使用时需要在页面样式中添加 *page { position: relative; }* 避免 *tooltip* 错位
?> 菜单项可以通过编辑 *plugins/editable/config.js* 进行修改,仅可以删减或调整顺序,添加或更名无效(颜色设置除外)
[组件实例](advanced/api#getCompent) 上提供了以下方法(*editable* 属性为 *true* 时才可以调用):
| 名称 | 功能 |
|:---:|:---:|
| undo | 撤销一个操作 |
| redo | 重做一个操作 |
| insertHtml | 在光标处插入指定 html 内容([2.1.0+](changelog/changelog#v210)) |
| insertImg | 在光标处插入一张图片 |
| insertTable(rows, cols) | 在光标处插入一个 rows 行 cols 列的表格([2.1.3+](changelog/changelog#v213)) |
| insertVideo | 在光标处插入一个视频 |
| insertAudio | 在光标处插入一个音频 |
| insertLink | 在光标处插入一个链接 |
| insertText | 在光标处插入一段文本 |
| clear | 清空内容 |
| getContent | 获取编辑后的 html 内容 |
?> 考虑到不同场景下希望获取链接的方法不同,需要在初始时给组件设置一个 *getSrc* 方法(否则插入图片、音视频、链接或修改链接等操作无法使用),每次组件内需要链接时会调用此方法,开发者可在此方法中自行决定如何获取链接,返回 **线上地址** 即可(具体用法见下方示例)
[2.2.0](changelog/changelog#v220) 版本起设置了 [domain](basic/prop#domain) 属性时,返回的地址可以缺省主域名
编辑完成后,通过 *getContent* 方法获取编辑后的 *html*,最后将 *editable* 属性设置为 *false* 即可正常渲染
!> 点击保存按钮时,部分平台 *tap* 事件早于 *blur* 事件触发,直接获取内容可能导致无法获取当前编辑的文本内容,因此建议设置一个小的延时后获取(可参考下方示例,[详细](https://github.com/jin-yufeng/mp-html/issues/368))
示例:
```javascript
Page({
onLoad () {
// ctx 为组件实例,获取方法见上
/**
* @description 设置获取链接的方法
* @param {String} type 链接的类型(img/video/audio/link)
* @param {String} value 修改链接时,这里会传入旧值
* @returns {Promise} 返回线上地址(2.2.0 版本起设置了 domain 属性时,可以缺省主域名)
* type 为 audio/video 时,可以返回一个源地址数组
* 2.1.3 版本起 type 为 audio 时,可以返回一个 object,包含 src、name、author、poster 等字段
* 2.2.0 版本起 type 为 img 时,可以返回一个源地址数组,表示插入多张图片(修改链接时仅限一张)
*/
this.ctx.getSrc = (type, value) => {
return new Promise((resolve, reject) => {
// 以图片为例
if (type == 'img') {
wx.chooseImage({
count: value === undefined ? 9 : 1, // 2.2.0 版本起插入图片时支持多张(修改图片链接时仅限一张)
success: res => {
wx.showLoading({
title: '上传中'
});
(async ()=>{
const arr = []
for (let item of res.tempFilePaths) {
// 依次上传
const src = await upload(item)
arr.push(src)
}
return arr
})().then(res => {
wx.hideLoading()
resolve(res)
})
},
fail: reject
})
}
})
}
},
finishEdit () {
setTimeout(() => {
var html = ctx.getContent() // 获取编辑好的 html
// 上传 html
wx.request({
url: 'xxx',
data: {
html
},
success: () => {
this.setData({
editable: false // 结束编辑
})
}
})
}, 50)
}
})
```
注意事项:
不要在 *editable* 属性被设置为 *true* 前通过 [setContent](advanced/api#setContent) 方法(用 [content](basic/prop#content) 属性)设置内容,否则在切换为 *true* 后会变成空白
## emoji
功能:解析 *emoji*
大小:*≈3KB*
支持平台:
| 微信小程序 | QQ 小程序 | 百度小程序 | 支付宝小程序 | 头条小程序 | uni-app |
|:---:|:---:|:---:|:---:|:---:|:---:|
| √ | √ | √ | √ | √ | √ |
说明:
将形如 *[笑脸]* 的文本替换为 *emoji* 字符 😄
匹配模式可以通过修改 *reg* 变量实现
默认配置了 *177* 个常用的 *emoji* 小表情,可以自行按照需要修改 *data* 变量
?> 与 [editable](#editable) 插件共用时,导出编辑好的 *html* 内容,会将 *emoji* 字符编码为文本形式,便于存储
## highlight
功能:代码块高亮显示
大小:*≈16KB*
支持平台:
| 微信小程序 | QQ 小程序 | 百度小程序 | 支付宝小程序 | 头条小程序 | uni-app |
|:---:|:---:|:---:|:---:|:---:|:---:|
| √ | √ | √ | √ | √ | √ |
说明:
编辑 *plugins/highlight/config.js* ,可以选择是否需要以下功能:
- *copyByLongPress* 是否需要长按代码块时显示复制代码内容菜单(*uni-app nvue* 暂不支持)
- *showLanguageName* 是否在代码块右上角显示语言的名称
- *showLineNumber* 是否在左侧显示行号
!> 修改该配置后需要重新 [生成组件包](advanced/develop#pack),在构建后的组件包中修改配置无法生效
引入本插件后,*html* 中符合以下格式的 *pre* 将被高亮处理:
```html
<!-- pre 中内含一个 code,并在 pre 或 code 的 class 中设置 language- -->
<pre><code class="language-css">p { color: red }</code></pre>
```
?> 与 [editable](#editable) 插件共用时,编辑状态下,不会进行高亮,可以直接修改代码文本
?> 本插件的高亮功能依赖于 [prismjs](https://prismjs.com/),默认配置中仅支持 *html*、*css*、*c-like*、*javascript* 语言和 *Tomorrow Night* 主题,如果需要更多语言或更换主题请前往 [官网](https://prismjs.com/download.html) 下载对应的 *prism.min.js* 和 *prism.css* 并替换 *plugins/highlight/* 目录下的文件(*prismjs* 的插件大多涉及 *dom* 操作,基本不可用,请勿选择)
## markdown
功能:渲染 *markdown*
大小:*≈37KB*
支持平台:
| 微信小程序 | QQ 小程序 | 百度小程序 | 支付宝小程序 | 头条小程序 | uni-app |
|:---:|:---:|:---:|:---:|:---:|:---:|
| √ | √ | √ | √ | √ | √ |
说明:
引入本插件后,会给组件添加一个 *markdown* 属性,将该属性设置为 *true* 后,即可通过 [content](basic/prop#content) 属性或 [setContent](advanced/api#setContent) 方法设置 *markdown* 内容即可
?> 若开启 [use-anchor](basic/prop#use-anchor) 属性,所有标题 `# xxx` 都会被设置为锚点,通过链接 `[xxx](#xxx)` 可以直接跳转
?> 本插件通过 [marked](https://github.com/markedjs/marked) 解析 *markdown* 文本,部分 *css* 摘选自 [github-markdown-css](https://github.com/sindresorhus/github-markdown-css)
?> 本插件可以和 [highlight](#highlight) 插件共用,实现 *markdown* 中代码块的高亮效果
## search
功能:关键词搜索
大小:*≈1.5KB*
支持平台:
| 微信小程序 | QQ 小程序 | 百度小程序 | 支付宝小程序 | 头条小程序 | uni-app |
|:---:|:---:|:---:|:---:|:---:|:---:|
| √ | √ | √ | √ | √ | √(nvue 不支持) |
说明:
引入后会在 [组件实例](advanced/api#getCompent) 上挂载一个 *search* 方法,用于关键词搜索
输入值
| 参数名 | 类型 | 默认值 | 说明 |
|:---:|:---:|:---:|---|
| key | String 或 RegExp | - | 要搜索的关键词,支持字符串和正则 |
| anchor | Boolean | false | 是否将搜索结果设置为锚点 |
| style | String | background-color:yellow | 标记搜索结果的样式 |
返回值:*Promise*
| 属性 | 类型 | 说明 |
|:---:|:---:|---|
| num | Number | 搜索结果数量 |
| highlight | Function(i, style='background-color:#FF9632') | 高亮第 i(1 ~ num)个结果,将其样式设置为 style |
| jump | Function(i, offset) | 跳转到第 i(1 ~ num)个结果,偏移量为 offset,anchor 为 true 才可用 |
示例:
```javascript
function search (key) {
// ctx 为组件实例
ctx.search(key, true).then(res => {
res.highlight(1)
res.jump(1, -50) // 高亮第 1 个结果并跳转到该位置,偏移量 -50
})
}
```
?> 具体用法可以参考示例小程序 [源代码](https://github.com/jin-yufeng/mp-html-demo)
附加说明:
1. 不传入 *key*(或为空)时即可取消搜索,取消所有的高亮,还原到原来的效果
2. 进行新的搜索时旧的搜索结果将被还原,旧的结果中的 *highlight* 等方法不再可用
3. 调用 *highlight* 方法高亮一个结果时,之前被高亮的结果会被还原,即始终只有一个结果被高亮
4. *key* 传入字符串时大小写敏感,如果要忽略大小写可以用正则的 *i*(字符串搜索效率高于正则)
5. 设置 *anchor* 为 *true* 会一定程度上降低效率,非必要不要开启
6. 暂不支持跨标签搜索,即只有一个文本节点内包含整个关键词才能被搜索到
## style
功能:解析和匹配 *style* 标签中的样式
?> 这里的 *style* 标签指的是传入 [content](basic/prop#content) 属性中的 *html* 里包含的 *style* 标签,且 *style* 标签要放在其他标签前面才能生效
大小:*≈3.5KB*
支持平台:
| 微信小程序 | QQ 小程序 | 百度小程序 | 支付宝小程序 | 头条小程序 | uni-app |
|:---:|:---:|:---:|:---:|:---:|:---:|
| √ | √ | √ | √ | √ | √ (nvue 直接支持) |
说明:
支持以下选择器:
| 名称 | 示例 |
|:---:|---|
| 标签名选择器 | p {} |
| class 选择器 | .class {} |
| id 选择器 | #id {} |
| 多选择器交集 | p.class {} |
| 多选择器并集 | p, .class {} |
| 后代选择器 | .class1 .class2 {} |
| 子选择器 | .class1 > .class2 {} |
| 伪类 | .class::before {} |
伪类仅支持 *before* 和 *after*,支持 *attr* 方法
不支持的选择器(属性选择器等)将被忽略
!> 由于小程序中无法动态写入 *css*,本插件的实现原理是通过解析,将匹配的样式添加到各标签的行内 *style* 中去,请慎用宽泛的选择器,以免大大增加解析结果大小,减慢渲染速度
## txv-video
功能:使用腾讯视频
大小:*≈1KB*
支持平台:
| 微信小程序 | QQ 小程序 | 百度小程序 | 支付宝小程序 | 头条小程序 | uni-app |
|:---:|:---:|:---:|:---:|:---:|:---:|
| √ | √ | | | | √ (h5 和 app 直接支持) |
说明:
引入本插件后,*html* 中符合下方格式的 *iframe* 标签(*src* 中含有 *vid*)将被转为通过腾讯视频播放:
```html
<iframe src="https://v.qq.com/txp/iframe/player.html?vid=xxxxxx" allowFullScreen="true"></iframe>
```
同时,其可以被 [pause-video](basic/prop#pause-video) 属性控制
!> 本插件仅用于将官方 [腾讯视频插件](https://github.com/tvfe/txv-miniprogram-plugin) 应用于本组件,使用前请确认已经成功申请使用该插件并按要求在小程序 *app.json* 中配置完成(*uni-app* 中的配置方法可以参考 [#103](https://github.com/jin-yufeng/mp-html/issues/103#issuecomment-654586246)),否则可能报错 **This application has not registered any plugins yet** 且无法生效
?> 腾讯视频插件 [v2](https://github.com/tvfe/txv-miniprogram-plugin) 默认自动播放,[v1](https://github.com/tvfe/txv-miniprogram-plugin/blob/master/archieve/readme.md) 不会,可按需选择
## img-cache
功能:图片本地缓存
大小:*≈4KB*
作者:[@PentaTea](https://github.com/PentaTea)
支持平台:
| 微信小程序 | QQ 小程序 | 百度小程序 | 支付宝小程序 | 头条小程序 | uni-app |
|:---:|:---:|:---:|:---:|:---:|:---:|
| | | | | | √(仅支持 app 的 vue 页面) |
说明:
引入本插件后,会给组件添加一个 *img-cache* 属性,将该属性设置为 *true* 后,将自动下载引用的图片并将 *src* 属性更换为本地地址
同时在 [组件实例](advanced/api#getCompent) 上挂载了 *imgCache* 对象,扩充缓存控制能力
*imgCache* 对象属性和方法:
| 属性 | 功能 |
|:---:|:---:|
| list | 当前缓存的 url 列表 |
| get(url) | 传入 url 获得本地地址 |
| delete(url) | 传入 url 删除缓存记录 |
| add(url) | 传入 url 并下载目标为缓存 |
| clear() | 清空所有缓存 |
!> 请尽量确保 *src* 中含有文件后缀名,不以后缀结尾也没关系,插件会从路径中推测合理的图片后缀,如果完全不包含后缀信息可能会无法保存到相册
## latex
功能:渲染 *latex* 公式
大小:**≈300KB**
作者:[@Zeng-J](https://github.com/Zeng-J)
支持平台:
| 微信小程序 | QQ 小程序 | 百度小程序 | 支付宝小程序 | 头条小程序 | uni-app |
|:---:|:---:|:---:|:---:|:---:|:---:|
| √ | √ | √ | √ | √ | √ |
说明:
引入本插件后,会将 *$xxx$* 的文本内容按照 *latex* 规则进行解析和渲染
?> [2.5.0](changelog/changelog#v250) 版本起支持 *$$xxx$$* 形式的块级公式
?> 与 [editable](#editable) 插件共用时,编辑状态下,公式不会渲染,可以直接修改公式文本
?> 在 *js* 的字符串中写 *latex* 公式时需注意 *\\* 会变成转义符,要使用 *\\\\* 或 *String.raw``* 的方式
?> 本插件通过 [katex-mini](https://github.com/rojer95/katex-mini) 解析 *latex* 文本,[字体文件](https://github.com/KaTeX/KaTeX/tree/main/fonts) 建议自行转存
## card
功能:商品(联络人)信息卡
大小:*≈7KB*
作者:[@whoooami](https://github.com/whoooami)
支持平台:
| 微信小程序 | QQ 小程序 | 百度小程序 | 支付宝小程序 | 头条小程序 | uni-app |
|:---:|:---:|:---:|:---:|:---:|:---:|
| √ | √ | √ | √ | √ | √(nvue 不支持) |
效果图:
![效果图](../assets/plugin/card.png)
参数列表:
|参数名|是否必须|类型|说明|
|:---- |:---|:----- |----- |
|src|是|String|图片Url|
|title|是|String|标题|
|desc|是|String|描述|
|url|是|String|跳转url|
|color|是|String|文字颜色|
|bgcolor|是|String|卡片背景颜色|
|border|是|String|卡片边框颜色|
说明:
1. 可以显示商品信息卡片/联络人信息卡片
基础库要求:
满足最低要求即可
?> 如果希望页面上使用本组件,组件的路径为 *path/to/mp-html/card/card*
## 开发插件 :id=develop
一个插件大致需要以下文件(*plugin/template* 中提供了一个模板)
- *build.js*
构建文件,需要导出一个 *object*,可以内含以下项:
| 名称 | 类型 | 默认值 | 功能 |
|:---:|:---:|:---:|---|
| main | string | index.js | 入口文件路径 |
| platform | string[] | ['mp-weixin', 'mp-qq', 'mp-baidu', 'mp-alipay', 'mp-toutiao', 'uni-app'] | 支持使用的平台 |
| template | string | - | 要被添加到模板文件中的标签 (nvue 不可用) |
| methods | object | {} | 用于处理模板中事件的方法 (nvue 不可用) |
| style | string | - | 用于模板文件的 css 样式 |
| import | string&#124;string[] | - | 用于模板文件的 css 文件路径 |
| usingComponents | object | {} | 用于模板的组件或插件列表 (nvue 不可用) |
| handler | function | - | 自定义文件处理方法 |
- *index.js*
入口文件,导出一个 *function*,每个组件在被创建时,会依次实例化各个插件,并传入组件实例可供调用
插件实例上可以挂载以下钩子方法,将在对应时机被调用
| 名称 | 触发时机 | 参数 | 返回值 |
|:---:|:---:|:---:|:---:|
| onUpdate | 更新 html 内容时触发 | 更新的 html 内容和解析配置 | 如果对输入值进行了修改,则返回修改后的内容 |
| onParse | 解析到一个标签时触发 | 标签和解析器实例 | 返回 false 将移除该标签 |
| onLoad | dom 树加载完成时触发 | - | - |
| onDetached | 组件被移除时触发 | - | - |
- *README.md*
使用说明
- *其他依赖文件*
插件目录下,除了 *.md* 的文件、*build.js* 和 *import* 字段中的 *css* 文件,其他的都会被拷贝到生成的组件包中,因此请不要放置无关文件
对于仅在原生平台中使用的内容可放在 *miniprogram* 目录下,仅在 *uni-app* 中使用的内容可放在 *uni-app* 目录下,两个目录下可以分别放置 *build.js*
如果在插件中需要用到解析器(将 *html* 字符串解析为 *nodes* 数组),可以引入 *src/parser.js* 使用,方法如下:
```javascript
const Parser = require('../parser.js')
var instance = new Parser(vm) // 实例化解析器,传入组件实例将自动获取相关配置
var nodes = instance.parse(content) // 解析完成
```
!> 如果编写了插件,在升级组件包时请注意备份,避免丢失
?> 欢迎提交实用的插件 [pull requests](https://github.com/jin-yufeng/mp-html/pulls) 到 *plugins* 文件夹
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

+189
View File
@@ -0,0 +1,189 @@
# 📫 事件 :id=event
## 获取方式 :id=method
- *uni-app*
*@* + 事件名 或 *v-on:* + 事件名
事件信息从 *event* 中获取
```vue
<template>
<view>
<mp-html @ready="ready" />
</view>
</template>
<script>
export default {
methods: {
ready (e) {
console.log(e)
}
}
}
</script>
```
- 支付宝小程序
*on* + 事件名(首字母大写)
事件信息从 *event* 中获取
```axml
<mp-html onReady="ready">
```
```javascript
Page({
ready (e) {
console.log(e)
}
})
```
- 其他小程序平台
*bind* + 事件名
事件信息从 *event.detail* 中获取
```wxml
<mp-html bindready="ready" />
```
```javascript
Page({
ready (e) {
console.log(e.detail)
}
})
```
## load
触发时机:*dom* 树加载完毕时
返回值:无
用途:可以调用 [api](advanced/api) 函数
## ready
触发时机:图片加载完毕时(不包含懒加载的图片)
?> 判断方式是 *350ms* 总高度无变化就认为加载完毕,部分情况下可能不准确;[2.4.0](changelog/changelog#v240) 版本起 [lazy-load](basic/prop#lazy-load) 属性为 *false* 时根据图片的 *load* 事件判断,可以基本准确触发
返回值:富文本区域的 *boundingClientRect* 结构体,包含大小位置信息
用途:此时进行 [锚点跳转](advanced/api#navigateTo) 可以基本保证跳转位置正确
?> 如果设置了 [懒加载](basic/prop#lazy-load),此时返回的大小不一定是最终大小,如果需要实时的大小,可以调用 [getRect](advanced/api#getRect) 方法
## error
触发时机:发生渲染错误时
返回值:一个 *object*,其中 *source* 为错误来源(包括 *img*、*video*、*audio*),*attrs* 为该标签的属性列表(包含 *src* 等信息),*errMsg* 是错误信息
用途:收集错误信息,减少使用出错率高的链接
## imgtap
触发时机:图片被点击时
返回值:该 *img* 标签的属性列表
用途:
默认情况下图片被点击时将自动预览(具体处理可见 [图片效果](overview/feature#img)),如果不希望如此,可将 [preview-img](basic/prop#preview-img) 属性设置为 *false* 并在这里自定义处理
如果需要用到富文本中所有图片的数组,可以通过 [imgList](advanced/api#imgList) 的 *api* 获取
示例:
```javascript
Page({
imgtap (e) {
// 对做了某种标记的图片进行预览
if (e.detail['data-flag']) {
wx.previewImage({
urls: [e.detail.src] // 仅预览单张图片
})
}
}
})
```
## linktap
触发时机:链接被点击时
返回值:该 *a* 标签的属性列表
?> [2.0.5](changelog/changelog#v205) 版本起增加返回该标签内部文本 *innerText*
用途:
默认情况下链接被点击时,对于外部链接,将被拷贝到剪贴板,如果不希望如此,可以将 [copy-link](basic/prop#copy-link) 属性的值设置为 *false* 后在这里自定义处理,可参考以下方案:
1. 跳转 *web-view*
跳转到一个新的页面,该页面放置一个 [web-view](https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html) 用于显示外部网页(需要注意 *web-view* 的使用限制)
2. 跳转其他小程序
对于其他小程序的链接(可通过自行设置的 *data-* 属性判断),通过 [navigateToMiniProgram](https://developers.weixin.qq.com/miniprogram/dev/api/open-api/miniprogram-navigate/wx.navigateToMiniProgram.html) 接口跳转(需要注意跳转限制)
3. 下载文档
对于文档类的链接(可通过后缀名或自行设置的 *data-* 属性判断),可以通过 [downloadFile](https://developers.weixin.qq.com/miniprogram/dev/api/network/download/wx.downloadFile.html) 接口下载文件后通过 [openDocument](https://developers.weixin.qq.com/miniprogram/dev/api/file/wx.openDocument.html) 接口打开文档(需要注意下载域名限制)
4. 下载压缩包
对于压缩包类的链接(可通过后缀名或自行设置的 *data-* 属性判断),可以通过 [downloadFile](https://developers.weixin.qq.com/miniprogram/dev/api/network/download/wx.downloadFile.html) 接口下载文件后通过 [FileSystemManager.unzip](https://developers.weixin.qq.com/miniprogram/dev/api/file/FileSystemManager.unzip.html) 接口解压,然后进行打开文档等操作(需要注意下载域名限制)
对于大文件(可通过 *data-* 属性标注),还可以在下载前进行询问,下载过程中通过 [DownloadTask](https://developers.weixin.qq.com/miniprogram/dev/api/network/download/DownloadTask.html) 提示下载进度等
示例:
```javascript
Page({
linktap (e) {
if (e.detail.href.includes('.doc')) {
// 下载 doc 文件
wx.downloadFile({
url: e.detail.href,
success (res) {
wx.hideLoading()
wx.openDocument({
filePath: res.tempFilePath
})
},
fail (err) {
wx.hideLoading()
wx.showModal({
title: '失败',
content: err.errMsg,
showCancel: false
})
}
})
} else if (e.detail.href.includes('xxx.com')) {
// 跳转到 webview
wx.navigateTo({
url: 'pages/webview/webview?url=' + e.detail.href,
})
} else if (e.detail['data-appid']) {
// 跳转其他小程序
wx.navigateToMiniProgram({
appId: e.detail['data-appid']
})
}
}
})
```
## play
?> [2.3.0](changelog/changelog#v230) 版本起支持
触发时机:音视频播放时
返回值:无
?> [2.5.0](changelog/changelog#v250) 版本起返回值变更为一个 *object*,其中 *source* 为播放来源(包括 *video*、*audio*),*attrs* 为该标签的属性列表(包含 *src* 等信息),可以统计播放量等信息
用途:和 [pauseMedia](advanced/api#pauseMedia) 的 `api` 配合可以实现与页面中其他音视频进行互斥播放
示例:
```javascript
Page({
// 页面中的音视频播放事件
pagePlay() {
// ctx 为组件实例
ctx.pauseMedia() // 暂停组件内的音视频播放
},
// 组件的 play 事件
componentPlay() {
// media 为页面中的音视频实例
media.pause() // 暂停页面中的音视频播放
}
})
```
## pause
?> [2.5.2](changelog/changelog#v252) 版本起支持
触发时机:音视频暂停时
返回值:一个 *object*,其中 *source* 为播放来源(包括 *video*、*audio*),*attrs* 为该标签的属性列表(包含 *src* 等信息)
## fullscreenchange
?> [2.5.2](changelog/changelog#v252) 版本起支持
触发时机:视频全屏状态变化时
返回值:一个 *object*,其中 *fullScreen* 为是否全屏(*true* / *false*),*direction* 为方向(*vertical* / *horizontal*),*attrs* 为该视频的属性列表(包含 *src* 等信息)
+141
View File
@@ -0,0 +1,141 @@
# 🔨 属性 :id=prop
!> 需要将某个属性设置为 *false* 时,应写作 *attr="{{false}}"*
## container-style
?> [2.1.0](changelog/changelog#v210) 版本起支持
功能:设置容器的样式
类型:*String*
示例:
```css
padding: 5px; /* 设置内边距 */
font-size: 18px; /* 设置默认的字体大小 */
overflow: hidden; /* 禁用横向滚动 */
display: inline; /* 行内显示 */
white-space: pre-wrap; /* 保留空格和换行符 */
white-space: pre-line; /* 保留换行符 */
```
## content
功能:用于渲染的 *html* 字符串
类型:*String*
## copy-link
功能:是否允许外部链接被点击时自动复制
类型:*Boolean*
默认值:*true*
?> 对于 *uni-app* 的 *h5* 和 *app* 平台,外链是能够直接跳转的,这种情况下如果该属性为 *true* 则直接跳转外链(而不是复制链接),为 *false* 则不跳转
## domain
功能:主域名(用于链接拼接)
类型:*String*
示例:
```html
<!-- 假设 domain 属性被设置为 https://example.com
以下链接均会被拼接为 https://example.com/path -->
<img src="//example.com/path" />
<img src="/path" />
<div style="background-image:url('path')"></div>
```
?> 通过 *base* 标签也可以设置主域名,但优先级低于此属性
!> 该属性必须填写 协议名://域名 的完整链接
暂不支持拼接含有 *../* 的相对路径链接
*a* 标签的 *href* 属性可能需要跳转到小程序内路径,因此不进行 *domain* 拼接
设置该属性后将无法使用本地图片
## error-img
功能:图片出错时的占位图链接
类型:*String*
!> 该属性不会进行拼接 [domain](#domain),需传入完整路径(可以使用本地路径)
## lazy-load
功能:是否开启图片懒加载
类型:*Boolean*
默认值:*false*
?> 不同平台懒加载的时机不同,具体参考各平台 *image* 组件懒加载的时机
## loading-img
功能:图片加载过程中的占位图链接
类型:*String*
!> 该属性不会进行拼接 [domain](#domain),需传入完整路径(可以使用本地路径)
## pause-video
功能:是否在播放一个视频时自动暂停其他视频
类型:*Boolean*
默认值:*true*
?> 如果需要多个视频同时播放的,请将此属性设置为 *false*
## preview-img
功能:是否允许图片被点击时自动预览
类型:*Boolean*
默认值:*true*
?> 自动预览允许左右滑动查看所有图片,如果不希望如此可以禁用自动预览并在 [imgtap](basic/event#imgtap) 事件中自行处理
!> 默认情况下 *base64* 图片无法点击预览,[2.5.0](changelog/changelog#v250) 版本起支持将本属性设置为 *"all"* 开启 *base64* 图片的预览,但需要注意各平台 *previewImage* 的 *api* 对 *base64* 图片支持度不高,需充分测试后使用,如果无法预览,可参考 [imgList](advanced/api#imgList) 中的方法进行转存
## scroll-table
功能:是否给每个表格添加一个滚动层使其能单独横向滚动
类型:*Boolean*
默认值:*false*
!> 如果表格设置了 *inline* 布局,该属性将不会生效以免破坏行内布局
## selectable
功能:是否开启文本长按复制
类型:*Boolean* / *String*
默认值:*false*
!> 将本属性的值设置为 *true* 在微信 *iOS* 端可能失效,[2.0.5](changelog/changelog#v205) 版本起支持将本属性设置为 "*force*" 来支持,但会带来以下影响:
1、所有文本块会显示为 *inline-block*(通过 [text](https://developers.weixin.qq.com/miniprogram/dev/component/text.html) 标签的 *user-select* 属性实现),需要自行适配
2、文字下划线、删除线等效果将失效([详细](https://github.com/jin-yufeng/mp-html/issues/382))
3、所有文本块都无法被 *rich-text* 包含,一定程度上增加标签数,减慢渲染速度
从 [2.3.1](changelog/changelog#v231) 版本起对此问题进行优化(通过 [rich-text](https://developers.weixin.qq.com/miniprogram/dev/component/rich-text.html) 标签的 *user-select* 属性实现,基础库 *2.24.0* 及以上生效),第 *3* 个问题已解决,第 *1*、*2* 个问题部分情况下还会存在
## set-title
功能:是否将 *title* 标签的内容设置到页面标题
类型:*Boolean*
默认值:*true*
## show-img-menu
?> [2.3.0](changelog/changelog#v230) 版本起支持控制预览时是否长按显示菜单(仅微信、百度小程序有效)
功能:是否允许图片被长按时显示菜单
类型:*Boolean*
默认值:*true*
!> 该属性目前仅微信、百度和 *uni-app* 的 *app* 平台有效
## tag-style
功能:设置标签的默认样式
类型:*Object*
示例:
```javascript
// 格式为 标签名: 样式
{
a: 'color:red' // a 标签默认为红色
}
```
?> 该属性非响应式,需要在设置 [content](#content) 属性前设置才能生效,动态修改不能实时生效
!> 该属性的原理是解析到各标签的内联 *style* 属性中去,如果对特别常用的标签设置默认样式,将大大加大解析结果大小,减慢渲染速度,这种情况下建议通过 [外部样式](overview/quickstart#setting) 引入
## use-anchor
功能:是否使用锚点链接
类型:*Boolean* / *Number*
默认值:*false*
?> 传入一个数字时表示跳转锚点的偏移量(单位 *px*)
?> 开启该属性会将所有设置了 *id* 属性的标签都暴露出来,一定程度上减慢渲染速度,非必要不要开启
+331
View File
@@ -0,0 +1,331 @@
# 📖 更新日志 :id=changelog
## v2.5.2
发布时间:*2025-12-14*
1. `A` 增加了音视频暂停 [pause](basic/event#pause) 和视频全屏 [fullscreenchange](basic/event#fullscreenchange) 事件 [#495](https://github.com/jin-yufeng/mp-html/issues/495) [#595](https://github.com/jin-yufeng/mp-html/issues/595)
2. `U` 优化了 [流式输出](overview/feature#stream) 效果,通过差量更新解决闪烁问题 [详细](https://github.com/jin-yufeng/mp-html/issues/657)
3. `U` [latex](advanced/plugin#latex) 插件更新字体文件 [详细](https://github.com/jin-yufeng/mp-html/pull/647) by [@JiuyeXD](https://github.com/JiuyeXD)
4. `U` 更新 [markdown](advanced/plugin#markdown) 插件中 `marked.js` 版本 [详细](https://github.com/jin-yufeng/mp-html/issues/672)
5. `U` 微信小程序替换遗漏的废弃 `api` `getSystemInfoSync` [详细](https://github.com/jin-yufeng/mp-html/pull/653) by [@zcSkr](https://github.com/zcSkr)
6. `F` 修复了 [markdown](advanced/plugin#markdown) 插件加粗文本遇到中文符号无效的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/664) by [@qp666](https://github.com/qp666)
## v2.5.1
发布时间:*2025-04-20*
主要更新:
1. `U` `uni-app` 包适配鸿蒙 `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` 修复了微信小程序 `glass-easel` 框架下真机换行异常的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/607) by [@PaperStrike](https://github.com/PaperStrike)
4. `F` 修复了 `uni-app` 包 `app` 端播放视频可能报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/617)
5. `F` 修复了 [latex](advanced/plugin#latex) 插件可能出现 `xxx can be used only in display mode` 的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/632)
6. `F` 修复了 `uni-app` 包 [latex](advanced/plugin#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](basic/event#play) 事件增加返回 `src` 等信息 [详细](https://github.com/jin-yufeng/mp-html/issues/526)
2. `U` [preview-img](basic/prop#preview-img) 属性支持设置为 `all` 开启 `base64` 图片预览 [详细](https://github.com/jin-yufeng/mp-html/issues/536)
3. `U` [editable](advanced/plugin#editable) 插件增加简易模式(点击文字直接编辑)
4. `U` [latex](advanced/plugin#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` 修复了 `uni-app` 包 `h5` 和 `app` 端部分情况下样式无法识别的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/518)
8. `F` 修复了 [latex](advanced/plugin#latex) 插件部分情况下显示不正确的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/580)
9. `F` 修复了 [editable](advanced/plugin#editable) 插件表格无法删除的问题
10. `F` 修复了 [editable](advanced/plugin#editable) 插件 `uni-app` 包 `vue3` `h5` 端点击图片报错的问题
11. `F` 修复了 [editable](advanced/plugin#editable) 插件 `uni-app` 包点击表格没有菜单栏的问题
## v2.4.3
发布时间:*2024-01-21*
主要更新:
1. `A` 增加 [card](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](advanced/plugin#latex) 插件公式会换行的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/540)
6. `F` 修复了 `uni-app` 包 [editable](advanced/plugin#editable) 和 [audio](advanced/plugin#audio) 插件共用时点击 `audio` 无法编辑的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/529) by [@whoooami](https://github.com/whoooami)
7. `F` 修复了支付宝小程序设置了宽高的图片可能显示不正常的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/544)
8. `F` 修复了 `uni-app` 包微信小程序部分情况下图片会报错 `replace of undefined` 的问题
9. `F` 修复了 `uni-app` 包快手小程序图片不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/571)
## v2.4.2
发布时间:*2023-05-14*
主要更新:
1. `A` [editable](advanced/plugin#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` 修复了 `uni-app` 包使用旧版编译器可能报错 `Bad attr nodes` 的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/472)
4. `F` 修复了 `uni-app` 包 `app` 端可能出现无法读取 `lazyLoad` 的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/513)
5. `F` 修复了 [editable](advanced/plugin#editable) 插件在点击换图时未拼接 [domain](basic/prop#domain) 的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/497) by [@TwoKe945](https://github.com/TwoKe945)
6. `F` 修复了 [latex](advanced/plugin#latex) 插件部分情况下不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/515)
7. `F` 修复了 [editable](advanced/plugin#editable) 插件点击音视频时其他标签框不消失的问题
## v2.4.1
发布时间:*2022-12-25*
主要更新:
1. `F` 修复了没有图片时 [ready](basic/event#ready) 事件可能不触发的问题
2. `F` 修复了加载过程中可能出现 `Root label not found` 错误的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/470)
3. `F` 修复了 [audio](advanced/plugin#audio) 插件退出页面可能会报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/457)
4. `F` 修复了 `uni-app` 包 `vue3` 运行到 `app` 在 `HBuilder X 3.6.10` 以上报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/480)
5. `F` 修复了原生包链接内有图片时可能错误换行的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/464)
6. `F` 修复了 `uni-app` 包 `nvue` 端链接中包含 `%22` 时可能无法显示的问题
7. `F` 修复了 `uni-app` 包 `vue3` 使用 [highlight](advanced/plugin#highlight) 插件可能报错的问题
8. `F` 修复了头条小程序使用 [editable](advanced/plugin#editable) 插件内容为空时点击会报错的问题
## v2.4.0
发布时间:*2022-08-27*
主要更新:
1. `A` 增加了 [setPlaybackRate](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](basic/event#ready) 事件触发时机,未设置懒加载的情况下基本可以准确触发 [详细](https://github.com/jin-yufeng/mp-html/issues/195)
4. `U` [highlight](advanced/plugin#highlight) 插件在编辑状态下不进行高亮处理,便于编辑
5. `F` 修复了 `flex` 布局下图片大小可能不正确的问题
6. `F` 修复了 [selectable](basic/prop#selectable) 属性没有设置 `force` 也可能出现渲染异常的问题
7. `F` 修复了表格中的图片大小可能不正确的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/448)
8. `F` 修复了含有合并单元格的表格可能无法设置竖直对齐的问题
9. `F` 修复了 [editable](advanced/plugin#editable) 插件在 `scroll-view` 中使用时工具条位置可能不正确的问题
10. `F` 修复了 `uni-app` 包 `vue3` 使用 [search](advanced/plugin#search) 插件可能导致错误换行的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/449)
## v2.3.2
发布时间:*2022-08-13*
主要更新:
1. `A` 增加 [latex](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](advanced/plugin#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](advanced/plugin#editable) 插件输入连续空格无效的问题
6. `F` 修复了 `uni-app` 包 `vue3` 图片设置 `inline` 会报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/438)
7. `F` 修复了 `uni-app` 包 `vue3` 使用 `table` 可能报错的问题
## v2.3.1
发布时间:*2022-05-20*
主要更新:
1. `U` `uni-app` 包 `app` 端支持使用本地图片
2. `U` 优化了微信小程序 [selectable](basic/prop#selectable) 属性在 `ios` 端的处理 [详细](basic/prop#selectable)
3. `U` 原生包取消样式隔离,部分平台可以直接引入页面样式 [#376](https://github.com/jin-yufeng/mp-html/issues/376)、[详细](overview/quickstart#externStyle)
4. `F` 修复了 [editable](advanced/plugin#editable) 插件不在顶部时 `tooltip` 位置可能错误的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/430)
5. `F` 修复了 `uni-app` 包 `vue3` 运行到微信小程序可能报错丢失内容的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/414)
6. `F` 修复了 `uni-app` 包 `vue3` 部分标签可能被错误换行的问题
7. `F` 修复了原生包个别情况下可能报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/428)
8. `F` 修复了 [editable](advanced/plugin#editable) 插件 `uni-app` 包的 `app` 端插入视频无法预览的问题
## v2.3.0
发布时间:*2022-04-01*
主要更新:
1. `A` 增加了 `play` 事件,音视频播放时触发,可用于与页面其他音视频进行互斥播放 [详细](basic/event#play)
2. `U` [show-img-menu](basic/prop#show-img-menu) 属性支持控制预览时是否长按弹出菜单
3. `U` 优化 `wxs` 处理,提高渲染性能 [详细](https://developers.weixin.qq.com/community/develop/article/doc/0006cc2b204740f601bd43fa25a413)
4. `U` `video` 标签支持 `object-fit` 属性
5. `U` 增加支持一些常用实体编码 [详细](https://github.com/jin-yufeng/mp-html/issues/418)
6. `F` 修复了图片仅设置高度可能不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/410)
7. `F` 修复了 `video` 标签高度设置为 `auto` 不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/411)
8. `F` 修复了使用 `grid` 布局时可能样式错误的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/413)
9. `F` 修复了含有合并单元格的表格部分情况下显示异常的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/417)
10. `F` 修复了百度小程序使用 `br` 标签可能部分不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/409)
11. `F` 修复了 [editable](advanced/plugin#editable) 插件连续插入内容时顺序不正确的问题
12. `F` 修复了 `uni-app` 包 `vue3` 使用 [audio](advanced/plugin#audio) 插件报错的问题
13. `F` 修复了 `uni-app` 包 [highlight](advanced/plugin#highlight) 插件使用自定义的 `prism.min.js` 报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/416)
## v2.2.2
发布时间:*2022-02-26*
主要更新:
1. `A` 增加了 [pauseMedia](advanced/api#pauseMedia) 的 `api`,可用于暂停播放音视频 [详细](https://github.com/jin-yufeng/mp-html/issues/317)
2. `U` 优化了长内容的加载速度
3. `U` `uni-app` 包适配 `vue3` [#389](https://github.com/jin-yufeng/mp-html/issues/389)、[#398](https://github.com/jin-yufeng/mp-html/pull/398) by [@zhouhuafei](https://github.com/zhouhuafei)、[#400](https://github.com/jin-yufeng/mp-html/issues/400)
4. `F` 修复了小程序端图片高度设置为百分比时可能不显示的问题
5. `F` 修复了 [highlight](advanced/plugin#highlight) 插件部分情况下可能显示不完整的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/403)
## v2.2.1
发布时间:*2021-12-24*
主要更新:
1. `A` [editable](advanced/plugin#editable) 插件增加上下移动标签功能
2. `U` [editable](advanced/plugin#editable) 插件支持在文本中间光标处插入内容
3. `F` 修复了 `uni-app` 包 `nvue` 端设置 `margin` 后可能导致高度不正确的问题
4. `F` 修复了 [highlight](advanced/plugin#highlight) 插件使用压缩版的 `prism.css` 可能导致背景失效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/367)
5. `F` 修复了 `uni-app` 包编辑状态下使用 [emoji](advanced/plugin#emoji) 插件内容为空时可能报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/371)
6. `F` 修复了使用 [editable](advanced/plugin#editable) 插件后将 [selectable](basic/prop#selectable) 属性设置为 `force` 不生效的问题
## v2.2.0
发布时间:*2021-10-11*
主要更新:
1. `A` 增加 [customElements](overview/quickstart#customelements) 配置项,便于添加自定义功能性标签 [详细](https://github.com/jin-yufeng/mp-html/issues/350)
2. `A` [editable](advanced/plugin#editable) 插件增加切换音视频自动播放状态的功能 [详细](https://github.com/jin-yufeng/mp-html/pull/341) by [@leeseett](https://github.com/leeseett)
3. `A` [editable](advanced/plugin#editable) 插件删除媒体标签时触发 `remove` 事件,便于删除已上传的文件
4. `U` [editable](advanced/plugin#editable) 插件 `insertImg` 方法支持同时插入多张图片 [详细](https://github.com/jin-yufeng/mp-html/issues/342)
5. `U` [editable](advanced/plugin#editable) 插入图片和音视频时支持拼接 [domian](basic/prop#domain) 主域名
6. `F` 修复了内部链接参数中包含 `://` 时被认为是外部链接的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/356)
7. `F` 修复了部分 `svg` 标签名或属性名大小写不正确时不生效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/351)
8. `F` 修复了 `uni-app` 包 `nvue` 页面运行到非 `app` 平台时可能样式错误的问题
9. `D` 移除了 `ad` 配置项(由 [customElements](overview/quickstart#customelements) 代替)
## v2.1.5
发布时间:*2021-08-13*
主要更新:
1. `A` 增加支持标签的 `dir` 属性
2. `F` 修复了 `ruby` 标签文字与拼音没有居中对齐的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/325)
3. `F` 修复了音视频标签内有 `a` 标签时可能无法播放的问题
4. `F` 修复了 [externStyle](overview/quickstart#setting) 中的 `class` 名包含下划线或数字时可能失效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/326)
5. `F` 修复了 `uni-app` 包 `h5` 端引入 [externStyle](overview/quickstart#setting) 可能不生效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/326)
6. `F` 修复了微信原生包 `a` 标签的 `style` 中包含 `inline` 时不响应事件的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/332)
## v2.1.4
发布时间:*2021-07-14*
主要更新:
1. `F` 修复了 `rt` 标签无法设置样式的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/318)
2. `F` 修复了表格中有单元格同时合并行和列时可能显示不正确的问题
3. `F` 修复了 `uni-app` 包的 `app` 端无法关闭图片长按菜单的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/322)
4. `F` 修复了 [editable](advanced/plugin#editable) 插件只能添加图片链接不能修改的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/312) by [@leeseett](https://github.com/leeseett)
## v2.1.3
发布时间:*2021-06-12*
主要更新:
1. `A` [editable](advanced/plugin#editable) 插件增加 `insertTable` 方法
2. `U` [editable](advanced/plugin#editable) 插件支持编辑表格中的空白单元格 [详细](https://github.com/jin-yufeng/mp-html/issues/310)
3. `F` 修复了 [externStyle](overview/quickstart#setting) 中使用伪类可能失效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/298)
4. `F` 修复了多个组件同时使用时 [tag-style](basic/prop#tag-style) 属性时可能互相影响的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/305) by [@woodguoyu](https://github.com/woodguoyu)
5. `F` 修复了包含 `linearGradient` 的 `svg` 可能无法显示的问题
6. `F` 修复了 `uni-app` 包编译到头条小程序时可能报错的问题
7. `F` 修复了 `uni-app` 包 `nvue` 端不触发 `click` 事件的问题
8. `F` 修复了 [editable](advanced/plugin#editable) 插件尾部插入时无法撤销的问题
9. `F` 修复了 [editable](advanced/plugin#editable) 插件的 `insertHtml` 方法只能在末尾插入的问题
10. `F` 修复了 [editable](advanced/plugin#editable) 插件插入音频不显示的问题
## v2.1.2
发布时间:*2021-04-24*
主要更新:
1. `A` 增加了 [img-cache](advanced/plugin#img-cache) 插件,可以在 `uni-app` 的 `app` 端缓存图片 [详细](https://github.com/jin-yufeng/mp-html/issues/292) by [@PentaTea](https://github.com/PentaTea)
2. `U` 支持通过 [container-style](basic/prop#container-style) 属性设置 `white-space` 来保留连续空格和换行符 [详细](question/faq#space)
3. `U` 代码风格符合 [standard](https://standardjs.com) 标准
4. `U` `uni-app` 包使用 [editable](advanced/plugin#editable) 插件编辑状态下支持预览视频 [详细](https://github.com/jin-yufeng/mp-html/issues/286)
5. `F` 修复了 `svg` 标签内嵌 `svg` 时无法显示的问题
6. `F` 修复了微信原生包 `img` 标签的 `style` 中包含 `inline` 时不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/287)
7. `F` 修复了支付宝和头条小程序部分区域不可复制的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/291)
## v2.1.1
发布时间:*2021-04-09*
主要更新:
1. `F` 修复了对 `p` 标签设置 [tag-style](basic/prop#tag-style) 可能不生效的问题
2. `F` 修复了 `svg` 标签中的文本无法显示的问题
3. `F` 修复了 `uni-app` 包的 `nvue` 端不设置 [container-style](basic/prop#container-style) 可能报错的问题
4. `F` 修复了 `uni-app` 包使用 [editable](advanced/plugin#editable) 插件编辑表格时可能报错的问题
5. `F` 修复了 `uni-app` 包使用 [highlight](advanced/plugin#highlight) 插件运行到头条小程序时可能没有样式的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/280)
6. `F` 修复了 `uni-app` 包使用 [editable](advanced/plugin#editable) 插件 `editable` 属性为 `false` 时会报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/284)
7. `F` 修复了 [style](advanced/plugin#style) 插件连续子选择器失效的问题
8. `F` 修复了 [editable](advanced/plugin#editable) 插件无法修改图片和字体大小的问题
## v2.1.0
发布时间:*2021-03-20*
主要更新:
1. `A` 增加了 [container-style](basic/prop#container-style) 属性 [详细](https://gitee.com/jin-yufeng/mp-html/pulls/1)
2. `A` 增加支持 `strike` 标签
3. `A` `editable` 插件增加 `placeholder` 属性 [详细](advanced/plugin#editable)
4. `A` `editable` 插件增加 `insertHtml` 方法 [详细](advanced/plugin#editable)
5. `U` 外部样式支持标签名选择器 [详细](overview/quickstart#setting)
6. `F` 修复了 `uni-app` 包 `nvue` 端部分情况下可能不显示的问题
## v2.0.5
发布时间:*2021-03-12*
主要更新:
1. `U` [linktap](basic/event#linktap) 事件增加返回内部文本内容 `innerText` [详细](https://github.com/jin-yufeng/mp-html/issues/271)
2. `U` [selectable](basic/prop#selectable) 属性设置为 `force` 时能够在微信 `iOS` 端生效(文本块会变成 `inline-block`) [详细](https://github.com/jin-yufeng/mp-html/issues/267)
3. `F` 修复了部分情况下竖向无法滚动的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/182)
4. `F` 修复了 `uni-app` 包多次修改富文本数据时部分内容可能不显示的问题
5. `F` 修复了百度小程序真机部分内容不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/272)
6. `F` 修复了 [腾讯视频](advanced/plugin#txv-video) 插件可能无法播放的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/265)
7. `F` 修复了 [highlight](advanced/plugin#highlight) 插件没有设置高亮语言时没有应用默认样式的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/276) by [@fuzui](https://github.com/fuzui)
## v2.0.4
发布时间:*2021-01-31*
主要更新:
1. `A` [editable](advanced/plugin#editable) 插件增加下划线和图片超链接的功能 [详细](https://github.com/jin-yufeng/mp-html/issues/254)
2. `U` 支付宝和头条小程序原生包直接通过 `template` 递归实现渲染
3. `F` 修复了 `img` 标签设置 `data-src` 可能导致图片不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/257)
4. `F` 修复了 `script` 标签中的 `<` 会被解析为标签的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/259)
5. `F` 修复了 `uni-app` 包的 `app` 端播放视频时可能高度突然变小的问题
6. `F` 修复了 `uni-app` 包的 `app` 端长按图片会报错的问题
7. `F` 修复了 `uni-app` 包的 `nvue` 端使用 [editable](advanced/plugin#editable) 插件后无法显示的问题
8. `F` 修复了 [editable](advanced/plugin#editable) 插件删除图片和切换内容时可能出现错误选择框的问题
9. `F` 修复了 [editable](advanced/plugin#editable) 插件无法编辑链接文本内容的问题
## v2.0.3
发布时间:*2021-01-15*
主要更新:
1. `U` 图片被点击时不冒泡(可以与整体的点击区分开,不影响链接中的图片)
2. `F` 修复了图片链接缺省协议名时可能无法预览的问题
3. `F` 修复了原生包 `video` 和 `audio` 标签内放置文本会报错的问题
4. `F` 修复了 [editable](advanced/plugin#editable) 插件清空内容时弹窗可能不消失的问题
5. `F` 修复了 [highlight](advanced/plugin#highlight) 插件部分情况下样式不正确的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/231)
6. `F` 修复了文档首页跳转到快速开始页时 `404` 的问题 by [@AnsonZnl](https://github.com/AnsonZnl)
## v2.0.2
发布时间:*2021-01-08*
主要更新:
1. `U` `uni-app` 包微信端利用 `virtualHost` 去除夹层,加快渲染
2. `F` 修复了部分情况下 `flex` 布局显示不正确的问题
3. `F` 修复了设置 [loading-img](basic/prop#loading-img) 会导致懒加载失效的问题
4. `F` 修复了头条原生包部分情况下表格显示不正确的问题
5. `F` 修复了 `uni-app` 的 `h5` 和 `app` 端部分插件样式无法应用的问题
6. `F` 修复了 `uni-app` 包没有自动将 `data-src` 设置为 `src` 的问题
7. `F` 修复了 `uni-app` 包的 `nvue` 端 [getRect](advanced/api#getRect) 方法无法使用的问题
8. `F` 修复了 `uni-app` 包运行到华为快应用可能报错的问题
9. `F` 修复了在低版本 taro 中使用可能无法正确解析的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/248)
10. `F` 修复了 [highlight](advanced/plugin#highlight) 插件 `pre` 和 `code` 之间有空白符时无法高亮的问题
11. `F` 修复了 [editable](advanced/plugin#editable) 插件清空内容后插入可能报错的问题
## v2.0.1
发布时间:*2021-01-01*
主要更新:
1. `F` 修复了 `a` 标签自动跳转到不存在页面时可能报错的问题
2. `F` 修复了含合并单元格的表格设置列宽可能导致显示不正确的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/239)
3. `F` 修复了表格中的图片可能错位的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/194)
4. `F` 修复了原生包使用 [editable](advanced/plugin#editable) 插件点击标签时可能报错的问题
5. `F` 修复了 `uni-app` 的 `h5` 和 `app` 端可能无法使用 `iframe` 和 `embed` 标签的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/245)
6. `F` 修复了 `uni-app` 使用部分插件会报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/246)
## v2.0.0
发布时间:*2020-12-26*
主要更新:
1. `U` 通过 `gulp` 进行构建,自动生成各平台压缩版代码,减小引入包大小 [详细](advanced/develop#pack)
2. `U` 没有设置 `href` 属性的 `a` 标签不应用链接的样式,可以用作一般标签的点击处理 [详细](question/faq#tap)
3. `U` 提供了统一的插件接口,扩展更加方便(代码高亮、`markdown` 等都可以直接通过引入插件实现)[详细](advanced/plugin)
4. `U` 实现了简单的编辑功能 [详细](advanced/plugin#editable)
5. `U` 支持生成各平台的示例项目,便于调试 [详细](overview/quickstart#demo)
6. `U` 原生包共用一份源代码(构建时进行自动转换),注释更加详细,便于了解和维护
7. `U` 通过 `jest` 进行单元测试,进一步保证代码质量 [详细](advanced/develop#test)
8. `U` 去除了一些冗余功能,进一步减小包大小(约 `24.5KB`)
9. `U` 减少了递归节点树,加快渲染速度
10. `U` `uni-app` 的 `app` 端使用非原生的 `video` 显示视频以解决无法同层带来的系列问题
11. `U` `uni-app` 的 `nvue` 端支持通过 `bgColor` 属性设置背景色(默认白色,不可设置为透明)
12. `F` 修复了 `uni-app` 的 `nvue` 端从不可见区域到可见时可能显示不正确的问题
*v1.x* 更新指南:
- 组件路径和名称
*parser* -> *mp-html*
- *npm* 包名
*parser-wx* -> *mp-html*
- 组件属性
更名:
*html* -> [content](basic/prop#content)
*autopause* -> [pause-video](basic/prop#pause-video)
*autoscroll* -> [scroll-table](basic/prop#scroll-table)
*autosetTitle* -> [set-title](basic/prop#set-title)
移除:
*compress*, *show-with-animation*, *use-cache*
新增:
[copy-link](basic/prop#copy-link), [error-img](basic/prop#error-img), [preview-img](basic/prop#preview-img), [show-img-menu](basic/prop#show-img-menu)
修改:
[use-anchor](basic/prop#use-anchor) 支持传入数字表示跳转偏移量
- 组件事件
更名 *linkpress* -> [linktap](basic/event#linktap)
移除 *parse* 事件
*imgtap* 和 *linktap* 事件中不再返回 *ignore* 方法,可以使用 [preview-img](basic/prop#preview-img) 和 [copy-link](basic/prop#copy-link) 属性禁用自动预览/拷贝
链接被点击时,不再支持自动跳转其他小程序,可以自行在 [linktap](basic/event#linktap) 事件中进行跳转
- api
[navigateTo](advanced/api#navigateTo) 返回 *Promise*,不再采用 *success* 和 *fail* 回调
*rect* 变更为 [getRect](advanced/api#getRect) 方法
移除 *getVideoContext* 方法
[imgList](advanced/api#imgList) 不再包含 *setItem* 和 *each* 方法
- 其他
默认不再支持匹配 *style* 标签中的样式,如有需要请使用 [style](advanced/plugin#style) 插件
不再支持 *base64* 图片预览(默认为不可预览的小图片)
取消了配置项(相关解析配置在 *parser.js* 中,*filter* 等方法用 [插件](advanced/plugin) 的方式替代)
取消了视频的懒加载(应避免在一个页面中使用过多视频,以免卡顿)
*ad* 标签默认不添加到模板(详见 [个性化](overview/quickstart#setting))
+50
View File
@@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>小程序富文本组件</title>
<link rel="icon" href="assets/logo/logo.ico" type="image/x-icon">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="小程序富文本组件">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="lib/vue.css">
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script")
hm.src = "https://hm.baidu.com/hm.js?69554d980eb5eb786919e3c3ad37b2ce"
var s = document.getElementsByTagName("script")[0]
s.parentNode.insertBefore(hm, s)
})()
</script>
</head>
<body>
<div id="app"></div>
<script>
window.$docsify = {
name: 'mp-html',
repo: 'https://github.com/jin-yufeng/mp-html',
coverpage: true,
loadSidebar: true,
subMaxLevel: 3,
auto2top: true,
search: {
placeholder: '搜索',
noData: '找不到结果'
}
}
// 渲染测试内容
function render () {
document.getElementById("show").srcdoc='<meta name="viewport" content="width=device-width"><style>img{max-width:100%}</style>'+document.getElementById("input").value.replace(/<script[\s\S]+?<\/script>/g, '')
}
// 清空测试内容
function reset () {
document.getElementById("input").value = ''
document.getElementById("show").srcdoc = ''
}
</script>
<script src="lib/docsify.min.js"></script>
<script src="lib/search.min.js"></script>
<script src="lib/prism-bash.min.js"></script>
</body>
</html>
+1
View File
@@ -0,0 +1 @@
!function(){function s(n){var r=Object.create(null);return function(e){var t=c(e)?e:JSON.stringify(e);return r[t]||(r[t]=n(e))}}var o=s(function(e){return e.replace(/([A-Z])/g,function(e){return"-"+e.toLowerCase()})}),l=Object.prototype.hasOwnProperty,y=Object.assign||function(e){for(var t=arguments,n=1;n<arguments.length;n++){var r,i=Object(t[n]);for(r in i)l.call(i,r)&&(e[r]=i[r])}return e};function c(e){return"string"==typeof e||"number"==typeof e}function u(){}function r(e){return"function"==typeof e}function p(e){e=e.match(/^([^:/?#]+:)?(?:\/{2,}([^/?#]*))?([^?#]+)?(\?[^#]*)?(#.*)?/);return"string"==typeof e[1]&&0<e[1].length&&e[1].toLowerCase()!==location.protocol||"string"==typeof e[2]&&0<e[2].length&&e[2].replace(new RegExp(":("+{"http:":80,"https:":443}[location.protocol]+")?$"),"")!==location.host}var h=document.body.clientWidth<=600,i=window.history&&window.history.pushState&&window.history.replaceState&&!navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/),n={};function d(e,t){if(void 0===t&&(t=!1),"string"==typeof e){if(void 0!==window.Vue)return b(e);e=t?b(e):n[e]||(n[e]=b(e))}return e}var f=document,g=f.body,m=f.head;function b(e,t){return t?e.querySelector(t):f.querySelector(e)}function k(e,t){return[].slice.call(t?e.querySelectorAll(t):f.querySelectorAll(e))}function v(e,t){return e=f.createElement(e),t&&(e.innerHTML=t),e}function a(e,t){return e.appendChild(t)}function w(e,t){return e.insertBefore(t,e.children[0])}function x(e,t,n){r(t)?window.addEventListener(e,t):e.addEventListener(t,n)}function _(e,t,n){r(t)?window.removeEventListener(e,t):e.removeEventListener(t,n)}function S(e,t,n){e&&e.classList[n?t:"toggle"](n||t)}function e(e,t){void 0===t&&(t=document);var n=t.readyState;if("complete"===n||"interactive"===n)return setTimeout(e,0);t.addEventListener("DOMContentLoaded",e)}var t=Object.freeze({__proto__:null,getNode:d,$:f,body:g,head:m,find:b,findAll:k,create:v,appendTo:a,before:w,on:x,off:_,toggleClass:S,style:function(e){a(m,v("style",e))},documentReady:e}),A=decodeURIComponent,T=encodeURIComponent;function E(e){var t={};return(e=e.trim().replace(/^(\?|#|&)/,""))&&e.split("&").forEach(function(e){e=e.replace(/\+/g," ").split("=");t[e[0]]=e[1]&&A(e[1])}),t}function R(e,t){void 0===t&&(t=[]);var n,r=[];for(n in e)-1<t.indexOf(n)||r.push(e[n]?(T(n)+"="+T(e[n])).toLowerCase():T(n));return r.length?"?"+r.join("&"):""}var O=s(function(e){return/(:|(\/{2}))/g.test(e)}),$=s(function(e){return e.split(/[?#]/)[0]}),F=s(function(e){if(/\/$/g.test(e))return e;e=e.match(/(\S*\/)[^/]+$/);return e?e[1]:""}),C=s(function(e){return e.replace(/^\/+/,"/").replace(/([^:])\/{2,}/g,"$1/")}),L=s(function(e){for(var t=e.replace(/^\//,"").split("/"),n=[],r=0,i=t.length;r<i;r++){var o=t[r];".."===o?n.pop():"."!==o&&n.push(o)}return"/"+n.join("/")});function z(e){return e.split("/").filter(function(e){return-1===e.indexOf("#")}).join("/")}function N(){for(var e=[],t=arguments.length;t--;)e[t]=arguments[t];return C(e.map(z).join("/"))}var M=s(function(e){return e.replace("#","?id=")});function D(e,t){return-1!==e.indexOf(t,e.length-t.length)}var P={};var I=function(e){this.config=e};function j(e){var t=location.href.indexOf("#");location.replace(location.href.slice(0,0<=t?t:0)+"#"+e)}I.prototype.getBasePath=function(){return this.config.basePath},I.prototype.getFile=function(e,t){void 0===e&&(e=this.getCurrentPath());var n,r,i=this.config,o=this.getBasePath(),a="string"==typeof i.ext?i.ext:".md";return e=i.alias?function e(t,n,r){var i=Object.keys(n).filter(function(e){return(P[e]||(P[e]=new RegExp("^"+e+"$"))).test(t)&&t!==r})[0];return i?e(t.replace(P[i],n[i]),n,t):t}(e,i.alias):e,n=e,r=a,e=(e=new RegExp("\\.("+r.replace(/^\./,"")+"|html)$","g").test(n)?n:/\/$/g.test(n)?n+"README"+r:""+n+r)==="/README"+a&&i.homepage||e,e=O(e)?e:N(o,e),t&&(e=e.replace(new RegExp("^"+o),"")),e},I.prototype.onchange=function(e){void 0===e&&(e=u),e()},I.prototype.getCurrentPath=function(){},I.prototype.normalize=function(){},I.prototype.parse=function(){},I.prototype.toURL=function(e,t,n){var r=n&&"#"===e[0],i=this.parse(M(e));if(i.query=y({},i.query,t),e=(e=i.path+R(i.query)).replace(/\.md(\?)|\.md$/,"$1"),r&&(e=(0<(r=n.indexOf("?"))?n.substring(0,r):n)+e),this.config.relativePath&&0!==e.indexOf("/")){n=n.substring(0,n.lastIndexOf("/")+1);return C(L(n+e))}return C("/"+e)};var H=function(r){function e(e){r.call(this,e),this.mode="hash"}return r&&(e.__proto__=r),((e.prototype=Object.create(r&&r.prototype)).constructor=e).prototype.getBasePath=function(){var e=window.location.pathname||"",t=this.config.basePath,e=D(e,".html")?e+"#/"+t:e+"/"+t;return/^(\/|https?:)/g.test(t)?t:C(e)},e.prototype.getCurrentPath=function(){var e=location.href,t=e.indexOf("#");return-1===t?"":e.slice(t+1)},e.prototype.onchange=function(n){void 0===n&&(n=u);var r=!1;x("click",function(e){e="A"===e.target.tagName?e.target:e.target.parentNode;e&&"A"===e.tagName&&!/_blank/.test(e.target)&&(r=!0)}),x("hashchange",function(Line truncated
+1
View File
@@ -0,0 +1 @@
!function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},a={bash:n,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:a},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:a},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:a.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:a.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|evaLine truncated
+1
View File
@@ -0,0 +1 @@
!function(){var u={},m={EXPIRE_KEY:"docsify.search.expires",INDEX_KEY:"docsify.search.index"};function p(e){var n={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};return String(e).replace(/[&<>"']/g,function(e){return n[e]})}function h(e){return e.text||"table"!==e.type||(e.cells.unshift(e.header),e.text=e.cells.map(function(e){return e.join(" | ")}).join(" |\n ")),e.text}function f(e){return e.text||"list"!==e.type||(e.text=e.raw),e.text}function g(i,e,r,o){void 0===e&&(e="");var s,e=window.marked.lexer(e),c=window.Docsify.slugify,d={},l="";return e.forEach(function(e,n){if("heading"===e.type&&e.depth<=o){var t=function(e){void 0===e&&(e="");var a={};return{str:e=e&&e.replace(/^('|")/,"").replace(/('|")$/,"").replace(/(?:^|\s):([\w-]+:?)=?([\w-%]+)?/g,function(e,n,t){return-1===n.indexOf(":")?(a[n]=t&&t.replace(/&quot;/g,"")||!0,""):e}).trim(),config:a}}(e.text),a=t.str,t=t.config;s=t.id?r.toURL(i,{id:c(t.id)}):r.toURL(i,{id:c(p(e.text))}),a&&(l=a.replace(/<!-- {docsify-ignore} -->/,"").replace(/{docsify-ignore}/,"").replace(/<!-- {docsify-ignore-all} -->/,"").replace(/{docsify-ignore-all}/,"").trim()),d[s]={slug:s,title:l,body:""}}else{if(0===n&&(s=r.toURL(i),d[s]={slug:s,title:"/"!==i?i.slice(1):"Home Page",body:e.text||""}),!s)return;d[s]?d[s].body?(e.text=h(e),e.text=f(e),d[s].body+="\n"+(e.text||"")):(e.text=h(e),e.text=f(e),d[s].body=d[s].body?d[s].body+e.text:e.text):d[s]={slug:s,title:"",body:""}}}),c.clear(),d}function y(e){return e&&e.normalize?e.normalize("NFD").replace(/[\u0300-\u036f]/g,""):e}function r(i,r){var t,a,n,e,o="auto"===i.paths,s=o?(t=r.router,a=[],Docsify.dom.findAll(".sidebar-nav a:not(.section-link):not([data-nosearch])").forEach(function(e){var n=e.href,e=e.getAttribute("href"),n=t.parse(n).path;n&&-1===a.indexOf(n)&&!Docsify.util.isAbsolutePath(e)&&a.push(n)}),a):i.paths,c="";s.length&&o&&i.pathNamespaces?(n=s[0],Array.isArray(i.pathNamespaces)?c=i.pathNamespaces.filter(function(e){return n.slice(0,e.length)===e})[0]||c:i.pathNamespaces instanceof RegExp&&((d=n.match(i.pathNamespaces))&&(c=d[0])),e=-1===s.indexOf(c+"/"),d=-1===s.indexOf(c+"/README"),e&&d&&s.unshift(c+"/")):-1===s.indexOf("/")&&-1===s.indexOf("/README")&&s.unshift("/");var d,l=((d=i.namespace)?m.EXPIRE_KEY+"/"+d:m.EXPIRE_KEY)+c,p=((d=i.namespace)?m.INDEX_KEY+"/"+d:m.INDEX_KEY)+c,c=localStorage.getItem(l)<Date.now();if(u=JSON.parse(localStorage.getItem(p)),c)u={};else if(!o)return;var h=s.length,f=0;s.forEach(function(a){return u[a]?f++:void Docsify.get(r.router.getFile(a),!1,r.config.requestHeaders).then(function(e){var n,t;u[a]=g(a,e,r.router,i.depth),h===++f&&(n=i.maxAge,t=l,e=p,localStorage.setItem(t,Date.now()+n),localStorage.setItem(e,JSON.stringify(u)))})})}var o,s="";function c(e){var n=Docsify.dom.find("div.search"),t=Docsify.dom.find(n,".results-panel"),a=Docsify.dom.find(n,".clear-button"),i=Docsify.dom.find(".sidebar-nav"),n=Docsify.dom.find(".app-name");if(!e)return t.classList.remove("show"),a.classList.remove("show"),t.innerHTML="",void(o.hideOtherSidebarContent&&(i&&i.classList.remove("hide"),n&&n.classList.remove("hide")));var e=function(e){var n=[],t=[];Object.keys(u).forEach(function(n){t=t.concat(Object.keys(u[n]).map(function(e){return u[n][e]}))});var a=(e=e.trim()).split(/[\s\-,\\/]+/);1!==a.length&&(a=[].concat(e,a));for(var i=0;i<t.length;i++)!function(e){var e=t[e],r=0,o="",s="",c="",d=e.title&&e.title.trim(),l=e.body&&e.body.trim(),e=e.slug||"";d&&(a.forEach(function(e){var n,t=new RegExp(p(y(e)).replace(/[|\\{}()[\]^$+*?.]/g,"\\$&"),"gi"),a=-1,i=-1;s=d?p(y(d)):d,c=l?p(y(l)):l,a=d?s.search(t):-1,i=l?c.search(t):-1,(0<=a||0<=i)&&(r+=0<=a?3:0<=i?2:0,i<0&&(i=0),a=(a=n=0)==(n=i<11?0:i-10)?70:i+e.length+60,l&&a>l.length&&(a=l.length),t="..."+c.substring(n,a).replace(t,function(e){return'<em class="search-keyword">'+e+"</em>"})+"...",o+=t)}),0<r&&(e={title:s,content:l?o:"",url:e,score:r},n.push(e)))}(i);return n.sort(function(e,n){return n.score-e.score})}(e),r="";e.forEach(function(e){r+='<div class="matching-post">\n<a href="'+e.url+'">\n<h2>'+e.title+"</h2>\n<p>"+e.content+"</p>\n</a>\n</div>"}),t.classList.add("show"),a.classList.add("show"),t.innerHTML=r||'<p class="empty">'+s+"</p>",o.hideOtherSidebarContent&&(i&&i.classList.add("hide"),n&&n.classList.add("hide"))}function d(e){o=e}function l(e,n){var t,a,i=n.router.parse().query.s;d(e),Docsify.dom.style("\n.sidebar {\n padding-top: 0;\n}\n\n.search {\n margin-bottom: 20px;\n padding: 6px;\n border-bottom: 1px solid #eee;\n}\n\n.search .input-wrap {\n display: flex;\n align-items: center;\n}\n\n.search .results-panel {\n display: none;\n}\n\n.search .results-panel.show {\n display: block;\n}\n\n.search input {\n outline: none;\n border: none;\n width: 100%;\n padding: 0 7px;\n line-height: 36px;\n font-size: 14px;\n border: 1px solid transparent;\n}\n\n.search input:focus {\n box-shadow: 0 0 5px var(--theme-color, #42b983);\n border: 1px solid var(--theme-color, #42b983);\n}\n\n.search input::-webkit-searLine truncated
+858
View File
@@ -0,0 +1,858 @@
@import url("https://fonts.googleapis.com/css?family=Roboto+Mono|Source+Sans+Pro:300,400,600");
* {
-webkit-font-smoothing: antialiased;
-webkit-overflow-scrolling: touch;
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-text-size-adjust: none;
-webkit-touch-callout: none;
box-sizing: border-box;
}
body:not(.ready) {
overflow: hidden;
}
body:not(.ready) [data-cloak],
body:not(.ready) .app-nav,
body:not(.ready) > nav {
display: none;
}
div#app {
font-size: 30px;
font-weight: lighter;
margin: 40vh auto;
text-align: center;
}
div#app:empty::before {
content: 'Loading...';
}
.emoji {
height: 1.2rem;
vertical-align: middle;
}
.progress {
background-color: var(--theme-color, #42b983);
height: 2px;
left: 0px;
position: fixed;
right: 0px;
top: 0px;
transition: width 0.2s, opacity 0.4s;
width: 0%;
z-index: 999999;
}
.search a:hover {
color: var(--theme-color, #42b983);
}
.search .search-keyword {
color: var(--theme-color, #42b983);
font-style: normal;
font-weight: bold;
}
html,
body {
height: 100%;
}
body {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
color: #34495e;
font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
font-size: 15px;
letter-spacing: 0;
margin: 0;
overflow-x: hidden;
}
img {
max-width: 100%;
}
a[disabled] {
cursor: not-allowed;
opacity: 0.6;
}
kbd {
border: solid 1px #ccc;
border-radius: 3px;
display: inline-block;
font-size: 12px !important;
line-height: 12px;
margin-bottom: 3px;
padding: 3px 5px;
vertical-align: middle;
}
li input[type='checkbox'] {
margin: 0 0.2em 0.25em 0;
vertical-align: middle;
}
.app-nav {
margin: 25px 60px 0 0;
position: absolute;
right: 0;
text-align: right;
z-index: 10;
/* navbar dropdown */
}
.app-nav.no-badge {
margin-right: 25px;
}
.app-nav p {
margin: 0;
}
.app-nav > a {
margin: 0 1rem;
padding: 5px 0;
}
.app-nav ul,
.app-nav li {
display: inline-block;
list-style: none;
margin: 0;
}
.app-nav a {
color: inherit;
font-size: 16px;
text-decoration: none;
transition: color 0.3s;
}
.app-nav a:hover {
color: var(--theme-color, #42b983);
}
.app-nav a.active {
border-bottom: 2px solid var(--theme-color, #42b983);
color: var(--theme-color, #42b983);
}
.app-nav li {
display: inline-block;
margin: 0 1rem;
padding: 5px 0;
position: relative;
cursor: pointer;
}
.app-nav li ul {
background-color: #fff;
border: 1px solid #ddd;
border-bottom-color: #ccc;
border-radius: 4px;
box-sizing: border-box;
display: none;
max-height: calc(100vh - 61px);
overflow-y: auto;
padding: 10px 0;
position: absolute;
right: -15px;
text-align: left;
top: 100%;
white-space: nowrap;
}
.app-nav li ul li {
display: block;
font-size: 14px;
line-height: 1rem;
margin: 0;
margin: 8px 14px;
white-space: nowrap;
}
.app-nav li ul a {
display: block;
font-size: inherit;
margin: 0;
padding: 0;
}
.app-nav li ul a.active {
border-bottom: 0;
}
.app-nav li:hover ul {
display: block;
}
.github-corner {
border-bottom: 0;
position: fixed;
right: 0;
text-decoration: none;
top: 0;
z-index: 1;
}
.github-corner:hover .octo-arm {
-webkit-animation: octocat-wave 560ms ease-in-out;
animation: octocat-wave 560ms ease-in-out;
}
.github-corner svg {
color: #fff;
fill: var(--theme-color, #42b983);
height: 80px;
width: 80px;
}
main {
display: block;
position: relative;
width: 100vw;
height: 100%;
z-index: 0;
}
main.hidden {
display: none;
}
.anchor {
display: inline-block;
text-decoration: none;
transition: all 0.3s;
}
.anchor span {
color: #34495e;
}
.anchor:hover {
text-decoration: underline;
}
.sidebar {
border-right: 1px solid rgba(0,0,0,0.07);
overflow-y: auto;
padding: 40px 0 0;
position: absolute;
top: 0;
bottom: 0;
left: 0;
transition: transform 250ms ease-out;
width: 300px;
z-index: 20;
}
.sidebar > h1 {
margin: 0 auto 1rem;
font-size: 1.5rem;
font-weight: 300;
text-align: center;
}
.sidebar > h1 a {
color: inherit;
text-decoration: none;
}
.sidebar > h1 .app-nav {
display: block;
position: static;
}
.sidebar .sidebar-nav {
line-height: 2em;
padding-bottom: 40px;
}
.sidebar li.collapse .app-sub-sidebar {
display: none;
}
.sidebar ul {
margin: 0 0 0 15px;
padding: 0;
}
.sidebar li > p {
font-weight: 700;
margin: 0;
}
.sidebar ul,
.sidebar ul li {
list-style: none;
}
.sidebar ul li a {
border-bottom: none;
display: block;
}
.sidebar ul li ul {
padding-left: 20px;
}
.sidebar::-webkit-scrollbar {
width: 4px;
}
.sidebar::-webkit-scrollbar-thumb {
background: transparent;
border-radius: 4px;
}
.sidebar:hover::-webkit-scrollbar-thumb {
background: rgba(136,136,136,0.4);
}
.sidebar:hover::-webkit-scrollbar-track {
background: rgba(136,136,136,0.1);
}
.sidebar-toggle {
background-color: transparent;
background-color: rgba(255,255,255,0.8);
border: 0;
outline: none;
padding: 10px;
position: absolute;
bottom: 0;
left: 0;
text-align: center;
transition: opacity 0.3s;
width: 284px;
z-index: 30;
cursor: pointer;
}
.sidebar-toggle:hover .sidebar-toggle-button {
opacity: 0.4;
}
.sidebar-toggle span {
background-color: var(--theme-color, #42b983);
display: block;
margin-bottom: 4px;
width: 16px;
height: 2px;
}
body.sticky .sidebar,
body.sticky .sidebar-toggle {
position: fixed;
}
.content {
padding-top: 60px;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 300px;
transition: left 250ms ease;
}
.markdown-section {
margin: 0 auto;
max-width: 80%;
padding: 30px 15px 40px 15px;
position: relative;
}
.markdown-section > * {
box-sizing: border-box;
font-size: inherit;
}
.markdown-section > :first-child {
margin-top: 0 !important;
}
.markdown-section hr {
border: none;
border-bottom: 1px solid #eee;
margin: 2em 0;
}
.markdown-section iframe {
border: 1px solid #eee;
/* fix horizontal overflow on iOS Safari */
width: 1px;
min-width: 100%;
}
.markdown-section table {
border-collapse: collapse;
border-spacing: 0;
display: block;
margin-bottom: 1rem;
overflow: auto;
width: 100%;
}
.markdown-section th {
border: 1px solid #ddd;
font-weight: bold;
padding: 6px 13px;
}
.markdown-section td {
border: 1px solid #ddd;
padding: 6px 13px;
}
.markdown-section tr {
border-top: 1px solid #ccc;
}
.markdown-section tr:nth-child(2n) {
background-color: #f8f8f8;
}
.markdown-section p.tip {
background-color: #f8f8f8;
border-bottom-right-radius: 2px;
border-left: 4px solid #f66;
border-top-right-radius: 2px;
margin: 2em 0;
padding: 12px 24px 12px 30px;
position: relative;
}
.markdown-section p.tip:before {
background-color: #f66;
border-radius: 100%;
color: #fff;
content: '!';
font-family: 'Dosis', 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
font-size: 14px;
font-weight: bold;
left: -12px;
line-height: 20px;
position: absolute;
height: 20px;
width: 20px;
text-align: center;
top: 14px;
}
.markdown-section p.tip code {
background-color: #efefef;
}
.markdown-section p.tip em {
color: #34495e;
}
.markdown-section p.warn {
background: rgba(66,185,131,0.1);
border-radius: 2px;
padding: 1rem;
}
.markdown-section ul.task-list > li {
list-style-type: none;
}
body.close .sidebar {
transform: translateX(-300px);
}
body.close .sidebar-toggle {
width: auto;
}
body.close .content {
left: 0;
}
@media print {
.github-corner,
.sidebar-toggle,
.sidebar,
.app-nav {
display: none;
}
}
@media screen and (max-width: 768px) {
.github-corner,
.sidebar-toggle,
.sidebar {
position: fixed;
}
.app-nav {
margin-top: 16px;
}
.app-nav li ul {
top: 30px;
}
main {
height: auto;
min-height: 100vh;
overflow-x: hidden;
}
.sidebar {
left: -300px;
transition: transform 250ms ease-out;
}
.content {
left: 0;
max-width: 100vw;
position: static;
padding-top: 20px;
transition: transform 250ms ease;
}
.app-nav,
.github-corner {
transition: transform 250ms ease-out;
}
.sidebar-toggle {
background-color: transparent;
width: auto;
padding: 30px 30px 10px 10px;
}
body.close .sidebar {
transform: translateX(300px);
}
body.close .sidebar-toggle {
background-color: rgba(255,255,255,0.8);
transition: 1s background-color;
width: 284px;
padding: 10px;
}
body.close .content {
transform: translateX(300px);
}
body.close .app-nav,
body.close .github-corner {
display: none;
}
.github-corner:hover .octo-arm {
-webkit-animation: none;
animation: none;
}
.github-corner .octo-arm {
-webkit-animation: octocat-wave 560ms ease-in-out;
animation: octocat-wave 560ms ease-in-out;
}
}
@-webkit-keyframes octocat-wave {
0%, 100% {
transform: rotate(0);
}
20%, 60% {
transform: rotate(-25deg);
}
40%, 80% {
transform: rotate(10deg);
}
}
@keyframes octocat-wave {
0%, 100% {
transform: rotate(0);
}
20%, 60% {
transform: rotate(-25deg);
}
40%, 80% {
transform: rotate(10deg);
}
}
section.cover {
align-items: center;
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
height: 100vh;
width: 100vw;
display: none;
}
section.cover.show {
display: flex;
}
section.cover.has-mask .mask {
background-color: #fff;
opacity: 0.8;
position: absolute;
top: 0;
height: 100%;
width: 100%;
}
section.cover .cover-main {
flex: 1;
margin: -20px 16px 0;
text-align: center;
position: relative;
}
section.cover a {
color: inherit;
text-decoration: none;
}
section.cover a:hover {
text-decoration: none;
}
section.cover p {
line-height: 1.5rem;
margin: 1em 0;
}
section.cover h1 {
color: inherit;
font-size: 2.5rem;
font-weight: 300;
margin: 0.625rem 0 2.5rem;
position: relative;
text-align: center;
}
section.cover h1 a {
display: block;
}
section.cover h1 small {
bottom: -0.4375rem;
font-size: 1rem;
position: absolute;
}
section.cover blockquote {
font-size: 1.5rem;
text-align: center;
}
section.cover ul {
line-height: 1.8;
list-style-type: none;
margin: 1em auto;
max-width: 500px;
padding: 0;
}
section.cover .cover-main > p:last-child a {
border-color: var(--theme-color, #42b983);
border-radius: 2rem;
border-style: solid;
border-width: 1px;
box-sizing: border-box;
color: var(--theme-color, #42b983);
display: inline-block;
font-size: 1.05rem;
letter-spacing: 0.1rem;
margin: 0.5rem 1rem;
padding: 0.75em 2rem;
text-decoration: none;
transition: all 0.15s ease;
}
section.cover .cover-main > p:last-child a:last-child {
background-color: var(--theme-color, #42b983);
color: #fff;
}
section.cover .cover-main > p:last-child a:last-child:hover {
color: inherit;
opacity: 0.8;
}
section.cover .cover-main > p:last-child a:hover {
color: inherit;
}
section.cover blockquote > p > a {
border-bottom: 2px solid var(--theme-color, #42b983);
transition: color 0.3s;
}
section.cover blockquote > p > a:hover {
color: var(--theme-color, #42b983);
}
body {
background-color: #fff;
}
/* sidebar */
.sidebar {
background-color: #fff;
color: #364149;
}
.sidebar li {
margin: 6px 0 6px 0;
}
.sidebar ul li a {
color: #505d6b;
font-size: 14px;
font-weight: normal;
overflow: hidden;
text-decoration: none;
text-overflow: ellipsis;
white-space: nowrap;
}
.sidebar ul li a:hover {
text-decoration: underline;
}
.sidebar ul li ul {
padding: 0;
}
.sidebar ul li.active > a {
border-right: 2px solid;
color: var(--theme-color, #42b983);
font-weight: 600;
}
.app-sub-sidebar li::before {
content: '-';
padding-right: 4px;
float: left;
}
/* markdown content found on pages */
.markdown-section h1,
.markdown-section h2,
.markdown-section h3,
.markdown-section h4,
.markdown-section strong {
color: #2c3e50;
font-weight: 600;
}
.markdown-section a {
color: var(--theme-color, #42b983);
font-weight: 600;
}
.markdown-section h1 {
font-size: 2rem;
margin: 0 0 1rem;
}
.markdown-section h2 {
font-size: 1.75rem;
margin: 45px 0 0.8rem;
}
.markdown-section h3 {
font-size: 1.5rem;
margin: 40px 0 0.6rem;
}
.markdown-section h4 {
font-size: 1.25rem;
}
.markdown-section h5 {
font-size: 1rem;
}
.markdown-section h6 {
color: #777;
font-size: 1rem;
}
.markdown-section figure,
.markdown-section p {
margin: 1.2em 0;
}
.markdown-section p,
.markdown-section ul,
.markdown-section ol {
line-height: 1.6rem;
word-spacing: 0.05rem;
}
.markdown-section ul,
.markdown-section ol {
padding-left: 1.5rem;
}
.markdown-section blockquote {
border-left: 4px solid var(--theme-color, #42b983);
color: #858585;
margin: 2em 0;
padding-left: 20px;
}
.markdown-section blockquote p {
font-weight: 600;
margin-left: 0;
}
.markdown-section iframe {
margin: 1em 0;
}
.markdown-section em {
color: #7f8c8d;
}
.markdown-section code,
.markdown-section pre,
.markdown-section output::after {
font-family: 'Roboto Mono', Monaco, courier, monospace;
}
.markdown-section code,
.markdown-section pre {
background-color: #f8f8f8;
}
.markdown-section pre,
.markdown-section output {
margin: 1.2em 0;
position: relative;
}
.markdown-section pre > code,
.markdown-section output {
border-radius: 2px;
display: block;
}
.markdown-section pre > code,
.markdown-section output::after {
-moz-osx-font-smoothing: initial;
-webkit-font-smoothing: initial;
}
.markdown-section code {
border-radius: 2px;
color: #e96900;
margin: 0 2px;
padding: 3px 5px;
white-space: pre-wrap;
}
.markdown-section > :not(h1):not(h2):not(h3):not(h4):not(h5):not(h6) code {
font-size: 0.8rem;
}
.markdown-section pre {
padding: 0 1.4rem;
line-height: 1.5rem;
overflow: auto;
word-wrap: normal;
}
.markdown-section pre > code {
color: #525252;
font-size: 0.8rem;
padding: 2.2em 5px;
line-height: inherit;
margin: 0 2px;
max-width: inherit;
overflow: inherit;
white-space: inherit;
}
.markdown-section output {
padding: 1.7rem 1.4rem;
border: 1px dotted #ccc;
}
.markdown-section output > :first-child {
margin-top: 0;
}
.markdown-section output > :last-child {
margin-bottom: 0;
}
.markdown-section code::after,
.markdown-section code::before,
.markdown-section output::after,
.markdown-section output::before {
letter-spacing: 0.05rem;
}
.markdown-section pre::after,
.markdown-section output::after {
color: #ccc;
font-size: 0.6rem;
font-weight: 600;
height: 15px;
line-height: 15px;
padding: 5px 10px 0;
position: absolute;
right: 0;
text-align: right;
top: 0;
}
.markdown-section pre::after,
.markdown-section output::after {
content: attr(data-lang);
}
/* code highlight */
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #8e908c;
}
.token.namespace {
opacity: 0.7;
}
.token.boolean,
.token.number {
color: #c76b29;
}
.token.punctuation {
color: #525252;
}
.token.property {
color: #c08b30;
}
.token.tag {
color: #2973b7;
}
.token.string {
color: var(--theme-color, #42b983);
}
.token.selector {
color: #6679cc;
}
.token.attr-name {
color: #2973b7;
}
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #22a2c9;
}
.token.attr-value,
.token.control,
.token.directive,
.token.unit {
color: var(--theme-color, #42b983);
}
.token.keyword,
.token.function {
color: #e96900;
}
.token.statement,
.token.regex,
.token.atrule {
color: #22a2c9;
}
.token.placeholder,
.token.variable {
color: #3d8fd1;
}
.token.deleted {
text-decoration: line-through;
}
.token.inserted {
border-bottom: 1px dotted #202746;
text-decoration: none;
}
.token.italic {
font-style: italic;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.important {
color: #c94922;
}
.token.entity {
cursor: help;
}
code .token {
-moz-osx-font-smoothing: initial;
-webkit-font-smoothing: initial;
min-height: 1.5rem;
position: relative;
left: auto;
}
+234
View File
@@ -0,0 +1,234 @@
# 功能介绍
## ⏳ 渲染效果 :id=show
1. *加载提示*
支持在 *mp-html* 标签内部放上自定义的加载提示,内容未加载完成(或为空)时将显示,加载完成后自动隐藏
```wxml
<mp-html>加载中...</mp-html>
```
2. *自动设置标题*
支持自动把 *title* 标签的内容设置到页面标题上,如不需要,可通过 [set-title](basic/prop#set-title) 属性关闭
3. *长按复制*
支持长按复制文本内容,可通过 [selectable](basic/prop#selectable) 属性开启
4. *支持 rpx*
支持 *rpx* 作为单位,自动根据屏幕宽度调整
5. *支持 html 实体*
支持所有形如 *&amp;#123;* 的 *html* 实体和大部分常用的形如 *&amp;nbsp;* 的实体
## 📰 图片效果 :id=img
1. *占位图*
支持设置图片未加载完成时的占位图 [loading-img](basic/prop#loading-img) 和加载出错时的占位图 [error-img](basic/prop#error-img)
2. *懒加载*
内容较长、图片较多时,开启懒加载有助于改善性能,需要时可通过 [lazy-load](basic/prop#lazy-load) 属性开启
3. *自动预览*
图片被点击时,将自动放大预览,如不需要,可通过 [preview-img](basic/prop#preview-img) 属性关闭。还可以在 [imgtap](basic/event#imgtap) 事件中进行自定义处理
自动预览通过特定的处理,可以实现左右滑动查看所有图片、预览重复链接不错位等效果
4. *预览高清图*
同一张图片,可以给显示时和预览时设置不同的链接地址以达到最佳效果
设置方式 1:给 *img* 标签增加一个 *original-src* 即可
```html
<!-- 显示时使用 xxx,预览时使用 yyy -->
<img src="xxx" original-src="yyy" />
```
设置方式 2:通过 [imgList](advanced/api#imgList) 的 *api* 进行设置
5. *长按弹出菜单*
微信和百度平台支持图片长按时弹出菜单,可以进行保存、分享等操作,如不需要,可通过 [show-img-menu](basic/prop#show-img-menu) 属性关闭
6. *装饰图片处理*
有时对于一些小的装饰性图片,可能不希望产生上述效果,此时可以给 *img* 标签设置 *ignore* 属性,将屏蔽预览、弹出菜单等操作,提升体验
```html
<!-- 设置 ignore 属性后这张图片不可预览、不会弹出菜单 -->
<img src="xxx" ignore />
```
在链接内的、*src* 为 *data url* 且没有设置 *original-src* 的图片,默认为不可预览的小图片
7. *支持原大小显示*
本组件通过合理转换,基本实现了和 *html* 中 *img* 的相同效果:没有设置宽度时按原大小显示;设置了宽度时按比例缩放;同时设置宽高时按设置的值显示。不必去考虑小程序中的 *mode* 等问题
8. *支持 svg*
虽然小程序中不支持 *svg* 系列标签,本组件通过在解析过程中转为 *data url* 图片的方式实现了 *svg* 的显示
## 🔗 链接效果 :id=link
1. *支持设置多种状态下的样式*
包括默认状态、点击态的样式,可以在 *src/node/node.wxss* 中进行修改
2. *锚点跳转*
支持跳转内部锚点,使用锚点需要开启 [use-anchor](basic/prop#use-anchor) 属性
跳转方式 1:给 *a* 标签的 *href* 属性设置为 *#id*,点击时即可跳转到对应 *id* 的位置(设置为 *#* 则跳转到开头)
跳转方式 2:通过 [navigateTo](advanced/api#navigateTo) 的 *api* 进行跳转
默认情况下锚点跳转通过控制页面滚动的方式进行,如果要在 *scroll-view* 内使用,可以通过 [in](advanced/api#in) 的 *api* 进行配置
3. *跳转内部路径*
如果需要点击 *a* 标签跳转到小程序内的一个页面,直接将其 *href* 属性设置为页面路径即可(包括 *tab* 页面,需要使用绝对路径)
```html
<!-- 该链接被点击后将跳转到 /pages/test/test 页面 -->
<a href="/pages/test/test">链接</a>
```
4. *复制外部链接*
对于外部链接,由于小程序无法直接打开,将自动复制到剪贴板,如不需要,可通过 [copy-link](basic/prop#copy-link) 属性关闭
?> 设置 *a* 标签的 *href* 属性时,如果是外部链接需将协议名 *http://* 写完整,否则会被认为是内部路径并尝试跳转
除这些默认的处理外,还可以在 [linktap](basic/event#linktap) 事件中进行自定义处理
## 📈 表格效果 :id=table
1. *支持独立横向滚动*
表格宽度通常较大,容易超出屏幕宽度,导致整体内容一起滚动,影响体验,可以通过设置 [scroll-table](basic/prop#scroll-table) 属性给所有表格添加一个滚动层使其能单独横向滚动
2. *支持常用表格属性*
支持 *border*, *cellspacing*, *cellpadding*, *align* 等常用表格属性
3. *支持含有合并单元格的表格*
附渲染原理:
小程序中没有 *table* 标签,使得显示表格一直是一个难题,本组件主要通过以下三种方式显示表格
| 显示方式 | 适用情况 | 说明 |
|:---:|:---:|:---:|
| *rich-text* 标签 | 表格内部没有链接、图片等特殊标签 | 效果最佳,几乎不需要进行转换 |
| *table* 布局 | 表格内有特殊标签但没有使用合并单元格 | 需要进行一定转换,将 *table*, *tr*, *td* 等标签转为对应的布局 |
| *grid* 布局 | 表格内有特殊标签且使用了合并单元格 | 需要进行复杂的转换将合并单元格用 *grid* 布局表现出来 |
## 📊 列表效果 :id=list
1. *支持多层嵌套*
支持嵌套多层列表,对于无序列表,不同的层级会显示不同的黑点格式
2. *支持多种有序列表格式*
通过设置 *ol* 标签的 *type* 属性,可以显示数字、字母、罗马数字等多种形式的标号
3. *支持不显示标号*
支持通过设置 *list-style:none* 的方式不显示 *li* 标签开头的标号
## 🎬 音视频效果 :id=video
1. *自动暂停*
在存在多个视频的情况下,同时播放可能会影响体验,本组件支持在播放一个视频的时候自动暂停其他所有视频,如不需要,可通过 [pause-video](basic/prop#pause-video) 属性关闭
音频在引入 [audio](advanced/plugin#audio) 插件后也可以实现此效果
2. *多源加载*
不同平台支持播放的格式不同,只设置一个 *src* 可能会出现兼容性问题导致无法播放,因此本组件支持像 *html* 中一样给 *video* 和 *audio* 设置多个 *source*,将按照顺序进行加载,直到可以播放,最大程度上避免无法播放
```html
<!-- 组件将依次加载 xxx 和 yyy -->
<video controls>
<source src="xxx">
<source src="yyy">
</video>
```
3. *自动添加控件*
对于既没有设置 *controls* 也没有设置 *autoplay* 的标签将自动把 *controls* 属性设置为 *true*,避免无法播放,影响体验
## ⌨️ 流式输出 :id=stream
本组件从 [2.5.2](changelog/changelog#v252) 版本起对流式输出做了性能优化,实现了差量更新,可以避免流式更新时的闪烁和卡顿问题。[示例项目](https://github.com/jin-yufeng/mp-html/issues/657#issuecomment-3361391352)
<img src="/mp-html/assets/tutorials/stream.gif" width="300" alt="流式输出">
## 📡 样式设置 :id=style
样式(*css*)是富文本中最重要的内容之一,本组件提供多种样式设置的方法,可以进行灵活的设置
1. *行内样式*
这是最常用的样式设置方法,直接将需要的样式放在对应标签的 *style* 属性中即可,这种方式仅作用于单个标签,优先级最高
2. *tag-style*
这是本组件独有的一种样式设置方式,可以给某一种标签名设置默认的样式
可以通过 [tag-style](basic/prop#tag-style) 属性设置,具体用法见对应说明
3. *外部样式*
如果希望将某些样式固定的用于渲染,可以添加到 *tools/config.js* 的 *externStyle* 字段中,该方法仅支持 *class* 选择器([2.1.0](changelog/changelog#v210) 版本起支持标签名选择器),优先级最低,具体见 [个性化](overview/quickstart#setting)
需要调整优先级时,可以通过设置 *!important* 实现
另外,通过引入 [style](advanced/plugin#style) 插件,还可以实现匹配 *style* 标签中样式的功能
## 🍭 全面的标签支持 :id=tag
本组件支持以下标签和属性:
| 标签 | 属性 |
|:---:|:---:|
| a | href |
| abbr | |
| address | |
| article | |
| aside | |
| audio | author, controls, loop, name, poster, src |
| b | |
| base | href |
| big | |
| blockquote | |
| body | |
| br | |
| caption | |
| center | |
| cite | |
| code | |
| col | span |
| colgroup | span |
| dd | |
| del | |
| div | |
| dl | |
| dt | |
| em | |
| embed | autostart, loop, src, type |
| fieldset | |
| font | color, face, size |
| footer | |
| h1 | |
| h2 | |
| h3 | |
| h4 | |
| h5 | |
| h6 | |
| head | |
| header | |
| hr | |
| html | |
| i | |
| img | ignore, original-src, src |
| ins | |
| label | |
| legend | |
| li | |
| mark | |
| nav | |
| ol | start, type |
| p | |
| pre | |
| q | |
| rt | |
| ruby | |
| s | |
| section | |
| small | |
| source | src |
| span | |
| strike | |
| strong | |
| style | |
| sub | |
| sup | |
| table | border, cellpadding, cellspacing |
| tbody | |
| td | colspan, rowspan |
| tfoot | |
| th | colspan, rowspan |
| thead | |
| tr | |
| tt | |
| u | |
| ul | |
| video | autoplay, controls, loop, muted, object-fit, poster, src |
说明:
1. 除上面列举的外,还支持 *svg* 系列的标签和 *id*、*style*、*class*、*align*、*height*、*width*、*dir* 属性
2. 对于不信任的标签,除个别将被直接移除,都会被转为一个行内标签,因此可以使用更多语义化标签
## 🌟 稳定性 :id=stable
本组件的解析脚本能够支持多种 *html* 格式,具有强大的稳定性:
1. 标签名中可以含有 *:* 等特殊字符(如 *o:p*)
2. 标签名和属性名大小写不敏感
3. 属性值可以不加引号、加单引号、加双引号,也可以缺省(默认 *true*)
4. 属性之间可以没有空格(通过引号划分)、有空格(可以多个)、有换行符
5. 支持正常格式、*CDATA* 等多种形式的注释
同时,对于一些错误情况,程序也能够自动处理:
1. 标签首尾不匹配
2. 属性值中冒号不匹配
3. 标签未闭合
以下情况均能正确解析:
```html
<!-- 不同的属性格式 -->
<font face="宋体" color='green' size=7>Hello</font>
<!-- 标签首尾不匹配或未闭合 -->
<div> World</section>
<!-- 大小写搭配 -->
<dIv StYle="color:green">!</DIv>
```
+287
View File
@@ -0,0 +1,287 @@
# 快速开始 :id=quickstart
## 📦 源码获取 :id=source
#### 小程序方式 :id=mp
!> 该方式暂不可用
打开微信小程序 *富文本插件*,点击 *获取组件包* 按钮,选择使用平台、[扩展插件](advanced/plugin) 以及 [个性化设置](#setting) 后即可生成组件包
![富文本插件](../assets/case/富文本插件.jpg)
#### npm 方式 :id=npm
```bash
# 通过 npm 获取
npm install mp-html
# 或通过 yarn 获取
yarn add mp-html
```
需要升级时:
```bash
# 通过 npm 升级
npm update mp-html
# 或通过 yarn 升级
yarn upgrade mp-html
```
#### git 方式 :id=git
```bash
# 通过 github 获取
git clone https://github.com/jin-yufeng/mp-html.git
# 或通过 gitee 获取
git clone https://gitee.com/jin-yufeng/mp-html.git
```
#### 下载 zip :id=zip
*github releases*:[https://github.com/jin-yufeng/mp-html/releases](https://github.com/jin-yufeng/mp-html/releases)
*gitee releases*:[https://gitee.com/jin-yufeng/mp-html/releases](https://gitee.com/jin-yufeng/mp-html/releases)
#### QQ 群 :id=qqgroup
*QQ* 交流群的群文件中也可以获取组件包
交流群1: `699734691`
交流群2: `778239129`
交流群3: `960265313`
## 📚 引入和使用 :id=use
### 📗 原生框架 :id=miniprogram
#### 引入 :id=mp-import
- npm 方式
?> 本方法仅适用于微信、*QQ* 小程序
1. 在小程序项目根目录下通过 [npm](#npm) 安装组件包
2. 开发者工具中勾选 *使用 npm 模块*(若没有此选项则不需要)并点击 *工具* - *构建 npm*
3. 在需要使用页面的 *json* 文件中添加
```json
{
"usingComponents": {
"mp-html": "mp-html"
}
}
```
- 源码引入
?> 本方法适用于所有平台
1. 将 [源码](#source) 中对应平台的代码包(*dist/platform*)拷贝到 *components* 目录下,更名为 *mp-html*
2. 在需要使用页面的 *json* 文件中添加
```json
{
"usingComponents": {
"mp-html": "/components/mp-html/index"
}
}
```
#### 使用 :id=mp-use
1. 在需要使用页面的 *wxml* 文件中添加
```wxml
<mp-html content="{{html}}" />
```
2. 在需要使用页面的 *js* 文件中添加
```javascript
Page({
onLoad () {
this.setData({
html: '<div>Hello World!</div>'
})
}
})
```
支持的 [属性](basic/prop) 和 [事件](basic/event) 见对应文档
### 📘 uni-app 框架 :id=uni-app
#### uni-modules 方式 :id=uni-modules
?> 本方法需要使用 *3.1.0+* 版本的 *HBuilder X* 开发
1. 进入 [插件市场](https://ext.dcloud.net.cn/plugin?id=805),点击右上角的 *使用 HBuilder X 导入插件* 按钮导入项目或点击 *下载插件ZIP* 按钮下载插件包并解压到项目的 *uni_modules/mp-html* 目录下
2. 在需要使用页面的 *(n)vue* 文件中添加
```vue
<template>
<view>
<!-- 不需要引入,可直接使用 -->
<mp-html :content="html" />
</view>
</template>
<script>
export default {
data () {
return {
html: '<div>Hello World!</div>'
}
}
}
</script>
```
3. 需要更新版本时在 *HBuilder X* 中右键 *uni_modules/mp-html* 目录选择 *从插件市场更新* 即可
#### 源码方式 :id=uni-app-source
1. 将 [源码](#source) 中 *dist/uni-app* 内的内容拷贝到 **项目根目录** 下
!> [插件市场](https://ext.dcloud.net.cn/plugin?id=805) 的 *非 uni_modules* 版本无法更新,请从其他方式获取 [源码](#source)
2. 在需要使用页面的 *(n)vue* 文件中添加
```vue
<template>
<view>
<mp-html :content="html" />
</view>
</template>
<script>
import mpHtml from '@/components/mp-html/mp-html'
export default {
// HBuilderX 2.5.5+ 可以通过 easycom 自动引入
components: {
mpHtml
},
data () {
return {
html: '<div>Hello World!</div>'
}
}
}
</script>
```
#### npm 方式 :id=uni-app-npm
1. 在项目根目录下通过 [npm](#npm) 安装组件包
2. 在需要使用页面的 *(n)vue* 文件中添加
```vue
<template>
<view>
<mp-html :content="html" />
</view>
</template>
<script>
import mpHtml from 'mp-html/dist/uni-app/components/mp-html/mp-html'
export default {
// 不可省略
components: {
mpHtml
},
data () {
return {
html: '<div>Hello World!</div>'
}
}
}
</script>
```
!> 使用 *cli* 方式运行的项目,通过 *npm* 方式引入时,需要在 *vue.config.js* 中配置 *transpileDependencies*,详情可见 [#330](https://github.com/jin-yufeng/mp-html/issues/330#issuecomment-913617687)
!> 如果在 *nvue* 中使用还要将 *dist/uni-app/static* 目录下的内容拷贝到项目的 *static* 目录下,否则无法运行
支持的 [属性](basic/prop) 和 [事件](basic/event) 见对应文档
由于 *uni-app* 编译过程中会进行压缩,构建 *uni-app* 包时基本不进行压缩,包的体积与原生包相比较大
#### 关于 nvue :id=nvue
*nvue* 使用原生渲染,不支持部分 *css* 样式,为实现和 *html* 相同的效果,组件内部通过 *web-view* 进行渲染,性能上差于原生,根据 *weex* 官方建议,*web* 标签仅应用在非常规的降级场景。因此,如果通过原生的方式(如 *richtext*)能够满足需要,则不建议使用本组件,如果有较多的富文本内容,则可以直接使用 *vue* 页面
由于渲染方式与其他端不同,有以下限制:
1. 不支持 [lazy-load](basic/prop#lazy-load) 属性
2. 视频不支持全屏播放
3. 如果在 *flex-direction: row* 的容器中使用,需要给组件设置宽度或设置 *flex: 1* 占满剩余宽度
### 📙 其他框架 :id=other
其他框架没有专用包,但也可以引入对应平台的原生包使用,具体方法参考各框架官方文档
- taro
[https://taro-docs.jd.com/docs/hybrid#使用原生组件](https://taro-docs.jd.com/docs/hybrid#%E4%BD%BF%E7%94%A8%E5%8E%9F%E7%94%9F%E7%BB%84%E4%BB%B6)
!> 在 *taro2* 中使用请使用 [示例项目](#demo) 中的非压缩组件包,否则可能出现异常,详见 [#301](https://github.com/jin-yufeng/mp-html/issues/301)
!> 在 *taro3* 的 *vue3* 中使用时需要修改 *content* 属性的属性名或使用 [setContent](advanced/api#setContent) 方法设置内容,详见 [taro#13146](https://github.com/NervJS/taro/issues/13146)
?> 在 *taro* 中使用时属性名需用驼峰写法,如 *copy-link* 属性应写作 *copyLink*
?> 需要 *taro* 专用包的开发者欢迎参与 [需求调研](https://github.com/jin-yufeng/mp-html/issues/374)
- kbone
[https://wechat-miniprogram.github.io/kbone/docs/guide/advanced.html#使用小程序自定义组件](https://wechat-miniprogram.github.io/kbone/docs/guide/advanced.html#%E4%BD%BF%E7%94%A8%E5%B0%8F%E7%A8%8B%E5%BA%8F%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BB%84%E4%BB%B6)
- chameleon
[https://cml.js.org/docs/io.html#怎么引入微信小程序组件](https://cml.js.org/docs/io.html#%E6%80%8E%E4%B9%88%E5%BC%95%E5%85%A5%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%BB%84%E4%BB%B6)
- remax
[https://remaxjs.org/guide/basic/custom-component](https://remaxjs.org/guide/basic/custom-component)
## 💡 运行示例 :id=demo
1. 安装依赖
```bash
# 通过 npm 安装
npm install
# 或通过 yarn 安装
yarn
```
2. 生成 *demo* 项目
```bash
# 生成微信示例项目到 dev/mp-weixin
npm run dev:weixin
# 生成 qq 示例项目到 dev/mp-qq
npm run dev:qq
# 生成百度示例项目到 dev/mp-baidu
npm run dev:baidu
# 生成支付宝示例项目到 dev/mp-alipay
npm run dev:alipay
# 生成头条示例项目到 dev/mp-toutiao
npm run dev:toutiao
# 生成 uni-app 示例项目到 dev/uni-app
npm run dev:uni-app
```
3. 运行
用各平台的开发者工具打开 *dev/platform* 文件夹即可
4. 监听修改
如果要对 *demo* 项目进行修改(如放入自己的测试内容)可在 *tools/demo* 目录中进行修改
如果要对组件包进行修改可在 *src* 目录中进行修改(参考 [二次开发](advanced/develop) )
可以通过 *watch* 命令监听修改并实时编译到 *dev* 目录下
```bash
# 监听并实时生成微信示例项目到 dev/mp-weixin
npm run watch:weixin
# 监听并实时生成 qq 示例项目到 dev/mp-qq
npm run watch:qq
# 监听并实时生成百度示例项目到 dev/mp-baidu
npm run watch:baidu
# 监听并实时生成支付宝示例项目到 dev/mp-alipay
npm run watch:alipay
# 监听并实时生成头条示例项目到 dev/mp-toutiao
npm run watch:toutiao
```
## 🎈 个性化 :id=setting
?> 本组件提供了以下配置项可以生成个性化的组件包,配置项可以通过 [示例小程序](#mp) 进行设置,或参考 [使用插件包](advanced/plugin#use) 中的 *npm* 方式自行设置配置文件并进行打包
#### plugins
需要使用的插件名称列表,关于插件的详细信息见 [插件](advanced/plugin)
#### externStyle
!> 暂不支持对图片设置宽高,详见 [#426](https://github.com/jin-yufeng/mp-html/issues/426)
外部样式,一个 *css* 字符串,将被用于 *html* 的渲染,但仅支持 *class* 选择器
?> [2.1.0](changelog/changelog#v210) 版本起增加支持 **标签名选择器**,通过这种方式给标签设置的样式全局有效,在样式较长或作用标签数量较大时这种方法的性能要高于 [tag-style](basic/prop#tag-style) 属性,且写法更加灵活(可以与伪类、*class* 配合等)
需要注意的是,由于 [组件](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html#%E7%BB%84%E4%BB%B6%E6%A0%B7%E5%BC%8F) 内仅支持 *class* 选择器,直接将标签名选择器 **写在 wxss 中是无效的**,必须写在本字段中,构建过程中会自动转换为 *class* 选择器
?> [2.3.1](changelog/changelog#v231) 版本起,组件取消样式隔离,部分平台(微信小程序 *2.11.0+* 基础库完全支持;*QQ*、百度小程序部分情况下支持)支持直接引入页面样式中的 *class* 选择器,无需使用本方法引入;若遇到样式无法生效或需要使用标签名选择器,则仍需要使用本方法
#### customElements
自定义标签列表([2.2.0](changelog/changelog#v220) 版本起支持),可以在这里注册需要使用的小程序功能标签(如 *ad*、*ad-custom*、*official-account*、*map* 等)
每个标签为一个 *object*,需要包含以下字段,注册完成后即可在传入的 `html` 中使用该组件
| 字段名 | 功能 | 类型 | 必填 | 备注 |
|:---:|:---:|:---:|:---:|:---:|
| name | 标签名 | String | 是 | |
| attrs | 需要使用的属性列表 | String[] | 否 | class 和 style 默认添加,无需填写 |
| platforms | 需要使用的平台 | String[] | 否 | 默认添加到所有平台,可以从 h5、mp-weixin、mp-qq、mp-baidu、mp-alipay、mp-toutiao、app-plus 中选择,不区分大小写 |
?> 仅能添加没有子节点的标签,且不响应任何事件,如果需要更加复杂的功能,可以通过 [插件](advanced/plugin#develop) 实现
示例:
```javascript
// 设置完成后 html 中添加 <ad unit-id="xxx" /> 即可使用该标签
customElements: [{
name: 'ad',
attrs: ['unit-id']
}]
```
剩余的是一些编译过程中压缩工具的配置,可以按需要设置
+16
View File
@@ -0,0 +1,16 @@
# 📝 贡献指南 :id=contribution
本组件欢迎所有开发者对以下方面提交 [pr](https://github.com/jin-yufeng/mp-html/pulls),一起完善本组件
1. 针对 [issue](https://github.com/jin-yufeng/mp-html/issues) 中 *bug* 的修复
2. 实现新功能
- 在主包中添加(需确保该功能适用面广且体积不大)
- 新增扩展插件(参考 [开发插件](advanced/plugin#develop))
3. 文档错误修复
开发过程中请注意:
1. 不要修改 [dist](https://github.com/jin-yufeng/mp-html/tree/master/dist) 目录下的文件(该文件夹在版本更新时会进行构建)和配置文件
2. 代码风格参考 [standard](https://standardjs.com)
3. 可参考 [二次开发](advanced/develop) 中的说明
感谢所有 [贡献者](https://github.com/jin-yufeng/mp-html/graphs/contributors) 对本组件的贡献
+152
View File
@@ -0,0 +1,152 @@
# 📘 常见问题 :id=question
## 无法使用扩展功能 :id=plugin
由于小程序空间有限,默认组件包中仅包含基本功能,其他 [扩展](advanced/plugin) 按需添加。
!> 编辑器、*markdown*、代码高亮、关键词搜索、*latex* 公式等属于 [扩展](advanced/plugin) 功能,直接获取的组件包中 **不包含** 这些功能
需要使用扩展功能的,参考 [使用插件](advanced/plugin#use) 的说明,通过示例小程序或 *npm* 打包的方式获取包含扩展功能的组件包替换原组件包,然后按照各个 [扩展](advanced/plugin) 插件的说明和示例进行使用
## 图片底部缝隙 :id=img
由于图片的默认 *display* 是 *inline-block*,多个图片连接时底部会有一条缝隙,可以通过设置 *vertical-align: bottom*, *display:block* 或 *float:left* 等方法去除
设置以上样式后仍有一个小缝隙的,可以进一步添加 *margin-top:-1px*
设置方法参考 [样式设置](overview/feature#style)
## 标签原样显示 :id=entity
如果出现渲染后 *html* 标签还是原样显示,请检查传入的 *html* 是否被转义:
1. *&lt;* 和 *&gt;* 被转义为 *&amp;lt;* 和 *&amp;gt;*
2. *&lt;img* 被转义为 *< img*
如果是则需要进行替换
```javascript
// 第一种
html = html.replace(/&lt;/g, '<').replace(/&gt;/g, '>') // 如果还转义了其他字符如 &amp; 等也要进行替换
// 第二种
html = html.replace(/< img/g, '<img')
```
## 空白符失效 :id=space
*html* 中,默认会将多个空白符(包括换行)合并为一个空格,若不希望如此,可参考以下方法:
1. 替换为指定标签或实体编码
换行可以使用 *br* 标签
连续空格可以使用 *&amp;nbsp;* *&amp;ensp;* *&amp;emsp;* 等实体编码
```javascript
html = html.replace(/\n/g, '<br>') // 替换换行符
```
2. 通过 *css* 设置 *white-space*
将 *css* 中的 *white-space* 设置为 *pre-line* 可以保留换行符,设置为 *pre-wrap* 可以保留空格和换行符
给特定标签设置的方法见 [样式设置](overview/feature#style),需要注意的是如果通过外部样式设置 *white-space* 将不会生效,因为在解析过程中为减小解析结果大小提前进行了空白符合并(解析过程中无法获取外部样式)
[2.1.2](changelog/changelog#v212) 版本起可以通过 [container-style](basic/prop#container-style) 属性全局设置 *white-space*
```html
<mp-html container-style="white-space:pre-wrap" />
```
## 表格没有边框 :id=table
*html* 中的 *table* 标签默认没有边框,一些编辑器有自带的表格样式,没有引入就会导致表格边框缺失,可通过以下方式解决:
1. 给 `table` 标签设置 `border` 属性
```javascript
html = html.replace(/<table/g, '<table border="1"')
```
2. 通过 [tag-style](basic/prop#tag-style) 属性或 [外部样式](overview/quickstart#externStyle) 给表格标签设置默认样式
```javascript
tagStyle: {
table: 'border-top: 1px solid gray; border-left: 1px solid gray; border-collapse:collapse',
th: 'border-right: 1px solid gray; border-bottom: 1px solid gray;',
td: 'border-right: 1px solid gray; border-bottom: 1px solid gray;'
}
```
## 多媒体内容不显示 :id=media
若出现 图片不显示/无法预览、音频/视频无法播放 等问题,可通过以下方式检查:
- 若视频不显示,请检查 *html* 中的视频是否为 *video* 标签(*iframe* 标签在小程序端仅微信小程序可以通过 [腾讯视频插件](advanced/plugin#txv-video) 播放,其他不支持)
- 若图片无法预览,请检查该图片是否为 *base64* 格式,目前不支持 *base64* 图片预览(原因参考 [#249](https://github.com/jin-yufeng/mp-html/issues/249#issuecomment-755290540);如果确需使用,可将 [parser.js#L425](https://github.com/jin-yufeng/mp-html/blob/master/src/miniprogram/parser.js#L425) 去掉,在部分平台可能可以使用)
- 若是 *svg* 无法显示,请检查是否包含响应式 *animate* 等标签,目前不支持(原因参考 [#569](https://github.com/jin-yufeng/mp-html/issues/569)),除此之外可能是 *svg* 标签名和属性名大小写问题,可以在 [svgDict](https://github.com/jin-yufeng/mp-html/blob/master/src/miniprogram/parser.js#L61) 中补充
- 若非以上原因依然无法显示,将该 图片/音频/视频 的链接放在原生标签 [image](https://developers.weixin.qq.com/miniprogram/dev/component/image.html)、[audio](https://developers.weixin.qq.com/miniprogram/dev/component/audio.html)、[video](https://developers.weixin.qq.com/miniprogram/dev/component/video.html) 或 api [wx.previewImage](https://developers.weixin.qq.com/miniprogram/dev/api/media/image/wx.previewImage.html) 中进行测试,如果也不能显示,则链接存在问题
若出现这种情况,可按照以下方法进行检查
1. 检查链接是否完整(缺少域名可以设置 [domain](basic/prop#domain) 属性)、有效(可以放在浏览器中测试)
2. 检查链接是否存在防盗链(可以参考 [#387](https://github.com/jin-yufeng/mp-html/issues/387))
3. 检查编码和格式是否支持(参考 [音频格式](https://developers.weixin.qq.com/miniprogram/dev/api/media/audio/InnerAudioContext.html#%E6%94%AF%E6%8C%81%E6%A0%BC%E5%BC%8F)、[视频格式和编码](https://developers.weixin.qq.com/miniprogram/dev/component/video.html#%E6%94%AF%E6%8C%81%E7%9A%84%E6%A0%BC%E5%BC%8F))
4. 查看 *error* 事件中的错误信息
## 长内容处理 :id=long
如果富文本内容特别长,可以考虑以下方案:
1. 分次渲染
小程序中单次 *setData* 大小不能超过 *1MB*,如果内容过长,可以先将内容拆分成几段,首先渲染第一段,后续内容在适当的时机(触底等)通过 [setContent](/advanced/api#setContent) 方法追加到末尾
2. 分页渲染
以上方案虽然能解决一次性设置数据过大问题,但过长的内容仍会导致总标签数量过大,页面性能下降的问题,因此,对于过长的内容,应该分页进行显示,每页仅显示一部分
## 懒加载失效 :id=lazy-load
如果富文本内容全部(或大部分)是图片,由于其图片未加载时大小为零,即使数量很多也会全部进入视图范围,导致懒加载失效,若出现这种情况,可通过以下方案解决
1. 通过 [tag-style](basic/prop#tag-style) 属性等方法给 *img* 父级标签的样式里设置 *min-height*(如果直接给图片本身设置 *min-height*,可能在加载过程中出现变形的情况)
2. 通过 [loading-img](basic/prop#loading-img) 属性设置加载过程中的占位图
## 一般标签的点击事件 :id=tap
默认情况下,组件仅支持 *a* 和 *img* 标签的点击事件,如果希望给标签添加点击事件,又不希望应用 *a* 标签的默认样式,可以使用没有 *href* 属性的 *a* 标签,该标签不会应用链接的默认样式,但被点击时会触发 *linktap* 事件,可以在 *data-* 属性中记录需要的信息
## 基础库要求 :id=lib
本组件尽最大可能兼容低版本基础库,各平台只要满足 **最低要求** 即可正常使用(不报错,但高基础库支持的功能不可用),可按照实际需要设置最低基础库要求
微信:
| 版本 | 功能 | 占比 |
|:---:|:---:|:---:|
| 2.9.0+ | ios 支持 webp 图片 | >99.74% |
| 2.7.0+ | 支持图片长按弹出菜单 | >99.87% |
| 2.4.0+ | 支持 video 同层渲染 | >99.90% |
| 2.3.0+ | 支持使用云文件 ID | >99.98% |
| 2.2.1+ | 支持 npm 引入 | >99.99% |
| 1.9.94+ | 支持使用 ad | >99.99% |
| 1.6.6+ | 可以使用 | >99.99% |
QQ:
| 版本 | 功能 |
|:---:|:---:|
| 安卓 1.10.2+,ios 1.4.7+ | 支持 video 同层渲染 |
| 1.1.7+ | 可以使用 |
百度:
| 版本 | 功能 | 占比 |
|:---:|:---:|:---:|
| 3.180.1+ | ios 支持 webp 图片 | >99.04% |
| 3.170.1+ | 支持图片长按弹出菜单 | >99.19% |
| 3.90.25+ | 可以使用 | >99.99% |
*3.240.10* - *3.260.25* 基础库由于 [此问题](https://smartprogram.baidu.com/forum/topic/show/125787),需要将以下样式拷贝到 *app.css* 以保证正确显示
```css
/* 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;
}
```
支付宝:
| 版本 | 功能 | 占比 |
|:---:|:---:|:---:|
| 1.11.0+ | 可以使用 | >97.95% |
头条:
| 版本 | 功能 |
|:---:|:---:|
| 1.59.0+ | 支持 video 同层渲染 |
| 1.19.0+ | 支持使用 ad |
| 1.7.0+ | 可以使用 |
!> 不支持 *video* 同层渲染时,需要注意原生组件的限制,视频的层级最高,且不能在 *scroll-view* 中使用
+30
View File
@@ -0,0 +1,30 @@
# 📩 反馈 :id=feedback
## 注意事项 :id=notice
反馈问题前,请先确认以下方式无法解决:
1. 在 [常见问题](question/faq) 中查看是否已有解决方案
2. 在 [issue](https://github.com/jin-yufeng/mp-html/issues) 中查找是否已有相同或类似的问题
3. 如果是对于渲染效果的问题,请先在下方的模拟器中尝试,如果在浏览器中渲染也不正常,请检查样式
<div style="display: flex;">
<div style="flex: 1; margin: 0 40px; display: flex; flex-direction: column;">
<textarea id="input" style="flex: 1; width: 100%; padding: 5px; resize: none;" placeholder="请输入 html 内容"></textarea>
<div style="text-align: center; margin-top: 10px;">
<button onclick="reset()">清空</button>
<button onclick="render()" style="margin-left: 20px;">渲染</button>
</div>
</div>
<div style="flex: 0 0 320px; height: 568px; box-shadow: 0px 0px 10px #c0c0c0;">
<iframe id="show" style="width: 100%; height: 100%; margin: 0;"></iframe>
</div>
</div>
## 反馈方式 :id=method
1. *issue* 方式
在 *github* 中提出 [issue](https://github.com/jin-yufeng/mp-html/issues/new/choose)(推荐,解决方案可以给其他人参考)
2. *QQ* 群方式
加入 *QQ* 交流群 *699734691* 或 *778239129*,并发送和交流相关问题
3. 邮箱方式
如果不希望公开问题,可以通过邮箱方式联系,发送邮件到 *mp_html@126.com*,邮件格式可参考 [issue 模板](https://github.com/jin-yufeng/mp-html/issues/new/choose)
!> 注意务必按照模板要求填写,未描述清楚或无法复现的问题将不予处理