如果您想了解jquery–访问bootstrap-wysihtml5编辑器对象的相关知识,那么本文是一篇不可错过的文章,我们将对jquery访问对象的方法进行全面详尽的解释,并且为您提供关于10个基于
如果您想了解jquery – 访问bootstrap-wysihtml5编辑器对象的相关知识,那么本文是一篇不可错过的文章,我们将对jquery访问对象的方法进行全面详尽的解释,并且为您提供关于10个基于jQuery或JavaScript的WYSIWYG 编辑器整理_jquery、bootstrap + bootstrap-table + jquery + bootstrap-paginator、Bootstrap 可视化 HTML 编辑器,summernote、bootstrap-4 – Bootstrap 4:如何在没有jQuery / minimal bootstrap.js的情况下使用NavBars?的有价值的信息。
本文目录一览:- jquery – 访问bootstrap-wysihtml5编辑器对象(jquery访问对象的方法)
- 10个基于jQuery或JavaScript的WYSIWYG 编辑器整理_jquery
- bootstrap + bootstrap-table + jquery + bootstrap-paginator
- Bootstrap 可视化 HTML 编辑器,summernote
- bootstrap-4 – Bootstrap 4:如何在没有jQuery / minimal bootstrap.js的情况下使用NavBars?
jquery – 访问bootstrap-wysihtml5编辑器对象(jquery访问对象的方法)
$(document).ready(function () { $('.someLink').live('click',function () { var wysihtml5Editor = $('#textarea').wysihtml5().editor; console.log('wysihtml5Editor: '+wysihtml5Editor); wysihtml5Editor.composer.commands.exec("bold"); }); });
Chrome控制台返回:
> wysihtml5Editor: undefined > Uncaught TypeError: Cannot read property 'composer' of undefined
所以,重点是.
访问wysihtml5对象的方法是什么?
一切都是在我的textarea插入一些HTML代码.
解决方法
$(document).ready(function () { $('.someLink').live('click',function () { $('#textarea').wysihtml5(); var wysihtml5Editor = $("#textarea").data("wysihtml5").editor; console.log('wysihtml5Editor: '+wysihtml5Editor); // The following is important since wysihtml5 is initialized asynchronously wysihtml5Editor.observe("load",function() { wysihtml5Editor.composer.commands.exec("bold"); }); }); });
10个基于jQuery或JavaScript的WYSIWYG 编辑器整理_jquery
在线编辑内容的时候,那些基于 JavaScript 的编辑器帮了我们大忙,这些所见即所得(WYSIWYG)编辑器,给我们提供了类似 Office?的操作体验。如今,任何网站内容管理系统(CMS)和博客系统都需要一个这样的编辑器。本文精选了5个基于 JavaScript?的编辑器,5个基于 jQuery 框架的编辑器。 MarkitUp – jQuery
Official Website | Demo
markItUp! 它不是一个“全功能,乱用”的编辑器。相反,它是一个非常轻量级的,可定制的和灵活的文本编辑器,以满足发展的需要,在其CMSes ,博客,论坛或网站。 markItUp !不是一个WYSIWYG编辑器,它是简易实用的文本编辑器。 快速移植和使用 支持键盘快捷键 支持Ajax的动态预览 兼容的浏览器: IE7, Safari 3.1, Firefox 2, Firefox 3. IE6 and Opera 9+ as-is. 许可: MIT/GPL 文件: 便携,节省资源,只有 6.5Kb. jWYSIWYG – jQuery
Official Website | Demo
jWYSIWYG,此插件是一个内置的内容编辑器,允许编辑HTML内容。这是一种替代WYMeditor与便捷实用的功能。文件大小不到 17Kb和26Kb总额只有9Kb 18Kb的代码和7Kb便携。 GNU General Public License v2 小巧轻便 支持Ajax的动态预览 兼容主流浏览器 Lightweight RTE- jQuery
Official Website | Demo
这一丰富文本编辑器尽可能的简单容易的改变我们基本的编辑需求。 超轻量级,只有 7kb 兼容主流浏览器 简洁,优雅 GNU General Public License HTMLBox – jQuery
Official Website | Demo
HTMLBox,跨浏览器的,开源的HTML / XHTML文本基础上的jQuery库。通过了Mozilla Firefox , Inrernet浏览器, Netscape和Safari浏览器的测试。一体化的HtmlBox易于集成到CMS,论坛,留言板,博客中。 易于集成 兼容主流浏览器. 大小只有 15kb (最小 11kb ) 支持XHTML输出. 支持Ajax的动态预览 有完整的用户手册,这将引导您完成每一步的整合HtmlBox到您的应用和定制它。 D Small Rich Text Editor – jQuery
Official Website | Demo
丰富的文本编辑器,应用了IFRAME元素,功能非常全,能满足我们复杂的文本编辑。 大小(~18k) ! (便携/Minified JS, Plugins & CSS合起来有12k w/o GZIP, HTML can be reduced to ~3k using GZIP, Images (w/o emoticons) are less than 3k) 兼容主流浏览器 支持所有的基本功能 支持插件功能 图片上传,通过AJAX 实现(使用的是 AjaxFileUpload plugin). 可以调整文本区域。 支持XHTML 1.0 验证 和 过滤(Note: this refers to the editor''s markup and not to it''s generated content which may or may not be valid!). 具有 HTML 修正功能 WYMEditor – jQuery
Official Website | Demo
WYMeditor是一个基于网络的WYSIWYM (你所看到的你的意思)的XHTML编辑器。 WYMeditor的主要概念是离开的细节文件的视觉版面,并把重点放在它的结构和意义,同时努力为用户提供舒适的文本编辑器 XHTML strict + CSS compliant 没有字体或文本格式, 大小或颜色 – 它们是基于您的css样式的 便于集成至您的应用程序中 无需安装,这是100 %的Javascript代码编写的-无插件,不延时 支持Image, link, table 支持 CSS 有APIs,支持插件 自由和开放源码 兼容主流浏览器 TinyMCE – non-jQuery
Official Website | Demo
TinyMCE是一个独立的平台,基于Web的Javascript的 HTML WYSIWYG编辑器,是开源的。超强的HTML文本或其他元素转换能力,以编辑实例。 易于集成-只需要几行代码 自定义-主题和插件,阻止无效的要素和属性。 兼容主流浏览器 – Mozilla, MSIE, FireFox, Opera, Safari and Chrome. 轻量级的 – PHP/.NET/JSP/Coldfusion GZip compressor, Makes TinyMCE 75% smaller and a lot faster to load. 兼容AJAX- Compatible – You can easily use AJAX to save and load content! 支持国际化 – Multilanguage support using language packs. 开源 – Free under the LGPL license, millions of ppl help test and improve this editor every day. fckeditor – Non-jQuery
Official Website | Demo
此HTML文本编辑器具有类似于MS Word一样的功能。它轻量级,无需安装 兼容主流浏览器 支持XHTML 1.0 可以定制自己的CSS 字体格式: type, size, color, style, bold, italic, etc 文本格式: alignment, indentation, bullets list, etc 支持 Cut, Paste, and Paste as Plain Text, Undo and Redo Paste from Word cleanup with auto detection 支持插入图片,上传,预览 单击右键有下拉菜单 支持 插件 有智能拼写检查程序 轻量级的和快速的 自动检测和个性化的浏览器 Yahoo YUI Rich Text Editor – Non-jQuery
Official Website | Demo
The Rich Text Editor是Yahoo YUI开发的,它可以取代标准HTML文本;支持文本字体选择,加粗,斜体 ,有序列表,无序列表,链接,拖放图片,工具栏通过插件是可扩展,能够实现高度的个性化设置. Xinha – Non-jQuery
Official Website | Demo
Xinha (pronounced like Xena, the Warrior Princess)是一个功能强大的所见即所得的HTML编辑器组件,在支持目前所有的浏览器。其configurabilty和可扩展性,可以很容易地 生成合适的内容,无限制
来源:http://blog.sn00py.cn/2010/03/10%e4%b8%aa%e5%9f%ba%e4%ba%8ejquery%e6%88%96javascript%e7%9a%84wysiwyg-%e7%bc%96%e8%be%91%e5%99%a8/
bootstrap + bootstrap-table + jquery + bootstrap-paginator
http://127.0.0.1:8848/pangBo/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
crossorigin="anonymous"></script>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.12.1/bootstrap-table.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.12.1/bootstrap-table.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.12.1/locale/bootstrap-table-zh-CN.min.js"></script>
<script src="js/bootstrap-paginator.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div>
<formrole="search">
<div>
<div>
<div>
<label>客户编号: </label>
<div>
<input type="text"placeholder="">
</div>
</div>
<div>
<label>客户姓名: </label>
<div>
<input type="text"placeholder="">
</div>
</div>
<div>
<label>手机号码: </label>
<div>
<input type="text"placeholder="">
</div>
</div>
</div>
<div>
<div>
<label>客户编号: </label>
<div>
<input type="text"placeholder="">
</div>
</div>
<div>
<label>客户编号: </label>
<div>
<input type="text"placeholder="">
</div>
</div>
<div>
<label>客户编号: </label>
<div>
<input type="text"placeholder="">
</div>
</div>
</div>
<div>
<button type="submit">查询</button>
</div>
</div>
</form>
</div>
<div>
<divrole="group" aria-label="...">
<button type="button" id="btn-one">可撤单</button>
<button type="button" id="btn-two">已撤单</button>
</div>
</div>
<div id="table-one">
<table id="table"></table>
<div>
<div id="example">
<ul id="pageLimit"></ul>
</div>
</div>
</div>
<div id="table-two">
<table id="table-ta-one"></table>
<div>
<div id="example-two">
<ul id="pageLimit-two"></ul>
</div>
</div>
</div>
<divid="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div>
<div>
<div>
<button type="button"data-dismiss="modal" aria-hidden="true">×</button>
<divid="myModalLabel">请输入登录密码:</div>
</div>
<div>
<div>
<input id="input-text" type="text" value=""placeholder="">
</div>
<button type="button" id="btn-ok">确定撤单</button>
</div>
</div>
</div>
</div>
</body>
</html>
<script type="text/javascript">
function operateFormatter(value, row, index) {
return [
''<button type="button"data-toggle="modal" data-target="#myModal">撤单</button>''
].join('''');
}
window.operateEvents = {
''click .RoleOfdelete'': function(e, value, row, index) {
console.log(''kkk'');
}
};
$(''#table'').bootstrapTable({
url: '''', //请求后台的URL(*)
method: ''GET'', //请求方式(*)
// toolbar: ''#toolbar'', //工具按钮用哪个容器
cache: false, //是否使用缓存,默认为true,所以一般情况下需要设置一下这个属性(*)
pagination: false, //是否显示分页(*)
// pageSize: 10, //每页的记录行数(*)
// pageNumber: 1, //初始化加载第一页,默认第一页,并记录
// sidePagination: "server", //分页方式:client客户端分页,server服务端分页(*)
uniqueId: "id", //每一行的唯一标识,一般为主键列
columns: [{
field: ''id'',
align: ''center'',
title: ''交易合同号''
},
{
field: ''ida'',
align: ''center'',
title: ''客户编号''
},
{
field: ''idb'',
align: ''center'',
title: ''客户姓名''
},
{
field: ''idc'',
align: ''center'',
title: ''手机号码''
},
{
field: ''idd'',
align: ''center'',
title: ''证件号码''
},
{
field: ''ide'',
align: ''center'',
title: ''产品代码''
},
{
field: ''idf'',
align: ''center'',
title: ''产品名称''
},
{
field: ''idg'',
align: ''center'',
title: ''购买金额''
},
{
field: ''idh'',
align: ''center'',
title: ''交易时间''
},
{
field: ''idi'',
align: ''center'',
title: ''撤单'',
events: operateEvents,
formatter: operateFormatter
},
],
data: [{
id: 1
},
{
id: 1
},
{
id: 1
}
],
onLoadError: function() {
showTips("数据加载失败!");
},
});
$(''#table-ta-one'').bootstrapTable({
url: '''', //请求后台的URL(*)
method: ''GET'', //请求方式(*)
// toolbar: ''#toolbar'', //工具按钮用哪个容器
cache: false, //是否使用缓存,默认为true,所以一般情况下需要设置一下这个属性(*)
pagination: false, //是否显示分页(*)
// pageSize: 10, //每页的记录行数(*)
// pageNumber: 1, //初始化加载第一页,默认第一页,并记录
// sidePagination: "server", //分页方式:client客户端分页,server服务端分页(*)
uniqueId: "id", //每一行的唯一标识,一般为主键列
columns: [{
field: ''id'',
align: ''center'',
title: ''交易合同号''
},
{
field: ''ida'',
align: ''center'',
title: ''客户编号''
},
{
field: ''idb'',
align: ''center'',
title: ''客户姓名''
},
{
field: ''idc'',
align: ''center'',
title: ''手机号码''
},
{
field: ''idd'',
align: ''center'',
title: ''证件号码''
},
{
field: ''ide'',
align: ''center'',
title: ''产品代码''
},
{
field: ''idf'',
align: ''center'',
title: ''产品名称''
},
{
field: ''idg'',
align: ''center'',
title: ''购买金额''
},
{
field: ''idh'',
align: ''center'',
title: ''交易时间''
}
],
data: [{
id: 1
},
{
id: 1
},
{
id: 1
}
],
onLoadError: function() {
showTips("数据加载失败!");
},
});
$(''#btn-one'').click(function() {
console.log(''kk'');
$(''#table-one'').show();
$(''#table-two'').hide();
$(''#btn-one'').css({
''background-color'': ''#e6e6e6''
})
})
$(''#btn-two'').click(function() {
console.log(''kkk'');
$(''#table-two'').show();
$(''#table-one'').hide();
$(''#btn-one'').css({
''background-color'': ''#FFF''
})
})
$(''#pageLimit'').bootstrapPaginator({
currentPage: 1, //当前的请求页面。
totalPages: 100, //一共多少页。
size: "normal", //应该是页眉的大小。
bootstrapMajorVersion: 3, //bootstrap的版本要求。
alignment: "right",
numberOfPages: 5, //一页列出多少数据。
itemTexts: function(type, page, current) { //如下的代码是将页眉显示的中文显示我们自定义的中文。
switch (type) {
case "first":
return "首页";
case "prev":
return "上一页";
case "next":
return "下一页";
case "last":
return "末页";
case "page":
return page;
}
}
});
$(''#pageLimit-two'').bootstrapPaginator({
currentPage: 1, //当前的请求页面。
totalPages: 100, //一共多少页。
size: "normal", //应该是页眉的大小。
bootstrapMajorVersion: 3, //bootstrap的版本要求。
alignment: "right",
numberOfPages: 5, //一页列出多少数据。
itemTexts: function(type, page, current) { //如下的代码是将页眉显示的中文显示我们自定义的中文。
switch (type) {
case "first":
return "首页";
case "prev":
return "上一页";
case "next":
return "下一页";
case "last":
return "末页";
case "page":
return page;
}
}
});
$(''#btn-ok'').click(function() {
var inputContent = $(''#input-text'').val();
if (inputContent == '''') {
alert(''密码不能为空 !'');
}
console.log(inputContent);
})
</script>
Bootstrap 可视化 HTML 编辑器,summernote
Bootstrap 可视化 HTML 编辑器之 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
效果图 2
效果图 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 dialogs dialogsInBody : true,// Dialogs can be placed in body, not in // summernote. disableDragAndDrop : false,// default false You can disable drag // and drop callbacks : { 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 dialogs dialogsInBody : 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上的action cache : 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); 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("<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); @Autowired private 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; @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<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''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 // Safari iframe.src == "javascript:''<html></html>'';") { // 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); }); }
贴上全部代码以供参考,但是这里我们只讲以下部分:
// 富文本编辑器
$("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>
页面效果为:
2、新版 iframeCallback 方法
var $form = $(form), $iframe = $("#callbackframe");
YUNM.debug("验证其他简单组件");
var data = $form.data(''bootstrapValidator''); if (data) { if (!data.isValid()) { return false; } } // 富文本编辑器 $("div.summernote", $form).each(function() { var $this = $(this); if ($this.summernote(''isEmpty'')) { } else { YUNM.debug($this.summernote(''code'')); // 使用base64对内容进行编码 // 1.解决复制不闭合的html文档,保存后显示错乱的bug // 2.解决文本中特殊字符导致的bug var editor = "<input type=''hidden'' name=''" + $this.attr("name") + "'' value=''" + $.base64.btoa($this.summernote(''code'')) + "'' />"; $form.append(editor); } }); YUNM.debug("验证通过");
比对之前的代码,可以发现代码有两处发生了变化:
- 当 summernote 为空时,之前没有做在 bootstrap 的 validator 中,是因为还没有搞清楚 summernote 这种非 input 标签在 validator 中的使用,下面会做详细说明。
- 对 summernote 的内容加上了 base64 编码处理,这会有很多好处,稍候介绍。
3、base64 的使用方法
js 端我在 Bootstrap wysiwyg 富文本数据如何保存到 mysql 这篇文章中做了说明,此处不再说明。
可能会有同学需要 javascript 端的 base64 编码,而需要在 springMVC 后端使用 base64 的解码,那么此处介绍一个 jar 包(Java Base64.jar),使用方法很简单,下载好 jar 包后,就可以使用如下方法解码:
import it.sauronsoftware.base64.Base64;
deal.setDescription(StringEscapeUtils.escapeHtml(Base64.decode(description, "utf-8")));
- 首先,base64 的 import 如上,来自于 javabase64.jar 包。
- decode 的编码前端 js 使用的 utf-8,此处自然也用 utf-8。
- 至于 StringEscapeUtils 类,也是一个非常实用的工具类,有兴趣的可详细关注一下(主要可以对 html 等等特殊标签进行转义)。
4、summernote 加入到 bootstrap validator 中
<div class="form-group">
<label for="" class="col-md-1 control-label">项目详情</label> <div class="col-md-10"> <div class="summernote" name="description" data-bv-excluded="false" data-bv-notempty placeholder="请对项目进行详细的描述,使更多的人了解你的云梦" action="${ctx}/file">${deal.description}</div> </div> </div>
- 注意 data-bv-excluded=”false”(由于 summernote 使用了 div 作为 form 表单的呈现形式,非一般的 input 标签,所以此处要将该 name=”description” 的 field 标识为非 excluded,默认的 validator 是不对 “[‘:disabled’, ‘:hidden’, ‘:not (:visible)’]” 三种标签做处理的,而 summernote 会默认作为 disabled 的一种,那么设置上 data-bv-excluded=”false” 后,validator 将会对 summernote 做非空的判断)、data-bv-notempty 属性。
- 当然有了上述两个属性后,并不能保证 validator 的有效性,那么接下来,请继续看。
onChange : function(contents, $editable) {
if ($this.parents().length > 0) { var $form = $this.parents().find("form.required-validate", $p); if ($form.length > 0) { var data = $form.data(''bootstrapValidator''); YUNM.debug($this.summernote(''isEmpty'')); if ($this.summernote(''isEmpty'')) { data.updateStatus($this.attr("name"), ''INVALID''); } else { data.updateStatus($this.attr("name"), ''VALID''); } } } }, onInit : function() { if ($this.parents().length > 0) { var $form = $this.parents().find("form.required-validate", $p); if ($form.length > 0) { var data = $form.data(''bootstrapValidator''); if (!$this.summernote(''isEmpty'')) { data.updateStatus($this.attr("name"), ''VALID''); } } } },
在 summernote 的 callbacks 中加入 onChange 、onInit,当文本域发生变化、初始化时,对 summernote 在 form 中的验证字段进行状态的更新,validator 中使用 updateStatus 方法。
/**
* Update all validating results of field
*
* @param {String|jQuery} field The field name or field element
* @param {String} status The status. Can be ''NOT_VALIDATED'', ''VALIDATING'', ''INVALID'' or ''VALID''
* @param {String} [validatorName] The validator name. If null, the method updates validity result for all validators
* @returns {BootstrapValidator}
*/
updateStatus: function(field, status, validatorName) {
OK,等补上以上两个内容后,整个 summernote 就完整了。
bootstrap-4 – Bootstrap 4:如何在没有jQuery / minimal bootstrap.js的情况下使用NavBars?
实际上,唯一需要的JS是用于处理移动请求中NAVBAR的打开/关闭的js.
有没有人创建了一个最小的,小的.js来处理这个?
我找到了一堆Bootstrap 3,但我没有看到Bootstrap 4.
谢谢
解决方法
https://thednp.github.io/bootstrap.native/v4.html
随着cdn
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/bootstrap.native@2.0.15/dist/bootstrap-native-v4.min.js"></script>
随着npm
运行命令:
npm install https://github.com/thednp/bootstrap.native
并导入:
var bsn = require(''bootstrap.native/dist/bootstrap-native-v4'');
今天关于jquery – 访问bootstrap-wysihtml5编辑器对象和jquery访问对象的方法的介绍到此结束,谢谢您的阅读,有关10个基于jQuery或JavaScript的WYSIWYG 编辑器整理_jquery、bootstrap + bootstrap-table + jquery + bootstrap-paginator、Bootstrap 可视化 HTML 编辑器,summernote、bootstrap-4 – Bootstrap 4:如何在没有jQuery / minimal bootstrap.js的情况下使用NavBars?等更多相关知识的信息可以在本站进行查询。
本文标签: