DIV可编辑后,与限制输入及光标偏移的纠葛
前言
最近在弄个人的网站,偶然间发现DIV可以设置编辑模式,之前设计的方案在此功能上需要限制输入的长度。网上搜索了一波,综合搜索的结果,考虑使用的监听事件有:keydown 、textInput 、input。因为可能输入中文,所以也要监听compositionstart和compositionend两个事件。
在试用过程中,发现:
- Keydown是监控到键盘的输入出发,调用顺序在compositionstart和compositionend之间,导致无法对中文的输入进行实时的监控。
- textInput和keydown一样,对中文一样无力,而且无法对粘贴进行监控。
- Input能对所有value改变事件进行监控,但是不支持撤销功能。
不用想,肯定选择范围最宽的'Input'了,没有撤销?那就实现一个。
思路及实现
撤销在文本框的直接感觉回到操作之前的文本(Ps:这里只考虑字符串的增加操作)。那将上一步添加的数据删除,已达到撤销相同的效果不就可以了。那么首先要得到上一步操作时光标位置的初始位置以及光标的偏移量,然后对操作后的字符串中添加的字串移除不就可以了。 顺着这个思路得到下面的代码。
var content = document.getElementById('add-content')
//注册中文的输入事件,
var isCN = false;
content.addEventListener('compositionstart',function(){
isCN = true;
});
content.addEventListener('compositionend',function(){
isCN = false;
})
//注册文本输入事件,获取光标的起止偏移数据,如果是非中文以及超出长度的输入,则撤销本次操作
var txtAnchorOffset, txtFocusOffset;
content.addEventListener("textInput",function(event){
var _sel = document.getSelection();
txtAnchorOffset = _sel.anchorOffset;
txtFocusOffset = _sel.focusOffset;
//必须加上isCN的判断,否则获取不到正确的光标数据
if(!isCN && this.textContent.length >= noteMax){
event.preventDefault();
}
}); //注册输入事件,对输入的数据进行
content.addEventListener("input",function(event){
setTimeout(function(){
if(!isCN){
var _this = content;
if(_this.textContent.length > noteMax){
var data = _this.textContent;
oldDate = data.slice(, txtAnchorOffset) + data.slice(txtFocusOffset, data.length);
//再次截取最大长度字符串,防止溢出
_this.textContent = oldDate.slice(, noteMax);
}
}
}, );
});
Emmmm,的确能移除了,但是光标却回到了字符串的开始位置。这可不行,这样不就成了阉割版的了吗? 继续查询网上移动文本域光标的实现方法,move()、setSelectionRange()在运行的时候都提示” xx is not a funtion”,网上查询后,好像说是只支持input和textarea标签。
后面在MDN官方文档上看到这个函数:
Selection.collapse(); 参数:parentNode光标落在的目标节点 offset 落在节点的偏移量。
有了函数,那就来开干!!
//注册输入事件,对输入的数据进行
content.addEventListener("input",function(event){
setTimeout(function(){
if(!isCN){
var _this = content;
if(_this.textContent.length > noteMax){
var data = _this.textContent;
oldDate = data.slice(, txtAnchorOffset) + data.slice(txtFocusOffset, data.length);
//再次截取最大长度字符串,防止溢出
_this.textContent = oldDate.slice(, noteMax);
//光标移动到起始偏移位置
document.getSelection().collapse(_this.firstChild, txtAnchorOffset);
}
}
}, );
});
注意:parentNode参数选择文本节点。
开始的时候,我传的值是_this,提示“Failed to execute 'collapse' on 'Selection': There is no child at offset X.”,后面,在debugger中发现文本域是div对象的子节点,有想法就去尝试。改成_this.firstChild后,目标达成。
到此基本上已经完成功能的设计,然后在加上移除粘贴内容就行了。完成的代码如下:
html
<div id="add-content" contenteditable="true" ></div>
Javascript
var content = document.getElementById('add-content')
//注册中文的输入事件,
var isCN = false;
content.addEventListener('compositionstart',function(){
isCN = true;
//撤销预输入内容,必须否则会替代末尾字符
if(this.textContent.length >= noteMax){
event.preventDefault();
}
});
content.addEventListener('compositionend',function(){
isCN = false;
})
//注册文本输入事件,获取光标的起止偏移数据,如果是非中文以及超出长度的输入,则撤销本次操作
var txtAnchorOffset, txtFocusOffset;
content.addEventListener("textInput",function(event){
var _sel = document.getSelection();
txtAnchorOffset = _sel.anchorOffset;
txtFocusOffset = _sel.focusOffset;
//必须加上isCN的判断,否则获取不到正确的光标数据
if(!isCN && this.textContent.length >= noteMax){
event.preventDefault();
}
});
//注册粘贴事件,获取粘贴数据的长度
var pastedLength;
content.addEventListener("paste",function(event){
if(!event.clipboardData) return;
pastedLength = event.clipboardData.getData('Text').length;
}); //注册输入事件,对输入的数据进行
content.addEventListener("input",function(event){
setTimeout(function(){
if(!isCN){
var _this = content;
if(_this.textContent.length > noteMax){
var data = _this.textContent;
if(pastedLength > ){
oldDate = data.slice(, txtAnchorOffset) + data.slice(txtFocusOffset+pastedLength, data.length);
//粘贴字符串长度置为0,以免影响到下一次判断。
pastedLength = ;
} else {
oldDate = data.slice(, txtAnchorOffset) + data.slice(txtFocusOffset, data.length);
}
//再次截取最大长度字符串,防止溢出
_this.textContent = oldDate.slice(, noteMax);
//光标移动到起始偏移位置
document.getSelection().collapse(_this.firstChild, txtAnchorOffset); }
}
}, );
});
总结
在这次的编码中,其实试过很多个方法,尤其是光标那一部分,失败了很多次。然后继续搜索寻找方法。最后还是在官方文档里面找到突破点,网上很多经验都是别人消化并根据自己的理解写出来的,官方文档却是原滋原味的,所以一定要以官方文档为参照,不要迷失方向。 中间其实曾放弃了一次,将div改成textarea光标一下子就能正确偏移了。但是想了一下,还是重新改成div,继续出发,继续寻找正确的方向,最后终于完成了想要的功能。
有想法就去实现它!!!成功了,能收获喜悦;不成功,也能在途中拓宽自己的知识面。还有,最好有个地方将其记录并分享出来,不管是成功或失败。成功的经验,或许能帮助到他人;失败的记录,或许能获得他人的帮助,然后再去完成它。
DIV可编辑后,与限制输入及光标偏移的纠葛的更多相关文章
- 2python脚本在window编辑后linux不能执行的问题
参考简书博主天道酬勤abcd python脚本在windows编辑后,在linux下执行提示 /usr/bin/python^M: bad interpreter: No such file or d ...
- 子div设置float后导致父div无法自动撑开的问题
子div设置float后会导致父div无法自动撑开 原因:内部的DIV因为float:left之后,就丢失了clear:both和display:block的样式,所以外部的DIV不会被撑开. 以下是 ...
- 百度编辑器ueditor每次编辑后多一个空行的解决办法
用ueditor进行编辑文章时,每次编辑后文章前面都会多出一个空行. <script id="editor" type="text/plain" styl ...
- WPF 自带Datagrid编辑后无法更新数据源的问题
原文 WPF 自带Datagrid编辑后无法更新数据源的问题 解决办法: 在列的绑定属性里加上UpdateSourceTrigger,示例XAML如下 <DataGrid Grid.Row=& ...
- elementUi中input输入字符光标在输入一个字符后,光标失去焦点
elementUi中input输入字符光标在输入一个字符后,光标就退出,无法输入需要再次聚焦然后输入一个字符又再次退出 首先,用elementUi正常用v-model绑定输入的值是不会造成光标退出的, ...
- 编辑后保留原URl搜索条件
首先需要知道的一个知识点: 1.request.GET是一个QueryDict类型的,要想取出?后面的结构就用request.GET.urlencode() 2.request.GET默认是不可修改的 ...
- 在.txt文件的首行写上.LOG后,后面每次对改文本文件进行编辑后,系统会自动在编辑内容后记录操作时间
在.txt文件的首行写上.LOG后,后面每次对改文本文件进行编辑后,系统会自动在编辑内容后记录操作时间
- PyCharm编辑HTML文件时输入{%不能自动补全
在PyCharm编辑HTML文件时输入Django模板语言时,发现录入 {% 不能自动补全. 找了一下,发现 setting 里可以设置 Python Template Languages,选择自己使 ...
- appium-清空输入框的内容后,再次输入内容会回退最后两个字符串
问题描述 有两个输入框,用户名和密码输入框 调用set_text方法,输入用户名 再次调用set_text方法,输入密码 清空用户名输入框的内容后,再次输入内容会回退最后两个字符串 出问题的代码 de ...
随机推荐
- npm i macaca-android -g 无法安装成功、安装成功后运行脚本提示app-debug.apk不存在的问题
转自https://testerhome.com/topics/8618Android 近期,macaca团队升级了macaca-android2.0.2和app-inspector1.2.28 ,导 ...
- artemplate include
include用于嵌入字模板 {{include 'template_name'}} 子模板 默认共享当前的数据 也可以自己指定数据 {{include 'template_name' templat ...
- Fiddler对https抓包时,提示"HTTPS decryption is disabled."原因及破解
Fiddler对https抓包时,提示"HTTPS decryption is disabled." 原因:没有启用 https 解密. 破解: ----------------- ...
- app 后台程序设计
限制客户端一分钟之内访问接口的次数 1.设备的唯一标识获取这个实际上IOS7后会存在问题,权限已经收回了,android可以2.唯一标识可以通过生成一个token区分3.每分钟的频率可以这样设置 ke ...
- flask请求访问数据
flask请求访问数据 在flask框架中,访问请求数据由全局的request对象来提供,在flask框架中,request对象具有 全局作用域: from flask import request ...
- Light oj 1002 Country Roads (Dijkstra)
题目连接: http://www.lightoj.com/volume_showproblem.php?problem=1002 题目描述: 有n个城市,从0到n-1开始编号,n个城市之间有m条边,中 ...
- 《linux就该这么学》学习笔记
本篇文章是根据刘遄老师的<linux就该这么学>中个人易忘知识点的读书笔记,结合的是个人弱点,可能不适合广大的网友同学,并在此声明本篇文章只是用于学习之用,绝无侵犯版权之意 linux就该 ...
- 洛谷 P2742 [USACO5.1]圈奶牛Fencing the Cows || 凸包模板
整篇都是仅做记录... 蓝书上的板子.水平序,单调栈.先求下凸包,再求上凸包.叉积的作用是判定向量的位置关系. 48行的作用是在求上凸包的时候不至于去删下凸包中的点.上凸包中第一个点被认为是t1. 另 ...
- WebSphere中数据源连接池太小导致的连接超时错误记录
WebSphere中数据源连接池太小导致的连接超时错误记录. 应用连接超时错误信息: [// ::: CST] webapp E com.ibm.ws.webcontainer.webapp.WebA ...
- Drawable(6)关于StateList的补充
模板: <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android=&quo ...