![cover](https://img-blog.csdnimg.cn/8ea6291f222845d9891701b12cd1c866.png)
Vue中实现富文本功能,适配小程序端,uniapp也可实现,vue-quill-editor适配小程序,将vue-quill-editor插件中的class样式换为style内联样式达到适配目的
下载插件vue-quill-editor,封装富文本组件 textEditor,引入自己的素材库,实现从自己封装的素材库中选取图片功能,将vue-editor-quill中的class样式修改为style样式从而进行小程序端的更改,编辑,小程序使用插件,更改对应源码,实现功能,编辑达到pc端和小程序端统一html,使得新增编辑都能够实现
1、Vue中实现富文本功能
1.1 拓展功能,上传图片从系统图片素材库中拉取图片,黏贴图片时,图片也存入图片素材库中
2、将自带的class样式换为style内联样式
3、适配小程序端(仅展示,不需要编辑)
4、小程序端新增编辑富文本
1、Vue中实现富文本功能
- 使用插件 vue-quill-editor ,先下载插件
npm insatll --save vue-quill-editor
- 在main.js 中引入
import VueQuillEditor from 'vue-quill-editor' //富文本
import * as Quill from 'quill'
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
Vue.use(VueQuillEditor);
- 封装富文本组件 textEditor
uploadPictures 为图片素材库 ,引入自己的素材库,
vxe-model 是vxe 插件的弹框组件
diyConfig 为组件传参,默认file,调用本地电脑上的图片,libImgStore为使用素材库中的图片
imgData 为调用图片素材库时必要的传参
getContent 为编辑时富文本Html传参
函数
editorFn 回调函数 返回值进行下一步处理
// 组件 textEditor.vue
<template>
<div>
<quill-editor class="editor" ref="myTextEditor" v-model="content" :options="editorOption" @blur="onEditorBlur($event)"
@focus="onEditorFocus($event)" @ready="onEditorReady($event)" @change="(e)=>onEditorChange(e)" >
</quill-editor>
<vxe-modal v-model="modalPic" width="1200" height="720" min-width="860" id="imgUpdata" min-height="420" resize remember storage transfer :esc-closable="true">
<template v-slot:title>
<span >素材库</span>
</template>
<uploadPictures :isChoice="imageData.isChoice" @getPic="getPic" @getPicD="getPicD" v-if="modalPic" :storeId.sync="imageData.storeId"></uploadPictures>
</vxe-modal>
</div>
</template>
<script>
// 图片素材库引入 uploadPictures
import uploadPictures from '@/components/uploadPictures';
import axios from "axios";
export default {
props: {
getContent:{
type: String,
default:""
},
diyConfig:{//自定义配置
type: Object,
default:()=>{
return {
image:'file',//file 上传图片从电脑文件中选择,libImgStore 微商城素材库
}
}
},
imageData:{
type: Object,
default:()=>{
return {}// storeId 店号,isChoice:多选单选
}
}
},
components: {
uploadPictures,
},
mounted() {
this.$nextTick(() => {
const quill = this.$refs.myTextEditor.quill
quill.root.addEventListener('paste', this.handlePaste)
//获取图片库中的分类
if(this.diyConfig.image == 'libImgStore'){
this.getClassList()
}
})
},
data() {
return {
content: null,
editorOption: {
modules: {
toolbar:{
container:[
["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
["blockquote", "code-block"], // 引用 代码块
[{
header: 1
}, {
header: 2
}], // 1、2 级标题
[{
list: "ordered"
}, {
list: "bullet"
}], // 有序、无序列表
[{
script: "sub"
}, {
script: "super"
}], // 上标/下标
[{
indent: "-1"
}, {
indent: "+1"
}], // 缩进
// [{'direction': 'rtl'}], // 文本方向
[{
// size: ["small", false, "large", "huge"]
size: ['14px', '16px', '18px', '20px', '24px', '28px', '32px']
}], // 字体大小
[{
header: [1, 2, 3, 4, 5, 6, false]
}], // 标题
[{
color: []
}, {
background: []
}], // 字体颜色、字体背景颜色
[{
font: ['SimSun',
'SimHei',
'Microsoft-YaHei',
'KaiTi',
'FangSong']
}], // 字体种类
[{
align: []
}], // 对齐方式
["clean"], // 清除文本格式
["link", "image", "video"] // 链接、图片、视频
],//工具菜单栏配置
handlers: {
'image': (e)=>this.imageHandle(e,this.quill)
}
}
},
placeholder: '添加内容...', //提示
readyOnly: false, //是否只读
theme: 'snow', //主题 snow/bubble
syntax: true, //语法检测
},
modalPic: false,
isHandlingImage: false,
}
},
directives: {
quillImageAdded: {
bind(el, binding) {
el.addEventListener('paste', (event) => {
console.log(event,"paste")
if (event.target.tagName === 'IMG') {
binding.value(event.target.src);
}
});
}
}
},
methods: {
// 失去焦点
onEditorBlur() {
// console.log(editor)
},
// 获得焦点
onEditorFocus() {
// console.log(editor)
},
// 开始
onEditorReady() {
// console.log(editor)
},
// 值发生变化
onEditorChange(editor) {
this.content = editor.html;
this.$emit('update:editor', this.content)
this.$emit('editorFn', this.content)
},
clearContent() {
this.content = ''
},
getClassList(){
this.$http.GET('/MA/mallPsdClassify/psdClassList').then(data => {
this.classList = data.data
this.formDatas[1].options = data.data.map(item => {
item.value = item.classifyId;
item.name = item.classifyId + '--' + item.classifyName;
return item;
});
})
},
imageHandle(e,quill){
if(this.diyConfig && this.diyConfig.image == 'libImgStore'){
if (e) {
alert('点击了上传图片')
} else {
quill.format('image', false);
}
}else{
quill.format('image', '');
}
},
// 获取图片信息
getPic(pc) {
let quill = this.$refs.myTextEditor.quill;
const range = quill.getSelection(true);
console.log(pc,"pc",range)
if (!range) return;
quill.insertEmbed(range.index, "image", pc.picUrl);
this.modalPic = false;
},
getPicD(pc) {
let quill = this.$refs.myTextEditor.quill;
const range = quill.getSelection(true);
if (!range) return;
// 将图片插入到富文本编辑器中
pc.reverse()
pc.forEach(element => {
quill.insertEmbed(range.index, "image", element.picUrl);
});
this.modalPic = false;
},
handlePaste(event) {
const clipboardData = event.clipboardData || window.clipboardData
if (!clipboardData) return
const items = clipboardData.items
if (!items) return
for (let i = 0; i < items.length; i++) {
const item = items[i]
if (item.type.indexOf('image') !== -1) {
const file = item.getAsFile()
// 处理粘贴的图片文件
this.handleImageUpload(file)
}
}
},
async handleImageUpload(file) {
this.isHandlingImage = false;
if(!this.isHandlingImage && this.diyConfig.image && this.diyConfig.image == 'libImgStore'){
this.isHandlingImage = true;
console.log(this.modalPic,"image.png",this.isHandlingImage)
if(this.modalPic){
this.isHandlingImage = false;
return
}
const formData = new FormData()
formData.append('file', file); // 有的后台需要传文件名,不然会报错
formData.append("type", 'image');
formData.append("storeId", this.imageData.storeId);
// 发送图片到服务器上传
axios ({
method: "post",
url: "/manager/crm-wx/wechat/media/uploadMedia",
data: formData,
headers: {
"Content-Type": "multipart/form-data"
}
}).then(res=>{
if (res.data.code==200 && res.data.data.url!=null) {
// 上传成功将照片传回父组件
const imageUrl = res.data.data.url;
let obj = {
classifyId:this.classList[0].classifyId,
classifyName: this.classList[0].classifyName,
media_id: res.data.data.media_id,
picUrl: imageUrl,
picName: file.name,
}
//图片上传成功后添加到图片素材库分类中
this.$http.POSTJSON("/MA/mallPsdClassifyRef/merge", [obj])
.then(data => {
if (data.code == 200) {
this.delDiyImg()
// // 上传成功后,在富文本框中插入图片
const quill = this.$refs.myTextEditor.quill
const range = quill.getSelection(true)
quill.insertEmbed(range.index, 'image', imageUrl)
quill.setSelection(range.index + 1)
// this.onEditorChange({html:this.content})
// 在富文本框中展示图片
// 如果你不想展示上传失败的图片,则可以省略这一步
// quill.format('image', imageUrl)
}else{
this.$message.warning("图片上传失败1!")
this.delDiyImg()
}
});
}else{
this.$message.warning("图片上传失败2!")
this.delDiyImg()
}
this.isHandlingImage = false;
}).catch(err=>{
console.log(err,"err")
this.$message.warning("图片上传失败3!")
this.delDiyImg()
this.isHandlingImage = false;
})
}
},
delDiyImg(){
const quill = this.$refs.myTextEditor.quill
const index = quill.getSelection().index
quill.deleteText(index-1, 1)
}
},
computed: {
editor() {
return this.$refs.myTextEditor.quillEditor;
}
},
watch: {
getContent: {
handler(newVal) {
console.log(newVal,"newVal")
this.content = newVal;
},
immediate: true
},
diyConfig: {
handler(newVal) {
if(newVal && newVal.image == 'libImgStore'){
let that = this
this.editorOption.modules.toolbar.handlers.image = function(val){
if (val) {
that.modalPic = true;
} else {
this.quill.format('image', false);
}
}
}else{
delete this.editorOption.modules.toolbar.handlers.image
}
},
immediate: true
}
}
}
</script>
<style lang="scss">
.ql-editor u ,.ql-snow u{
text-decoration: underline;
}
.ql-editor s,del , .ql-snow s,del{
text-decoration: line-through;
}
.ql-editor i,em , .ql-snow i,em{
font-style: italic;
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=SimHei]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=SimHei]::before {
content: "黑体";
font-family: "SimHei";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Microsoft-YaHei]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Microsoft-YaHei]::before {
content: "微软雅黑";
font-family: "Microsoft YaHei";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=KaiTi]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=KaiTi]::before {
content: "楷体";
font-family: "KaiTi";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=FangSong]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=FangSong]::before {
content: "仿宋";
font-family: "FangSong";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Arial]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Arial]::before {
content: "Arial";
font-family: "Arial";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Times-New-Roman]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Times-New-Roman]::before {
content: "Times New Roman";
font-family: "Times New Roman";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=sans-serif]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=sans-serif]::before {
content: "sans-serif";
font-family: "sans-serif";
}
.ql-font-SimSun {
font-family: "SimSun";
}
.ql-font-SimHei {
font-family: "SimHei";
}
.ql-font-Microsoft-YaHei {
font-family: "Microsoft YaHei";
}
.ql-font-KaiTi {
font-family: "KaiTi";
}
.ql-font-FangSong {
font-family: "FangSong";
}
.ql-font-Arial {
font-family: "Arial";
}
.ql-font-Times-New-Roman {
font-family: "Times New Roman";
}
.ql-font-sans-serif {
font-family: "sans-serif";
}
/* 字号设置 */
/* 默认字号 */
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
content: "14px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="14px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="14px"]::before {
content: "14px";
font-size: 14px;
}
.ql-size-14px {
font-size: 14px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="16px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="16px"]::before {
content: "16px";
font-size: 16px;
}
.ql-size-16px {
font-size: 16px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="18px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="18px"]::before {
content: "18px";
font-size: 18px;
}
.ql-size-18px {
font-size: 18px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="20px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="20px"]::before {
content: "20px";
font-size: 20px;
}
.ql-size-20px {
font-size: 20px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="24px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="24px"]::before {
content: "24px";
font-size: 24px;
}
.ql-size-24px {
font-size: 24px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="26px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="26px"]::before {
content: "26px";
font-size: 26px;
}
.ql-size-26px {
font-size: 26px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="28px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="28px"]::before {
content: "28px";
font-size: 28px;
}
.ql-size-28px {
font-size: 28px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="32px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="32px"]::before {
content: "32px";
font-size: 32px;
}
.ql-size-32px {
font-size: 32px;
}
.editor {
line-height: normal !important;
}
.ql-snow .ql-tooltip[data-mode=link]::before {
content: "请输入链接地址:" !important;
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
border-right: 0px;
content: '保存' !important;
padding-right: 0px;
}
.ql-snow .ql-tooltip[data-mode=video]::before {
content: "请输入视频地址:" !important;
}
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
content: '文本' !important;
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
content: '标题1' !important;
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
content: '标题2' !important;
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
content: '标题3' !important;
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
content: '标题4' !important;
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
content: '标题5' !important;
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
content: '标题6' !important;
}
.quill-editor .ql-editor .ql-container img{
max-width: 400px;
}
</style>
在页面中使用
<textEditor ref="editor" :editor.sync="content" :getContent="getContent"
:diyConfig="{image:'libImgStore'}" :imageData="{storeId: form.storeId,isChoice:'多选'}"
style="width:340px;" @editorFn="editorFn"></textEditor>
此时富文本已经可以使用了
2、 将自带的class样式换为style内联样式
可以参考文档 https://www.kancloud.cn/liuwave/quill/1409946#_61
将main.js 中引入的文件换为 下面文件
import VueQuillEditor from 'vue-quill-editor' //富文本
import * as Quill from 'quill'
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
// 设置字体大小
const fontSizeStyle = Quill.import('attributors/style/size') // 引入这个后会把样式写在style上
fontSizeStyle.whitelist = [ '14px', '16px', '18px', '20px', '24px', '28px', '32px']
Quill.register(fontSizeStyle, true)
const Font = Quill.import('attributors/style/font') // 引入这个后会把样式写在style上
const fonts = [
'SimSun',
'SimHei',
'Microsoft-YaHei',
'KaiTi',
'FangSong'
]
Font.whitelist = fonts // 将字体加入到白名单
Quill.register(Font, true)
var Align = Quill.import('attributors/style/align')
Quill.register(Align, true)
var Direction = Quill.import('attributors/style/direction')
Quill.register(Direction, true)
Vue.use(VueQuillEditor);
中间这个部分 会在写入样式时,写入style样式,达到目的
其中的 whitelist 、fonts、这两个数组赋值,是将富文本自带的数组换为自定义的数组了
查看原本数据 可以 console.log(Quill.imports) 单独打印出来看
3、 小程序中展示(仅展示,不编辑)
使用uview 中自带的富文本功能,Parse只需把富文本传值传入即可展示,对应的样式查看官方文档
https://v1.uviewui.com/components/parse.html
基本使用,长按复制,样式设置 等功能都能满足 (注意有1.0版本和2.0 版本)根据下载的插件看不同版本的文档
4、小程序中新增、编辑管理端中存入的富文本
1、下载插件
https://ext.dcloud.net.cn/plugin?id=12013 富文本插件
下载到自己项目中
2、把不需要的功能屏蔽,或者如果有满足不了的可以自己开发。
源码中 上传图片代码有两处,根据平台不同,找到对应代码,图片我默认给宽度100%了,所以我控制了不让调整大小,更剧自己需求具体适配
在微信小程序中适配是 // #ifdef MP 从这以下的代码
添加一个参数用来控制富文本的样式 ,我主要是用来更改他的高度
下载插件后的代码 piaoyi-editor 更改完后的代码,可直接复制替换
<template>
<view class="container-editor">
<view class="textarea">
<view class="page-body">
<view class='wrapper ql-editor'>
<PickerColor ref="colorPicker" :color="{r: 255,g: 0,b: 0,a: 0.6}" @confirm="confirm"></PickerColor>
<view class='toolbar' @tap="format">
<view :class="formats.fontSize === '24px' ? 'ql-active' : ''" class="iconfont icon-font-size"
data-name="fontSize" data-value="24px"></view>
<view :class="formats.color? 'ql-active' : ''" class="iconfont icon-zitiyanse" data-name="color" :data-value="formats.color">
</view>
<view :class="formats.header === 1 ? 'ql-active' : ''" class="iconfont icon-formatheader1"
data-name="header" :data-value="1"></view>
<view :class="formats.header === 2 ? 'ql-active' : ''" class="iconfont icon-formatheader2"
data-name="header" :data-value="2"></view>
<view :class="formats.bold ? 'ql-active' : ''" class="iconfont icon-zitijiacu" data-name="bold">
</view>
<view :class="formats.italic ? 'ql-active' : ''" class="iconfont icon-zitixieti"
data-name="italic"></view>
<view :class="formats.underline ? 'ql-active' : ''" class="iconfont icon-zitixiahuaxian"
data-name="underline"></view>
<view :class="formats.strike ? 'ql-active' : ''" class="iconfont icon-shanchuxian"
data-name="strike"></view>
<view :class="formats.align === 'left' ? 'ql-active' : ''" class="iconfont icon-zuoduiqi"
data-name="align" data-value="left"></view>
<view :class="formats.align === 'center' ? 'ql-active' : ''" class="iconfont icon-juzhongduiqi"
data-name="align" data-value="center"></view>
<view :class="formats.align === 'right' ? 'ql-active' : ''" class="iconfont icon-youduiqi"
data-name="align" data-value="right"></view>
<view :class="formats.align === 'justify' ? 'ql-active' : ''" class="iconfont icon-zuoyouduiqi"
data-name="align" data-value="justify"></view>
<!-- <view :class="formats.lineHeight ? 'ql-active' : ''" class="iconfont icon-LineHeight"
data-name="lineHeight" data-value="2"></view>
<view :class="formats.letterSpacing ? 'ql-active' : ''" class="iconfont icon-Character-Spacing"
data-name="letterSpacing" data-value="2em">
</view> -->
<!-- <view :class="formats.marginTop ? 'ql-active' : ''" class="iconfont icon-duanqianju"
data-name="marginTop" data-value="10px"></view>
<view :class="formats.previewarginBottom ? 'ql-active' : ''" class="iconfont icon-duanhouju"
data-name="marginBottom" data-value="10px"></view> -->
<!-- <view class="iconfont icon-rili4" @tap="insertDate"></view> -->
<!-- <view class="iconfont icon-checklist" data-name="list" data-value="check"></view> -->
<view :class="formats.list === 'ordered' ? 'ql-active' : ''" class="iconfont icon-youxupailie"
data-name="list" data-value="ordered"></view>
<view :class="formats.list === 'bullet' ? 'ql-active' : ''" class="iconfont icon-wuxupailie"
data-name="list" data-value="bullet"></view>
<!-- <view class="iconfont icon-outdent" data-name="indent" data-value="-1"></view>
<view class="iconfont icon-indent" data-name="indent" data-value="+1"></view> -->
<!-- <view class="iconfont icon-fengexian" @tap="insertDivider"></view> -->
<view class="iconfont icon-charutupian" @tap="insertImage"></view>
<view class="iconfont icon-undo" @tap="undo"></view>
<view class="iconfont icon-redo" @tap="redo"></view>
<view class="iconfont icon-format" @tap="clear"></view>
</view>
<!-- showImgResize -->
<editor id="editor" class="editor" placeholder="开始输入..." showImgSize showImgToolbar
@statuschange="onStatusChange" :read-only="readOnly" @ready="onEditorReady" :style="[editStyle]"
@input="saveContens">
</editor>
</view>
</view>
</view>
</view>
</template>
<script>
import PickerColor from "./color-picker.vue"
export default {
components: {
PickerColor
},
props: {
api: {
type: String,
default: ''
},
photoUrl: {
type: String,
default: ''
},
values: {
type: String,
default: ''
},
readOnly: {
type: Boolean,
default: false
},
maxlength: {
type: Number,
default: 300
},
name: {
type: String,
default: 'file'
},
editStyle: {
type: Object,
default: ()=>{}
},
},
data() {
return {
currentTab: 0,
curColor: '#000000',
show: true,
hdid: "",
myHtml: "",
formats: {}
}
},
methods: {
showPicker() {
this.$refs.colorPicker.open()
},
confirm(e) {
this.editorCtx.format('color', e.hex)
},
saveContens() {
let that = this;
let maxlength = parseInt(that.maxlength);
that.editorCtx.getContents({
success: function(res) {
let html_text = res.html;
let html_length = html_text.length;
if (html_length > maxlength) {
uni.showModal({
title: '最多只能输入' + maxlength + '字',
confirmText: '确定',
showCancel: false,
success(res) {
that.$emit("changes", {
html: res.html,
length: html_length
});
}
});
} else {
that.$emit("changes", {
html: res.html=='<p><br></p>'?'':res.html,
length: html_length
});
}
},
})
},
update() {
//获取一下是否有数据
let that = this;
setTimeout(() => {
that.editorCtx.setContents({
"html": that.values
});
}, 1000)
},
onEditorReady() {
let that = this;
uni.createSelectorQuery().in(this).select('#editor').context((res) => {
that.editorCtx = res.context;
that.update();
}).exec((result) => {});
},
undo() {
this.editorCtx.undo()
},
redo() {
this.editorCtx.redo()
},
format(e) {
let {
name,
value
} = e.target.dataset
if (!name) return
if (name == 'color') {
this.showPicker()
} else {
this.editorCtx.format(name, value)
}
},
onStatusChange(e) {
const formats = e.detail
this.formats = formats
},
insertDivider() {
this.editorCtx.insertDivider();
},
clear() {
let that = this
this.editorCtx.clear({
success: res=>{
this.$emit("changes",{html:""})
}
});
},
insertDate() {
const date = new Date()
const formatDate = `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`
this.editorCtx.insertText({
text: formatDate
})
},
insertImage() {
let that = this;
// #ifdef APP-PLUS || H5
uni.chooseImage({
count: 1, //默认9
sizeType: ['compressed'], //可以指定是原图还是压缩图,默认二者都有
sourceType: ['album'], //从相册或者相机选择
success: (res) => {
const tempFilePaths = res.tempFilePaths[0]
if (!this.api || !this.photoUrl) {
that.editorCtx.insertImage({
src: tempFilePaths,
alt: '图像',
success: function() {}
})
uni.showToast({
title: '未传入api字段或者photoUrl字段,此为临时图片路径',
duration: 3000,
icon: 'none'
})
} else {
uni.uploadFile({
url: this.photoUrl + this.api,
filePath: tempFilePaths,
name: this.name,
formData: {},
success: (uploadFileRes) => {
var obj = JSON.parse(uploadFileRes.data)
if (obj.code == 200) {
this.img = this.photoUrl + '/' + obj.data
wx.showToast({
title: obj.msg,
icon: 'none'
})
this.editorCtx.insertImage({
src: this.img,
alt: '图像',
width: "100%",
success: function() {
const imageElement = document.querySelector('.custom-image-class');
console.log(imageElement,"imageElement")
if (imageElement) {
imageElement.style.width = '100%'; // 设置宽度为20px
}
}
})
} else {
wx.showToast({
title: obj.msg,
icon: 'none'
})
}
}
});
}
},
fail() {
uni.showToast({
title: '未授权访问相册权限,请授权后使用',
icon: 'none'
})
}
});
// #endif
// #ifdef MP
uni.chooseMedia({
count: 1,
mediaType: ['image'],
sourceType: ['album'],
sizeType: 'compressed',
success: (chooseImageRes) => {
const tempFilePaths = chooseImageRes.tempFiles[0].tempFilePath;
console.log(tempFilePaths)
if (!this.api || !this.photoUrl) {
that.editorCtx.insertImage({
src: tempFilePaths,
alt: '图像',
success: function() {}
})
uni.showToast({
title: '未传入api字段或者photoUrl字段,此为临时图片路径',
duration: 3000,
icon: 'none'
})
} else {
uni.uploadFile({
url: this.photoUrl + this.api,
filePath: tempFilePaths,
name: this.name,
formData: {},
success: (uploadFileRes) => {
var obj = JSON.parse(uploadFileRes.data)
console.log(obj,"uploadFileRes")
if (obj.code == 200) {
// this.img = path + '/' + obj.data
this.img = obj.data.url
wx.showToast({
title: obj.msg,
icon: 'none'
})
this.editorCtx.insertImage({
src: this.img,
alt: '图像',
width: "100%",
success: function() {}
})
} else {
wx.showToast({
title: obj.msg,
icon: 'none'
})
}
},
fail(err) {
console.log(err)
uni.showToast({
title: err.errMsg,
icon: 'none'
})
}
});
}
}
})
// #endif
}
}
}
</script>
<style>
@import url('iconfont.css');
.tabs {
display: flex;
justify-content: space-around;
background-color: #FFFFFF;
}
.tabs .current {
border-bottom: 2px solid #0369D6;
}
.tabs .tab {
font-size: 32upx;
}
.main {
padding: 20upx;
background-color: #FFFFFF;
}
.main .item {
display: flex;
justify-content: space-between;
line-height: 80upx;
border-bottom: 1px solid #F2F2F2;
}
.main .item .left {
min-width: 200upx;
}
.main .title {
padding-bottom: 20upx;
font-weight: bold;
border-bottom: 1px solid #F2F2F2;
}
.main .textarea {
border: 1px solid #F2F2F2;
}
.wrapper {
padding: 0 10upx;
}
.iconfont {
display: inline-block;
width: 9%;
cursor: pointer;
font-size: 40upx !important;
text-align: center;
padding: 10upx 0;
}
.icon-rili4 {
font-size: 48upx !important;
}
.icon-duanqianju,
.icon-duanhouju,
.icon-zitijiacu,
.icon-zitixieti,
.icon-zitixiahuaxian,
.icon-shanchuxian {
font-size: 36upx !important;
}
.toolbar {
box-sizing: border-box;
border-bottom: 0;
margin-bottom: 10upx;
}
.ql-container {
box-sizing: border-box;
width: 100%;
min-height: 600upx;
height: auto;
background: #fff;
font-size: 32upx;
line-height: 1;
padding-bottom: 60upx;
}
/deep/ .ql-editor.ql-blank:before {
font-size: 28upx;
font-style: inherit;
}
.ql-active {
color: #ff0000;
}
button {
width: 150upx;
font-size: 30upx;
}
.editor {
color: #333;
}
</style>
插件已经修改为成后,就可以在页面中使用了
3、在页面中使用
注意下面部分需要换成自己的接口
完整代码 如下
<template>
<view class="richtext">
<piaoyiEditor :values="desc" :maxlength="3000" @changes="saveContens" :readOnly="readOnly" :photoUrl="photoUrl"
:api="api" :name="name" :editStyle="editStyle"/>
<view class="q-flex-center q-position-fixed-Bottom q-borderBox u-p-b-20 u-p-t-20 q-shadow bottomBar">
<view class="buttonSTY" @click="submit">
确认
</view>
</view>
</view>
</template>
<script>
import piaoyiEditor from '@/uni_modules/piaoyi-editor/components/piaoyi-editor/piaoyi-editor.vue';
export default {
data() {
return {
readOnly: false, //是否只读
photoUrl: '', //服务器图片域名或者ip
api: '/wechat/media/uploadMedia', //上传图片接口地址
txt: '',
name: 'file',
desc: '<div>11111222</div>',
editStyle: {
height: "calc(100vh - 130px)",
}
};
},
components: {
piaoyiEditor
},
onLoad(option){
this.desc = decodeURIComponent(option.desc);
this.txt = this.desc;
},
onShow() {
this.photoUrl = this.$common.api_url+this.$common.fileserver;
this.api = `/wechat/media/uploadMedia?type=image&storeId=${uni.getStorageSync('shopNo')}`;
},
methods: {
saveContens(e) {
console.log(e,"e")
this.txt = e.html
},
submit(){
let that = this;
let pages = getCurrentPages()
let prevPage = pages[pages.length - 2];
uni.navigateBack({
delta: 1,
success() {
prevPage.$vm.richTextSubmit(encodeURIComponent(that.txt));
},
})
},
},
}
</script>
<style scoped>
.bottomBar{
background: #fff;
}
.buttonSTY{
width: 600rpx;
text-align: center;
background: #FC6B3A;
height: 80rpx;
font-size: 30rpx;
line-height: 80rpx;
color: #f3f3f3;
border-radius: 40rpx;
}
</style>
![Logo](https://devpress.csdnimg.cn/79de2bf0b7994defa4242ef90d5513fa.jpg)
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)