本文为转载,原文:Laravel项目中使用markdown编辑器及图片粘贴上传七牛云
Markdown
Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式。
本次我们选用的编辑器是: Editor.md,官网中也有很详细的介绍。从官网中下载安装
下载的内容中,也有很多demo可以借鉴。
在下载的包中,去除一些多余的内容,只保留我们需要的内容,然后加到项目的public目录下,如下图红色框内的内容:
项目中使用
在项目中使用editor.md编辑内容时,首先要先在blade模板中添加相对应的引用,css的引用如下:
<link rel="stylesheet" href="{{asset('editormd/editormd.min.css')}}">
js的引用如下:
<script src="{{asset('editormd/editormd.min.js')}}" type="text/javascript"></script>
然后在html中添加以下代码,作为编辑器区域。
<div id="myeditormd"> <textarea style="display:none;"></textarea> </div>
最后在添加js代码,加载出editor.md:
<script type="text/javascript"> var testEditor; $(function () { testEditor = editormd("myeditormd",{ "100%", height:600, syncScrolling:"single", taskList : true, tocm: true, path:"{{asset('/editormd/lib/')}}" + "/", tex:true, flowChart : true, sequenceDiagram:true, saveHTMLToTextarea : true, imageUploadURL: "php/upload.php", }); }); </script>
相关参数含义:
saveHTMLToTextarea: 保存 HTML 到 Textarea
tex: 科学公式TeX语言支持,默认关闭
flowChart: 流程图支持,默认关闭
sequenceDiagram: 时序/序列图支持,默认关闭
toolbar: 工具栏,默认开启
watch: 实时预览,默认开启
如此,便可完整的加载出编辑器了。效果如下图:
其中还有些比较重要的js方法。
testEditor.gotoLine(90);//跳转至第90行 testEditor.show();//显示编辑器 testEditor.hide;//隐藏编辑器 testEditor.getMarkdown();//获取markdown代码 testEditor.getHTML();//获取markdown解析后的html代码 testEditor.watch();//开启实时预览 testEditor.unwatch();//关闭实时预览 testEditor.previewing();//预览 testEditor.fullscreen();//全屏 testEditor.showToolbar();//显示工具栏 testEditor.hideToolbar();//隐藏工具栏
在编辑器中编辑完内容后,一般情况下,保存的是markdown标记。但是如何解析已保存的markdown标记呢。
markdown解析
添加以下引用:
//css引用 <link rel="stylesheet" href="{{asset('editormd/editormd.min.css')}}"> //js引用 <script src="{{asset('editormd/editormd.min.js')}}" type="text/javascript"></script> <script src="{{asset('editormd/lib/marked.min.js')}}"></script> <script src="{{asset('editormd/lib/prettify.min.js')}}"></script> <script src="{{asset('editormd/lib/raphael.min.js')}}"></script> <script src="{{asset('editormd/lib/underscore.min.js')}}"></script> <script src="{{asset('editormd/lib/sequence-diagram.min.js')}}"></script> <script src="{{asset('editormd/lib/flowchart.min.js')}}"></script> <script src="{{asset('editormd/lib/jquery.flowchart.min.js')}}"></script>
然后在html中添加解析的区域
<div id="show_editor"> <textarea style="display: none">{{$article->content}}</textarea> </div>
其中{{$article->content}}为数据库中读取的已保存的markdown标记。
最后再添加响应的js代码,便可完美解析了。
<script type="text/javascript"> $(function() { var testEditormdView; testEditormdView = editormd.markdownToHTML("show_editor", { htmlDecode : "style,script,iframe", // you can filter tags decode emoji : true, taskList : true, tex : true, // 默认不解析 flowChart : true, // 默认不解析 sequenceDiagram : true, // 默认不解析 }); }); </script>
解析后的效果如下图:
图片粘贴上传
首先分析一下实现步骤:
- QQ截图后在编辑器中粘贴,肯定会有一个粘贴事件,即 paste 事件
- 在事件回调函数中对前端进行图片的一次压缩
- 前端压缩多是使用canvas,返回的是base64,这里我使用了一个 localResizeIMG.js的插件
- 将生成好的base64传给后台,后台可以进行图片的第二次压缩,但是感觉没必要
-
后台先得到七牛云的upToken,即一个上传的凭证,然后执行七牛sdk提供的上传函数
paste事件
截图之后,在富文本编辑器中右键黏贴或者CTRL V就会触发这个事件,这个事件有一个clipboardData属性。我们需要使用js代码监听paste事件,并获取clipboardData属性,代码如下:
-
function paste(event) { var clipboardData = event.clipboardData; var items, item, types; if (clipboardData) { items = clipboardData.items; if (!items) { return; } // 保存在剪贴板中的数据类型 types = clipboardData.types || []; for (var i = 0; i < types.length; i++) { if (types[i] === 'Files') { item = items[i]; break; } } // 判断是否为图片数据 if (item && item.kind === 'file' && item.type.match(/^image//i)) { // 读取该图片 var file = item.getAsFile(), reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function () { //前端压缩 lrz(reader.result, { 1080}).then(function (res) { $.ajax({ url: "{{asset('php-sdk/myapis/uploadImageToQiliu.php')}}", type: 'post', data: { "image": res.base64, "name": new Date().getTime() + ".png" }, contentType: 'application/x-www-form-urlencoded;charest=UTF-8', success: function (data) { var imageName; try { imageName = JSON.parse(data).key; } catch (e) { alert(e.toString); } var qiniuUrl = '![](http://opgmvuzyu.bkt.clouddn.com/' + imageName + ')'; testEditor.insertValue(qiniuUrl); } }) }); } } } } document.addEventListener('paste', function (event) { paste(event); })
前端压缩
前端压缩使用的是localResizeIMG.js插件。
兼容IE10以上,所以还得做个IE版本判断,然后看自己是否需要使用干这个插件,我这里就不写IE的判断了。
使用方法也很简单,lrz方法接受一个文件路径或者base64的图片,可以设置一个压缩宽度的对象,低于这个宽度的图片不会压缩,大于这个宽度的就会压缩,然后在then方法中取得压缩后的图片:
得先引入这个插件,可以使用src引入,也支持amd or cmd模块化-
<script src="{{asset('js/lrz.bundle.js')}}" type="text/javascript"></script>
开始使用:
-
//image就是经过paste事件后得到的图片 lrz(image, { 1080}).then(function (res) { var base64 = res.base64; }
七牛云sdk
七牛云注册好像就送10G的云储存,需要的可以去注册,先下载七牛云sdk,我使用的是php,地址https://developer.qiniu.com/kodo/sdk/php
配置这个上传的文件也很简单。将下载后的压缩包解压,删掉一下没用的文件,然后拖到项目中:
uploadImageToQiliu.php文件是自己新增的,代码如下:-
<?php require_once __DIR__ . '/../autoload.php'; use QiniuAuth; // 引入上传类 use QiniuStorageUploadManager; $accessKey = '你的accessKey'; $secretKey = '你的secretKey'; // 初始化签权对象。 $auth = new Auth($accessKey, $secretKey); $bucket = "空间名字"; $upToken = $auth->uploadToken($bucket); // 初始化 UploadManager 对象并进行文件的上传。 $uploadMgr = new UploadManager(); $key = $_POST['name']; $filePath = $_POST['image']; list($ret, $err) = $uploadMgr->putFile($upToken, $key, $filePath); if ($err !== null) { echo json_encode($err); } else { echo json_encode($ret); }
accessKey和secretKey注册后就可以看到,bucket是云储存空间名字。
接下来是前台传图片和图片名给后台,图片名我就直接用 new Date().getTime() 了。-
$.ajax({ url: "{{asset('php-sdk/myapis/uploadImageToQiliu.php')}}", type: 'post', data: { "image": res.base64, "name": new Date().getTime() + ".png" }, contentType: 'application/x-www-form-urlencoded;charest=UTF-8', success: function (data) { var imageName; try { imageName = JSON.parse(data).key; } catch (e) { alert(e.toString); } var qiniuUrl = '![](http://opgmvuzyu.bkt.clouddn.com/' + imageName + ')'; testEditor.insertValue(qiniuUrl); } })
testEditor 是我使用的markdown编辑器的对象实例,testEditor.insertValue(qiniuUrl);就是把格式化好的markdown语句插到光标处。
整个前端代码如下:-
<script type="text/javascript"> function paste(event) { var clipboardData = event.clipboardData; var items, item, types; if (clipboardData) { items = clipboardData.items; if (!items) { return; } // 保存在剪贴板中的数据类型 types = clipboardData.types || []; for (var i = 0; i < types.length; i++) { if (types[i] === 'Files') { item = items[i]; break; } } // 判断是否为图片数据 if (item && item.kind === 'file' && item.type.match(/^image//i)) { // 读取该图片 var file = item.getAsFile(), reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function () { //前端压缩 lrz(reader.result, { 1080}).then(function (res) { $.ajax({ url: "{{asset('php-sdk/myapis/uploadImageToQiliu.php')}}", type: 'post', data: { "image": res.base64, "name": new Date().getTime() + ".png" }, contentType: 'application/x-www-form-urlencoded;charest=UTF-8', success: function (data) { var imageName; try { imageName = JSON.parse(data).key; } catch (e) { alert(e.toString); } var qiniuUrl = '![](http://opgmvuzyu.bkt.clouddn.com/' + imageName + ')'; testEditor.insertValue(qiniuUrl); } }) }); } } } } document.addEventListener('paste', function (event) { paste(event); }) </script>
再编辑器中粘贴完图片的效果如下:
-