概要
Editor.md
- 開源線上 Markdown 編輯器- 圖片上傳:
- csrf 問題
- 補充複製貼上、拖拽上傳
- 意外離開頁面的措施
- localStorge 儲存正在編輯的內容
- 離開頁面時提示
TOC
目錄- 專案實踐
下載
百度搜尋進入 github
下載即可。
開發中使用 editormd.js
,上線後使用 min.js
。
頁面中使用
<!-- laravel框架注意新增這個 meta -->
<meta name="_token" content="{{ csrf_token() }}">
<!-- 引入editormd.css -->
<link href="{{asset('static/editormd')}}/css/editormd.css" rel="stylesheet">
<form class="layui-form" accept-charset="UTF-8">
@csrf
<!--儲存TOC-->
<input id="markdownToC" type="hidden" name="toc" value="">
<!-- MD editor -->
<div id="editor">
<textarea
style="display:none;"
class="form-control"
id="content-editormd-markdown-doc"
name="body_original"
place-holder="請使用Markdown語法">
</textarea>
</div>
</form>
<!-- 當然 jquery 怎麼能少呢 -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<!-- 引入 editormd.js -->
<script src="{{asset('static/editormd')}}/editormd.js"></script>
<script>
// 這裡你需要判斷是編輯模式還是建立模式
var model = "{{isset($article) ? 'edit' : 'create'}}";
// 是否是釋出、儲存草稿、儲存修改,而不是意外離開頁面
var isSubmit = false;
// 檢測是否支援本地儲存
function enableLocalStorage(){
// 菜鳥教程裡推薦的寫法
if(localStorage){
try {
localStorage.setItem("test", "yes");
localStorage.removeItem("test");
return true;
} catch (err) {
console.log(err);
}
}
return false;
}
var enableLS = enableLocalStorage();
// 編輯器
var editor = editormd("editor", {
width : "100%",
height : 600,
fontSize:"14px",
placeholder:'請使用 Markdown 語法',
lineNumbers:false, //行號
styleActiveLine:false, //當前行高亮
// tocContainer : "#test",//你可以將TOC結構輸出到自定義容器中
path : "{{asset('static')}}/editormd/lib/",
toolbarIcons : function() {
return ["h3","h4","bold", "quote", "hr","|", "list-ul","list-ol", "|","link", "image", "table", "|", "watch", "fullscreen","preview"]
},
syncScrolling: true, //左右側預覽同步
toolbarAutoFixed:true,//工具欄自動固定定位的開啟與禁用
saveHTMLToTextarea : true, // 儲存 HTML 到 Textarea
imageUpload : true, //圖片上傳
imageFormats : ["jpg", "jpeg", "gif", "png"],//上傳圖片格式
imageUploadURL : "{{route('img-upload')}}",//圖片上傳URL
onload : function() {
console.log(this);
// 如果瀏覽器支援本地儲存
if(enableLS){
let markdownBody = localStorage.getItem('markdownBody');
// 注意 只有建立時才使用本地儲存
if(markdownBody && model=='create'){
this.setMarkdown(markdownBody);//填充markdown編輯區域
}
}
},
onchange: function(){
// 提取TOC
$('#markdownToC').val(JSON.stringify(this.markdownToC));
// 儲存編輯區域的內容
if(enableLS && model=='create'){
localStorage.setItem("markdownBody", this.getMarkdown());
}
}
});
// 監聽離開頁面動作
window.onbeforeunload=function(e){
// 如果不是點選的釋出文章或儲存草稿或儲存修改 離開頁面時提示
if(!isSubmit){
return "確定離開頁面?系統可能不會儲存更改";
}
}
</script>
瞭解 editormd 的資料結構
上方 onload
中我們新增了 console.log(this)
onload : function() {
console.log(this);
}
你可以瞭解下有用的資訊如:
classPrefix: "editormd-"
類字首markdownToC: []
TOC目錄可以this.markdownToC
獲得- 你可以找到所有的
settings
而不用到處找文件
等等,我只截了一部分 - 所有的工具欄
處理表單
檢查元素
可以看到下面的 textarea
是 editormd
生成的儲存 html
原始碼的表單
那麼後端就可以這麼接收
$article['body_original'] = $post['body_original'];
$article['body_html'] = $post['editor-html-code'];
關於 TOC
目錄表單,已在上面程式碼中體現了,即在 onchange
中
<input id="markdownToC" type="hidden" name="toc" value="">
onchange: function(){
$('#markdownToC').val(JSON.stringify(this.markdownToC));
}
圖片上傳
laravel 框架圖片上傳 csrf 問題
所說的就是編輯器工具欄的上傳圖片
我們需要改動下 editormd
的一個圖片檔案的原始碼/editormd/plugins/image-dialog/image-dialog.js
大概在 49 行左右,它建立了一個表單 form
,我們只需要新增一個 csrf
的 input
到 form
裡就可以了。
// 新增程式碼 1
var csrfToken = $('meta[name="_token"]').attr('content');
var csrfField = csrfToken ? "<input type='hidden' name='_token' value='" + csrfToken + "' />": '';
// 新增程式碼 2
+ csrfField +
補充複製貼上、拖入上傳
需要引入一個外掛 paste-upload-img.js
,依賴 jquery.js
function initPasteDragImg(Editor){
var doc = document.getElementById(Editor.id)
doc.addEventListener('paste', function (event) {
var items = (event.clipboardData || window.clipboardData).items;
var file = null;
if (items && items.length) {
// 搜尋剪下板items
for (var i = 0; i < items.length; i++) {
if (items[i].type.indexOf('image') !== -1) {
file = items[i].getAsFile();
break;
}
}
} else {
console.log("當前瀏覽器不支援");
return;
}
if (!file) {
console.log("貼上內容非圖片");
return;
}
uploadImg(file,Editor);
});
var dashboard = document.getElementById(Editor.id)
dashboard.addEventListener("dragover", function (e) {
e.preventDefault()
e.stopPropagation()
})
dashboard.addEventListener("dragenter", function (e) {
e.preventDefault()
e.stopPropagation()
})
dashboard.addEventListener("drop", function (e) {
e.preventDefault()
e.stopPropagation()
var files = this.files || e.dataTransfer.files;
uploadImg(files[0],Editor);
})
}
function uploadImg(file,Editor){
var formData = new FormData();
var fileName=new Date().getTime()+"."+file.name.split(".").pop();
formData.append('editormd-image-file', file, fileName);
// 如果使用的 laravel 框架需要加上
var csrfToken = $('meta[name="_token"]').attr('content');
formData.append('_token', csrfToken);
$.ajax({
url: Editor.settings.imageUploadURL,
type: 'post',
data: formData,
processData: false,
contentType: false,
dataType: 'json',
success: function (msg) {
var success=msg['success'];
if(success==1){
var url=msg["url"];
if(/\.(png|jpg|jpeg|gif|bmp|ico)$/.test(url)){
Editor.insertValue("![圖片alt]("+msg["url"]+" ''圖片title'')");
}else{
Editor.insertValue("[下載附件]("+msg["url"]+")");
}
}else{
console.log(msg);
alert("上傳失敗");
}
}
});
}
然後在 onload
中新增
onload : function() {
initPasteDragImg(this);
}
專案實踐 (laravel)
Route::resource('articles', 'ArticleController');//資源路由
Route::post('articles/create/upload', 'ArticleController@upload')->name('img-upload');//圖片上傳
關於資源路由
class ArticleController extends Controller
{
// 文章列表 GET /articles route('articles.index')(路由命名以下不再備註)
public function index()
// 顯示建立頁面 GET /articles/create route('articles.create')
public function create()
// 儲存你建立的資料 POST /articles route('articles.store')
public function store(Request $request)
// 顯示對應id的文章內容 GET articles/1 route('articles.show',['article'=>$article->id])
public function show($id)
// 顯示編輯表單 GET articles/1/edit route('articles.edit',['article'=>$article->id])
public function edit($id)
// 儲存編輯的資料 PUT/PATCH articles/1 route('articles.update',['article'=> $article->id])
public function update(Request $request, $id)
// 刪除 DELETE articles/1 route('articles.destroy',['article'=>$article->id])
public function destroy($id)
}
關於 blade
目錄結構 (僅供參考)
views
-- articles
----index.blade.php
----create.blade.php
----show.blade.php
----edit.blade.php
關於提取文章摘要
$desc = strip_tags($post['editor-html-code']); // 去除html標籤
$article['desc'] = trim(mb_substr($desc,0,40)); // 提取前40個字
關於 TOC
前端傳入 JSON.stringify(this.markdownToC)
格式如下
[{"text":"標題","level":3,"slug":"-"},{"text":"文字加粗","level":3,"slug":"-"},{"text":"引用","level":3,"slug":"-"},{"text":"全屏","level":3,"slug":"-"},{"text":"如何上傳圖片","level":3,"slug":"-"}]
後端直接儲存到資料庫即可
$article['toc'] = $post['toc'];
//提取時
$toc = json_decode($article->toc,true);
顯示時示例
<ul>
@foreach($toc as $item)
<li style="padding: 7px 0;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;">
<span>{{str_repeat(' ', $item['level'])}}</span>
<span><a href="#{{$item['text']}}" >{{$item['text']}}</a></span>
</li>
@endforeach
</ul>
本作品採用《CC 協議》,轉載必須註明作者和本文連結