基于contenteditable属性的简易web在线编辑器

web在线编辑器的实现有两种形式:一种基于iframe,另一种则基于contenteditable。

为元素设置contenteditable属性,可以让元素的区域内可编辑。

<div class="textareaByDiv" contenteditable></div>

设置可编辑区域的css属性,这里用less来写:

				.textareaByDiv{
					width: 1000px;
					height: 600px;
					border: 1px solid #bbb;
					padding: 10px;
					img{
						max-width: 300px;
					}
				}

在设置img的最大尺寸,以免在插入图片预览时,图片过大。

接下来为按钮的HTML代码,我原本采用bootstrap,但全部写在这里显得太乱,样式部分大家自己参照bootstrap文档来写,我这里只写和文本编辑器相关的内容。

<!-- 设置字体的按钮组 -->
<div class="btnsGroupOfEdit">
	<ul class="dropdown-menu">
		<li><a href="javascript:;" class="editBtn" data-edittype="fontname" data-editvalue="Microsoft YaHei">微软雅黑</a></li>
		<li><a href="javascript:;" class="editBtn" data-edittype="fontname" data-editvalue="KaiTi">楷体</a></li>
	</ul>
</div>
	<!-- 设置字号的按钮组 -->
<div class="btnsGroupOfEdit">
	<ul class="dropdown-menu">
		<li><a href="javascript:;" class="editBtn" data-edittype="fontsize" data-editvalue="7">一号</a></li>
		<li><a href="javascript:;" class="editBtn" data-edittype="fontsize" data-editvalue="6">二号</a></li>
		<li><a href="javascript:;" class="editBtn" data-edittype="fontsize" data-editvalue="5">三号</a></li>
		<li><a href="javascript:;" class="editBtn" data-edittype="fontsize" data-editvalue="4">四号</a></li>
		<li><a href="javascript:;" class="editBtn" data-edittype="fontsize" data-editvalue="3">五号</a></li>
		<li><a href="javascript:;" class="editBtn" data-edittype="fontsize" data-editvalue="2">六号</a></li>
		<li><a href="javascript:;" class="editBtn" data-edittype="fontsize" data-editvalue="1">七号</a></li>
	</ul>
</div>
	<!-- 设置颜色的按钮组 -->
<div class="btnsGroupOfEdit">
	<ul class="dropdown-menu color-drop-menu">
		<li><a href="javascript:;" class="editBtn" data-edittype="forecolor" data-editvalue="#000">颜色1</a></li>
		<li><a href="javascript:;" class="editBtn" data-edittype="forecolor" data-editvalue="#FF0036">颜色2</a></li>
		<li><a href="javascript:;" class="editBtn" data-edittype="forecolor" data-editvalue="#B5B527">颜色3</a></li>
		<li><a href="javascript:;" class="editBtn" data-edittype="forecolor" data-editvalue="#4F4FD9">颜色3</a></li>
		<li><a href="javascript:;" class="editBtn" data-edittype="forecolor" data-editvalue="#1FAF56">颜色4</a></li>
	</ul>
</div>

<div class="btnsGroupOfEdit">
	<button type="button" class="editBtn bold " data-edittype="bold">
		粗体
	</button>
	<button type="button" class="editBtn italic" data-edittype="italic">
		斜体
	</button>
	<button type="button" class="editBtn underline" data-edittype="underline">
		下划线
	</button>
    <button type="button" class="editBtn removeFormat" data-edittype="removeformat">
      	清空格式
    </button>
    <button type="button" class="editBtn" data-edittype="justifyleft">
    	左对齐
	</button>
	<button type="button" class="editBtn" data-edittype="justifycenter">
		居中
	</button>
</div>


<div class="btnsGroupOfEdit">
	<!-- 按下按钮时,弹出弹出框输入url -->
	<button type="button" class="showPopWinOfEdit">
		插入链接
	</button>
	<div class="popWinOfEdit hide">
		<input type="text" class="form-control" id="exampleInputName2" placeholder="输入url">
		<button type="button" class="editBtn" data-edittype="createlink">确定</button>
	</div>
</div>

<div class="btnsGroupOfEdit">
	<button type="button" class="editBtn" data-edittype="formatblock" data-editvalue="<pre>"></>插入代码</button>
</div>

	<!-- 插入图片按钮 -->
<button type="button" class="imgBtn">
  	<span class="glyphicon glyphicon-picture" aria-hidden="true">
  		<input type="file" id="exampleInputName2" placeholder="输入url">
  	</span>
</button>

按钮效果如下:

在按钮的HTML源码中,

我们通过btnsGroupOfEdit以及editBtn来找到按钮,通过data-edittype来确定操作类型,如果操作需要设置值,则通过data-editvalue来设置。

