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 ...
随机推荐
- 关于CentOS 7安装jdk1.8
安装之前先检查一下系统有没有自带open-jdk 命令: rpm -qa |grep java rpm -qa |grep jdk rpm -qa |grep gcj 如果没有输入信息表示没有安装. ...
- E20180306-hm-xa
base n. 基地; 基础; 根据; 基数(如十进制的10 和二进制的2) designate vt. 指派; 指明,指出; 表明,意味着; 把…定名为;
- bzoj 4078: [Wf2014]Metal Processing Plant【二分+2-SAT+枚举+并查集】
枚举从大到小s1,二分s2(越大越有可能符合),2-SAT判断,ans取min 思路倒是挺简单的,就是二分的时候出了比较诡异的问题,只能二分s2的值,不能在数组上二分... 有个优化,就是当不是二分图 ...
- 动态规划:最大连续子序列乘积 分类: c/c++ 算法 2014-09-30 17:03 656人阅读 评论(0) 收藏
题目描述: 给定一个浮点数序列(可能有正数.0和负数),求出一个最大的连续子序列乘积. 分析:若暴力求解,需要O(n^3)时间,太低效,故使用动态规划. 设data[i]:第i个数据,dp[i]:以第 ...
- 08 H5新增input元素
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- linux安装glassfish并布署
1 https://glassfish.java.net/download.html 2 准备工作:需要jdk7以上版本 Java EE 7 requires JDK 7 (or above) 下载g ...
- win7 系统 右键很慢
一般都是显卡驱动造成的, 在桌面按右键反应慢,通常都是显卡驱动程序惹的祸,最最简单有效的办法就是:开始--运行--. 运行regsvr32 /u igfxpph.dll
- HDU 5996 博弈
http://acm.hdu.edu.cn/showproblem.php?pid=5996 博弈论待补. 这题变化了一下,因为注意到奇数层的东西(层数从1开始),对手可以模仿地动,那就相当于没动. ...
- AJPFX总结关于Java中过滤出字母、数字和中文的正则表达式
1.Java中过滤出字母.数字和中文的正则表达式 (1)过滤出字母的正则表达式 [^(A-Za-z)] (2) 过滤出 数字 的正则表达式 [^(0-9)] (3) 过滤出 中文 的正则 ...
- vue-cli 3 配置打包环境
从新建项目到设置打包环境 1.vue create vue-cli-env 2.新建 vue.config.js 文件,设置baseUrl: './' 3.新建各个环境的文件,例如:.env.deve ...