此次项目中须要用到编辑器插件,因而上网查了一下。因为须要的编辑器功能比较简单,不须要太多复杂功能,因此选择了一款特别轻量的summernote插件,并且后台操做也很简单。
官网:http://summernote.org/
github地址:https://github.com/summernote...css
先来看一下官网的截图html
麻雀虽小五脏俱全。彻底能够知足编辑器的须要。java
按照官网连接下载下来的是git
咱们须要使用的是在dist文件夹内github
其中font主要是编辑器内的图标显示,lang是各类语言,css则是样式。咱们主要来看一下summernote.js。ajax
$.fn.extend({ summernote: function () { var type = $.type(list.head(arguments)); var isExternalAPICalled = type === 'string'; var hasInitOptions = type === 'object'; var options = hasInitOptions ? list.head(arguments) : {}; options = $.extend({}, $.summernote.options, options); options.langInfo = $.extend(true, {}, $.summernote.lang['en-US'], $.summernote.lang[options.lang]); this.each(function (idx, note) { var $note = $(note); if (!$note.data('summernote')) { var context = new Context($note, options); $note.data('summernote', context); $note.data('summernote').triggerEvent('init', context.layoutInfo); } }); var $note = this.first(); if ($note.length) { var context = $note.data('summernote'); if (isExternalAPICalled) { return context.invoke.apply(context, list.from(arguments)); } else if (options.focus) { context.invoke('editor.focus'); } } return this; } });
这就是初始化summernote时执行的函数。spring
$.extend(object) 能够理解为JQuery 添加一个静态方法。 $.fn.extend(object) 能够理解为JQuery实例添加一个方法。
默认的options以下数据库
options: { modules: { 'editor': Editor, 'clipboard': Clipboard, 'dropzone': Dropzone, 'codeview': Codeview, 'statusbar': Statusbar, 'fullscreen': Fullscreen, 'handle': Handle, // FIXME: HintPopover must be front of autolink // - Script error about range when Enter key is pressed on hint popover 'hintPopover': HintPopover, 'autoLink': AutoLink, 'autoSync': AutoSync, 'placeholder': Placeholder, 'buttons': Buttons, 'toolbar': Toolbar, 'linkDialog': LinkDialog, 'linkPopover': LinkPopover, 'imageDialog': ImageDialog, 'imagePopover': ImagePopover, 'videoDialog': VideoDialog, 'helpDialog': HelpDialog, 'airPopover': AirPopover }, buttons: {}, lang: 'zh-CN', // toolbar工具栏默认 toolbar: [ ['style', ['style']], ['font', ['bold', 'underline', 'clear']], ['fontname', ['fontname']], ['color', ['color']], ['para', ['ul', 'ol', 'paragraph']], ['table', ['table']], ['insert', ['link', 'picture', 'video']], ['view', ['fullscreen', 'codeview', 'help']] ], // popover popover: { image: [ ['imagesize', ['imageSize100', 'imageSize50', 'imageSize25']], ['float', ['floatLeft', 'floatRight', 'floatNone']], ['remove', ['removeMedia']] ], link: [ ['link', ['linkDialogShow', 'unlink']] ], air: [ ['color', ['color']], ['font', ['bold', 'underline', 'clear']], ['para', ['ul', 'paragraph']], ['table', ['table']], ['insert', ['link', 'picture']] ] }, // air mode: inline editor airMode: false, width: null, height: null, focus: false, tabSize: 4, styleWithSpan: false, shortcuts: true, textareaAutoSync: true, direction: null, styleTags: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'], fontNames: [ 'Arial', 'Arial Black', 'Comic Sans MS', 'Courier New', 'Helvetica Neue', 'Helvetica', 'Impact', 'Lucida Grande', 'Tahoma', 'Times New Roman', 'Verdana' ], fontSizes: ['8', '9', '10', '11', '12', '14', '18', '24', '36'], // pallete colors(n x n) colors: [ ['#000000', '#424242', '#636363', '#9C9C94', '#CEC6CE', '#EFEFEF', '#F7F7F7', '#FFFFFF'], ['#FF0000', '#FF9C00', '#FFFF00', '#00FF00', '#00FFFF', '#0000FF', '#9C00FF', '#FF00FF'], ['#F7C6CE', '#FFE7CE', '#FFEFC6', '#D6EFD6', '#CEDEE7', '#CEE7F7', '#D6D6E7', '#E7D6DE'], ['#E79C9C', '#FFC69C', '#FFE79C', '#B5D6A5', '#A5C6CE', '#9CC6EF', '#B5A5D6', '#D6A5BD'], ['#E76363', '#F7AD6B', '#FFD663', '#94BD7B', '#73A5AD', '#6BADDE', '#8C7BC6', '#C67BA5'], ['#CE0000', '#E79439', '#EFC631', '#6BA54A', '#4A7B8C', '#3984C6', '#634AA5', '#A54A7B'], ['#9C0000', '#B56308', '#BD9400', '#397B21', '#104A5A', '#085294', '#311873', '#731842'], ['#630000', '#7B3900', '#846300', '#295218', '#083139', '#003163', '#21104A', '#4A1031'] ], lineHeights: ['1.0', '1.2', '1.4', '1.5', '1.6', '1.8', '2.0', '3.0'], tableClassName: 'table table-bordered', insertTableMaxSize: { col: 10, row: 10 }, dialogsInBody: false, dialogsFade: false, maximumImageFileSize: null, callbacks: { onInit: null,//初始化回调函数 onFocus: null,//汇集 onBlur: null,//失去焦点 onEnter: null,//回车键的回调函数 onKeyup: null, onKeydown: null, onSubmit: null,//提交时回调函数 onImageUpload: null,//这就是上传图片的回调函数 onImageUploadError: null//上传图片出错 }, codemirror: { mode: 'text/html', htmlMode: true, lineNumbers: true }, keyMap: { pc: { 'ENTER': 'insertParagraph', 'CTRL+Z': 'undo', 'CTRL+Y': 'redo', 'TAB': 'tab', 'SHIFT+TAB': 'untab', 'CTRL+B': 'bold', 'CTRL+I': 'italic', 'CTRL+U': 'underline', 'CTRL+SHIFT+S': 'strikethrough', 'CTRL+BACKSLASH': 'removeFormat', 'CTRL+SHIFT+L': 'justifyLeft', 'CTRL+SHIFT+E': 'justifyCenter', 'CTRL+SHIFT+R': 'justifyRight', 'CTRL+SHIFT+J': 'justifyFull', 'CTRL+SHIFT+NUM7': 'insertUnorderedList', 'CTRL+SHIFT+NUM8': 'insertOrderedList', 'CTRL+LEFTBRACKET': 'outdent', 'CTRL+RIGHTBRACKET': 'indent', 'CTRL+NUM0': 'formatPara', 'CTRL+NUM1': 'formatH1', 'CTRL+NUM2': 'formatH2', 'CTRL+NUM3': 'formatH3', 'CTRL+NUM4': 'formatH4', 'CTRL+NUM5': 'formatH5', 'CTRL+NUM6': 'formatH6', 'CTRL+ENTER': 'insertHorizontalRule', 'CTRL+K': 'linkDialog.show' }, mac: { 'ENTER': 'insertParagraph', 'CMD+Z': 'undo', 'CMD+SHIFT+Z': 'redo', 'TAB': 'tab', 'SHIFT+TAB': 'untab', 'CMD+B': 'bold', 'CMD+I': 'italic', 'CMD+U': 'underline', 'CMD+SHIFT+S': 'strikethrough', 'CMD+BACKSLASH': 'removeFormat', 'CMD+SHIFT+L': 'justifyLeft', 'CMD+SHIFT+E': 'justifyCenter', 'CMD+SHIFT+R': 'justifyRight', 'CMD+SHIFT+J': 'justifyFull', 'CMD+SHIFT+NUM7': 'insertUnorderedList', 'CMD+SHIFT+NUM8': 'insertOrderedList', 'CMD+LEFTBRACKET': 'outdent', 'CMD+RIGHTBRACKET': 'indent', 'CMD+NUM0': 'formatPara', 'CMD+NUM1': 'formatH1', 'CMD+NUM2': 'formatH2', 'CMD+NUM3': 'formatH3', 'CMD+NUM4': 'formatH4', 'CMD+NUM5': 'formatH5', 'CMD+NUM6': 'formatH6', 'CMD+ENTER': 'insertHorizontalRule', 'CMD+K': 'linkDialog.show' } }, icons: { 'align': 'icon-align', 'alignCenter': 'icon-align-center', 'alignJustify': 'icon-align-justify', 'alignLeft': 'icon-align-left', 'alignRight': 'icon-align-right', 'indent': 'icon-indent-right', 'outdent': 'icon-indent-left', 'arrowsAlt': 'icon-resize-full', 'bold': 'icon-bold', 'caret': 'icon-caret-down', 'circle': 'icon-circle', 'close': 'icon-close', 'code': 'icon-code', 'eraser': 'icon-eraser', 'font': 'icon-font', 'frame': 'icon-frame', 'italic': 'icon-italic', 'link': 'icon-link', 'unlink': 'icon-chain-broken', 'magic': 'icon-magic', 'menuCheck': 'icon-check', 'minus': 'icon-minus', 'orderedlist': 'icon-list-ol', 'pencil': 'icon-pencil', 'picture': 'icon-picture', 'question': 'icon-question', 'redo': 'icon-redo', 'square': 'icon-square', 'strikethrough': 'icon-strikethrough', 'subscript': 'icon-subscript', 'superscript': 'icon-superscript', 'table': 'icon-table', 'textHeight': 'icon-text-height', 'trash': 'icon-trash', 'underline': 'icon-underline', 'undo': 'icon-undo', 'unorderedlist': 'icon-list-ul', 'video': 'icon-facetime-video' } }
关于编辑器须要的工具栏toolbar具体属性可查看官网summernote-toolbar属性json
因为项目中我是直接使用fontawesome,因此我没有再引入summernote.font,直接在options中的icons中修改。但比较麻烦,不知道有什么更好的方法,求指导。app
关于图片上传、提交、按键等回调函数也是在options中,详见callbacks部分。
初始化一个编辑器很简单。只须要定义
<div class="summernote" id="myid"></div> $(function () { $('.summernote').summernote(); //或者 $('#myid').summernote(); });
$('.summernote').summernote({ placeholder:'请输入文章内容', ... });
$('.summernote').summernote({ toolbar:[ ['style',['bold','italic','underline','clear']], ['fontsize',['fontsize']], ['para',['ul','ol','paragraph']], ['color',['color']] ], ... });
须要说起的是,summernote默认的图片上传方式为base64方式。若须要修改,看如下代码。
【必定要注意:onImageUpload方法修改时要放在callbacks内配置,不然没用】
$('#myid').summernote({ callbacks:{ onImageUpload: function(files, editor, $editable) { UploadFiles(files,insertImg); } }, ... }); function insertImg(){ for(i in imageUrl){ $('.summernote').summernote('editor.insertImage',imageUrl[i]); } } function UploadFiles(files,func){ //这里files是由于我设置了可上传多张图片,因此须要依次添加到formData中 var formData = new FormData(); for(f in files){ formData.append("file", files[f]); } $.ajax({ data: formData, type: "POST", url: "/uploadMultipleFile", cache: false, contentType: false, processData: false, success: function(imageUrl) { func(imageUrl); }, error: function() { console.log("uploadError"); } }) }
咱们项目的后台是用spring+springMVC实现的。后台图片上传代码以下:
@RequestMapping(value = "/uploadMultipleFile", method = RequestMethod.POST, produces = "application/json;charset=utf8") @ResponseBody public String uploadMultipleFileHandler(@RequestParam("file") MultipartFile[] files, HttpServletRequest request) throws IOException { return UploadUtil.uploadImage(request.getServletContext().getRealPath("/"), files); } //UploadUtil.java中uploadImage方法以下 public static String uploadImage(String serverPath, MultipartFile[] files) { try { String uploadPath = serverPath + getImageRelativePath(); String images = "{}"; //若是不存在目录,建立一个目录 isDirectory(uploadPath); if (files != null && files.length > 0) { for (int i = 0; i < files.length; i++) { MultipartFile file = files[i]; //save file if (!file.isEmpty()) { String savePath = getImageRelativePath() + file.getOriginalFilename();//数据库保存的图片路径 images = JSONUtil.addProperty(images, String.valueOf(i), savePath); save(file, uploadPath); } } } return images; } catch (Exception e) { e.printStackTrace(); return "{}"; } }
$('#myid').summernote('code',content);
须要注意的是,content是html代码,可能存在引号嵌套的问题致使报错,记得将引号进行转义。
后台处理-java代码:
content = content.replaceAll("'","\\\\'"); content = content.replaceAll("\"", "\\\\\"");
var content = $('.summernote').summernote('code');
此次项目须要使用附件,但发现summernote貌似没有附件功能,因而本身研究了一下代码,根据项目的需求,在link
连接部分进行了修改。
效果以下:
首先,咱们先看link
按钮所绑定的事件。
context.memo('button.link', function () { return ui.button({ contents: ui.icon(options.icons.link), tooltip: lang.link.link, click: context.createInvokeHandler('linkDialog.show') }).render(); });
由上面的代码能够发现click
事件为:linkDialog.show
,那么咱们再来看一下linkDialog
。
var LinkDialog = function (context) { ... this.initialize = function () {//初始化 ... var body = '<div class="form-group">' + '<label>' + lang.link.textToDisplay + '</label>' + '<input class="note-link-text form-control" type="text" />' + '</div>' + '<div class="form-group">' + '<label>' + lang.link.attachment + '</label>' + '<input class="note-link-attachment form-control" type="file" />' + '</div>' + '<div class="form-group">' + '<label>' + lang.link.url + '</label>' + '<input class="note-link-url form-control" type="text" value="http://" />' + '</div>' + (!options.disableLinkTarget ? '<div class="checkbox">' + '<label>' + '<input type="checkbox" checked> ' + lang.link.openInNewWindow + '</label>' + '</div>' : '' ); var footer = '<button href="#" class="btn btn-primary note-link-btn disabled" disabled>' + lang.link.insert + '</button>'; } }
能够看到,点击连接按钮出现的弹框样式就在LinkDialog
的initialize
方法中的body
,因此我在中间添加了一个input
上传附件的部分。
'<div class="form-group">' + '<label>' + lang.link.attachment + '</label>' + '<input class="note-link-attachment form-control" type="file" />' + '</div>' +
那么,咱们须要在lang.link
属性中,新增一个attachment
附件属性。
除此以外,在中文的转换部分summernote-zh-CN.min.js中,添加link
的attachment: '添加附件'
好了,那么咱们接下来须要处理的问题是上传文件后的处理。
this.showLinkDialog = function (linkInfo) { return $.Deferred(function (deferred) { ... //上传文件的输入框 $linkAttachment = self.$dialog.find('.note-link-attachment'), ui.onDialogShown(self.$dialog, function () { ... //对于输入框的事件绑定 $linkAttachment.on('change', function() { UploadFiles($linkAttachment.val(),function(url){ $linkUrl.val(url);//将上传后的URL赋值到linkUrl的输入框中 }); }); } } }
UploadFiles与上述修改上传图片的形式同样。
若是这篇文章对您有帮助,欢迎点赞。若是有疏漏,欢迎指正。
本文地址:http://lsxj615.com/2016/08/10...