我们采用jquery事件委托的方式,具体代码如下:

	//文本编辑域
	var btnsGroupOfEdit = $('.btnsGroupOfEdit')
	var editType = null
	var editValue = null
	var editer = null
	var fileInput = btnsGroupOfEdit.find('input[type=file]')

	btnsGroupOfEdit.on('click', '.editBtn', function(event) {
		event.preventDefault();
		/* Act on the event */
		editType = $(event.currentTarget).data('edittype')

		switch(editType){
			case 'forecolor':
			case 'fontname':
			case 'fontsize':
			case 'formatblock':
				editValue = $(event.currentTarget).data('editvalue')
				console.log('emit')
				
				break
			case 'insertimage'://图片上传不在这里解决,放在下面input的change监听事件中单独解决
			case 'createlink':
				var parent = $(event.currentTarget).parents('.popWinOfEdit')
				var inputText = parent.children('input[type=text]')
				editValue = inputText.val()
				//找到文本域并聚焦
				var contentBox = parent.parents('.contentBox')
				editer = contentBox.find('.textareaByDiv')
				console.log(editer)
				editer.focus();
				checkPopWinOfEdit($(event.currentTarget))
				break
			default:
				editValue = null
		}
		document.execCommand(editType,false,editValue)
	});

jquery事件委托有一点要注意,event.target是你实际点击到的目标,event.currentTarget是你绑定的目标,无论你点击的是什么,都可以通过事件冒泡来触发event.currrentTarget,因而我们在这里使用event.currentTarget。

由于有的富文本操作有值,有的富文本操作没有值,这里我们采用swich语句来分类处理。

由于“设置链接”会弹出一个模态框让用户输入url,在模态框按下确定按钮时,模态框会消失,checkPopWinOfEdit()函数来实现模态框的出现和消失,函数的具体细节如下:

	function checkPopWinOfEdit(target){
		var parent = target.parents('.btnsGroupOfEdit')
		var popWinOfEdit = parent.children('.popWinOfEdit')
		if (popWinOfEdit.hasClass('hide')) {
			popWinOfEdit.removeClass('hide')
		}else{
			popWinOfEdit.addClass('hide')
		}
	}

此外还要为模态框的激活按钮绑定事件:

	showPopWinOfEdit.click(function(event) {
		/* Act on the event */
		event.stopPropagation()
		checkPopWinOfEdit($(this))
	});

对于图片上传按钮,我们使用一个<button>来包裹一个<input type="file">,通过css使得<button>的样式覆盖<input type="file">的样式。在点击的时候却实际上点击的是<input type="file">,CSS的代码很简单大家就自己想办法调啦~

图片上传后,用对象url的方法插入到编辑域以实现预览。具体这部分的内容,请参考我的另一篇博文《使用对象URL实现本地预览图片

图片预览的源码如下:

	//上传图片预览
	//还需要将图片上传到后台
	fileInput.change(function(event) {
		/* Act on the event */
		var files = this.files
		var url = window.URL.createObjectURL(files[0])
		//聚焦文本框
		var contentBox = $(this).parents('.contentBox')
		editer = contentBox.find('.textareaByDiv')
		editer.focus();
		 if (url) {  
        	if (/image/.test(files[0].type)) {    //如果上传的文件类型为image  
            	document.execCommand('insertimage',false,url)
        	}else{  
            	alert('please upload a picture!')  
        	}  
    	}else{  
        	alert('your browser doesnt support obj urls!')
    	}  
	});

最后,一个非常粗糙的web文本编辑器就实现了!除了图片插入,基本上其他按钮都是选中后单击有效。尤其是插入代码按钮,如果直接点击的话,似乎文本域后面所有的内容都在<pre>中。对于我们这里的插入代码功能,一定要先将代码粘贴到文本域之后,选中后再编辑哦!


----------------------------------------------------------------------------------

2017-7-1更新,实现功能:将富文本编辑器区域里的内容通过表单提交到服务器,并在展示页面中显示出来。

由于富文本编辑器区域里的内容不是表单的元素,因此在提交的时候需要通过submit事件将区域内的内容取出来,放到type="hidden"的<input>中,具体jquery代码如下:

//博文数据提交
	var form = $('.hasTextArea')
	form.submit(function(event){
		// event.preventDefault()
		var contentBody = form.children('.hiddenContentBody')//获取隐藏的input
		var textArea = form.children('.textareaByDiv')//获取富文本区域
		contentBody.val(textArea.html())//将富文本编辑器的内容赋值给隐藏的input

	})

其实以上代码只是《javascript高级程序设计》里这部分内容的jquery代码实现而已,而且基本上代码量也没少。

用submit事件而不用click事件的原因在于,浏览器的差异性导致click事件可能在表单提交之后发生,因此这里我们用submit事件。

最后,在服务器给富文本内容的数据类型定义为字符串即可,即

content:String

我使用的是jade模板进行渲染,如果直接将数据作为渲染元素的话,会出现渲染两次的情况,并且格式也有可能乱掉,这是我失败的渲染方式:

#{article.content}

经过一番查找,并没有发生重复提交的现象,我猜测多半是由于jade模板的渲染问题。因此我改变了一下思路,将数据放在页面上的一个<input type="hidden">中,然后在页面载入完成时候,将该<input>中的值取出来插入到容器中,以下是代码:

$(document).ready(function(){
	var html = $('.hiddenContent').val()
	var box = $('.htmlBox')
	box.append(html)
})

是不是非常非常简单?这样一个完整的富文本编辑器就实现了!

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值