bootstrap-wysiwyg是一款轻量级的富文本编辑插件,大致长这样

uniapp springboot 富文本显示 bootstrap富文本编辑器插件_css


在此记录一下我使用它踩过的坑和经验。

插件的引入

插件其实分为两部分:顶部的一系列编辑按钮和下方的div编辑框
前台代码如下:

<div style="height: 50px;"></div>
	<!--这里加上是为了让提示信息显示 不然会被遮挡-->
	<div class="btn-toolbar" data-role="editor-toolbar"
		data-target="#editor">
		<div class="btn-group">
			<a class="btn dropdown-toggle" data-toggle="dropdown" title="Font"><i
				class="icon-font"></i><b class="caret"></b></a>
			<ul class="dropdown-menu">
			</ul>
		</div>
		<div class="btn-group">
			<a class="btn dropdown-toggle" data-toggle="dropdown"
				title="Font Size"><i class="icon-text-height"></i> <b
				class="caret"></b></a>
			<ul class="dropdown-menu">
				<li><a data-edit="fontSize 5"><font size="5">Huge</font></a></li>
				<li><a data-edit="fontSize 3"><font size="3">Normal</font></a></li>
				<li><a data-edit="fontSize 1"><font size="1">Small</font></a></li>
			</ul>
		</div>
		<div class="btn-group">
			<a class="btn" data-edit="bold" title="Bold (Ctrl/Cmd+B)"><i
				class="icon-bold"></i></a>
			<!--加粗-->
			<a class="btn" data-edit="italic" title="Italic (Ctrl/Cmd+I)"><i
				class="icon-italic"></i></a>
			<!-- 斜体-->
			<a class="btn" data-edit="strikethrough" title="Strikethrough"><i
				class="icon-strikethrough"></i></a>
			<!-- 删除线-->
			<a class="btn" data-edit="underline" title="Underline (Ctrl/Cmd+U)"><i
				class="icon-underline"></i></a>
			<!-- 下划线-->
		</div>
		<div class="btn-group">
			<a class="btn" data-edit="insertunorderedlist" title="Bullet list"><i
				class="icon-list-ul"></i></a>
			<!-- 加点-->
			<a class="btn" data-edit="insertorderedlist" title="Number list"><i
				class="icon-list-ol"></i></a>
			<!-- 数字排序-->
			<a class="btn" data-edit="outdent" title="Reduce indent (Shift+Tab)"><i
				class="icon-indent-left"></i></a>
			<!-- 减少缩进-->
			<a class="btn" data-edit="indent" title="Indent (Tab)"><i
				class="icon-indent-right"></i></a>
			<!--增加缩进-->
		</div>
		<div class="btn-group">
			<a class="btn" data-edit="justifyleft"
				title="Align Left (Ctrl/Cmd+L)"><i class="icon-align-left"></i></a>
			<!--左对齐-->
			<a class="btn" data-edit="justifycenter" title="Center (Ctrl/Cmd+E)"><i
				class="icon-align-center"></i></a>
			<!--居中-->
			<a class="btn" data-edit="justifyright"
				title="Align Right (Ctrl/Cmd+R)"><i class="icon-align-right"></i></a>
			<!--右对齐-->
			<a class="btn" data-edit="justifyfull" title="Justify (Ctrl/Cmd+J)"><i
				class="icon-align-justify"></i></a>
			<!--垂直对齐-->
		</div>
		<div class="btn-group">
			<a class="btn dropdown-toggle" data-toggle="dropdown"
				title="Hyperlink"><i class="icon-link"></i></a>
			<!-- 链接-->
			<div class="dropdown-menu input-append">
				<input class="span2" placeholder="URL" type="text"
					data-edit="createLink" />
				<button class="btn" type="button">Add</button>
			</div>
			<a class="btn" data-edit="unlink" title="Remove Hyperlink"><i
				class="icon-cut"></i></a>
		</div>
		<div class="btn-group">
			<a class="btn" title="Insert picture (or just drag & drop)"
				id="pictureBtn"><i class="icon-picture"></i></a> <input type="file"
				data-role="magic-overlay" data-target="#pictureBtn"
				data-edit="insertImage" />
		</div>
		<div class="btn-group">
			<a class="btn" data-edit="undo" title="Undo (Ctrl/Cmd+Z)"><i
				class="icon-undo"></i></a>
			<!--撤销-->
			<a class="btn" data-edit="redo" title="Redo (Ctrl/Cmd+Y)"><i
				class="icon-repeat"></i></a>
			<!--恢复-->
		</div>
		<input type="text" data-edit="inserttext" id="voiceBtn"
			x-webkit-speech="">
	</div>

	<div id="editor">${content}</div>

