一、安装及引入
官网:https://ckeditor.com/ckeditor-5/download/
我这边使用的是自定义构建,然后下载下来。
二、简单使用
引入js
<script src="../../../assets/plugins/ckeditor5/ckeditor.js"></script>
html:
<el-form-item label="服务内容">
<textarea id="editor"></textarea>
</el-form-item>
js:
ClassicEditor
.create( document.querySelector( '#editor' ))
.then( editor => {
this.editor = editor;
} )
.catch( error => {
console.error( error );
} );
获取富文本内容
var data = encodeURIComponent(this.editor.getData())
设置富文本内容
this.editor.setData(decodeURIComponent(content));
PS:这边进行编解码,便于存入数据库中
三、自动保存
ClassicEditor
.create( document.querySelector( '#editor' ), {
autosave: {
save( editor ) {
// 获取编辑器中的数据
const data = editor.getData();
// 将数据保存到本地
localStorage.setItem( 'autosave', data );
},
waitingTime: 5000 // 设置保存间隔时间为 5 秒
}
})
.then( editor => {
this.editor = editor;
// 获取本地保存的数据
const savedData = localStorage.getItem( 'autosave' );
if ( savedData ) {
// 提示用户是否恢复数据 (sweatAlert:https://sweetalert.js.org/)
swal({
title: "提示",
text: "检测到上次编辑的内容,是否恢复?",
icon: "warning",
buttons: true,
dangerMode: true,
}).then((willDo) => {
if (willDo) {
// 将数据恢复到编辑器中
editor.setData( savedData );
} else {
// 清空本地保存的数据
localStorage.removeItem( 'autosave' );
}
});
}
} )
.catch( error => {
console.error( error );
} );
四、图片上传
自定义UploadAdapter.js:
/**
* 图片压缩处理,转换为等比的高800px的图像
* @params file File类型的图片文件
* @return Promise<file> 返回一个promise,值为一个压缩后的图片文件
*/
function imgCutdown(file) {
return new Promise((resolve) => {
const render = new FileReader();
render.onload = function(progress) {
const target = progress.target;
if (!target) return;
const reuslt = target.result;
if (typeof reuslt === "string") {
const image = new Image();
image.src = reuslt;
image.onload = function() {
const h = 800;
const rate = h / image.height;
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
if (!context) return;
canvas.width = image.width * rate;
canvas.height = h;
context.drawImage(
image,
0,
0,
image.width,
image.height,
0,
0,
canvas.width,
canvas.height
);
canvas.toBlob(
function(b) {
const file = new File([b], "pic", {
type: "image/jpeg",
});
resolve(file);
},
"image/jpeg",
0.5
);
};
}
};
render.readAsDataURL(file);
});
}
const uploadUrl = '/backend/upload/media';
// 自定义适配器类
class MyUploadAdapter {
constructor(loader) {
this.loader = loader;
}
upload() {
return this.loader.file.then(
(file) =>
new Promise((resolve, reject) => {
this._initRequest();
this._initListeners(resolve, reject, file);
this._sendRequest(file);
})
);
}
abort() {
if (this.xhr) {
this.xhr.abort();
}
}
_initRequest() {
const xhr = (this.xhr = new XMLHttpRequest());
xhr.open("POST", uploadUrl, true);
xhr.responseType = "json";
}
_initListeners(resolve, reject, file) {
const xhr = this.xhr;
const loader = this.loader;
const genericErrorText = `Couldn't upload file: ${file.name}.`;
xhr.addEventListener("error", () => reject(genericErrorText));
xhr.addEventListener("abort", () => reject());
xhr.addEventListener("load", () => {
const response = xhr.response;
if (!response || response.error) {
return reject(
response && response.error ? response.error.message : genericErrorText
);
}
resolve({
default: response.data,
});
});
if (xhr.upload) {
xhr.upload.addEventListener("progress", (evt) => {
if (evt.lengthComputable) {
loader.uploadTotal = evt.total;
loader.uploaded = evt.loaded;
}
});
}
}
async _sendRequest(file) {
const data = new FormData();
// 判断如果上传图片大于1M,则进行压缩处理
if (file.size > 1000 * 1024) {
file = await imgCutdown(file);
}
// 上传参数就根据后端的处理而设置了
data.append("file", file);
data.append("name", file.name);
data.append("group", "image");
this.xhr.send(data);
}
}
后端代码:
@RestController
@RequestMapping("/upload")
public class UploadController extends BaseController {
@Autowired
private QNYService qnyService;
@Value("${QNY_DOMAIN}")
private String QNY_DOMAIN;
@RequestMapping("media")
public ApiResponse uploadImage(HttpServletRequest request, String group) throws IOException {
MultipartFile file = ((StandardMultipartHttpServletRequest) request).getFile("file");
String key = "upload/" + group + "/" + this.get32UUID();
qnyService.uploadFile(file, key);
return ApiResponse.buildOk(QNY_DOMAIN+key);
}
}
public class ApiResponse {
int code;
String msg;
Object data;
}
QNYServiceImpl:
@Service
@Slf4j
public class QNYServiceImpl implements QNYService {
@Value("${QNY_ACCESS_KEY}")
String QNY_ACCESS_KEY;
@Value("${QNY_SECRET_KEY}")
String QNY_SECRET_KEY;
private static final String BUCKET_NAME = "ehu";
@Autowired
private RedisService redisService;
@Override
public void deleteImg(String url) {
Configuration cfg = new Configuration(Region.huadong());
Auth auth = Auth.create(QNY_ACCESS_KEY, QNY_SECRET_KEY);
BucketManager bucketManager = new BucketManager(auth, cfg);
try {
bucketManager.delete(BUCKET_NAME, url);
} catch (QiniuException ex) {
log.error("qiniuyun delete fail code {} msg {}", ex.code(), ex.response.toString(), ex);
}
}
@Override
public String getUploadToken() {
String token = redisService.getQNYToken();
if( token == null){
Auth auth = Auth.create(QNY_ACCESS_KEY, QNY_SECRET_KEY);
token = auth.uploadToken(BUCKET_NAME);
redisService.setQNYToken(token);
}
return token;
}
@Override
public String uploadUrlFile(String url, String prefix) {
Configuration cfg = new Configuration(Region.huadong());
Auth auth = Auth.create(QNY_ACCESS_KEY,QNY_SECRET_KEY);
BucketManager bucketManager = new BucketManager(auth,cfg);
try {
FetchRet fetch = bucketManager.fetch(url, BUCKET_NAME, prefix + UuidUtil.get32UUID());
return fetch.key;
} catch (QiniuException e) {
log.error("qiniuyun upload fail url{}", url, e);
throw new RuntimeException(e);
}
}
@Override
public void uploadFile(MultipartFile file, String key) throws IOException {
Configuration cfg = new Configuration(Region.huadong());
Auth auth = Auth.create(QNY_ACCESS_KEY, QNY_SECRET_KEY);
String upToken = auth.uploadToken(BUCKET_NAME);
UploadManager uploadManager = new UploadManager(cfg);
uploadManager.put(file.getBytes(), key, upToken);
}
}
html:
<script src="../../../assets/plugins/ckeditor5/UploadAdapter.js"></script>
<script type="text/javascript">
...
mounted() {
ClassicEditor
.create( document.querySelector( '#editor' ))
.then( editor => {
editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
return new MyUploadAdapter(loader);
};
this.editor = editor;
} )
.catch( error => {
console.error( error );
} );
}
</script>