說明如何使用 Quill 作為 Html Edtior,提供使用者在後台介面輸出資料、維護內容的便捷方式。相較於老牌的 CKEditor 以及 TinyMCE,本次所要介紹的新世代的 Html Editor Quill。
![logo](/assets/DotNetIcon.png)
說明
View (Html Partial)
在需要使用的 View 使用相關的 css 以及 js,示範使用 cdn 的方式,也可以使用 Client Side Library Manager (LibMan) 的方式管理與使用。
由於使用會需要以 js 註冊 Editor 以及將 Html 元素賦值對照的關係,因此以 HTML Partial 的方式方便反覆使用。
_QuillHtmlEditor.cshtml
<!-- Include the Quill Styles -->
<link href="https://cdn.quilljs.com/1.3.7/quill.snow.css" rel="stylesheet" />
<!-- Include the Quill library -->
<script src="https://cdn.quilljs.com/1.3.7/quill.js"></script>
<script src="https://cdn.jsdelivr.net/npm/quill-image-resize-module@3.0.0/image-resize.min.js"></script>
<!-- Initialize Quill editor -->
<script>
var toolbarOptions = [
['bold', 'italic', 'underline', 'strike'],
['blockquote', 'code-block'],
[{ 'color': [] }, { 'background': [] }],
[{ 'header': 1 }, { 'header': 2 }],
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
[{ 'script': 'sub' }, { 'script': 'super' }],
[{ 'indent': '-1' }, { 'indent': '+1' }],
[{ 'direction': 'rtl' }],
[{ 'size': ['small', false, 'large', 'huge'] }],
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
[{ 'align': [] }],
['image'],
['clean']
];
// 註冊 Quill 在 #editor Element
var quill = new Quill('#editor', {
modules: {
toolbar: toolbarOptions,
imageResize: {
displaySize: true
},
},
placeholder: 'Enter some text here...',
theme: 'snow'
});
// 加入 Listener 處理 Quill 編輯的結果至 Form Input
document.addEventListener("DOMContentLoaded", function () {
document.querySelector('form').addEventListener('submit', function (event) {
document.querySelector('#Content').value = quill.root.innerHTML;
});
});
</script>
Create.cshtml
在 Create 的 View 當中,需要加入 #editor
的元素,讓 Quill 渲染為 Html Editor,原本應該用於提供使用者輸入的 Input Content 則刪除,並透先前的註冊,在 Form Submit 時做對照的賦值,提供後端進行使用。
@model NorthwindShop2.Web.Models.CMS.Article
@{
ViewBag.Title = "Create";
}
<h2>New Article</h2>
<hr />
@using (Html.BeginForm("Create", "Article", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.Title, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Title, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Title, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group mb-3">
@Html.LabelFor(model => model.Content, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
<div id="editor" class="fs-6">
</div>
@Html.HiddenFor(model => model.Content)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Attachments, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
<input type="file" name="attachments" multiple class="form-control" />
@Html.ValidationMessageFor(model => model.Attachments, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-outline-primary me-3" />
@Html.ActionLink("Back to List", "Index", null, new { @class = "btn btn-outline-secondary me-3" })
</div>
</div>
</div>
}
@Html.Partial("_QuillHtmlEditor")
Edit 在 View 的差別是將已經存在的 Content 使用 Html.Raw
的方式加入倒 #editor
的 innerHtml。
Edit.cshtml
<div class="form-group mb-3">
@Html.LabelFor(model => model.Content, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
<div id="editor">
@Html.Raw(Model.Content)
</div>
@Html.HiddenFor(model => model.Content)
</div>
</div>
Controller
ArticleController.cs
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(
[Bind(Include = "Title,Content")] Article article,
IEnumerable<HttpPostedFileBase> attachments)
{
article.DatePublished = DateTime.Now;
if (ModelState.IsValid)
{
db.Articles.Add(article);
db.SaveChanges();
foreach (var file in attachments)
{
if (file != null && file.ContentLength > 0)
{
var attachment = new Attachment
{
FileName = Path.GetFileName(file.FileName),
FileType = file.ContentType,
ArticleId = article.Id
};
using (var reader = new BinaryReader(file.InputStream))
{
attachment.FileData = reader.ReadBytes(file.ContentLength);
}
db.Attachments.Add(attachment);
}
}
db.SaveChanges();
return RedirectToAction("Index");
}
return View(article);
}
Model
Html Editor 會製作出 Html Tag 的內容,因此 Model 需要設定 AllowHtml
。
Article.cs
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
[AllowHtml]
public string Content { get; set; }
public DateTime DatePublished { get; set; }
public virtual List<Attachment> Attachments { get; set; }
}
後續行動
相對於 TinyMCE 的持續更新,目前 Quill 最新的更新是在 2019,也考慮到 TinyMCE 的普及以及社群的討論熱度,未來打算在驗證使用 TinyMCE 結合 ASP.NET MVC 的方式。
TinyMCE | Quill | |
---|---|---|
Functions | 支援多種文本格式、表格、媒體等元素的編輯和管理 | 支援常用的文本格式和樣式,也可擴展功能 |
Extensionality | 提供了豐富的 API 和事件處理函數,可以方便地進行自定義和擴展 | 使用模組化架構,也可進行自定義和擴展 |
Usage | 使用簡單直觀,支援多種語言和鍵盤快捷鍵 | 使用簡單直觀,支援多種語言和快捷鍵 |
Stability | 歷史久、瀏覽器兼容性佳 | 使用 Virtual DOM 達到渲染快速的效能 |
License | MIT License | BSD 3-Clause “New” or “Revised” License |
Comparison with Other Rich Text Editors | Quill