Angular4+使用CKEditor5實現富文本編輯器
編輯器支持文本輸入,基本文本樣式:對齊、加粗等;粘貼上傳圖片等功能,本文圖片上傳基于自定義的上傳方法
CKEditor5提供了幾種封裝好的不同風格的富文本編輯器
- Classic editor –
ClassicEditor- Inline editor –
InlineEditor- Balloon editor –
BalloonEditor- Document editor –
DecoupledEditor
實現一:使用CKEditor5-Angular2組件
npm install --save @ckeditor/ckeditor5-angular
根據需要選擇所要的editor類型,要另外安裝:
npm install --save @ckeditor/ckeditor5-build-classic
在對應的Module.ts中引入CKEditorModule
import { CKEditorModule } from '@ckeditor/ckeditor5-angular';
@NgModule( {
imports: [
CKEditorModule,
// ...
],
// ...
} )
實現【ckeditor/ckeditor5-build-decoupled-document】為例
config可以配置工具欄選項等等
config文檔
contentText:文本框的內容
<ckeditor
[editor]="Editor"
[(ngModel)]="contentText"
(ready)="onReady($event)"
[config]="config"
>
</ckeditor>
import { Component, OnInit, ViewChild, ElementRef, Output, Input, EventEmitter } from '@angular/core';
import * as DecoupledEditor from '@ckeditor/ckeditor5-build-decoupled-document';
//如果是classic-editor則替換成注釋中的語句
//import * as ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import { HttpClient } from '@angular/common/http';
import { UploadAdapter } from '../service/uploadAdapter';//自定義的圖片上傳方法
@Component({
selector: 'app-editor',
templateUrl: './editor.component.html',
styleUrls: ['./editor.component.scss']
})
export class EditorComponent implements OnInit {
@ViewChild('toolbar') toolbar:ElementRef<any>;
@Input() url:string='';
@Input() config?:Object ={};//config設置配置編輯器的工具欄等屬性
public contentText:string ='';
public Editor = DecoupledEditor;
constructor(
private http:HttpClient
) { }
ngOnInit() { }
onReady($event){
//使用decoupled-document editor需要在onReady中實現方法insertBefore
$event.ui.getEditableElement().parentElement.insertBefore(
$event.ui.view.toolbar.element,
$event.ui.getEditableElement()
);
//以下語句是配置自定義圖片上傳的UploadAdapter,如果富文本中不包含圖片可以不設置
//編輯器中的上傳圖片后,會先上傳到服務器中,除非額外實現圖片刪除方法,否則即使文本中的圖片刪除了,服務器中的文件資源依然存在
$event.plugins.get('FileRepository').createUploadAdapter = (loader)=> {
return new UploadAdapter(loader,this.url,this.http);
};
}
}
UploadAdapter:自定義圖片上傳Service
自定義圖片上傳需要后端實現圖片上傳接口
其他圖片上傳方式:CkEditor可以與CKFinder結合實現上傳圖片,但是要進行服務器端的配置,還有其他圖片上傳方式可以參考文檔
圖片上傳-Image Upload doc
自定義圖片上傳文檔-Custom image upload adapter
upload adapter需要實現UploadAdapter interface里的
abort() upload()方法
import { HttpParams, HttpClient } from "@angular/common/http";
export class UploadAdapter {
constructor(
private loader,
public url:string,
private http:HttpClient
) {}
//自定義的上傳文件方法,可以根據需要封裝
uploadFile(file,url?:string,user?:string){
let name = '';
let formData:FormData = new FormData();
let headers = new Headers();
name = file.name;
formData.append('file', file, name);
const dotIndex = name.lastIndexOf('.');
const fileName = dotIndex>0?name.substring(0,dotIndex):name;
formData.append('name', fileName);
formData.append('source', user);
headers.append('Content-Type', 'multipart/form-data');
headers.append('Accept', 'application/json');
let params = new HttpParams();
const options = {
params: params,
reportProgress: true,
};
return this.http.post(url,formData,options);
}
//upload需要返回一個Promise對象,我用的httpClient.post返回值是Obeserver對象,把結果轉成Promise
//封裝的不太好,其實Obeserver可以直接轉為Promise
// 上傳成功返回圖片url一定要以{ default: result['urls']}返回給Promise對象否則會報錯
upload() {
let upload = new Promise((resolve, reject)=>{
this.loader['file'].then(
(data)=>{
this.uploadFile(data,this.url,'')
.subscribe(
(result)=>{
resolve({ default: result['urls']})
},
(error)=>{
reject(data.msg);
}
);
}
);
});
return upload;
}
abort() {
console.log("abort")
}
}
實現二:直接創(chuàng)建Editor
<div class="document-editor">
<div #toolbar class="document-editor__toolbar"></div>
<div class="document-editor__editable-container">
<div #documentEditor class="document-editor__editable editor"
[(ngModel)]="contentText"
>
</div>
</div>
</div>
//component使用classic editor
constructor()
{
let MyCustomUploadAdapterPlugin = ( editor )=> {
editor.plugins.get( 'FileRepository' ).createUploadAdapter = ( loader ) => {
return new UploadAdapter( loader,'',this.http );
};
}
const editorElement = this.editorItem.elementRef.nativeElement;
this.Editor.create(
editorElement,{
// toolbar: ['imageUpload'],
extraPlugins:[MyCustomUploadAdapterPlugin]//自定義image uploadAdapter配置在extraPlugins中
//使用ckfinder配置如下
// ckfinder:{
// uploadUrl:“your server url”,
// // options:{
// // resourceType: 'Images'
// // }
// },
}
).then((result) => {
console.log("success",result,this.Editor);
}).catch((err) => {
console.log("err",err);
});
}
//使用DecoupledEditor
const el = this.documentEditor.nativeElement
DecoupledEditor
.create( el, {
} )
.then( editor => {
const toolbarContainer = this.toolbar.nativeElement;
toolbarContainer.appendChild( editor.ui.view.toolbar.element );
this.Editor = editor;
this.Editor.plugins.get('FileRepository').createUploadAdapter = (loader)=> {
return new UploadAdapter(loader,this.url,this.http);
};
} )
.catch( err => {
console.error( err );
} );
設置Editor高度的時候,如果按照官方文檔設置,由于image caption中也是editor所以會出現image caption太長的情況,設置Editor可以暫時采用這種方式,后續(xù)更新后可采用更好的方法
設置編輯框高度
:host ::ng-deep .ck-editor__editable {
border: 1px solid gainsboro;
}
:host ::ng-deep .ck-editor__editable:not(.ck-editor__nested-editable) {
min-height: 500px !important;
}
Angular中展示富文本
對于富文本字符串要進行轉換之后才可以正常顯示樣式,否則可能存在文本的樣式丟失
<div [innerHTML]='reportContent | safeHtml'></div>
import { Pipe, PipeTransform } from "@angular/core";
import { DomSanitizer } from '@angular/platform-browser';
// https://angular.io/guide/security
@Pipe({ name: 'safeHtml' })
export class SafeHtmlPipe implements PipeTransform {
constructor(private sanitized: DomSanitizer) { }
transform(value) {
// img圖片自適應,組件中的元素樣式對于innerHTML追加的元素無效
value = value.replace(/\<img/gi,'<img style="max-width:100%;" ');
return this.sanitized.bypassSecurityTrustHtml(value);
}
}
Reference & Recommend Reading