先看下配置的效果图:
vue2组件
使用的版本是:
"@wangeditor/editor": "^5.1.23"
"@wangeditor/editor-for-vue": "^1.0.2"
<template>
<div>
<div style="border: 1px solid #dcdfe6; margin-top: 10px">
<!-- 工具栏 -->
<Toolbar style="border-bottom: 1px solid #dcdfe6"
:editor="editor"
:defaultConfig="toolbarConfig"
:mode="mode" />
<!-- 编辑器 -->
<Editor style="height: 400px; overflow-y: hidden"
:defaultConfig="editorConfig"
v-model="valueHtml"
@onChange="onChange"
@onCreated="onCreated"
:mode="mode" />
</div>
</div>
</template>
<script>
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
export default {
name: 'MyEditor',
components: { Editor, Toolbar },
props: {
content: {
type: String,
default: ''
}
},
data() {
const that = this
return {
editor: null,
mode: 'default',
valueHtml: '',
toolbarConfig: {
// toolbarKeys: [ /* 显示哪些菜单,如何排序、分组 */ ],
// 隐藏菜单
excludeKeys: [
'blockquote',
'group-video',
'insertImage',
// 'emotion',
'codeBlock',
'fullScreen',
'fontFamily',
// 'lineHeight',
'|',
'numberedList'
]
},
exitIds: [],
latestError: '',
editorConfig: {
placeholder: '请输入内容...',
// autoFocus: false,
// 所有的菜单配置,都要在 MENU_CONF 属性下
MENU_CONF: {
uploadImage: {
server: `${process.env.VUE_APP_SHOP_API}/shop/products/uploadShopImg`,
fieldName: 'file',
headers: {
Authorization: this.$store.getters.token
},
// maxFileSize: 1 * 1024 * 1024,
maxNumberOfFiles: 20,
allowedFileTypes: ['image/png,image/jpeg,image/jpg'],
withCredentials: true,
timeout: 5 * 1000,
onBeforeUpload(file) {
const fileList = Object.values(file)
const typeList = ['image/jpg', 'image/jpeg', 'image/png']
for (const i of fileList) {
// 不符合上传条件,未抛出过异常,继续抛异常信息 return false
if (!typeList.includes(i.type) && !that.exitIds.includes(i.id)) {
that.exitIds.push(i.id)
that.$message.error('图片只能是 JPG、JPEG、PNG 格式!')
return false
} else if (i.size / 1024 / 1024 > 1 && !that.exitIds.includes(i.id)) {
that.exitIds.push(i.id)
that.$message.error('图片大小不能超过1M! 请重新上传!')
return false
}
}
for (const j in file) {
const obj = {}
if (typeList.includes(file[j].type) && file[j].size / 1024 / 1024 <= 1) {
obj[j] = file[j]
return obj
}
}
},
onProgress() {
// console.log('progress', progress)
},
onSuccess(file, res) {
// console.log(`${file.name} 上传成功`, res)
},
// 自定义插入
customInsert(res, insertFn) {
that.exitIds = []
insertFn(res.data, '')
},
onError(file, res) {
const fileType = file.type
const fileSize = file.size
const typeList = ['image/jpg', 'image/jpeg', 'image/png']
if (!typeList.includes(fileType)) {
return that.$message.error('图片只能是 JPG、JPEG、PNG 格式!')
} else if (fileSize / 1024 / 1024 > 1) {
return that.$message.error('图片大小不能超过1M! 请重新上传')
}
}
}
}
}
}
},
watch: {
content: {
handler(newVal, oldVal) {
this.valueHtml = newVal
},
immediate: true
},
valueHtml: {
handler(newVal, oldVal) {
if (newVal) {
this.$emit('update-modelValue', newVal)
}
},
deep: true
}
},
methods: {
onCreated(editor) {
this.editor = Object.seal(editor) // 【注意】一定要用 Object.seal() 否则会报错
},
// onChange 时获取编辑器最新内容
onChange(editor) {
this.valueHtml = editor.getHtml()
}
},
mounted() {
// 模拟 ajax 请求,异步渲染编辑器
setTimeout(() => {
this.valueHtml = this._props.content
this.editor.blur()
}, 200)
},
beforeDestroy() {
const editor = this.editor
if (editor === null) return
editor.destroy() // 组件销毁时,及时销毁 editor ,重要!!!
}
}
</script>
<style src="@wangeditor/editor/dist/css/style.css"></style>
父组件中的使用
<textEditor :content="postForm.text" @update-modelValue="changeContent"></textEditor>
vue3组件
<template>
<div style="border: 1px solid #ccc">
<Toolbar
id="editor"
style="border-bottom: 1px solid #ccc"
:editor="editorRef"
:defaultConfig="toolbarConfig"
:mode="mode"
/>
<Editor
style="height: 500px; overflow-y: hidden"
v-model="valueHtml"
:defaultConfig="editorConfig"
:mode="mode"
@onCreated="handleCreated"
@on-change="handleChange"
/>
</div>
</template>
<script lang="ts">
import '@wangeditor/editor/dist/css/style.css' // 引入 css
import {
defineComponent,
onBeforeUnmount,
shallowRef,
onMounted,
ref,
reactive,
toRefs,
watch,
} from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import message from '@/utils/message'
import useStore from '@/store'
export default defineComponent({
emits: ['update-modelValue'],
components: { Editor, Toolbar },
props: {
modelValue: {
type: String,
default: '',
},
disabled: {
type: Boolean,
default: false,
},
},
setup(props, context) {
const editorRef = shallowRef()
const valueHtml = ref(props.modelValue)
watch(
() => valueHtml.value,
newValue => {
context.emit('update-modelValue', newValue)
}
)
watch(
() => props.modelValue,
newValue => {
valueHtml.value = newValue
}
)
watch(
() => props.disabled,
newValue => {
if (newValue) {
editorRef.value.disable()
} else {
editorRef.value.enable()
}
}
)
onMounted(() => {})
const token: any = sessionStorage.getItem('token')
//工具栏设置
const toolbarConfig = {
excludeKeys: [
'group-video',
'insertImage',
'insertLink',
'emotion',
'codeBlock',
'fullScreen',
],
}
//编辑器设置
const editorConfig = {
placeholder: '请输入内容...',
MENU_CONF: {
uploadImage: {
server: `${
import.meta.env.VITE_APP_BASE_API
}/file/fileManager/getImportFileUrl`,
fieldName: 'file',
headers: {
Authorization: `${JSON.parse(token)}`,
},
maxFileSize: 5 * 1024 * 1024,
maxNumberOfFiles: 20,
allowedFileTypes: ['image/png,image/jpeg,image/jpg'],
withCredentials: true,
timeout: 5 * 1000,
onBeforeUpload(file: object) {
let fileObj = Object.values(file)[0].data
const isJPG =
fileObj.type == 'image/jpg' ||
fileObj.type == 'image/jpeg' ||
fileObj.type == 'image/png'
if (!isJPG) {
message.error('图片只能是 JPG、GIF、PNG 格式!')
}
// 判断图片大小
let isLt = fileObj.size / 1024 / 1024 < 5 // 判断是否小于5M
if (!isLt) {
message.error('图片大小不能超过5M! 请重新上传')
}
if (!isJPG) {
return false
} else if (!isLt) {
return false
} else {
return file
}
},
onProgress(progress: any) {
//console.log('progress', progress)
},
onSuccess(file: any, res: any) {
//console.log(`${file.name} 上传成功`, res)
},
customInsert(res: any, insertFn: any) {
insertFn(res.message, '123', res.message)
},
onError(file: any, err: any, res: any) {
//console.log(`${file.name} 上传出错`, err, res)
},
},
uploadVideo: {
server: `${
import.meta.env.VITE_APP_BASE_API
}/file/fileManager/importFile`,
fieldName: 'file',
maxFileSize: 5 * 1024 * 1024, // 5M
maxNumberOfFiles: 3,
allowedFileTypes: ['video/mp4'],
metaWithUrl: false,
withCredentials: true,
timeout: 15 * 1000,
customInsert(res: any, insertFn: any) {
insertFn(res.data.url)
},
onBeforeUpload(file: any) {
return file
},
onProgress(progress: any) {
//console.log('progress', progress)
},
onSuccess(file: any, res: any) {
//console.log(`${file.name} 上传成功`, res)
},
onFailed(file: any, res: any) {
//console.log(`${file.name} 上传失败`, res)
},
onError(file: any, err: any, res: any) {
//console.log(`${file.name} 上传出错`, err, res)
},
},
},
}
// 组件销毁时,也及时销毁编辑器
onBeforeUnmount(() => {
console.log(onBeforeUnmount, 'onBeforeUnmount')
const editor = editorRef.value
if (editor == null) return
editor.destroy()
})
const handleCreated = (editor: any) => {
editorRef.value = editor
if (props.disabled) {
editor.disable()
} else {
editor.enable()
}
}
const handleChange = (editor: any) => {
//
}
return {
editorRef,
valueHtml,
mode: 'default',
toolbarConfig,
editorConfig,
handleCreated,
handleChange,
}
},
})
</script>