Vue项目中使用Tinymce,图片上传服务器接口对接方法
微wx笑
2021-01-21【前端开发】
4
0关键字:
Vue Tinymce 图片上传 接口对接
TinyMCE提供了图片上传处理函数images_upload_handler, 该函数有三个参数:blobInfo,success callback,failure callback, 分别是图片内容, 一个成功的回调函数以及一个失败
TinyMCE提供了图片上传处理函数images_upload_handler, 该函数有三个参数:blobInfo,success callback,failure callback, 分别是图片内容, 一个成功的回调函数以及一个失败的回调函数,具体上传图片代码在上面已经写,这里就不赘述; 需要注意的是,当向后台上传完图片, 我们要调用success函数来用服务器地址替换<image>标签的src属性。
以下是我基于“vue-element-admin”的项目图片上传服务器接口对接方法
src/components/Tinymce/index.vue
<template>
<div :class="{fullscreen:fullscreen}" :style="{width:containerWidth}">
<textarea :id="tinymceId" />
<!-- <div>
<editorImage color="#1890ff" @successCBK="imageSuccessCBK" />
</div> -->
</div>
</template>
<script>
/**
* docs:
* https://panjiachen.github.io/vue-element-admin-site/feature/component/rich-editor.html#tinymce
*/
// import editorImage from './components/EditorImage'
import plugins from './plugins'
import toolbar from './toolbar'
import load from './dynamicLoadScript'
import { uploadFile } from '@/api/upload.js'
// why use this cdn, detail see https://github.com/PanJiaChen/tinymce-all-in-one
const tinymceCDN = 'https://cdn.jsdelivr.net/npm/tinymce-all-in-one@4.9.3/tinymce.min.js'
export default {
name: 'Tinymce',
// components: { editorImage },
props: {
id: {
type: String,
default: function() {
return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
}
},
value: {
type: String,
default: ''
},
toolbar: {
type: Array,
required: false,
default() {
return []
}
},
menubar: {
type: String,
default: 'file edit insert view format table'
},
height: {
type: [Number, String],
required: false,
default: 360
},
width: {
type: [Number, String],
required: false,
default: 'auto'
}
},
data() {
return {
hasChange: false,
hasInit: false,
tinymceId: this.id,
fullscreen: false,
languageTypeList: {
'en': 'en',
'zh': 'zh_CN',
'es': 'es_MX',
'ja': 'ja'
}
}
},
computed: {
language() {
return this.languageTypeList[this.$store.getters.language]
},
containerWidth() {
const width = this.width
if (/^[\d]+(\.[\d]+)?$/.test(width)) { // matches `100`, `'100'`
return `${width}px`
}
return width
}
},
watch: {
value(val) {
if (!this.hasChange && this.hasInit) {
this.$nextTick(() =>
window.tinymce.get(this.tinymceId).setContent(val || ''))
}
},
language() {
this.destroyTinymce()
this.$nextTick(() => this.initTinymce())
}
},
mounted() {
this.init()
},
activated() {
if (window.tinymce) {
this.initTinymce()
}
},
deactivated() {
this.destroyTinymce()
},
destroyed() {
this.destroyTinymce()
},
methods: {
init() {
// dynamic load tinymce from cdn
load(tinymceCDN, (err) => {
if (err) {
this.$message.error(err.message)
return
}
this.initTinymce()
})
},
initTinymce() {
const _this = this
window.tinymce.init({
language: this.language,
selector: `#${this.tinymceId}`,
height: this.height,
body_class: 'panel-body ',
object_resizing: false,
toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
menubar: this.menubar,
plugins: plugins,
end_container_on_empty_block: true,
powerpaste_word_import: 'clean',
code_dialog_height: 450,
code_dialog_width: 1000,
advlist_bullet_styles: 'square',
advlist_number_styles: 'default',
imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
default_link_target: '_blank',
link_title: false,
paste_data_images: true,
nonbreaking_force_tab: true, // inserting nonbreaking space need Nonbreaking Space Plugin
init_instance_callback: editor => {
if (_this.value) {
editor.setContent(_this.value)
}
_this.hasInit = true
editor.on('NodeChange Change KeyUp SetContent', () => {
this.hasChange = true
this.$emit('input', editor.getContent())
})
},
setup(editor) {
editor.on('FullscreenStateChanged', (e) => {
_this.fullscreen = e.state
})
},
automatic_uploads: true,
images_upload_handler: (blobInfo, success, failure) => {
const formData = new FormData()
formData.append('file', blobInfo.blob())
uploadFile(formData).then(res => {
if (res.data) {
console.log('res.data', res.data)
success(res.data)
return
}
failure('上传失败')
}).catch(() => {
failure('上传出错')
})
},
// it will try to keep these URLs intact
// https://www.tiny.cloud/docs-3x/reference/configuration/Configuration3x@convert_urls/
// https://stackoverflow.com/questions/5196205/disable-tinymce-absolute-to-relative-url-conversions
convert_urls: false
// 整合七牛上传
// images_dataimg_filter(img) {
// setTimeout(() => {
// const $image = $(img);
// $image.removeAttr('width');
// $image.removeAttr('height');
// if ($image[0].height && $image[0].width) {
// $image.attr('data-wscntype', 'image');
// $image.attr('data-wscnh', $image[0].height);
// $image.attr('data-wscnw', $image[0].width);
// $image.addClass('wscnph');
// }
// }, 0);
// return img
// },
// images_upload_handler(blobInfo, success, failure, progress) {
// progress(0);
// const token = _this.$store.getters.token;
// getToken(token).then(response => {
// const url = response.data.qiniu_url;
// const formData = new FormData();
// formData.append('token', response.data.qiniu_token);
// formData.append('key', response.data.qiniu_key);
// formData.append('file', blobInfo.blob(), url);
// upload(formData).then(() => {
// success(url);
// progress(100);
// })
// }).catch(err => {
// failure('出现未知问题,刷新页面,或者联系程序员')
// console.log(err);
// });
// },
})
},
destroyTinymce() {
const tinymce = window.tinymce.get(this.tinymceId)
if (this.fullscreen) {
tinymce.execCommand('mceFullScreen')
}
if (tinymce) {
tinymce.destroy()
}
},
setContent(value) {
window.tinymce.get(this.tinymceId).setContent(value)
},
getContent() {
window.tinymce.get(this.tinymceId).getContent()
},
imageSuccessCBK(arr) {
arr.forEach(v => window.tinymce.get(this.tinymceId).insertContent(`<img src="${v.url}" >`))
}
}
}
</script>
<style scoped>
.tinymce-container {
position: relative;
line-height: normal;
}
.tinymce-container {
::v-deep {
.mce-fullscreen {
z-index: 10000;
}
}
}
.tinymce-textarea {
visibility: hidden;
z-index: -1;
}
.editor-custom-btn-container {
position: absolute;
right: 4px;
top: 4px;
/*z-index: 2005;*/
}
.fullscreen .editor-custom-btn-container {
z-index: 10000;
position: fixed;
}
.editor-upload-btn {
display: inline-block;
}
</style>这里面主要的几个部分改动
1、支持粘贴图片
写文章插入图片的时候,经常会用到屏幕截图,截图后直接粘贴到编辑器中,是比较方便的。但是默认这个功能并没有开启,需要添加以下配置:
paste_data_images: true,
2、支持自动上传
automatic_uploads: true,
3、编写上传处理程序
images_upload_handler: (blobInfo, success, failure) => {
const formData = new FormData()
formData.append('file', blobInfo.blob())
uploadFile(formData).then(res => {
if (res.data) {
console.log('res.data', res.data)
success(res.data)
return
}
failure('上传失败')
}).catch(() => {
failure('上传出错')
})
},这里的 res.data 就是上传到服务器之后的图片地址,我对接的后端接口 response 的内容是JSON结构,类似下面这样:
{
"code": 200,
"message": "成功",
"data": "/ufs/2021/1/17c5a6fd70804ff784ed21b112854b60.png"
}4、上传图片方法 uploadFile
import { uploadFile } from '@/api/upload.js'src/api/upload.js
import request from '@/utils/request'
export function uploadFile(data) {
return request({
url: '/api/common/upload',
method: 'post',
headers: {
'Content-Type': 'multipart/form-data'
},
data
})
}这里比较重要的是 headers 'Content-Type': 'multipart/form-data',只有设置为'multipart/form-data'才能上传文件。
本文由 微wx笑 创作,采用 署名-非商业性使用-相同方式共享 4.0 许可协议,转载请附上原文出处链接及本声明。
原文链接:https://www.ivu4e.cn/blog/front/2021-01-21/612.html



