动手实现并开源IDEOnline——代码高亮【富文本编辑框】
来源:互联网 发布:mysql安装教程5.7.20 编辑:程序博客网 时间:2024/05/19 04:51
百度了很久,貌似类似的开源代码还没有人贡献(翻墙的不算),鄙人不才,尝试用了近期学的前端知识,做了这样一个简陋的代码编辑器,一是对之前所学知识的总结,二是抛砖引玉,期待能和大佬交流学习。
首先吹一下效果:
以上就是实际运行效果,根据输入的字段进行匹配,并将匹配成功的部分高亮显示(也就是关键字的高亮);对于数字,支持整数、浮点数、科学计数法,如图显示为原谅色(拿到源码的可以自行在css中进行修改)。支持WebKit内核的浏览器,支持高版本IE(测试使用的是IE11)。
另外,文档内容极简,如图:
常驻文档的只有一个可编辑div,不像别的在线ide那样,一个textarea一个div改z-index覆盖来覆盖去的……这里只有一个div,即使用到textarea,也是动态生成的,并且用完就被丢弃。(也正因此涉及到光标跑来跑去的,到处定位。这几天做的头皮发麻……不过好歹还是完成了。)
然后说一下缺陷:
1.对于匹配成功一次的字段,一旦设置完成了样式,不管对其内容进行何种修改,样式不会还原。比如:输入var ,变红,然后将它改成vasari,他还是红色的。
这个可以通过RegExp来debug掉,目前只会一点皮毛,先行放置,留待后续学习。
2.一个文字节点之后跟随的标点符号,会染上该节点的颜色,直到下一个文字节点为止。
这个bug属于我对键盘敲击事件的event.which分的不够细导致的,标点符号分起来太多了,我只是简单的写一下,理一理思路。
3.ctrl+V的文本有显示不全的问题,不过只是看起来不完全而已。这个出现的原因后面再说,免得各位看官不懂我在胡言乱语些什么。
4.欢迎各位大佬捉虫。
下面正式进入代码分析部分。
涉及到:少量css知识,少量HTML知识,JavaScript,jQuery。
可以收获:富文本编辑框的实现方式,富文本编辑框插入图片、链接的方法。
首先谈谈思路:
完整的一次编辑过程,从div获得焦点开始,到div写入带样式的文字结束。
div获得焦点
保存焦点位置
div开始编辑内容
输入文字(字母+数字)
生成textarea,焦点交给textarea
输入文字以外的内容
取出保存的div的位置,
插入textarea的文字和样式,
焦点挪到插入文字的后面,
删掉textarea。
div编辑完成。
这样就可以保证常驻文档的只有一个div,不存在任何被隐藏或遮盖的冗余文字。
上面的思路换算成文档事件的话也就是:
1.div的onkeydown事件,保存光标位置,在光标所在位置生成textarea,交付输入焦点;
保存光标位置:
首先在函数外创建一个变量rangeClone,用来保存这里的光标位置。
if(document.selection){
varsel = document.selection.createRange();
rangeClone=sel;
//IE
if(window.getSelection){
varsel = window.getSelection();
rangeClone=sel.getRangeAt(0);
//Chrome
然后要在光标位置生成textarea,则要获取到光标在文档的坐标位置,代码如下:(分别接在两个if后面)
//IE
if (sel.type !="Control") {
range= sel.createRange();
range.collapse(true);
x=range.boundingLeft;
y=range.boundingTop;
}
}
//Chrome
if (sel.rangeCount){
varrange = sel.getRangeAt(0).cloneRange();
if(range.getClientRects){
range.collapse(true);
varrects = range.getClientRects();
if(rects.length>0) {
varrect = rects[0];
}
//光标在行首时,rect为undefined
if(rect){
if(rect.left){
x=rect.left;
}
else{
x=8;
}
y=rect.top;
}
}
//回退并添加一个空节点
if((x == 0 && y==0)||rect === undefined) {
varspan = document.createElement("span");
if(span.getClientRects){
//向span添加一个宽度为0的空字符,确保span拥有内容和位置
span.appendChild(document.createTextNode("\u200b") );
range.insertNode(span);
rect= span.getClientRects()[0];
x=rect.left;
y=rect.top;
varspanParent=span.parentNode;
spanParent.removeChild(span);
spanParent.normalize();
}
}
}
}
这里有个很关键的点,我花了半个下午事件debug终于找出原因,写在注释部分了。也就是当输入了enter后,光标到首行,此时由于是空的节点,所以长度为零,rect也就未定义了。所以要在后面进行处理,即添加一个没有宽度的占位字符,辅助定位。
根据这里取到的x和y,就能确定即将生成的textarea应该定位在何处了,
if((event.which>=96&&event.which<=105)||(event.which>=48&&event.which<=57)||(event.which>=65&&event.which<=90)||(event.which>=97&&event.which<=122)){
//当输入字母,数字。
vartxt="<textareaclass='showText' style='position: absolute; top:"+y+"px;left:"+x+"px'></textarea>"
$("#showDiv").after(txt)
valClone=$("#showDiv").html();
varspanSeat= document.createElement('span');
spanSeat.innerHTML="   ";
spanSeat.setAttribute("id","spanSeat");
rangeClone.insertNode(spanSeat);
$(".showText").focus();
}
可以看到这里并不是简单的定义好x,y之后就结束了,后面那部分代码的作用是,在div的相同的位置生成一个span,作为占位符,避免在插入文字时,textarea的空间对div后面的内容遮盖(有兴趣可以尝试屏蔽一下看看效果。)
2.textarea的onkeydown事件,接收到字母数字时,保留字母数字,并扩展textarea的宽度(防止遮盖。这就是导致粘贴的文本显示不全的原因,textarea宽度是根据按了多少个键来增减的,ctrlA只有两个键,却增加了大量文本内容,自然就出现了显示不全的毛病。)代码分析如下:
if((event.which>=96&&event.which<=105)||(event.which>=48&&event.which<=57)||(event.which>=65&&event.which<=90)||(event.which>=97&&event.which<=122)){
//输入了文字,改变了文本框内容
var widthOld =parseInt($(".showText").css("width"));
$(".showText").css("width",widthOld+14+"px");
}
else if(event.which==8||event.which==46){
//按了Backspace或者delete
varwidthOld= parseInt($(".showText").css("width"));
$(".showText").css("width",widthOld-14+"px");
if($(".showText").val().length==1){
$(".showText").val("");
$(".showText").blur();
if(window.getSelection){
rangeClone=window.getSelection().getRangeAt(0);
rangeClone.selectNodeContents(spanOld);
rangeClone.setStart(spanOld,spanOld.length);
rangeClone.collapse(false);
window.getSelection().removeAllRanges();
window.getSelection().addRange(rangeClone);
}
}
}
else{
$(".showText").blur();
$("#showDiv").focus();
if(window.getSelection){
rangeClone=window.getSelection().getRangeAt(0);
rangeClone.selectNodeContents(spanOld);
rangeClone.setStart(spanOld,spanOld.length);
rangeClone.collapse(false);
window.getSelection().removeAllRanges();
window.getSelection().addRange(rangeClone);
}
}
简单来说就是分析按键的Unicode值,当输入字母数字时,扩展textarea的长度,
按下退格或者删除时,减少textarea的长度,并在其长度减少为0时,删去textarea节点。
而输入符号则代表需要关键字匹配的文字部分已经输入完毕了,此时把焦点交还给div,并把光标设置到div新增内容(保存在一个span节点中)之后,这样就完成了。
这里是通过range来实现光标位置设置的,首先将range锁定到刚添加的span上,此时相当于有一个蓝块包裹着span:span,就像这样。这个蓝块就是range,也就是我们平常鼠标拖动选择字段时的那个蓝块。然后把这个蓝块块的起点往后移动span的长度,光标也正是在这个起点处,因此光标就顺利的移动到了刚添加的span节点的末尾。接下来,只需要清除因为自动focus而生成的位于div头部的光标,然后在添加我们手动生成的这个光标,就达成了光标移动到刚添加的文字后面的效果。
3.textarea的onblur事件,主要做收尾工作,即复制和添加textarea的文字,样式,并保存到div,删除上面设置的占位节点,以及textarea。
$("body").on("blur",".showText",function(){
$("#showDiv").focus();
varspan = document.createElement('span');
span.setAttribute("class",regExp($(".showText").val()));
span.innerHTML=$(".showText").val();
rangeClone.insertNode(span);
spanOld=span;
$("#spanSeat").remove();
$(".showText").remove();
})
4.补充事件:textarea的onkeyup事件,因为在keyup的时候,textarea.val()的值才会更新,所以,需要在这里对占位符的内容进行设置,才能保证占位符的大小与textarea完全一致,既不出现遮盖,也不会断层,整齐美观。
$("body").on("keyup",".showText",function(){
document.getElementById("spanSeat").innerHTML=$(".showText").val();
})
对于占位符的文字,如何避免重影呢?css设置字体颜色为透明即可。
color:transparent;
css部分由于没有做太多设置,仅仅是对div盒子的几个参数设置了一下,在此就不赘述了。
以上,在线IDE的代码高亮部分就设置完成了,后面几天会研究下自动缩进,再后面会尝试用Ajax做代码补全。
- 动手实现并开源IDEOnline——代码高亮【富文本编辑框】
- summernote富文本编辑框
- 使用tinyMCE实现富文本编辑
- 富文本编辑框的使用
- 富文本编辑框的使用
- 基于jQuery和bootstrap的富文本编辑插件—summernote
- 富文本编辑
- iOS通过html模版实现富文本编辑
- Android实现EditText的富文本编辑
- label 富文本编辑 多个关键字高亮 (一些特殊的字符有可能匹配不到 如:*)
- 动手敲代码——链表(C语言实现)
- 动手写代码——基于Spark的TextRank实现
- Bootstrap 集成富文本编辑框(tinyeditor)
- 使用KindEditor创建富文本编辑框
- JavaScript示例八(富文本编辑框)
- summernote富文本编辑框的使用
- 百度富文本编辑框的使用
- Qt使用QTextEdit进行文本编辑实现查找高亮
- 阵列,配额与LVM
- &&重载实现寻找子集
- 【《Real-Time Rendering 3rd》 提炼总结】(六) 第七章 · 高级着色:BRDF及相关技术
- 文件流FileOutputStream类
- H5---js有哪些内置对象
- 动手实现并开源IDEOnline——代码高亮【富文本编辑框】
- Spring Boot实战学习笔记5
- iOS GCD中如何控制最大并发数
- 为什么模板不支持分离编译?
- 如何自己写一个公用的NPM包
- Hibernate01
- MySQL复制中因服务器ID重复报错(Last_IO_Errno: 1593)
- 基于C语言sprintf函数的深入理解
- kafka系列之集群部署使用(二)