下面需要引入插件运行所需的css和js

<link
	href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.no-icons.min.css"
	rel="stylesheet">
<link type="text/css" rel="stylesheet"
	href="${ctxStatic}/editor/index.css" />

<link rel="stylesheet"
	href="http://netdna.bootstrapcdn.com/font-awesome/3.0.2/css/font-awesome.css">
<link type="text/css" rel="stylesheet"
	href="${ctxStatic}/editor/prettify.css" />
<link type="text/css" rel="stylesheet"
	href="${ctxStatic}/bootstrap/2.3.1/css_default/bootstrap-responsive.min.css" />



<script
	src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/2.0.0-beta1/js/bootstrap-select.js"></script>
	
<script type="text/javascript"
	src="${ctxStatic}/editor/bootstrap-wysiwyg.js"></script>
	
<script type="text/javascript"
	src="${ctxStatic}/editor/jquery.hotkeys.js"></script>

<script type="text/javascript"
	src="${ctxStatic}/bootstrap/2.3.1/js/bootstrap.min.js"></script>
	
<script type="text/javascript"
	src="${ctxStatic}/bootstrap/2.3.1/js/bootstrap.js"></script>

这里有一个坑,网上的教程只提到了引入bootstrap.min.js
如果不额外引入bootstrap.js,会无法使用字体切换的js方法。

下面是一些js函数:

$(function() {
			function initToolbarBootstrapBindings() {
				var fonts = [ 'Serif', 'Sans', 'Arial', 'Arial Black', 'Courier',
						'Courier New', 'Comic Sans MS', 'Helvetica', 'Impact', 'Lucida Grande', 'Lucida Sans', 'Tahoma', 'Times',
						'Times New Roman', 'Verdana' ],
					fontTarget = $('[title=Font]').siblings('.dropdown-menu');
				$.each(fonts, function(idx, fontName) {
					fontTarget.append($('<li><a data-edit="fontName ' + fontName + '" style="font-family:\'' + fontName + '\'">' + fontName + '</a></li>'));
				});
				$('a[title]').tooltip({
					container : 'body'
				});
				$('.dropdown-menu input').click(function() {
					return false;
				}).change(function() {
					$(this).parent('.dropdown-menu').siblings('.dropdown-toggle').dropdown('toggle');
				}).keydown('esc', function() {
					this.value = '';
					$(this).change();
				});

				$('[data-role=magic-overlay]').each(function() {
					var overlay = $(this),
						target = $(overlay.data('target'));
					overlay.css('opacity', 0).css('position', 'absolute').offset(target.offset()).width(target.outerWidth()).height(target.outerHeight());
				});
				$('#voiceBtn').hide();

			}
			;
			initToolbarBootstrapBindings();
			$('#editor').wysiwyg();
			window.prettyPrint && prettyPrint();
		});

引入这些之后,页面应该可以正常显示富文本编辑器了

实现保存到数据库并回显

接下来我需要实现将富文本编辑器的内容存到数据库,然后可以再次读取出来进行回显。
首先进行存储,我打算将整个富文本编辑框中的html元素全部存储到数据库,因为它本身就是个div。这里我使用了mysql数据库,在表中加了一个mediumblob类型的字段,最大能存储16m的数据。

写一个js函数,获取div中的html元素,并调用ajax接口进行保存。

$(function() {
		$("#btnSubmit").click(function() {
			var title = document.getElementById("title").value;
			var content = document.getElementById("editor").innerHTML;
			var id = document.getElementById("hid").value;
			$.ajax({
				url : '${ctx}/article/articleContent/savearticle',
				type : 'post',
				async : false,
				dataType : 'json',
				data : {
					title : title,
					content : content,
					id:id
				},
				success : function(data) {
					if(data==1){
					  window.location.href="${ctx}/article/articleContent/list"
					}
					else{
					  alert("保存失败!");
					}
				},
				error : function(){
				   alert("保存失败!");
				}
			});
		});
	});

