目前公司项目后台基于antdesign pro vue进行快速开发,富文本编辑器统一使用的是vue-ueditor-wrap,但是后端上传图片需要携带token,单独上传至七牛云,所以挂了好久都没处理图片,解决后第一时间记录下。
1.安装下vue-ueditor-wrap npm安装即可,然后去网上找了个UEditor配置包(可能不需要)放在public文件夹里
2.在src中的components文件夹里创建一个VueUeditorWrap的文件夹,里面新建一个index.vue
3.在script中引入vue-ueditor-wrap,注册组件,还有引入上传图片方法,在props中获取到时候从父页面传入的富文本内容
import VueUeditorWrap from 'vue-ueditor-wrap';
import { uploadPicture } from '@/api/common'
export default {
components: {
VueUeditorWrap
},
props:{
editorData:{
type: String,
}
},
}
4. 页面使用组件,加入配置项还有初始化前操作,编写上传vue代码
<template>
<div>
<vue-ueditor-wrap :config="editorConfig" v-model="editorHtmlData" @beforeInit="addCustomButtom" />
<!-- 自定义上传 -->
<a-modal title="图片上传"
:visible="dialogdVisible"
@ok="handleOk"
@cancel="handleCancel">
<div class="clearfix">
<a-upload
action="/"
list-type="picture-card"
:file-list="editorFileList"
@preview="handlePreview"
:before-upload="beforeUploadEditor"
:customRequest="doCustomUploadEditor"
:remove="doRemoveEditor"
>
<div v-if="editorFileList.length < 8">
<a-icon type="plus" />
<div class="ant-upload-text">上传图片</div>
</div>
</a-upload>
<a-modal :visible="previewVisible" :footer="null" @cancel="handlePreviewCancel">
<img alt="example" style="width: 100%" :src="previewImage" />
</a-modal>
</div>
</a-modal>
</div>
</template>
5.data中配置项还有工具栏设置
data() {
return {
editorHtmlData:this.editorData,
editorHandler: null,
editorConfig: {
toolbars: [[ //定制工具栏图标
'fullscreen', 'source', '|', 'undo', 'redo', '|',
'bold', 'italic', 'underline', 'fontborder', 'strikethrough', 'superscript', 'subscript', 'removeformat', 'formatmatch', 'autotypeset', 'blockquote', 'pasteplain', '|', 'forecolor', 'backcolor', 'insertorderedlist', 'insertunorderedlist', 'selectall', '|',
'rowspacingtop', 'rowspacingbottom', 'lineheight', '|',
'customstyle', 'paragraph', 'fontfamily', 'fontsize', '|',
'directionalityltr', 'directionalityrtl', 'indent', '|',
'justifyleft', 'justifycenter', 'justifyright', 'justifyjustify', '|', 'touppercase', 'tolowercase', '|',
'imagenone', 'imageleft', 'imageright', 'imagecenter', '|',
'emotion', 'map', 'insertcode', 'background', '|',
'horizontal', 'date', 'time', 'spechars', '|',
'inserttable', 'deletetable', 'insertparagraphbeforetable', 'insertrow', 'deleterow', 'insertcol', 'deletecol', 'mergecells', 'mergeright', 'mergedown', '|',
'print', 'preview',
]],
autoHeightEnabled: false, //编译器不自动被内容撑高
initialFrameHeight: 350, //初始容器高度
initialFrameWith: "100%",
serverUrl: '', //上传文件地址
UEDITOR_HOME_URL: "/UEditor/", //UEditor资源文件的存放路径
},
dialogdVisible: false,
previewVisible: false,
previewImage: '',
editorFileList: [],
}
},
6.定义事件,在watch中监听内容改变,使用$emit向父组件传值,微调下样式,完成组件的封装
watch:{
editorData (newValue) {
this.editorHtmlData = newValue
},
editorHtmlData (newValue) {
this.$emit("on-change",newValue)
}
},
methods: {
// 自定义初始化
addCustomButtom (editorId) {
let _this = this;
window.UE.registerUI('test-button', function (editor, uiName) {
// 注册按钮执行时的 command 命令,使用命令默认就会带有回退操作
editor.registerCommand(uiName, {
execCommand: () => {
_this.editorFileList = [];
_this.dialogdVisible = true;
_this.editorHandler = editor;
}
})
// 创建一个 button
var btn = new window.UE.ui.Button({
// 按钮的名字
name: uiName,
// 提示
title: '图片上传',
// 需要添加的额外样式,可指定 icon 图标,图标路径参考常见问题 2
cssRules: "background-position: -380px 0;",
// 点击时执行的命令
onclick: function () {
// 这里可以不用执行命令,做你自己的操作也可
editor.execCommand(uiName)
}
})
// 当点到编辑内容上时,按钮要做的状态反射
editor.addListener('selectionchange', function () {
var state = editor.queryCommandState(uiName)
if (state === -1) {
btn.setDisabled(true)
btn.setChecked(false)
} else {
btn.setDisabled(false)
btn.setChecked(state)
}
})
// 因为你是添加 button,所以需要返回这个 button
return btn
}, 46 /* 指定添加到工具栏上的哪个位置,默认时追加到最后 */, editorId /* 指定这个 UI 是哪个编辑器实例上的,默认是页面上所有的编辑器都会添加这个按钮 */)
},
// 成功
handleOk(e) {
let imageList = this.editorFileList;
let imageHtml = "";
(imageList || []).map(item => {
imageHtml = imageHtml + "<p><img src=\"" + item.url + "\"/></p>";
})
if (imageHtml != "") {
this.editorHandler.execCommand('inserthtml', imageHtml);
}
this.dialogdVisible = false;
},
// 取消
handleCancel(e) {
this.dialogdVisible = false;
},
// 取消预览
handlePreviewCancel() {
this.previewVisible = false;
},
// 预览
handlePreview(file) {
this.previewImage = file.url || file.preview;
this.previewVisible = true;
},
// 上传图片验证
beforeUploadEditor(file) {
const isFileTypeValid = ['image/jpeg', 'image/png', 'image/gif'].includes(file.type);
if (!isFileTypeValid) {
this.$message.error('只支持上传 jpg / png / gif 格式的图片');
return false;
}
const isLt1M = file.size / 1024 / 1024 < 1;
if (!isLt1M) {
this.$message.error('图片大小不能超过 1M');
return false;
}
return true;
},
// 移除图片
doRemoveEditor(file) {
console.log(file)
this.editorFileList = this.editorFileList.filter((item) => {
return item.uid != file.uid;
});
},
// 上传图片
async doCustomUploadEditor(info) {
const {file} = info;
let data = new FormData();
data.append('file',file);
const result = await uploadPicture(data)
if (result) {
const obj = {
uid: result.src,
name: 'image.png',
status: 'done',
url: result.src,
};
this.editorFileList.push(obj);
}else {
const obj = {
uid: result.src,
name: 'image.png',
status: 'error',
};
this.editorFileList.push(obj);
}
},
},
<style scoped>
.ant-upload-select-picture-card i {
font-size: 32px;
color: #999;
}
.ant-upload-select-picture-card .ant-upload-text {
margin-top: 8px;
color: #666;
}
</style>
7.在页面中使用组件
<li>
<p>文章详情</p>
<div>
<u-editor :editorData="content" @on-change="handleChange"/>
</div>
</li>
<script>
import UEditor from '@/components/VueUeditorWrap/index.vue'
export default {
components: {
UEditor
},
data() {
return {
content: null
}
},
methods: {
// 修改内容
handleChange (value) {
this.content = value
},
}
}
</script>
前端小菜鸡第一次写文章,不喜勿喷,写的菜,有问题的话欢迎指正。