ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CKEditor5视频引入、实时预览与自定义Toolbar插件开发实战

CKEditor5视频引入、实时预览与自定义Toolbar插件开发实战 這陣子又跟 CKEditor5 纏上了。客戶的後台管理系統需要一個富文本編輯器規格表上寫得明明白白要有影片引入、編輯當下就要能立即預覽、工具列還不能是預設那一大串必須支援自訂 toolbar。如果你也在查「CKEditor5 要怎麼插入影片」或「toolbar 按鈕為什麼少一個」這篇就是為你寫的。我會把整個思考過程從元件選型、外掛開發、上傳與後端收稿一路講到常見坑盡量讓你可以直接照著抄。這個題目在簡體社群常被寫成「CKEditor5富文本编辑器 - 视频引入、预览及自定义toolbar」我用繁體中文把流程重新整理一遍。影片就是 video預覽就是 preview自訂就是 customtoolbar 就是工具列。不管你是前端、全端、還是維護老後台的人只要專案裡有「文章編輯器」這篇應該都幫得上。1. 專案概述與需求拆解1.1 這個專案到底在解決什麼問題先講需求場景。客戶希望後台管理員撰寫公告、教學文章、活動頁面時可以直接把一段示範影片放進內文而不是只給一個超連結。管理員多半不懂 HTML他們要的是「按一個按鈕、貼上網址或選一個檔案、影片就出現在文章裡」而且編輯當下就要能看到畫面。儲存之後前台網站也要用同樣的影片內容正常播放。另一個需求是工具列瘦身。CKEditor5 預設的 ClassicEditor 工具列擺了十幾個按鈕但客戶實際只用到標題、粗體、清單、插入影片、原始碼模式其他按鈕只會造成誤按。因此必須做成「依照後台角色或頁面類型決定顯示哪些工具列按鈕」的彈性架構。拆解下來核心需求有三個影片引入可以透過網址嵌入也可以上傳影片檔到伺服器然後自動插入文章。即時預覽編輯器內就能看到video標籤的播放器儲存前可以先確認內容長相。自訂 toolbar不是用預設一大串而是依照需求動態組出工具列包含自訂的影片按鈕。這三個需求單獨看都不難但實際上很多人會在「影片」這一步卡住。原因很簡單CKEditor5 官方 build 預設只有圖片處理沒有大家想像中的「影片按鈕」。要支援影片必須自己補上 schema、conversion、command、button才能讓整個流程順暢運作。1.2 為什麼選擇 CKEditor5市面上富文本編輯器很多常見的還有 Quill、TinyMCE、Slate 之類。我在這個專案選 CKEditor5不是因為它最簡單而是因為它的擴充架構相對乾淨也提供了完整的文件與範例。CKEditor5 是 CKEditor 4 之後的大改版底層改成 model-view-controller 架構。簡單說編輯器內看到的是「view」實際儲存的資料是「model」兩者之間靠 conversion 機制互相轉換。你可以把 model 想成資料庫裡的一筆結構化資料view 想成瀏覽器畫面上看到的 HTML。好處是輸出乾淨、格式統一壞處是學習門檻比 Quill 高一點尤其當你要自訂一個全新的元素時得先理解 schema 與 conversion。如果你是團隊裡唯一負責編輯器整合的人我建議不要急著直接把網路上的程式碼複製貼上。先花半小時讀懂 CKEditor5 官方的「Custom plugins」教學後面寫起程式碼會順很多。這篇也是預設你已經能安裝、能跑起一個最基本的 CKEditor5 編輯器。2. 整體設計影片引入、預覽與工具列的底層邏輯2.1 CKEditor5 的架構與外掛機制CKEditor5 整個編輯器由一堆 Plugin 組成。Typing、Paragraph、Heading、Bold 都是 Plugin。Plugin 可以做三件事註冊 schema、定義 conversion、註冊 command 與 UI 元件。當你呼叫ClassicEditor.create(el, config)時config 裡的plugins陣列決定載入哪些外掛。每個外掛都可以在init()裡把事情掛進編輯器。例如editor.model.schema.register()定義「影片元素」長什麼樣子可以有哪些屬性、能不能放在段落中間。editor.conversion.for(downcast)定義 model 轉成 view 的規則也就是編輯畫面上要顯示成什麼 HTML。editor.conversion.for(upcast)定義 view 轉成 model 的規則也就是讀取既有 HTML 時怎麼把video認成編輯器內的影片元素。editor.commands.add()註冊一個指令例如「插入影片」。editor.ui.componentFactory.add()註冊一個工具列按鈕。所以「插入影片」這件事本質上是「新增一個自訂元素」。只要 schema 允許、conversion 有寫好後端拿到editor.getData()就會輸出完整的video標籤。2.2 影片引入的三種路徑與選型考量在規劃階段我整理過三種做法這裡直接給比較表方案適合情境優點缺點官方 MediaEmbed只需要嵌入 YouTube、Vimeo 等外部影音平台設定簡單幾乎零程式碼不支援直接放 mp4 影片檔General HTML Support SourceEditing後台使用者懂 HTML願意自己貼語法彈性最大任何 HTML 都能放行一般管理員不會用且有 XSS 風險自訂 VideoPlugin後台使用者只會按按鈕需要上傳與預覽使用體驗最好可完全掌控要自己寫 schema、conversion、command我的結論是如果客戶只是要貼 YouTube 影片用官方 MediaEmbed 就夠了。但如果需求是「上傳一支 mp4直接在文章內播放」那最終還是得走第三種自訂 VideoPlugin。實務上我也會同時安裝 MediaEmbed讓管理員可以另外嵌入 YouTube 或 Vimeo兩者並不衝突。如果你想要快速驗證可以先用第二種方案開啟 General HTML Support 與 SourceEditing然後在原始碼模式下貼一段video controls srcxxx.mp4/video。這樣十秒就能看到影片在編輯器內顯示但缺點是對一般使用者不友善。我的正式做法是第三種下面會完整示範。2.3 預覽的本質很多人以為「預覽」是 CKEditor5 特別提供的功能其實不是。當你把video標籤放進編輯器編輯器本身在 editing view 就是一個普通的video元素瀏覽器原生就支援影片播放。所以你不需要寫任何預覽邏輯只要 conversion 正確編輯當下就能看到播放器。真正要注意的是「前台預覽」與「安全性」的問題。文章儲存後你可能會在另一個管理頁面用innerHTML把editor.getData()的內容塞進畫面讓管理員預覽整篇文章。這樣做雖然方便但如果文章內容可能混入惡意 HTML就有 XSS 風險。比較安全的做法是用 sandbox 屬性的 iframe 來隔離或先經過 DOMPurify 之類的消毒工具。另外有些網頁會跳出「你嘗試預覽的文件可能對你的計算機有害」的警語這通常是 Windows 檔案總管對從網路下載的檔案加了 Mark-of-the-WebMOTW造成的跟編輯器本身無關。我在第五節會再補一段實際處理方式。2.4 自訂 Toolbar 的規則與注意事項CKEditor5 的工具列設定很直覺在 config 中指定toolbar.items即可。舉例toolbar: { items: [ undo, redo, |, heading, |, bold, italic, |, bulletedList, numberedList, |, insertVideo, sourceEditing ] }|是群組分隔線-則會讓後面的按鈕換行。這裡有個容易踩的坑insertVideo這個名字必須跟componentFactory.add(insertVideo, ...)註冊的名稱完全一樣否則按鈕不會出現。如果你發現工具列少了一個按鈕第一件事去看editor.ui.componentFactory.names()它會列出所有已註冊的元件名稱比對一下就知道了。另外要注意CKEditor5 的工具列可以動態調整。有些人會依照登入者角色帶入不同toolbar.items例如管理員有 SourceEditing 按鈕、一般編輯者沒有。這在實務上很常見。你可以先建立一個按鈕列表根據角色 filter 後再丟給 config不需要寫多餘的 UI 邏輯。3. 實操從零打造一個可上傳、可預覽影片的 CKEditor5 元件3.1 環境準備與安裝這個專案我用的是 npm 安裝方式。如果你使用打包工具例如 Webpack 或 Vite可以直接安裝 ClassicEditor buildnpm install ckeditor/ckeditor5-build-classic但因為我們要自訂 Plugin建議改用「線上 Builder」或直接安裝分散的套件。線上 BuilderCKEditor 5 Builder可以在網頁上勾選你要的功能下載一個客製化包包裡面已經帶好所有相依套件。如果你希望完全掌控版本也可以手動安裝npm install --save ckeditor/ckeditor5-core npm install --save ckeditor/ckeditor5-ui npm install --save ckeditor/ckeditor5-engine npm install --save ckeditor/ckeditor5-build-classic npm install --save ckeditor/ckeditor5-html-support npm install --save ckeditor/ckeditor5-source-editing實際打包時我只在頁面引入 ClassicEditor 的建置檔與樣式另外把自訂 Plugin 寫在獨立檔案方便日後維護。3.2 設定 General HTML Support 放行 video 標籤如果你只是想先測測看「HTML 預覽」這件事最快的方法是開啟GeneralHtmlSupport然後在htmlSupport設定allow。範例如下ClassicEditor.create(document.querySelector(#editor), { plugins: [ // 其他 plugin GeneralHtmlSupport, SourceEditing ], htmlSupport: { allow: [ { name: video, attributes: [src, controls, autoplay, loop, muted, poster, width, height, style] }, { name: source, attributes: [src, type] } ] } });這樣設定之後你在原始碼模式貼video controls srchttps://example.com/video.mp4/video編輯器內就會出現播放器。這個做法適合快速驗證但我不建議只在這個方案就上線因為一般後台使用者不會想開原始碼模式貼 HTML。3.3 自訂 VideoPlugin註冊按鈕、開啟對話框、插入影片標籤正式做法是寫一個 VideoPlugin。我先把最核心的程式碼完整貼出來接著逐步解釋。// InsertVideoCommand.js import { Command } from ckeditor/ckeditor5-core; export default class InsertVideoCommand extends Command { execute(videoUrl) { const editor this.editor; const model editor.model; model.change(writer { const videoElement writer.createElement(video, { src: videoUrl, controls: controls, style: max-width: 100%; }); const insertPosition model.document.selection.getFirstPosition(); model.insertContent(videoElement, insertPosition); }); } }這裡的writer.createElement(video, ...)會建立一個 model 節點名字叫video。你可能會問「為什麼是 videoCKEditor5 預設沒有這個元素啊」沒有錯所以我們要在 Plugin 裡先跟編輯器說明 video 元素長什麼樣這就是 schema 的工作。// VideoPlugin.js import { Plugin } from ckeditor/ckeditor5-core; import { ButtonView } from ckeditor/ckeditor5-ui; import InsertVideoCommand from ./InsertVideoCommand; export default class VideoPlugin extends Plugin { static get pluginName() { return VideoPlugin; } init() { const editor this.editor; editor.model.schema.register(video, { isObject: true, allowWhere: $block, allowAttributes: [src, controls, poster, style] }); editor.conversion.for(upcast).elementToElement({ view: { name: video }, model: (viewElement, { writer }) { return writer.createElement(video, { src: viewElement.getAttribute(src), controls: viewElement.hasAttribute(controls) ? controls : undefined, poster: viewElement.getAttribute(poster), style: viewElement.getAttribute(style) }); } }); editor.conversion.for(downcast).elementToElement({ model: video, view: (modelElement, { writer }) { return writer.createContainerElement(video, { src: modelElement.getAttribute(src), controls: modelElement.getAttribute(controls), poster: modelElement.getAttribute(poster), style: modelElement.getAttribute(style) }); } }); editor.commands.add(insertVideo, new InsertVideoCommand(editor)); editor.ui.componentFactory.add(insertVideo, locale { const button new ButtonView(locale); button.set({ label: 插入影片, icon: svg viewBox0 0 20 20 xmlnshttp://www.w3.org/2000/svgpath dM2 4h16v12H2z fillnone strokecurrentColor/polygon points8,7 14,10 8,13 fillcurrentColor//svg, tooltip: true }); button.on(execute, () { const url window.prompt(請輸入影片網址mp4、webm 或外部影片頁面網址); if (url) { editor.execute(insertVideo, url); } }); return button; }); } }這段程式碼做了四件事schema.register定義 video 元素是 block object允許放在段落之間並允許特定屬性。upcast把從資料來源讀進來的video轉成 model 節點。downcast把 model 節點轉回video並帶上屬性。componentFactory.add新增一個工具列按鈕點擊後用window.prompt請使用者輸入網址再執行insertVideo指令。我用了window.prompt是為了讓範例最少化實際產品我建議改成自訂 modal讓使用者可以輸入網址或上傳檔案。底層邏輯都一樣只是 UI 比較友善。3.4 將自訂按鈕掛進 Toolbar有了 Plugin 之後要記得在 config 中載入並把按鈕放進 toolbar。import ClassicEditor from ckeditor/ckeditor5-build-classic; import VideoPlugin from ./VideoPlugin; ClassicEditor .create(document.querySelector(#editor), { plugins: [ VideoPlugin, // 其他官方 plugin ], toolbar: { items: [ undo, redo, |, heading, |, bold, italic, |, bulletedList, numberedList, |, insertVideo ] } }) .then(editor { window.editor editor; }) .catch(error { console.error(error); });如果一切正常工具列最後面會出現一個「插入影片」的按鈕。點下去跳出輸入框輸入https://example.com/video.mp4編輯器內就會出現可播放的影片。這裡有一個小技巧如果你使用ckeditor/ckeditor5-build-classic這個建置包config 的plugins陣列要特別注意。有些版本的 ClassicEditor 已經內建一堆 plugin你把plugins重新指定後可能會覆蓋掉原本預設的 plugin。最保險的方法是用ClassicEditor.builtinPlugins展開再加上自訂 Pluginplugins: [ ...ClassicEditor.builtinPlugins, VideoPlugin ]這樣可以避免「按鈕都進 toolbar 了但編輯器功能壞掉」的奇怪問題。3.5 前端預覽與後端收稿的配合儲存時我們會用editor.getData()取得 HTML 字串這個字串會包含video標籤。如果你的後端原本有自己的 HTML 過濾器請先確認白名單有沒有放行 video 標籤否則影片標籤很可能會被默默刪掉。前台預覽文章時如果是管理員介面我建議用 iframe sandboxiframe sandbox srcdocbase target_blank${html}/iframesandbox 可以限制執行 JavaScript至少不會讓內文裡可能的script直接在管理員的後台頁面執行。當然最根本的防線還是後端要 sanitize。3.6 上傳影片的設計很多需求不只是貼網址而是「上傳一支影片到伺服器然後插入文章」。這部分跟一般檔案上傳一樣我會在按鈕的 execute 裡建立一個隱藏的input typefile讓使用者選檔後用FormData送到後端。button.on(execute, () { const input document.createElement(input); input.type file; input.accept video/*; input.onchange async () { const file input.files[0]; if (!file) return; const formData new FormData(); formData.append(file, file); try { const response await fetch(/api/upload/video, { method: POST, body: formData }); if (!response.ok) { throw new Error(上傳失敗); } const data await response.json(); editor.execute(insertVideo, data.url); } catch (error) { console.error(error); alert(影片上傳失敗請確認檔案格式與大小); } }; input.click(); });這裡要注意的是acceptvideo/*只是前端提示後端還是要檢查真實的 MIME 類型與副檔名。影片檔案通常很大伺服器如果沒有調大上限上傳到一半就會被擋掉。4. 上傳背後的檔案處理與安全底線4.1 影片上傳介面怎麼設計後台管理員通常不是技術人員上傳介面要越簡單越好。我自己的建議是支援拖曳上傳或檔案選取。上傳時顯示進度條至少要有「處理中」的狀態。上傳完成後先回傳一個臨時 URL讓使用者在編輯器內看到預覽。如果伺服器轉檔時間較長用非同步工作處理不要讓 HTTP 請求卡住。影片格式方面瀏覽器原生播放最保險的格式是 MP4H.264 AAC與 WebM。假如你允許使用者上傳.avi或.mkvChrome 或 Safari 不一定能直接播放後續就要做轉檔這會讓專案複雜很多。客戶如果只是內部後台要放影片我會在後端直接把非 MP4 檔轉成 MP4確保前台一定可以播放。4.2 後端接收與檔案大小限制後端我用 Node.js 搭配 Multer 做範例const multer require(multer); const upload multer({ storage: multer.diskStorage({ destination: uploads/, filename: (req, file, cb) { const ext path.extname(file.originalname); cb(null, ${Date.now()}-${Math.round(Math.random() * 1e9)}${ext}); } }), limits: { fileSize: 200 * 1024 * 1024 }, fileFilter: (req, file, cb) { if (file.mimetype.startsWith(video/)) { cb(null, true); } else { cb(new Error(請上傳影片檔案)); } } }); app.post(/api/upload/video, upload.single(file), (req, res) { const url /uploads/${req.file.filename}; res.json({ url }); });如果前面有 Nginx記得調整client_max_body_size例如client_max_body_size 200m;如果後端是 PHP則要檢查upload_max_filesize與post_max_size。很多「上傳到一半失敗」的問題其實根本不是程式有 bug而是伺服器設定擋掉了。4.3 儲存與輸出的衛生問題sanitize 是必須的我一直強調 sanitize因為富文本編輯器的源頭就是讓使用者輸入 HTML如果後端完全信任這串 HTML等於把系統的大門打開。CKEditor5 本身會過濾掉它不認識的元素但自制 Plugin 既然允許video標籤就要小心攻擊者塞入其他屬性例如video srchttps://example.com/x.mp4 onerroralert(document.cookie)/video瀏覽器在載入影片失敗時會觸發onerror如果你的 sanitize 規則只擋script沒擋事件屬性XSS 就成立了。正確做法是白名單只允許必要的屬性video src... controls poster... stylemax-width:100%;/video後端可以用sanitize-html或DOMPurify設定白名單例如const sanitizeHtml require(sanitize-html); const clean sanitizeHtml(dirtyHtml, { allowedTags: [p, br, strong, em, h2, h3, ul, ol, li, video], allowedAttributes: { video: [src, controls, poster, style] }, allowedStyles: { video: { max-width: [/^\d(px|%)$/] } } });style屬性也要限制否則 CSS 可能造成版面破壞甚至使用background: url(...)做奇怪的事情。安全這件事寧可一開始就嚴格也不要出事之後再補洞。4.4 繞開 XSS 的正確姿勢除了後端 sanitize前端也應該對editor.getData()的輸出做處理。我的標準流程是後端收稿後立即 sanitize。儲存前把base href換成自己的網域避免相對路徑被改成惡意網址。前台渲染時如果只是預覽優先使用 iframe sandbox。真正要直接嵌進頁面時再允許受信任的影片標籤其餘一律轉成純文字。不要依賴瀏覽器或編輯器自動擋掉 XSS因為編輯器只是編輯介面不是安全邊界。只要有「使用者可以輸入 HTML」的地方後端驗證永遠是主戰場。5. 常見問題與排錯技巧實錄5.1 影片標籤被過濾器吞掉我遇過最常見的狀況編輯器內明明看得到影片存檔後再打開video不見了。第一時間不要懷疑 CKEditor5先去後端檢查資料庫存的是什麼。如果後端有套 HTML 過濾器或 WYSIWYG 元件庫它們很可能預設不允許 video 標籤直接就把整段刪掉。排查方法很簡單在瀏覽器 console 輸入editor.getData()看輸出有沒有包含video。有包含問題在後端檢查 sanitize 白名單。沒包含問題在前端 schema 或 conversion檢查 upcast / downcast 是否註冊成功。5.2 編輯器內一片空白或無法預覽編輯器內沒畫面最常見的原因有downcast沒註冊model 存在但 view 不知道要顯示成什麼。影片網址是空白或錯誤瀏覽器無法載入。影片格式是 Safari 不吃的 WebM。頁面是 HTTPS但影片網址是 HTTP瀏覽器擋掉混合內容。混合內容的解法很簡單把所有影片網址統一改成 https或使用同源的相對路徑。後端在儲存時也可以強制把http://轉成https://避免管理員貼了奇怪的網址。5.3 上傳失敗與請求被擋上傳大檔失敗先看瀏覽器的 Network 面板確認請求有沒有真的送到後端。常見原因Nginxclient_max_body_size太小。PHPupload_max_filesize太小。Node.js 的 body parser 沒設定limit。後端 timeout 太短大型影片上傳時間超過伺服器給的請求上限。我習慣先準備一支小檔案測試確認小檔能過之後再逐步加大比較容易抓出是哪一層卡住。5.4 工具列按鈕莫名消失按鈕沒出現十之八九不是 CSS 問題而是註冊流程有誤。檢查順序如下Plugin 有沒有放進plugins陣列。componentFactory.add(insertVideo, ...)裡的名字跟toolbar.items裡的名字是否完全一致。有沒有在建立編輯器時把過多的 CSS reset 影響到按鈕顯示。如果使用ClassicEditor.builtinPlugins展開自訂 Plugin 有沒有放在後方覆蓋同名元件。也可以直接在 console 執行editor.ui.componentFactory.names()這個方法會列出目前所有已註冊的 UI 元件是排錯最快的方式。5.5 作業系統或瀏覽器跳出「檔案可能有害」之類的警語如果你在使用者點擊預覽或下載影片時系統跳出「你嘗試預覽的文件可能對你的計算機有害。如果你信任此文件以及其來源請打開此文件」的字樣這通常不是你的網站被入侵而是 Windows 對從網路下載的檔案加了 MOTWMark-of-the-Web標記。瀏覽器下載的檔案會被標記為「來自網際網路」Windows 檔案總管的預覽窗格會因此跳出警告。處理方式要看情境如果是後台管理員要預覽伺服器上的影片最直接的做法是讓管理員經由你網站的播放頁面觀看不要用檔案總管預覽。如果是使用者下載後在檔案總管打不開可以在檔案上按右鍵選擇「內容」勾選「解除封鎖」或使用 PowerShell 指令Unblock-File -Path 檔案路徑。如果只是想要讓 Windows 預覽窗格不要一直跳警告可以關閉預覽窗格或改用自動播放器檢視。老實說這個問題跟 CKEditor5 沒有直接關係但因為影片上傳常常伴隨著「預覽」環節很多人在整合時會一起碰到我就把它列進來了。5.6 如果你想預覽的是 Office 或 PDFOnlyOffice/AList 延伸如果你把富文本編輯器用在知識庫或檔案管理系統可能不只要在文章內播放影片還希望管理員可以直接預覽.pdf、.docx、.xlsx這類文件。這條路跟「影片預覽」截然不同因為瀏覽器原生不支援 docx 或 xlsx 的內容渲染。常見做法是用 Docker 部署 OnlyOffice Document Server再搭配 AList 或自己的檔案服務來做檔案列表與預覽入口。架構大概是OnlyOffice Document Server 負責把 Office 文件轉成可檢視的格式或是在 iframe 中提供完整的編輯與預覽介面。AList 負責串接儲存空間提供檔案下載或預覽 URL。前端可以產出一個「在 OnlyOffice 中開啟」的按鈕透過 iframe 嵌入預覽頁面。如果你目前的專案剛好是「後台文章編輯器 上傳附件」附件如果是 PDF其實也可以用iframe srcxxx.pdf讓瀏覽器直接預覽。Office 文件就比較麻煩需要 OnlyOffice 或微軟的 Office Online Viewer 之類的服務。不過這屬於另一個專案範疇了有需要再單獨拉一篇講。5.7 排查順序與除錯 SOP最後我整理一個自己的除錯順序遇到問題時照著跑通常可以在五分鐘內定位步驟動作檢查重點1看瀏覽器 console是否有 JavaScript 錯誤2看 Network 面板是否有請求失敗、上傳中斷3執行editor.getData()確認 model 輸出是否正確4比對 schema 註冊editor.model.schema是否有 video5比對 conversion上傳後與取得資料時HTML 是否來回一致6檢查後端 sanitize白名單是否放行 video 與必要屬性7檢查伺服器靜態檔案影片 URL 是否能直接存取、MIME 是否正確6. 個人實作體會與幾個可以再往下玩的方向6.1 我推薦的設定組合做了幾個專案之後我現在遇到「富文本編輯器 影片需求」時預設會用這個組合ClassicEditor 為基底。官方 Essentials、Paragraph、Heading、List、Bold、Italic。SourceEditing讓進階使用者能手動修 HTML。MediaEmbed讓使用者可以直接貼 YouTube 或 Vimeo 連結。自訂 VideoPlugin提供上傳或輸入超過影音平台範圍的影片。後端 sanitize 白名單放行p、h2、h3、ul、ol、li、a、img、video、source、figure、figcaption等必要元素。工具列我則會依角色拆成兩份例如const commonToolbar [undo, redo, |, heading, |, bold, italic, |, bulletedList, numberedList]; const adminToolbar [...commonToolbar, |, sourceEditing]; const editorToolbar [...commonToolbar, |, insertVideo];這樣做比較好維護之後同事要加按鈕只要改陣列就好。6.2 實務上最常踩的坑除了前面講的 sanitize、上傳大小、componentFactory 名稱之外還有幾個容易被忽略的小地方。第一個是 React 或 Vue 的 StrictMode。某些前端框架在開發模式下會把元件掛載兩次如果你的 CKEditor5 初始化程式碼寫得不夠嚴謹編輯器可能建立兩次造成「奇怪的按鈕重複」或「toolbar 錯亂」。我自己習慣在元件銷毀時確實呼叫editor.destroy()。第二個是編輯器內容的「換行」問題。vlack 元素在 CKEditor5 的 model 與 HTML 之間來回轉換時有可能因為 conversion 沒寫好而多出pnbsp;/p。這雖然不會影響影片功能但會讓 store 內容看起來很髒。後來我會在後端存檔前先做一次 HTML 清理把連續空白段落合併。第三個是「貼上網址時自動轉成影片」。很多人以為 CKEditor5 像 Word 一樣貼上 YouTube 網址就會自動嵌入其實預設不會。要達到這個效果得去設定MediaEmbed的預設 provider或者自己處理 paste 事件。如果你需要這個功能可以在editor.model.document.on(clipboardInput)事件中攔截貼上內容判斷是否為影片網址再轉成指令執行。6.3 下一步可以擴充的功能如果你做完基本影片引入後還有餘力我會建議往這幾個方向玩拖拉上傳把影片檔案拖進編輯器時自動上傳並插入。線上剪輯預覽針對管理員上傳的影片產生一張 poster 封面。浮動工具列使用 BalloonEditor 或 DecoupledEditor讓工具列可以在選取文字時彈出。多國語言按鈕自訂 Plugin 的 label 可以依使用者語言切換。與檔案管理服務整合例如接上 S3、OSS甚至前面提到的 AList讓上傳的檔案不只存在本機。我自己最近的測試是把這個 VideoPlugin 封成一個 Vue 3 component讓不同後台頁面只要傳入toolbar設定就可以重用。跑通以後整個團隊要接 CKEditor5 就變成「丟元件、設參數」的流程維護成本低很多。最後分享一個實際操作上的心得如果你只是要在公司內部後台放影片而且使用者都是固定一群人不要一開始就想做到多完美。先照著這篇把按鈕、上傳、預覽串起來讓大家實際用一週再根據回饋調整工具列與格式限制。很多看似需要的功能往往在真實使用後才發現其實用不到反而是一些你沒想過的按鈕像是「從原始碼貼 HTML」才是管理員真正依賴的後門。工具列不要做太死留一點彈性給進階使用者之後你才不會一直被叫去改需求。
返回列表