---
# System prepended metadata

title: CKEditor5 使用說明

---

# CKEditor5 使用說明

## 1.安裝說明

[官方下載連結](https://ckeditor.com/ckeditor-5/download/)

1.選擇經典版下載
![](https://i.imgur.com/dlJs8gt.png)
2.選擇Zip package下載
![](https://i.imgur.com/8qo9hfA.png)
3.將其解壓縮結構長成這樣
![](https://i.imgur.com/aY5FJDz.png)

## 2.CKEditor5與MVC搭配使用

1.將專案放進wwwroot/lib/底下
![](https://i.imgur.com/u802513.png)

2.在view/Shared/_Layout.cshtml引入ckeditor.js
![](https://i.imgur.com/O6a6ROE.png)

```
   <script src="~/lib/ckeditor5/build/ckeditor.js"></script>
```
3.在index.cshtml加入textarea id="editor" 用意是把texttarea轉成CKEditor編輯器
```
  <div class="row">
    <div class="col">
        <div class="form-group">
            <label  class="control-label"></label>
            <textarea class="form-control editor" id="editor"></textarea>
            <span  class="text-danger"></span>
        </div>
    </div>

	
	<button id=getdata>Print data</button>
</div>
```
4.在js引入初始化CKEditor程式碼
```
 window.addEventListener("load", (e) => {

	ClassicEditor
		.create(document.querySelector('.editor'), {
			extraPlugins: [MyCustomUploadAdapterPlugin],
			toolbar: {
				items: [
					'heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', '|',
					'alignment', 'outdent', 'indent', '|', 'fontSize', 'fontColor', '|',
					'imageUpload', 'blockQuote', 'insertTable', 'mediaEmbed', 'undo', 'redo'
				]
			},
			language: 'en',
			image: {
				toolbar: [
					'imageTextAlternative',
					'imageStyle:inline',
					'imageStyle:block',
					'imageStyle:side'
				]
			},
			table: {
				contentToolbar: [
					'tableColumn',
					'tableRow',
					'mergeTableCells'
				]
			},
			licenseKey: '',


		})
		.then(editor => {
			window.editor = editor;
		})
		.catch(error => {
			console.error('Oops, something went wrong!');
			console.error(error);
		});
});

```
5.專案跑起來畫面
![](https://i.imgur.com/l9Ymp6G.png)

## 3.CKEditor5圖片上傳
base64儲存方式將以下程式碼放入js即可使用

```
  class MyUploadAdapter {
	constructor(loader) {
		// The file loader instance to use during the upload.
		this.loader = loader;
	}

	// Starts the upload process.
	upload() {
		var reader = new FileReader();

		return new Promise((resolve, reject) => {
			reader.addEventListener('load', () => {
				resolve({ default: reader.result });
			});

			reader.addEventListener('error', err => {
				reject(err);
			});

			reader.addEventListener('abort', () => {
				reject();
			});

			this.loader.file.then(file => {
				reader.readAsDataURL(file);
			});
		})
	}

	// Aborts the upload process.
	abort() {
		if (this.xhr) {
			this.xhr.abort();
		}
	}

	// Initializes the XMLHttpRequest object using the URL passed to the constructor.
	_initRequest() {
		const xhr = (this.xhr = new XMLHttpRequest());

		// Note that your request may look different. It is up to you and your editor
		// integration to choose the right communication channel. This example uses
		// a POST request with JSON as a data structure but your configuration
		// could be different.
		xhr.open("POST", "/Home/ImageTest", true);
		xhr.responseType = "json";
	}

	// Initializes XMLHttpRequest listeners.
	_initListeners(resolve, reject, file) {
		const xhr = this.xhr;
		const loader = this.loader;
		const genericErrorText = `無法上傳檔案: ${file.name}.`;

		xhr.addEventListener("error", () => reject(genericErrorText));
		xhr.addEventListener("abort", () => reject());
		xhr.addEventListener("load", () => {
			const response = xhr.response;

			console.log('response', response);

			// This example assumes the XHR server's "response" object will come with
			// an "error" which has its own "message" that can be passed to reject()
			// in the upload promise.
			//
			// Your integration may handle upload errors in a different way so make sure
			// it is done properly. The reject() function must be called when the upload fails.
			if (!response || response.error) {
				return reject(response && response.error ? response.error.message : genericErrorText);
			}

			// If the upload is successful, resolve the upload promise with an object containing
			// at least the "default" URL, pointing to the image on the server.
			// This URL will be used to display the image in the content. Learn more in the
			// UploadAdapter#upload documentation.
			resolve({
				default: response.url,
			});
		});

		// Upload progress when it is supported. The file loader has the #uploadTotal and #uploaded
		// properties which are used e.g. to display the upload progress bar in the editor
		// user interface.
		if (xhr.upload) {
			xhr.upload.addEventListener("progress", evt => {
				if (evt.lengthComputable) {
					loader.uploadTotal = evt.total;
					loader.uploaded = evt.loaded;
				}
			});
		}
	}

	// Prepares the data and sends the request.
	_sendRequest(file) {
		// Prepare the form data.
		const data = new FormData();

		data.append("Files", file);

		console.log('file:', file);

		// Important note: This is the right place to implement security mechanisms
		// like authentication and CSRF protection. For instance, you can use
		// XMLHttpRequest.setRequestHeader() to set the request headers containing
		// the CSRF token generated earlier by your application.

		// Send the request.
		this.xhr.send(data);
	}
}

// ...

function MyCustomUploadAdapterPlugin(editor) {
	editor.plugins.get("FileRepository").createUploadAdapter = loader => {
		// Configure the URL to the upload script in your back-end here!
		return new MyUploadAdapter(loader);
	};
}

```

取得CKEdiotr html 主要是getDataFromTheEditor()
```
function getDataFromTheEditor() {
	return window.editor.getData();
}

document.getElementById('getdata').addEventListener('click', () => {
	alert(getDataFromTheEditor());

	//document.getElementById('test').value = getDataFromTheEditor();
	
});
```
取得範例如下，將該html儲存到db，到前端只要輸入@Html.Raw(@Model.Content)就能將編輯畫面整個顯示
![](https://i.imgur.com/t4ykOHN.png)

## 4.特殊技巧
如果要編輯CKEditor畫面可以將儲存的html利用setData()塞入編輯畫面中

```
window.editor.setData()
```
 
 [github下載連結](https://github.com/hungho0208/CKEditor5)