Laravel项目中使用markdown编辑器及图片粘贴上传七牛云

本文为转载,原文: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",{
                width:"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>

解析后的效果如下图:


图片粘贴上传

首先分析一下实现步骤:

  1. QQ截图后在编辑器中粘贴,肯定会有一个粘贴事件,即 paste 事件
  2. 在事件回调函数中对前端进行图片的一次压缩
  3. 前端压缩多是使用canvas,返回的是base64,这里我使用了一个 localResizeIMG.js的插件
  4. 将生成好的base64传给后台,后台可以进行图片的第二次压缩,但是感觉没必要
  5. 后台先得到七牛云的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, {width: 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, {width: 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 Qiniu\Auth;
// 引入上传类
use Qiniu\Storage\UploadManager;
$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, {width: 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>

再编辑器中粘贴完图片的效果如下:


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容