这样就成功的保存到了数据库~
这里需要注意:上面这个ajax传递的content
var content = document.getElementById(“editor”).innerHTML;
已经对html元素做了转义,直接存入数据库即可。

回显数据
在我打算对文章进行修改时,我需要读取数据库中保存的数据,一开始我只是直接读取数据库的数据,没做任何处理,发现一些html标签显示为“?”查找网上资料得知,需要进行反转义,将数据库中的数据转化为html元素。
String contentString = StringEscapeUtils.unescapeHtml4(articleContent.getContent()); 这就是反转义

中文乱码
之后我又遇到了中文乱码的问题,输出一下日志发现存入的是正常的中文,但读取出来中文就变成乱码了,这肯定和blob有关,写一个处理blob类型的字符转换工具类

import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;



public class MyBlobTypeHandler extends BaseTypeHandler<String> {  
    //###指定字符集  
    private static final String DEFAULT_CHARSET = "utf-8";  

    public void setNonNullParameter(PreparedStatement ps, int i,  
            String parameter, JdbcType jdbcType) throws SQLException {  
        ByteArrayInputStream bis;  
        try {  
            //###把String转化成byte流  
            bis = new ByteArrayInputStream(parameter.getBytes(DEFAULT_CHARSET));  
        } catch (UnsupportedEncodingException e) {  
            throw new RuntimeException("Blob Encoding Error!");  
        }     
        ps.setBinaryStream(i, bis, parameter.length());  
    }  

    @Override  
    public String getNullableResult(ResultSet rs, String columnName)  
            throws SQLException {  
        Blob blob = (Blob) rs.getBlob(columnName);  
        byte[] returnValue = null;  
        if (null != blob) {  
            returnValue = blob.getBytes(1, (int) blob.length());  
        }  
        try {  
            //###把byte转化成string  
            return new String(returnValue, DEFAULT_CHARSET);  
        } catch (UnsupportedEncodingException e) {  
            throw new RuntimeException("Blob Encoding Error!");  
        }  
    }  

    public String getNullableResult(CallableStatement cs, int columnIndex)  
            throws SQLException {  
        Blob blob = (Blob) cs.getBlob(columnIndex);  
        byte[] returnValue = null;  
        if (null != blob) {  
            returnValue = blob.getBytes(1, (int) blob.length());  
        }  
        try {  
            return new String(returnValue, DEFAULT_CHARSET);  
        } catch (UnsupportedEncodingException e) {  
            throw new RuntimeException("Blob Encoding Error!");  
        }  
    }

    @Override
    public String getNullableResult(ResultSet rs, int columnIndex)
            throws SQLException {
        // TODO Auto-generated method stub
        return null;
    }




}

然后需要在mapper.xml中显式的说明content字段的typeHandler
<result column="content" property="content" typeHandler="com.common.utils.MyBlobTypeHandler" />

发现中文乱码问题就解决了~

后记:
页面中使用了bootstrap的fileinput插件,导致富文本框的右侧工具栏无法点击,但是台式机一切正常,我使用的是笔记本电脑,我以为是分辨率导致的问题。请教了公司的前端大神,发现。。。
这是由于fileinput插件的js封装了一个
模态框,默认的class是fade,这个隐藏的模态框在笔记本的分辨率下正好挡住了富文本框右侧的工具栏。
解决方法:在fileinput插件的初始化js函数下添加一行代码如下:

$("#imgInput").fileinput({
			showUpload : false,
			dropZoneEnabled : false,
			language : 'zh', //设置语言
			maxFileCount : 1,
			mainClass : "input-group-lg",
			allowedFileExtensions : [ 'jpg', 'gif', 'png', 'bmp', 'jpeg' ], //接收的文件后缀
			elErrorContainer : '#file-errors',
		});
		$("#kvFileinputModal").hide()

kvFileinputModal就是那个隐藏的模态框的id