目录
[editor 组件](#editor 组件)
selectorQuery.select(selector)
selectorQuery.selectAll(selector)
selectorQuery.selectViewport()
nodesRef.fields(object,callback)
[editorContext.format(name, value)](#editorContext.format(name, value))
editorContext.insertDivider(OBJECT)
editorContext.insertImage(OBJECT)
editorContext.getContents(OBJECT)
editor 组件
富文本编辑器,可以对图片、文字格式进行编辑和混排。
在web开发时,可以使用contenteditable
来实现内容编辑。但这是一个dom API,在非H5平台无法使用。于是微信小程序和uni-app的App-vue提供了editor
组件来实现这个功能,并且在uni-app的H5平台也提供了兼容。从技术本质来讲,这个组件仍然运行在视图层webview中,利用的也是浏览器的contenteditable
功能。
编辑器导出内容支持带标签的 html
和纯文本的 text
,编辑器内部采用 delta
格式进行存储。
通过setContents
接口设置内容时,解析插入的 html
可能会由于一些非法标签导致解析错误,建议开发者在应用内使用时通过 delta 进行插入。
富文本组件内部引入了一些基本的样式使得内容可以正确的展示,开发时可以进行覆盖。需要注意的是,在其它组件或环境中使用富文本组件导出的html时,需要额外引入这段样式,并维护<ql-container><ql-editor></ql-editor></ql-container>
的结构,参考:使用 editor 组件导出的 html。
图片控件仅初始化时设置有效。
相关 api:editorContext
属性说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
read-only | boolean | false | 否 | 设置编辑器为只读 |
placeholder | string | 否 | 提示信息 | |
show-img-size | boolean | false | 否 | 点击图片时显示图片大小控件 |
show-img-toolbar | boolean | false | 否 | 点击图片时显示工具栏控件 |
show-img-resize | boolean | false | 否 | 点击图片时显示修改尺寸控件 |
@ready | eventhandle | 否 | 编辑器初始化完成时触发 | |
@focus | eventhandle | 否 | 编辑器聚焦时触发,event.detail = {html, text, delta} | |
@blur | eventhandle | 否 | 编辑器失去焦点时触发,detail = {html, text, delta} | |
@input | eventhandle | 否 | 编辑器内容改变时触发,detail = {html, text, delta} | |
@statuschange | eventhandle | 否 | 通过 Context 方法改变编辑器内样式时触发,返回选区已设置的样式 |
editorContext
editor 组件对应的 editorContext 实例,可通过 uni.createSelectorQuery 获取。
uni.createSelectorQuery()
返回一个 SelectorQuery
对象实例。可以在这个实例上使用 select
等方法选择节点,并使用 boundingClientRect
等方法选择需要查询的信息。
Tips:
- 使用
uni.createSelectorQuery()
需要在生命周期mounted
后进行调用。 - 默认需要使用到
selectorQuery.in
方法。
SelectorQuery
查询节点信息的对象
selectorQuery.in(component)
将选择器的选取范围更改为自定义组件 component
内,返回一个 SelectorQuery
对象实例。(初始时,选择器仅选取页面范围的节点,不会选取任何自定义组件中的节点)。
代码示例
const query = uni.createSelectorQuery().in(this);
query
.select("#id")
.boundingClientRect((data) => {
console.log("得到布局位置信息" + JSON.stringify(data));
console.log("节点离页面顶部的距离为" + data.top);
})
.exec();
注意
- 支付宝小程序不支持 in(component),使用无效果
selectorQuery.select(selector)
在当前页面下选择第一个匹配选择器 selector
的节点,返回一个 NodesRef
对象实例,可以用于获取节点信息。
selector 说明:
selector
类似于 CSS 的选择器,但仅支持下列语法。
- ID 选择器:
#the-id
- class 选择器(可以连续指定多个):
.a-class.another-class
- 子元素选择器:
.the-parent > .the-child
- 后代选择器:
.the-ancestor .the-descendant
- 跨自定义组件的后代选择器:
.the-ancestor >>> .the-descendant
(H5 暂不支持) - 多选择器的并集:
#a-node, .some-other-nodes
selectorQuery.selectAll(selector)
在当前页面下选择匹配选择器 selector
的所有节点,返回一个 NodesRef
对象实例,可以用于获取节点信息。
selectorQuery.selectViewport()
选择显示区域,可用于获取显示区域的尺寸、滚动位置等信息,返回一个 NodesRef
对象实例。
selectorQuery.exec(callback)
执行所有的请求。请求结果按请求次序构成数组,在 callback 的第一个参数中返回。
NodesRef
用于获取节点信息的对象
nodesRef.fields(object,callback)
获取节点的相关信息。第一个参数是节点相关信息配置(必选);第二参数是方法的回调函数,参数是指定的相关节点信息。
object 参数说明
字段名 | 类型 | 默认值 | 必填 | 说明 | 平台差异说明 |
---|---|---|---|---|---|
id | Boolean | false | 否 | 是否返回节点 id |
|
dataset | Boolean | false | 否 | 是否返回节点 dataset |
App、微信小程序、H5 |
rect | Boolean | false | 否 | 是否返回节点布局位置(left right top bottom ) |
|
size | Boolean | false | 否 | 是否返回节点尺寸(width height ) |
|
scrollOffset | Boolean | false | 否 | 是否返回节点的 scrollLeft scrollTop ,节点必须是 scroll-view 或者 viewport |
|
properties | Array<string> | [] | 否 | 指定属性名列表,返回节点对应属性名的当前属性值(只能获得组件文档中标注的常规属性值,id class style 和事件绑定的属性值不可获取) | 仅 App 和微信小程序支持 |
computedStyle | Array<string> | [] | 否 | 指定样式名列表,返回节点对应样式名的当前值 | 仅 App 和微信小程序支持 |
context | Boolean | false | 否 | 是否返回节点对应的 Context 对象 | 仅 App 和微信小程序支持 |
editorContext.format(name, value)
修改样式
参数 | 类型 | 说明 |
---|---|---|
name | String | 属性 |
value | String | 值 |
支持设置的样式列表
name | value | 平台差异说明 |
---|---|---|
bold | ||
italic | ||
underline | ||
strike | ||
ins | ||
script | sub / super | |
header | H1 / H2 / h3 / H4 / h5 / H6 | |
align | left / center / right / justify | left百度小程序不支持 |
direction | rtl | |
indent | -1 / +1 | |
list | ordered / bullet / check | |
color | hex color | |
backgroundColor | hex color | |
margin/marginTop/marginBottom/marginLeft/marginRight | css style | 百度小程序不支持 |
padding/paddingTop/paddingBottom/paddingLeft/paddingRight | css style | 百度小程序不支持 |
font/fontSize/fontStyle/fontVariant/fontWeight/fontFamily | css style | 百度小程序不支持 |
lineHeight | css style | 百度小程序不支持 |
letterSpacing | css style | 百度小程序不支持 |
textDecoration | css style | 百度小程序不支持 |
textIndent | css style | 百度小程序不支持 |
wordWrap | css style | 百度小程序不支持 |
wordBreak | css style | 百度小程序不支持 |
whiteSpace | css style | 百度小程序不支持 |
对已经应用样式的选区设置会取消样式。css style 表示 css 中规定的允许值。
editorContext.insertDivider(OBJECT)
插入分割线
OBJECT 参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
success | Function | 否 | 接口调用成功的回调函数 | |
fail | Function | 否 | 接口调用失败的回调函数 | |
complete | Function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
editorContext.insertImage(OBJECT)
插入图片。
微信小程序平台地址为临时文件时,获取的编辑器html格式内容中 <img>
标签增加属性 data-local,delta 格式内容中图片 attributes 属性增加 data-local 字段,该值为传入的临时文件地址。 开发者可选择在提交阶段上传图片到服务器,获取到网络地址后进行替换。替换时对于html内容应替换掉 <img>
的 src 值,对于 delta 内容应替换掉 insert { image: abc }
值。
OBJECT 参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
src | String | 是 | 图片地址,仅支持 http(s)、base64、本地图片 | |
alt | String | 否 | 图像无法显示时的替代文本 | |
width | String | 否 | 图片宽度(pixels/百分比),2.6.5+ 支持,百度小程序不支持 | |
height | String | 否 | 图片高度 (pixels/百分比),2.6.5+ 支持,百度小程序不支持 | |
extClass | String | 否 | 添加到图片 img 标签上的类名,2.6.5+ 支持 | |
data | Object | 否 | data 被序列化为 name=value;name1=value2 的格式挂在属性 data-custom 上,2.6.5+ 支持 | |
success | Function | 否 | 接口调用成功的回调函数 | |
fail | Function | 否 | 接口调用失败的回调函数 | |
complete | Function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
editorContext.getContents(OBJECT)
获取编辑器内容
OBJECT 参数说明
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
success | Function | 否 | 接口调用成功的回调函数 | |
fail | Function | 否 | 接口调用失败的回调函数 | |
complete | Function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
object.success 回调函数
属性 | 类型 | 说明 |
---|---|---|
html | string | 带标签的 HTML 内容 |
text | string | 纯文本内容 |
delta | Object | 表示内容的 delta 对象 |
完整例子
<template>
<view class="edit">
<view class="title">
<input type="text" v-model="artData.title" placeholder="请输入完整的标题" placeholder-class="placeholderClass" />
</view>
<view class="content">
<editor
class="myEdit"
placeholder="写点什么吧~~"
show-img-resize
show-img-toolbar
show-img-size
@ready="onEditReady"
@focus="OnFocus"
@statuschange="statuschange"
></editor>
</view>
<view class="btnGroup">
<u-button type="primary" text="确认发表" @click="onSubmit" :disabled="!artData.title"></u-button>
</view>
<view class="tools" v-show="toolsShow">
<!-- 标题 -->
<view class="item" @click="headChange">
<text class="iconfont icon-zitibiaoti" :class="headShow ? 'active' : ''"></text>
</view>
<!-- 加粗 -->
<view class="item" @click="boldChange">
<text class="iconfont icon-zitijiacu" :class="boldShow ? 'active' : ''"></text>
</view>
<!-- 斜体 -->
<view class="item" @click="italicChange">
<text class="iconfont icon-zitixieti" :class="italicShow ? 'active' : ''"></text>
</view>
<!-- 分割线 -->
<view class="item" @click="insertDivider"><text class="iconfont icon-fengexian"></text></view>
<view class="item" @click="insertImage"><text class="iconfont icon-charutupian"></text></view>
<!-- 完成 -->
<view class="item" @click="editOk"><text class="iconfont icon-duigou_kuai"></text></view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
toolsShow: false,
editorContent: null,
headShow: false,
boldShow: false,
italicShow: false,
artData: {
title: '',
content: ''
}
};
},
methods: {
// 初始化
onEditReady() {
// 查询节点信息的对象
// 将选择器的选取范围更改为自定义组件 component 内,返回一个 SelectorQuery 对象实例。(初始时,选择器仅选取页面范围的节点,不会选取任何自定义组件中的节点)。
// 在当前页面下选择第一个匹配选择器 selector 的节点,返回一个 NodesRef 对象实例,可以用于获取节点信息。
// 获取节点的相关信息。第一个参数是节点相关信息配置(必选);第二参数是方法的回调函数,参数是指定的相关节点信息。
// 执行所有的请求。请求结果按请求次序构成数组,在 callback 的第一个参数中返回。
uni.createSelectorQuery()
.in(this)
.select('.myEdit')
.fields(
{
size: true, //是否返回节点尺寸(width height)
context: true //是否返回节点尺寸(width height)
},
(res) => {
console.log(res);
this.editorContent = res.context;
}
)
.exec();
},
// 离开焦点
OnFocus() {
this.toolsShow = true;
},
// 添加分割线
insertDivider() {
this.editorContent.insertDivider();
},
// 添加大标题
headChange() {
this.headShow = !this.headShow;
this.editorContent.format('header', this.headShow ? 'H2' : false);
},
// 加粗
boldChange() {
this.boldShow = !this.boldShow;
this.editorContent.format('bold');
},
// 斜体
italicChange() {
this.italicShow = !this.italicShow;
this.editorContent.format('italic');
},
// 用于检查对象detail是否包含名为name的属性
checkStatus(name, detail, key) {
if (detail.hasOwnProperty(name)) {
this[key] = true;
} else {
this[key] = false;
}
},
// 通过 Context 方法改变编辑器内样式时触发,返回选区已设置的样式(解决标题标签回弹问题)
statuschange(e) {
let detail = e.detail;
console.log(detail);
this.checkStatus('header', detail, 'headShow');
this.checkStatus('bold', detail, 'boldShow');
this.checkStatus('italic', detail, 'italicShow');
},
// 添加图像
insertImage() {
// 打开相机
uni.chooseImage({
count: 3, //默认9
sizeType: ['compressed'], //可以指定是原图还是压缩图,默认二者都有
success: async (res) => {
let tempFiles = res.tempFiles;
for (let item of tempFiles) {
uni.showLoading({
mask: true,
title: '上传中...'
});
try {
let res = await uniCloud.uploadFile({
filePath: item.path, //要上传的文件对象
cloudPath: item.name //cloudPath为云端文件名,
});
// 设置图片地址 图片地址,仅支持 http(s)、base64、本地图片
this.editorContent.insertImage({
src: res.fileID
});
uni.hideLoading();
} catch (e) {
uni.hideLoading();
uni.showModal({
content: '上传失败',
title: '提示'
});
}
}
}
});
},
// 确认
editOk() {
this.toolsShow = false;
},
onSubmit() {
console.log(11);
this.editorContent.getContents({
success: (res) => {
console.log(res);
this.artData.content = res.html;
}
});
}
}
};
</script>
<style lang="scss">
/deep/ .ql-blank::before {
font-style: normal;
color: #e0e0e0;
}
.edit {
padding: 30rpx;
.title {
input {
height: 120rpx;
font-size: 46rpx;
border-bottom: 1px solid #e4e4e4;
margin-bottom: 30rpx;
color: #000;
}
.placeholderClass {
color: #e0e0e0;
}
}
.content {
.myEdit {
height: calc(100vh - 500rpx);
margin-bottom: 30rpx;
}
}
.tools {
width: 100%;
height: 80rpx;
background: #fff;
border-top: 1rpx solid #f4f4f4;
position: fixed;
left: 0;
bottom: 0;
display: flex;
justify-content: space-around;
align-items: center;
.iconfont {
font-size: 36rpx;
color: #333;
// 选择按钮的高亮
&.active {
color: #0199fe;
}
}
}
}
</style>