先上效果图,
demo代码:editor.vue
<template>
<view>
<editor id="editor" ref="editor" style="height: auto;" class="ql-container" showImgSize showImgToolbar
showImgResize @statuschange="onStatusChange" :read-only="readOnly" @ready="onEditorReady"
@input="editorInput" placeholder="请输入商品描述..."></editor>
<view class="toolMenu" @touchend.prevent="tool">
<text class="toolBtn iconfont icon-charutupian" data-name="tupian"
:class="currentTool=='tupian' ? 'selected' : ''"></text>
<text class="toolBtn iconfont icon-zitiyanse" data-name="wenzi"
:class="currentTool=='wenzi' ? 'selected' : ''"></text>
<text class="toolBtn iconfont icon-fuwenben" data-name="wenben"
:class="currentTool=='wenben' ? 'selected' : ''"></text>
<text class="toolBtn iconfont icon-editor-link" data-name="link"
:class="currentTool=='link' ? 'selected' : ''"></text>
<text class="toolBtn iconfont icon-shangyibu" data-name="undo"></text>
<text class="toolBtn iconfont icon-xiayibu" data-name="redo"></text>
</view>
<view v-if="currentTool=='wenzi'" @touchend.prevent="format">
<view class="formatTitle">文字格式</view>
<view class="formatMenu">
<view class="formatItem"> <text data-name="bold" :class="formats.bold ? 'selected' : ''"
class=" formatBtn iconfont icon-zitijiacu"></text>
</view>
<view class="formatItem"><text data-name="italic" :class="formats.italic ? 'selected' : ''"
class="formatBtn iconfont icon-zitixieti"></text></view>
<view class="formatItem"><text data-name="underline" :class="formats.underline ? 'selected' : ''"
class="formatBtn iconfont icon-zitixiahuaxian"></text></view>
<view class="formatItem"><text data-name="strike" :class="formats.strike ? 'selected' : ''"
class="formatBtn iconfont icon-zitishanchuxian"></text></view>
</view>
<view class="formatTitle">对齐方式</view>
<view class="formatMenu">
<view class="formatItem"><text data-name="align" data-value="left"
:class="formats.align === 'left' ? 'selected' : ''"
class="formatBtn iconfont icon-zuoduiqi"></text></view>
<view class="formatItem"><text data-name="align" data-value="center"
:class="formats.align === 'center' ? 'selected' : ''"
class="formatBtn iconfont icon-juzhongduiqi"></text></view>
<view class="formatItem"><text data-name="align" data-value="right"
:class="formats.align === 'right' ? 'selected' : ''"
class="formatBtn iconfont icon-youduiqi"></text></view>
<view class="formatItem"><text data-name="align" data-value="justify"
:class="formats.align === 'justify' ? 'selected' : ''"
class="formatBtn iconfont icon-zuoyouduiqi"></text></view>
</view>
</view>
<view v-if="currentTool=='wenben'" @touchend.prevent="format">
<view class="formatBox">
<view class="box1">
<view class="formatTitle">标题</view>
<view class="formatMenu">
<view class="formatItem"> <text data-name="header" :data-value="1"
:class="formats.header === 1 ? 'selected' : ''" class=" formatBtn ">H1</text>
</view>
<view class="formatItem"><text data-name="header" :data-value="2"
:class="formats.header === 2 ? 'selected' : ''" class="formatBtn ">H2</text>
</view>
<view class="formatItem"><text data-name="header" :data-value="3"
:class="formats.header === 3 ? 'selected' : ''" class="formatBtn ">H3</text>
</view>
</view>
</view>
<view class="box2">
<view class="formatTitle">背景</view>
<view class="formatMenu">
<view class="formatItem"> <text data-name="backgroundColor" data-value="#dbdbdb"
:class="formats.backgroundColor=== '#dbdbdb' ? 'selected' : ''"
class=" formatBtn iconfont icon-zitibao"></text>
</view>
</view>
</view>
</view>
<view class="formatBox">
<view class="box1">
<view class="formatTitle">排序</view>
<view class="formatMenu">
<view class="formatItem"><text data-name="list" data-value="ordered"
:class="formats.list === 'ordered' ? 'selected' : ''"
class="iconBig formatBtn iconfont icon-youxupailie"></text></view>
<view class="formatItem"><text data-name="list" data-value="bullet"
:class="formats.list === 'bullet' ? 'selected' : ''"
class="iconBig formatBtn iconfont icon-wuxupailie"></text></view>
</view>
</view>
<view class="box2">
<view class="formatTitle">分割</view>
<view class="formatMenu">
<view class="formatItem"> <text data-name="divider" class="iconBig formatBtn iconfont icon-fengexian"
></text>
</view>
</view>
</view>
</view>
</view>
<u-popup :show="linkShow" @close="linkShow=false">
<view>
<view class="topbar">
<view class="left">取消</view>
<view class="center">添加链接</view>
<view :class="linkAdd?'linkAdd':''" class="right">添加</view>
</view>
<view class="inputBox">
<u--input placeholder="请输入链接地址,分享你的见闻" :focus="true" @change="linkOnChange">
<text slot="prefix" style="color: #909399" class=" iconfont icon-editor-link"></text>
</u--input>
</view>
<view class="inputBox">
<u--input placeholder="请输入链接描述(选填)" prefixIcon="edit-pen"
prefixIconStyle="font-size: 22px;color: #909399">
</u--input>
</view>
</view>
</u-popup>
</view>
</template>
<script>
export default {
data() {
return {
readOnly: false,
formats: {},
editorCtx: '',
currentTool: '',
linkShow: false,
linkAdd: false,
}
},
onLoad() {
uni.onKeyboardHeightChange(res => {
console.log(res.height)
})
},
onUnload() {
uni.offKeyboardHeightChange()
},
methods: {
readOnlyChange() {
this.readOnly = !this.readOnly
},
//图文详情-富文本初始化
onEditorReady() {
uni.createSelectorQuery().select('#editor').context((res) => {
this.editorCtx = res.context
}).exec()
},
//图文详情-富文本编辑输入时事件
editorInput(e) {
this.Content = e.detail.text
this.ContentHtml = e.detail.html
},
format(e) {
let {
name,
value
} = e.target.dataset
if (!name) return
console.log('format', name, value)
if ("divider" == name) {
this.editorCtx.insertDivider({
success: function() {
console.log('insert divider success')
}
})
} else {
this.editorCtx.format(name, value)
}
},
tool(e) {
let {
name
} = e.target.dataset
if (!name) return
this.currentTool = name;
console.log('currentTool', name)
if ("tupian" === name) {
}
if ("wenzi" === name) {
uni.hideKeyboard()
}
if ("wenben" === name) {
uni.hideKeyboard()
}
if ("link" === name) {
this.linkShow = true
}
if ("undo" === name) {
this.editorCtx.undo()
}
if ("redo" === name) {
this.editorCtx.redo()
}
},
onStatusChange(e) {
const formats = e.detail
this.formats = formats
},
linkOnChange(e) {
console.log(e);
this.linkAdd = !!e;
}
}
}
</script>
<style lang="scss">
@import url('//at.alicdn.com/t/c/font_3813365_m08rcwzvql.css');
.toolMenu {
border-top: 1px solid $border-color-light;
display: flex;
flex-direction: row;
text-align: center;
.toolBtn {
flex: 1;
padding: 16rpx;
}
.selected {
color: $font-color-light;
}
.disabled {
color: #ccc;
}
}
.formatTitle {
margin: 28rpx;
color: $font-color-light;
}
.formatMenu {
background-color: $border-color-light;
display: flex;
flex-direction: row;
text-align: center;
padding: 28rpx;
.formatItem {
flex: 1;
}
.formatBtn {
padding: 20rpx;
}
.iconBig {
font-size: 20px;
}
.selected {
background-color: $font-color-disabled;
}
}
.formatBox {
display: flex;
flex-direction: row;
.box1 {
flex: 1;
}
.box2 {
margin-left: 32rpx;
}
}
.topbar {
margin: 16rpx;
margin-bottom: 32rpx;
display: flex;
flex-direction: row;
.left,
.right {
color: $font-color-disabled;
}
.center {
flex: 1;
text-align: center;
}
.linkAdd {
color: #333;
}
}
.inputBox {
margin: 32rpx;
}
</style>
注:插入图片我使用的自定义插件,没有放在代码,插入后,记得获取editor的html进行替换成网络链接
this.selectFiles.forEach((item, index) => {
if (this.ContentHtml.includes(item)) { //存在此图片
this.ContentHtml = this.ContentHtml.replace(this.selectFiles[index],
this.$api.cos207 + index + ".jpg");
}
});
超链接因为editor没有提供,使用的是html后续插入替换,这里代码就不放了,大概思路是插入‘【超链接1】’的文本,然后提交的时候进行替换