rush:js;">
相信你也看到了我为div加上 的三个属性 name、placeholder、action,那么我们来详细介绍一下三个属性 的作用:
name,为外层form表单提供summernote数据保存时的数据模型的属性 名,和input标签 的name属性 作用一致,稍候在form提交的时候具体介绍。
placeholder,很直白,为summernote提供初始状态的文本描述,当然还需要后续加工,div显然是不支持 placeholder属性 的。
action,为图片 上传 提供后端接收地址,稍候在介绍图片 上传 onImageUpload会再次用到。
另外${deal.description}其实你不需要太多关注,和textarea的赋值的用法 一致,就是单纯的显示 保存后的内容 。
2、summernote初始化
rush:js;">
$('div.summernote').each(function() {
var $this = $(this);
var placeholder = $this.attr("placeholder") || '';
var url = $this.attr("action") || '';
$this.summernote({
lang : 'zh-CN',// default false You can
dis able 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嘛。
dis ableDragAndDrop,设置为false吧,有的时候拖拽会出点问题,你可实践。
②、summernote从本地上传 图片 方法
1、前端onImageUpload方法
假如问度娘如下的话:“onImageUpload方法 怎么写?”,度娘大多会为你找到如下回答:
rush:js;">
$(\'.summernote\').summernote({
height:300,onImageUpload: function(files,editor,welEditable) {
sendFile(files[0],welEditable);
}
});
});
function sendFile(file,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.inser
timage (welEditable,url);
}
});
}
以上资源来自于stackoverflow。
但其实呢,summernote-develop版本的summernote已经不支持 这种onImageUpload写法,那么如今的写法是什么样子呢?参照summernote的官网例子。
onImageUpload
rush:js;">
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):
rush:js;">
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,// div上的action
cache : 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('inser
timage ',function($image) {
// t
odo ,后续可以对image对象
增加 新的css式样等等,这里
默 认
});
}
}
},// ajax请求失败时处理
error : YUNM.ajaxError
});
});
}
}
注释当中加的很详细,这里把其他关联的代码 一并贴出,仅供参照。
rush:js;">
debug : function(msg) {
if (this._set.debug) {
if (typeof (console) != "undefined")
console.log(msg);
else
alert(msg);
}
},jsonEval : function(data) {
try {
if ($.type(data) == 'string')
return eval('(' + data + ')');
else
return data;
} catch (e) {
return {};
}
},ajaxError : function(xhr,ajaxOptions,thrownError) {
if (xhr.responseText) {
$.showErr("
" + xhr.responseText + "
");
} else {
$.showErr("
Http status: " + xhr.status + " " + xhr.statusText + "
" + "
ajaxOptions: " + ajaxOptions + "
"
+ "
thrownError: " + thrownError + "
");
}
},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增加 文件 的配置
这里就不做过多介绍了,可参照我之前写的SpringMVC之context-dis patcher.xml,了解基本的控制器
2.2、FileController.java
rush:js;">
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);
@Autowired
private FileService fileService;
@RequestMapping("")
public void index(HttpServletRequest request,HttpServletResponse response) {
logger.debug("
获取 上传 文件 ...");
try {
UploadFile uploadFiles = fileService.saveFile(request);
rende
rjson Done(response,uploadFiles);
} catch (Exception e) {
logger.error(e.getMessage());
logger.error(e.getMessage(),e);
rende
rjson Error(response,"
文件 上传 失败");
}
}
}
2.3、FileService.java
rush:js;">
package com.honzh.spring.service;
import java.io.IOException;
import java.util.I
tera tor;
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;
@Service
public class FileService {
private static Logger logger = Logger.getLogger(FileService.class);
public UploadFile saveFile(HttpServletRequest request) throws IOException {
logger.debug("
获取 上传 文件 ...");
// 转换为
文件 类型的request
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
//
获取 对应file对象
Map
fileMap = multipartRequest.getFileMap();
Itera tor fileItera tor = multipartRequest.getFileNames();
// 获取 项目的相对路径(http://localhost:8080/file)
String requestURL = request.getRequestURL().toString();
String prePath = requestURL.substring(0,requestURL.indexOf(Variables.ctx));
while (fileItera tor.hasNext()) {
String fileKey = fileItera tor.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.geto riginalFilename();
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
rush:js;">
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 filesy
stem Name) {
this.saveDirectory = saveDirectory;
this.fileName = filesy
stem Name;
}
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还需要上传 一张项目封面。
rush:js;">
先看一下form的属性 :
enctype:”multipart/form-data”,表明为文件 类型的form保存
iframeCallback方法 ,稍候详细介绍,主要是对有文件 上传 的form表单进行封装。
1、iframeCallback
rush:js;">
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 = "
";
$form.append(editor);
} else {
$.showErr("请填写项目详情");
return false;
}
});
if ($iframe.size() == 0) {
$iframe = $("
").appendTo("body");
}
if (!form.ajax) {
$form.append('
');
}
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
// Safari
iframe.src == "javascript:'';") { // For FF,IE
return;
}
var doc = iframe.contentDocument || iframe.document;
// fixing Opera 9.26,10.00
if (doc.readyState && doc.readyState != 'complete')
return;
// fixing Opera 9.64
if (doc.body && doc.body.innerHTML == "false")
return;
var response;
if (doc.XMLDocument) {
// response is a xml document Internet Explorer property
response = 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 text
response = doc.body.innerHTML;
}
} else {
// response is a xml document
response = doc;
}
callback(response);
});
}
贴上全部代码 以供参考,但是这里我们只讲以下部分:
rush:js;">
// 富文本编辑器
$("div.summernote",$form).each(function() {
var $this = $(this);
if (!$this.summernote('isEmpty')) {
var editor = " ";
$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 。
保存到数据库 中是什么样子呢?
rush:js;">
你好,有兴趣可以加入到沉默 王二的群啊
页面 效果 为:
好了,好了,终于写完了,没想到写的这么累,如果你有什么新鲜的玩意,也可以联系我啊,欢迎你的指导!
关于Bootstrap 富文本编辑器summernote小编就给大家介绍到这里,希望对大家有所帮助!有不同见解欢迎提出宝贵意见,共同学习进步!