国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

超漂亮的Bootstrap 富文本編輯器summernote

2019-11-20 10:17:44
字體:
來源:轉載
供稿:網友

 Summernote 是一個簡單,靈活,所見即所得(WYSIWYG)的編輯器,基于 jQuery 和 Bootstrap 構建。Summernote 所有主要的操作都支持快捷鍵,有一個功能強大的 API,它提供了大量的自定義選項的設計(寬,高,有效的項目等等)和功能。對于主要的腳本語言或框架(PHP,Ruby,Django,NodeJS),該項目有提供了集成示例。

Bootstrap summernote,用其官網上的介紹就是“Super Simple WYSIWYG editor”,不過在我看來,與bootstrap中文官網上提供的“bootstrap-wysiwyg”要更simple,更漂亮,更好用!

雖然我之前嘗試過使用bootstrap-wysiwyg,可參照Bootstrap wysiwyg富文本數據如何保存到mysql,但事后諸葛亮的經驗告訴我,summernote絕對是更佳的富文本編輯器,這里對其工作team點三十二個贊?。。。?!

經過一天時間的探索,對summernote有所掌握,那么為了更廣大前端愛好者提供便利,我將費勁一番心血來介紹一下summernote,超級福利啊。

一、官方API和源碼下載

工欲善其事必先利其器,首先把summernote的源碼拿到以及對應官方API告訴大家是首個任務!

官網(demo和api)

github源碼下載,注意下載開發版

二、效果圖

效果圖1

效果圖1

效果圖2

效果圖2

效果圖3

效果圖3

三、開講內容

大的方向為以下三個內容:

summernote的頁面布局(資源引入、初始參數)
summernote從本地上傳圖片方法(前端onImageUpload方法、后端springMVC文件保存)
summernote所在form表單的數據提交

①、summernote的頁面布局

