安装
npm install --save @ckeditor/ckeditor5-build-decoupled-document
API
https://ckeditor.com/docs/ckeditor5/latest/api/index.html
组件
<template>
<div class="rich-container">
<div class="rich-editor document-editor">
<div id="toolbar-container" class="document-editor__toolbar" />
<div class="document-editor__editable-container">
<div id="editor" class="document-editor__editable" />
</div>
</div>
</div>
</template>
<script>
import DecoupledEditor from '@ckeditor/ckeditor5-build-decoupled-document'
import '@ckeditor/ckeditor5-build-decoupled-document/build/translations/zh-cn' // 中文包
import viewToPlainText from '@ckeditor/ckeditor5-clipboard/src/utils/viewtoplaintext';
import UploadAdapter from './uploadAdapter.js'
export default {
data() {
return {
editor: null, // 编辑器实例
content: '', // 编辑内容
}
},
mounted() {
this.initCKEditor()
},
methods: {
initCKEditor() {
// 初始化编辑器
DecoupledEditor.create(document.querySelector('#editor'), {
language: 'zh-cn', // 中文
removePlugins: ['MediaEmbed'] // 除去视频按钮
}).then(editor => {
editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
return new UploadAdapter(loader)
}
const toolbarContainer = document.querySelector('#toolbar-container')
toolbarContainer.appendChild(editor.ui.view.toolbar.element)
this.editor = editor // 将编辑器保存起来,用来随时获取编辑器中的内容等,执行一些操
editor.model.document.on('change:data', () => {
//把富文本编辑器获取到的内容
this.content = editor.getData();
});
}).catch(error => {
console.error(error)
})
},
// 设置值
setContent(val) {
this.editor.setData(val)
},
// 获取值
getContent(textType) {
// 纯文本
if(textType == 'text'){
return viewToPlainText(this.editor.editing.view.document.getRoot())
}
// html文本
return this.content
}
}
}
</script>
<style lang="scss">
.rich-editor {
width: 100%;
min-height: 500px;
margin: 20px auto;
}
</style>
<style>
.document-editor {
border: 1px solid var(--ck-color-base-border);
border-radius: var(--ck-border-radius);
display: flex;
flex-flow: column nowrap;
}
.ck.ck-editor__editable:not(.ck-editor__nested-editable).ck-focused {
border: none;
}
.document-editor__toolbar {
z-index: 1;
box-shadow: 0 0 5px hsla( 0,0%,0%,.2 );
border-bottom: 1px solid var(--ck-color-toolbar-border);
}
.document-editor__toolbar .ck-toolbar {
border: 0;
border-radius: 0;
}
.document-editor__editable-container {
/* padding: 20px; */
background: var(--ck-color-base-foreground);
overflow-y: scroll;
}
.document-editor__editable-container .document-editor__editable.ck-editor__editable {
min-height: 500px;
padding: 20px;
border: 1px hsl( 0,0%,82.7% ) solid;
border-radius: var(--ck-border-radius);
background: white;
box-shadow: 0 0 5px hsla( 0,0%,0%,.1 );
margin: 0 auto;
}
.main__content-wide .document-editor__editable-container .document-editor__editable.ck-editor__editable {
width: 18cm;
}
.document-editor .ck-content,
.document-editor .ck-heading-dropdown .ck-list .ck-button__label {
font: 16px/1.6 "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.document-editor .ck-heading-dropdown .ck-list .ck-button__label {
line-height: calc( 1.7 * var(--ck-line-height-base) * var(--ck-font-size-base) );
min-width: 6em;
}
.document-editor .ck-heading-dropdown .ck-list .ck-heading_heading1 .ck-button__label,
.document-editor .ck-heading-dropdown .ck-list .ck-heading_heading2 .ck-button__label {
transform: scale(0.8);
transform-origin: left;
}
.document-editor .ck-content h2,
.document-editor .ck-heading-dropdown .ck-heading_heading1 .ck-button__label {
font-size: 2.18em;
font-weight: normal;
}
.document-editor .ck-content h2 {
line-height: 1.37em;
padding-top: .342em;
margin-bottom: .142em;
}
.document-editor .ck-content h3,
.document-editor .ck-heading-dropdown .ck-heading_heading2 .ck-button__label {
font-size: 1.75em;
font-weight: normal;
color: hsl( 203, 100%, 50% );
}
.document-editor .ck-heading-dropdown .ck-heading_heading2.ck-on .ck-button__label {
color: var(--ck-color-list-button-on-text);
}
.document-editor .ck-content h3 {
line-height: 1.86em;
padding-top: .171em;
margin-bottom: .357em;
}
.document-editor .ck-content h4,
.document-editor .ck-heading-dropdown .ck-heading_heading3 .ck-button__label {
font-size: 1.31em;
font-weight: bold;
}
.document-editor .ck-content h4 {
line-height: 1.24em;
padding-top: .286em;
margin-bottom: .952em;
}
.document-editor .ck-content blockquote {
font-family: Georgia, serif;
margin-left: calc( 2 * var(--ck-spacing-large) );
margin-right: calc( 2 * var(--ck-spacing-large) );
}
.document-editor .ck-content .image {
margin: 0 !important;
}
@media only screen and (max-width: 960px) {
.document-editor__editable-container .document-editor__editable.ck-editor__editable {
padding: 1.5em;
}
}
@media only screen and (max-width: 1200px) {
.main__content-wide .document-editor__editable-container .document-editor__editable.ck-editor__editable {
width: 100%;
}
}
@media only screen and (min-width: 1360px) {
.main .main__content.main__content-wide {
padding-right: 0;
}
}
@media only screen and (min-width: 1600px) {
.main .main__content.main__content-wide {
width: 24cm;
}
.main .main__content.main__content-wide .main__content-inner {
width: auto;
margin: 0 50px;
}
.main__content-wide .document-editor__editable-container .document-editor__editable.ck-editor__editable {
width: 60%;
}
}
</style>
uploadAdapter(图片上传的地址)
import axios from 'axios'
import { getImgList} from '@/utils/index'
export default class UploadAdapter {
constructor(loader) {
this.loader = loader
}
upload() {
// let URl = process.env.NODE_ENV === 'development' ? '/api' + '/main//sys/api/file/upload' : process.env.VUE_APP_BASE_API + '/main//sys/api/file/upload'
return this.loader.file.then(file => new Promise((resolve, reject) => {
const data = new FormData()
data.append('file', file)
axios.request({
url: '/main//sys/api/file/upload',// 上传文件的接口地址,实际请填写完整地址
method: 'post',
data,
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(res => {
if (res.data.code === 0) {
getImgList({picIds:res.data.data},val=>{
const url = val // 后台返回的上传成功后的图片地址
url?resolve({default: url}):resolve({default: ''})
})
}
}).catch(error => {
reject(error)
})
}))
}
abort() {
//可以书写删除服务器图片的逻辑
}
}