1、npm 包安装
npm i -s @ckeditor/ckeditor5-build-decoupled-document @ckeditor/ckeditor5-vue2
2、引入
在vue main.js或者nuxt plugins文件夹下的文件中
import Vue from 'vue'
import '@ckeditor/ckeditor5-build-decoupled-document/build/translations/zh-cn'
import CKEditor from '@ckeditor/ckeditor5-vue2'
Vue.use(CKEditor)
3、富文本组件定义
<template>
<div
ref="editorContent"
style="height: calc(100% - 2.5rem)"
class="overflow-hidden z-50"
>
<div id="toolbar-container"></div>
<ckeditor
ref="editor"
v-model="editorStr"
style="height: calc(100% - 3rem)"
:editor="editor"
placeholder="请编辑消息内容"
:config="config"
@ready="onEditorReady"
/>
</div>
</template>
<script>
import DecoupledEditor from '@ckeditor/ckeditor5-build-decoupled-document'
import UploadAdapter from '@/components/UploadAdapter' // 自定义上传
import { mapActions } from 'vuex'
export default {
name: 'Editor',
model: {
prop: 'content',
event: 'change',
},
props: {
content: {
type: String,
default: '',
},
},
data() {
return {
editor: DecoupledEditor,
showPreview: false,
previewMsg: {},
config: {
// removeDialogTabs: 'image:advanced;image:Link',
language: 'zh-cn',
previewText: '',
// removePlugins: ['Table', 'BlockQuote', 'indent'],
extraPlugins: [],
toolbar: {
items: [
'undo',
'redo',
'|',
'heading',
'|',
'fontfamily',
'fontsize',
'fontColor',
'fontBackgroundColor',
'|',
'bold',
'italic',
'underline',
'strikethrough',
'|',
'alignment',
'uploadImage',
'|',
'numberedList',
'bulletedList',
'|',
'outdent',
'indent',
'|',
'link',
'blockquote',
'insertTable',
'mediaEmbed',
],
},
},
editorStr: '',
el: '',
}
},
watch: {
content(val) {
this.editorStr = val
},
editorStr(val) {
this.$emit('change', val)
},
},
mounted() {},
methods: {
...mapActions(['upload']),
onEditorReady(editor) {
const that = this
document
.querySelector('#toolbar-container')
.appendChild(editor.ui.view.toolbar.element)
window.editor = editor
that.editorStr = that.content
// console.log(
// editor,
// '》》》》',
// Array.from(editor.ui.componentFactory.names())
// )
editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
// 将当前vue对象挂载到loader,使得自定义上传可以访问vue对象中的上传方法及其他属性
loader.that = that
return new UploadAdapter(loader)
}
},
},
}
</script>
<style>
.ck.ck-editor__main {
height: calc(100% - 2.5rem);
}
.ck.ck-editor {
height: 100%;
}
.ck-editor__editable {
height: 100%;
overflow-x: auto;
}
.ck.ck-editor__editable_inline {
border: #e2e3e5 solid 1px;
border-top: 0;
}
.ck ck-balloon-rotator {
z-index: 199999;
}
</style>
在components自定义上传UploadAdapter.js
/**
* 自定义上传图片插件
*/
class UploadAdapter {
constructor(loader) {
this.loader = loader
}
async upload() {
const file = await this.loader.file
const { that } = this.loader
const date = that.$moment().format('YYYY-MM-DD')// vue全局属性
const path = `/images/notice/${date}/${file.name}`
// 方法返回数据格式: {default: "url"}
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve, reject) => {
try {
// 阿里云oss上传封装的upload方法
const { code, url, msg } = await that.upload({ file, path })
if (code === 0) resolve({ default: url })
else reject(msg)
} catch (e) {
reject(e)
}
})
}
}
export default UploadAdapter
在 store.js actions 中定义upload上传
import crypto from 'crypto'
import OSS from 'ali-oss'
export const actions = {
md5(ctx, val) {
const md5 = crypto.createHash('md5')
md5.update(val)
return md5.digest('hex')
},
// 获取oss上传信息
async ossToken({ dispatch, state, commit }) {
const format = 'YYYY-MM-DD HH:mm'
const now = this.$moment().format(format)
const { Expiration = '' } = state.sts
const expire = this.$moment(Expiration).format(format)
if (Expiration && expire > now) return { code: 0, result: state.sts }
const data = await dispatch('get', { url: '/api/oss/sts' })
commit('setSts', data.result || {})
return data
},
// oss 上传文件
async upload({ dispatch }, { path, file }) {
const data = await dispatch('ossToken')
if (data.code > 0) return data
else {
const {
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
SecurityToken: stsToken,
region,
bucket,
} = data.result
const client = new OSS({
region,
accessKeyId,
accessKeySecret,
stsToken,
bucket,
})
try {
const { name } = await client.put(path, file)
return {
code: 0,
url: `http://${bucket}.${region}.aliyuncs.com/${name}`,
}
} catch (e) {
return { code: 201, msg: e }
}
}
},
async get(ctx, { url, params = {} }) {
//在vue main.js 中 store.$axios = axios,nuxt项目中不用处理
const { data } = await this.$axios.get(url, { params })
return data
}
}