<!DOCTYPE html><html lang="zh-CN"><%@ include file="/components/common/taglib.jsp"%><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /><title>summernote - bs3fa4</title><!-- include jquery --><script type="text/javascript" src="${ctx}/components/jquery/jquery.js"></script><!-- include libs stylesheets --><link type="text/css" rel="stylesheet" href="${ctx}/components/bootstrap/css/bootstrap.css" /><script type="text/javascript" src="${ctx}/components/bootstrap/js/bootstrap.min.js"></script><!-- include summernote --><link type="text/css" rel="stylesheet" href="${ctx}/components/summernote/summernote.css" /><script type="text/javascript" src="${ctx}/components/summernote/summernote.js"></script><script type="text/javascript" src="${ctx}/components/summernote/lang/summernote-zh-CN.js"></script><script type="text/javascript">$('div.summernote').each(function() {var $this = $(this);var placeholder = $this.attr("placeholder") || '';var url = $this.attr("action") || '';$this.summernote({lang : 'zh-CN',placeholder : placeholder,minHeight : 300,dialogsFade : true,// Add fade effect on dialogsdialogsInBody : true,// Dialogs can be placed in body, not in// summernote.disableDragAndDrop : false,// default false You can disable drag// and dropcallbacks : {onImageUpload : function(files) {var $files = $(files);$files.each(function() {var file = this;var data = new FormData();data.append("file", file);$.ajax({data : data,type : "POST",url : url,cache : false,contentType : false,processData : false,success : function(response) {var json = YUNM.jsonEval(response);YUNM.debug(json);YUNM.ajaxDone(json);if (json[YUNM.keys.statusCode] == YUNM.statusCode.ok) {// 文件不為空if (json[YUNM.keys.result]) {var imageUrl = json[YUNM.keys.result].completeSavePath;$this.summernote('insertImage', imageUrl, function($image) {});}}},error : YUNM.ajaxError});});}}});});</script></head><body><div class="container"><form class="form-horizontal required-validate" action="#" enctype="multipart/form-data" method="post" onsubmit="return iframeCallback(this, pageAjaxDone)"><div class="form-group"><label for="" class="col-md-2 control-label">項目封面</label><div class="col-md-8 tl th"><input type="file" name="image" class="projectfile" value="${deal.image}"/><p class="help-block">支持jpg、jpeg、png、gif格式,大小不超過2.0M</p></div></div><div class="form-group"><label for="" class="col-md-2 control-label">項目詳情</label><div class="col-md-8"><div class="summernote" name="description" placeholder="請對項目進行詳細的描述,使更多的人了解你的" action="${ctx}/file">${deal.description}</div></div></div></form></div></body></html>

<!DOCTYPE html>html5的標記是必須的,注意千萬不能是<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">這種doctype,否則summernote的組件顯示怪怪的,按鈕的大小布局不一致,這里就不再上圖了,但是千萬注意!
bootstrap 的版本號最好為v3.3.5

1、布局div

<div class="summernote" name="description" placeholder="請對項目進行詳細的描述,使更多的人了解你的" action="${ctx}/file">${deal.description}</div>

相信你也看到了我為div加上的三個屬性name、placeholder、action,那么我們來詳細介紹一下三個屬性的作用:

name,為外層form表單提供summernote數據保存時的數據模型的屬性名,和input標簽的name屬性作用一致,稍候在form提交的時候具體介紹。

placeholder,很直白,為summernote提供初始狀態的文本描述,當然還需要后續加工,div顯然是不支持placeholder屬性的。

action,為圖片上傳提供后端接收地址,稍候在介紹圖片上傳onImageUpload會再次用到。
另外${deal.description}其實你不需要太多關注,和textarea的賦值的用法一致,就是單純的顯示保存后的內容。

2、summernote初始化

$('div.summernote').each(function() {var $this = $(this);var placeholder = $this.attr("placeholder") || '';var url = $this.attr("action") || '';$this.summernote({lang : 'zh-CN',placeholder : placeholder,minHeight : 300,dialogsFade : true,// Add fade effect on dialogsdialogsInBody : true,// Dialogs can be placed in body, not in// summernote.disableDragAndDrop : false,// default false You can disable drag// and drop});});

使用jquery獲取到頁面上的summernote,對其進行初始化,我們來詳細介紹列出參數的用法(先不介紹圖片上傳的onImageUpload 方法)。

lang ,指定語言為中文簡體

placeholder ,summernote初始化顯示的內容。

minHeight,最小高度為300,注意這里沒有使用height,是有原因的,這里稍作解釋,就不上圖了。當使用height指定高度后,假如上傳比height高的圖片,summernote就不會自動調整高度,并且前文中“效果圖3”中標出的紅色區域會不貼著圖片,而溢出到summernote外部。

dialogsFade,增加summernote上彈出窗口滑進滑出的動態效果。
dialogsInBody,這個屬性也很關鍵,默認為false,字面上的意思是summernote的彈出框是否在body中(in嘛),設置為false時,dialog的式樣會繼承其上一級外部(如上文中的form-horizontal)容器式樣,那么顯示的效果就很別扭,這里也不再上圖;那么設置為true時,就不會繼承上一級外部div的屬性啦,從屬于body嘛。

disableDragAndDrop,設置為false吧,有的時候拖拽會出點問題,你可實踐。

②、summernote從本地上傳圖片方法

1、前端onImageUpload方法

假如問度娘如下的話:“onImageUpload方法怎么寫?”,度娘大多會為你找到如下回答:

$(/'.summernote/').summernote({height:300,onImageUpload: function(files, editor, welEditable) {sendFile(files[0],editor,welEditable);}});});function sendFile(file, editor, welEditable) {data = new FormData();data.append("file", file);url = "http://localhost/spichlerz/uploads";$.ajax({data: data,type: "POST",url: url,cache: false,contentType: false,processData: false,success: function (url) {editor.insertImage(welEditable, url);}});}</script>

以上資源來自于stackoverflow。

但其實呢,summernote-develop版本的summernote已經不支持這種onImageUpload寫法,那么如今的寫法是什么樣子呢?參照summernote的官網例子。

onImageUpload

Override image upload handler(default: base64 dataURL on IMG tag). You can upload image to server or AWS S3: more…// onImageUpload callback$('#summernote').summernote({callbacks: {onImageUpload: function(files) {// upload image to server and create imgNode...$summernote.summernote('insertNode', imgNode);}}});// summernote.image.upload$('#summernote').on('summernote.image.upload', function(we, files) {// upload image to server and create imgNode...$summernote.summernote('insertNode', imgNode);});

那么此時onImageUpload的具體寫法呢?(后端為springMVC):

callbacks : {// onImageUpload的參數為files,summernote支持選擇多張圖片onImageUpload : function(files) {var $files = $(files);// 通過each方法遍歷每一個file$files.each(function() {var file = this;// FormData,新的form表單封裝,具體可百度,但其實用法很簡單,如下var data = new FormData();// 將文件加入到file中,后端可獲得到參數名為“file”data.append("file", file);// ajax上傳$.ajax({data : data,type : "POST",url : url,// div上的actioncache : false,contentType : false,processData : false,// 成功時調用方法,后端返回json數據success : function(response) {// 封裝的eval方法,可百度var json = YUNM.jsonEval(response);// 控制臺輸出返回數據YUNM.debug(json);// 封裝方法,主要是顯示錯誤提示信息YUNM.ajaxDone(json);// 狀態ok時if (json[YUNM.keys.statusCode] == YUNM.statusCode.ok) {// 文件不為空if (json[YUNM.keys.result]) {// 獲取后臺數據保存的圖片完整路徑var imageUrl = json[YUNM.keys.result].completeSavePath;// 插入到summernote$this.summernote('insertImage', imageUrl, function($image) {// todo,后續可以對image對象增加新的css式樣等等,這里默認});}}},// ajax請求失敗時處理error : YUNM.ajaxError});});}}

注釋當中加的很詳細,這里把其他關聯的代碼一并貼出,僅供參照。

debug : function(msg) {if (this._set.debug) {if (typeof (console) != "undefined")console.log(msg);elsealert(msg);}},jsonEval : function(data) {try {if ($.type(data) == 'string')return eval('(' + data + ')');elsereturn data;} catch (e) {return {};}},ajaxError : function(xhr, ajaxOptions, thrownError) {if (xhr.responseText) {$.showErr("<div>" + xhr.responseText + "</div>");} else {$.showErr("<div>Http status: " + xhr.status + " " + xhr.statusText + "</div>" + "<div>ajaxOptions: " + ajaxOptions + "</div>"+ "<div>thrownError: " + thrownError + "</div>");}},ajaxDone : function(json) {if (json[YUNM.keys.statusCode] == YUNM.statusCode.error) {if (json[YUNM.keys.message]) {YUNM.debug(json[YUNM.keys.message]);$.showErr(json[YUNM.keys.message]);}} else if (json[YUNM.keys.statusCode] == YUNM.statusCode.timeout) {YUNM.debug(json[YUNM.keys.message]);$.showErr(json[YUNM.keys.message] || YUNM.msg("sessionTimout"), YUNM.loadLogin);}},

2、后端springMVC文件保存

2.1、為springMVC增加文件的配置

<bean id="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver" p:defaultEncoding="UTF-8"><property name="maxUploadSize" value="1024000000"></property></bean><mvc:annotation-driven conversion-service="conversionService" /><bean id="conversionService"class="org.springframework.format.support.FormattingConversionServiceFactoryBean"><property name="converters"><list><!-- 這里使用string to date可以將dao在jsp到controller轉換的時候直接將string格式的日期轉換為date類型 --><bean class="com.honzh.common.plugin.StringToDateConverter" /><!-- 為type為file類型的數據模型增加轉換器 --><bean class="com.honzh.common.plugin.CommonsMultipartFileToString" /></list></property></bean>

這里就不做過多介紹了,可參照我之前寫的SpringMVC之context-dispatcher.xml,了解基本的控制器

2.2、FileController.java

package com.honzh.spring.controller;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.log4j.Logger;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import com.honzh.common.base.UploadFile;import com.honzh.spring.service.FileService;@Controller@RequestMapping(value = "/file")public class FileController extends BaseController {private static Logger logger = Logger.getLogger(FileController.class);@Autowiredprivate FileService fileService;@RequestMapping("")public void index(HttpServletRequest request, HttpServletResponse response) {logger.debug("獲取上傳文件...");try {UploadFile uploadFiles = fileService.saveFile(request);renderJsonDone(response, uploadFiles);} catch (Exception e) {logger.error(e.getMessage());logger.error(e.getMessage(), e);renderJsonError(response, "文件上傳失敗");}}}

2.3、FileService.java

package com.honzh.spring.service;import java.io.IOException;import java.util.Iterator;import java.util.Map;import java.util.Random;import javax.servlet.http.HttpServletRequest;import org.apache.commons.io.FileUtils;import org.apache.log4j.Logger;import org.springframework.stereotype.Service;import org.springframework.web.multipart.MultipartFile;import org.springframework.web.multipart.MultipartHttpServletRequest;import com.honzh.common.Variables;import com.honzh.common.base.UploadFile;import com.honzh.common.util.DateUtil;@Servicepublic class FileService {private static Logger logger = Logger.getLogger(FileService.class);public UploadFile saveFile(HttpServletRequest request) throws IOException {logger.debug("獲取上傳文件...");// 轉換為文件類型的requestMultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;// 獲取對應file對象Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();Iterator<String> fileIterator = multipartRequest.getFileNames();// 獲取項目的相對路徑(http://localhost:8080/file)String requestURL = request.getRequestURL().toString();String prePath = requestURL.substring(0, requestURL.indexOf(Variables.ctx));while (fileIterator.hasNext()) {String fileKey = fileIterator.next();logger.debug("文件名為:" + fileKey);// 獲取對應文件MultipartFile multipartFile = fileMap.get(fileKey);if (multipartFile.getSize() != 0L) {validateImage(multipartFile);// 調用saveImage方法保存UploadFile file = saveImage(multipartFile);file.setPrePath(prePath);return file;}}return null;}private UploadFile saveImage(MultipartFile image) throws IOException {String originalFilename = image.getOriginalFilename();logger.debug("文件原始名稱為:" + originalFilename);String contentType = image.getContentType();String type = contentType.substring(contentType.indexOf("/") + 1);String fileName = DateUtil.getCurrentMillStr() + new Random().nextInt(100) + "." + type;// 封裝了一個簡單的file對象,增加了幾個屬性UploadFile file = new UploadFile(Variables.save_directory, fileName);file.setContentType(contentType);logger.debug("文件保存路徑:" + file.getSaveDirectory());// 通過org.apache.commons.io.FileUtils的writeByteArrayToFile對圖片進行保存FileUtils.writeByteArrayToFile(file.getFile(), image.getBytes());return file;}private void validateImage(MultipartFile image) {}}

2.4、UploadFile.java

package com.honzh.common.base;import java.io.File;import com.honzh.common.Variables;public class UploadFile {private String saveDirectory;private String fileName;private String contentType;private String prePath;private String completeSavePath;private String relativeSavePath;public UploadFile(String saveDirectory, String filesystemName) {this.saveDirectory = saveDirectory;this.fileName = filesystemName;}public String getFileName() {return fileName;}public String getSaveDirectory() {return saveDirectory;}public String getContentType() {return contentType;}public void setContentType(String contentType) {this.contentType = contentType;}public String getPrePath() {if (prePath == null) {return "";}return prePath;}public void setPrePath(String prePath) {this.prePath = prePath;setCompleteSavePath(prePath + getRelativeSavePath());}public String getCompleteSavePath() {return completeSavePath;}public void setCompleteSavePath(String completeSavePath) {this.completeSavePath = completeSavePath;}public String getRelativeSavePath() {return relativeSavePath;}public void setRelativeSavePath(String relativeSavePath) {this.relativeSavePath = relativeSavePath;}public void setSaveDirectory(String saveDirectory) {this.saveDirectory = saveDirectory;}public void setFileName(String fileName) {this.fileName = fileName;}public File getFile() {if (getSaveDirectory() == null || getFileName() == null) {return null;} else {setRelativeSavePath(Variables.ctx + "/" + Variables.upload + "/" + getFileName());return new File(getSaveDirectory() + "/" + getFileName());}}}

后端文件保存方法也非常簡單,懂java的同學都可以看得懂,那么對于后端不使用springmvc的同學,你可以再找找方法。

辛苦的介紹完前兩節后,我們來一個動態圖看一下效果吧!

這里寫圖片描述

③. summernote所在form表單的數據提交

這里,我們再回顧一下summernote所在的form表單,其中還包含了一個普通file的input標簽,也就是說,該form還需要上傳一張項目封面。

<form class="form-horizontal required-validate" action="#" enctype="multipart/form-data" method="post" onsubmit="return iframeCallback(this, pageAjaxDone)">

先看一下form的屬性:

enctype:”multipart/form-data”,表明為文件類型的form保存

iframeCallback方法,稍候詳細介紹,主要是對有文件上傳的form表單進行封裝。

1、iframeCallback

function iframeCallback(form, callback) {YUNM.debug("帶文件上傳處理");var $form = $(form), $iframe = $("#callbackframe");var data = $form.data('bootstrapValidator');if (data) {if (!data.isValid()) {return false;}}// 富文本編輯器$("div.summernote", $form).each(function() {var $this = $(this);if (!$this.summernote('isEmpty')) {var editor = "<input type='hidden' name='" + $this.attr("name") + "' value='" + $this.summernote('code') + "' />";$form.append(editor);} else {$.showErr("請填寫項目詳情");return false;}});if ($iframe.size() == 0) {$iframe = $("<iframe id='callbackframe' name='callbackframe' src='about:blank' style='display:none'></iframe>").appendTo("body");}if (!form.ajax) {$form.append('<input type="hidden" name="ajax" value="1" />');}form.target = "callbackframe";_iframeResponse($iframe[0], callback || YUNM.ajaxDone);}function _iframeResponse(iframe, callback) {var $iframe = $(iframe), $document = $(document);$document.trigger("ajaxStart");$iframe.bind("load", function(event) {$iframe.unbind("load");$document.trigger("ajaxStop");if (iframe.src == "javascript:'%3Chtml%3E%3C/html%3E';" || // For// Safariiframe.src == "javascript:'<html></html>';") { // For FF, IEreturn;}var doc = iframe.contentDocument || iframe.document;// fixing Opera 9.26,10.00if (doc.readyState && doc.readyState != 'complete')return;// fixing Opera 9.64if (doc.body && doc.body.innerHTML == "false")return;var response;if (doc.XMLDocument) {// response is a xml document Internet Explorer propertyresponse = doc.XMLDocument;} else if (doc.body) {try {response = $iframe.contents().find("body").text();response = jQuery.parseJSON(response);} catch (e) { // response is html document or plain textresponse = doc.body.innerHTML;}} else {// response is a xml documentresponse = doc;}callback(response);});}

貼上全部代碼以供參考,但是這里我們只講以下部分:

// 富文本編輯器$("div.summernote", $form).each(function() {var $this = $(this);if (!$this.summernote('isEmpty')) {var editor = "<input type='hidden' name='" + $this.attr("name") + "' value='" + $this.summernote('code') + "' />";$form.append(editor);} else {$.showErr("請填寫項目詳情");return false;}});

通過form獲取到summernote對象$this 后,通過!$this.summernote('isEmpty')來判斷用戶是否對富文本編輯器有內容上的填寫,保證不為空,為空時,就彈出提示信息。

$this.summernote('code')可獲得summernote編輯器的html內容,將其封裝到input對象中,name為前文中div提供的name,供后端使用。

這里其他地方就不做多解釋了,詳細可參照Bootstrap wysiwyg富文本數據如何保存到mysql。

保存到數據庫中是什么樣子呢?

<p><img src="http://localhost:8080/ymeng/upload/2016033117093076.jpeg" style=""></p><p><br></p><p>你好,有興趣可以加入到沉默王二的群啊<br></p>

頁面效果為:

這里寫圖片描述

好了,好了,終于寫完了,沒想到寫的這么累,如果你有什么新鮮的玩意,也可以聯系我啊,歡迎你的指導!

關于Bootstrap 富文本編輯器summernote小編就給大家介紹到這里,希望對大家有所幫助!有不同見解歡迎提出寶貴意見,共同學習進步!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 宁陕县| 巴中市| 丰顺县| 东至县| 商河县| 特克斯县| 北安市| 苗栗市| 光山县| 蓝山县| 远安县| 扶沟县| 武强县| 天长市| 当涂县| 孟连| 德格县| 新蔡县| 柳河县| 东明县| 石景山区| 卢氏县| 宜君县| 德惠市| 成都市| 巴林左旗| 保山市| 九龙城区| 广德县| 兴隆县| 华安县| 安陆市| 玉门市| 八宿县| 武宣县| 漠河县| 海口市| 鹿邑县| 鹿邑县| 奉贤区| 宣恩县|