前两个月,公司内部需要开发关于大数据方面的辅助工具语料分词系统,在这个项目中遇到以下几个主要问题,在此分享~
一、input宽度根据内定文本宽度自适应
背景:项目需求中,前台展示,需要从后台获取的.txt文件解析成很多字符串,然后分别放在前台input框中,贴图:
其中,每一个字符串,长度不一,所以,input框要根据字符串的长度,发生变化,这里就要解决input自适应的问题了。
方法一:网上搜索的,误差很大,仅供参考~
然后,我又改善了一下,减小误差。
//字符串文本
var a1 = "人民网/nz 莫斯科/nsf 31日/t 电/n (/w 记者/nnt 屈海齐/nr )/w 据/p 俄新社/nt 报道/v ,/w 《/w [今日/t 俄罗斯/nsf]/nz 》/w (/w RussiaToday/x )/w [总裁/nnt德米特里·基谢廖夫/nrf决定]/v 任命/vn 玛格丽特·西莫尼/nrf 杨/ng 为/p 《/w [今日/t 俄罗斯/nsf]/nz 》/w 通讯社/nis 主编/v ,/w 同时/c 兼任/v 《/w [今日/t俄罗斯/nsf]/nz 》/w [电视/n 频道/n]/nz 主编/v 。/w 玛格丽特·西蒙尼扬/nrf 1980年/t 生于/v [克拉斯/nrf 诺达尔/nrf]/ns 。/w 毕业/v 于/p [库班/nrf 国立/b 大学/nis 新闻系//w 频道/n 主编/v 。/w 2013年12月9日/t ,/w [俄罗斯/nsf 总统/nnt]/nz 普京/nrf 下令/v 在/p 三个月/t 内/f 将/d 《/w 俄新社/nt 》/w 和/cc 《/w [俄罗斯/nsf 之/uzhi 声/qv]/nz 》/w 电台/nis 合并/v 为/p 《/w [今日/t 俄罗斯/nsf]/nz 》/w [国际/n 通讯社/nis]/nt 。/w ";
//把字符串根据空格整理成数组
var strArr = a1.split(" ");
console.log(strArr) for(var i= 0;i<=strArr.length;i++){
var ssd = strArr[i]
//数组元素存放容器
$("body").append('<div class="q1" style="display:inline-block;font-size:12px;fontFamily:"Serif""></div> ');
$(".q1").text(ssd) var wid =$(".q1").text(strArr[i]).width(); $(".q1").remove();
//获取宽度赋值给input宽度
$(".a1").append($('<input type="text">').val(strArr[i]).css({
width: wid +18 ,
fontSize: "12px",
fontFamily:"Serif",
boxSizing:"border-box",
padding:"5px"
}))
}
想法:
首先,在body里新创建一个div(不建议使用span等块状级元素),设置display:inline-block、字体、字体大小。然后把字符串值赋值进去,获取div宽度,再删除掉div。把获取的宽度设置成input的宽度,这里的width = wid +18,需要在页面调试合适宽度。其中,input内的字符串也要设置字体、字体大小,减少误差。最后成为这样~
方法二:根据scrollWidth、clientWidth判断。
scrollWidth:对象的实际内容的宽度,不包边线宽度,会随对象中内容超过可视区后而变大。
clientWidth:对象内容的可视区的宽度。
在input内,scrollWidth也就相对于input中value值的长度。clientWidth相当于input默认宽度(能看到的宽度)。
for (var i = 0; i < strArr.length; i++) {
var ssd = strArr[i];
$(".a1").append($('<input type="text">').val(strArr[i]));
}
$("input").each(function(index, item){
if (item.scrollWidth > item.clientWidth) {
item.style.width = item.scrollWidth + 4 + "px";
}
})
注意两点:
一点是,代码中展示的scrollWidth > clientWidth的时候,因为value值内容含字母符号等,获取scrollWidth有几像素的误差,加上就可以了,调试过后,没问题。
第二点,scrollWidth < clientWidth 时候又该怎么让input自适应呢??? 做东西呢,不能过于死脑筋。把input的宽度设置5px或者10px,让scrollWidth 总是大于clientWidth不就可以了吗!老铁,没毛病吧,哈哈哈哈~
二、input合并
关于合并,在开始解决这个功能之前,应该分析出该功能实现所遇到的核心问题。
- 点击多个input是否连续,非连续不可合并。(项目需求)
- 获取到的value值如何添加到合并的位置上。
分析完问题,方向明确了,也就好做了。
首先是连续问题,先看代码:
var inputArr = [];
var item = 0;
var len;
var inputVal="";
$("#demo").on("click","input",function(){
//添加选中样式
$(this).toggleClass('bd1');
item = $(this).index();
inputArr.push(item);
//再次点击,inputArr数组删除 所对应的item值
len=inputArr.length;
for(var i=0;i<len;i++){
if(item == inputArr[i]){
inputArr.splice(i,1);
console.log(inputArr);
return;
}
};
//数组排序
inputArr.sort();
console.log(inputArr)
});
说明:
这里只是做了准备工作。点击input框获取它的index值,然后把index值push到一个新数组,然后进行排序。其中for循环是input框取消选中时,删除新数组中所对应的index值。
接下来需要一个判断数组是否为连续的如[1,2,3,4,5]方法,网上这类的有很多,我用了其中一个:
function isContinuationInteger(arr){
if(!arr){
return false;
}
if(arr.length==0){
return true;
}
var len=arr.length;
var n0=arr[0];
var sortDirection=1;
if(arr[0]>arr[len-1]){
sortDirection=-1;
}
if((n0*1+(len-1)*sortDirection)!==arr[len-1]){
return false;
}
var isContinuation=true;
for(var i=0;i<len;i++){
if(arr[i]!==(i+n0*sortDirection)){
isContinuation=false;
break;
}
}
return isContinuation;
}
然后就是点击合并按钮,所要处理的事件了。
$("#combine").on("click",function(){
var strArr = '';
if(!isContinuationInteger(inputArr)){
alert('不合法');
return ;
}else{
inputArr.map(function(v){
strArr += $('input').eq(v).val();
})
$(".bd1").each(function(e){
console.log(e);
$(this).eq(e).before($('<input type="text" readonly>').val(strArr));
$(this).remove();
inputArr =[];
//console.log($(this).eq(e))
})
}
})
这里要注意的有:
- 点击事件需要用到on()方法,不可直接用click方法,主要原因是在这个点击事件内添加了新的input框,然后,新的input也可以实现合并功能,也就有了事件委托。
- 数组遍历map()方法,调用数组中的每一个元素,然后把相对应的value值合并成一个字符串。
- 新的input添加,这里用到点击input动态添加的class,然后是each()方法返回的index值,再根据input框所在位置eq(),在它之前添加input,然后删除它本身。
- 以上步骤完成之后,一定要清空存放input框index值的数组。这点要注意。
三、input拆分
input拆分,核心问题在于,获取光标所在位置,然后根据空格键进行拆分,用js或者jq实现的话,很麻烦,为了效率在网上找一些封装方法。要是用angluar或者vue,根据ng-model或者v-model双向数据绑定,再用watch监督,根据value值中的光标位置,点击快捷键会出现空格,然后进行字符串拆分,应该就容易了!(纯想法,有兴趣的可以尝试一下)
这里主要是jq实现:
首先是封装方法,还是前边讲的,有很多时候不能死脑筋,换种思路,问题就迎刃而解了。如果说,根据光标位置进行快捷键进行拆分不好获取,是不是可以找一些方法在光标位置插入某个字符串,然后再根据这个字符串进行分割,然后就找到了下面的封装方法:
/* 在textarea处插入文本--Start */
(function($) {
$.fn.extend({
insertContent : function(myValue, t) {
var $t = $(this)[0];
if (document.selection) { // ie
this.focus();
var sel = document.selection.createRange();
sel.text = myValue;
this.focus();
sel.moveStart('character', -l);
var wee = sel.text.length;
if (arguments.length == 2) {
var l = $t.value.length;
sel.moveEnd("character", wee + t);
t <= 0 ? sel.moveStart("character", wee - 2 * t - myValue.length) : sel.moveStart( "character", wee - t - myValue.length);
sel.select();
}
} else if ($t.selectionStart
|| $t.selectionStart == '0') {
var startPos = $t.selectionStart;
var endPos = $t.selectionEnd;
var scrollTop = $t.scrollTop;
$t.value = $t.value.substring(0, startPos)
+ myValue
+ $t.value.substring(endPos,$t.value.length);
this.focus();
$t.selectionStart = startPos + myValue.length;
$t.selectionEnd = startPos + myValue.length;
$t.scrollTop = scrollTop;
if (arguments.length == 2) {
$t.setSelectionRange(startPos - t,
$t.selectionEnd + t);
this.focus();
}
} else {
this.value += myValue;
this.focus();
}
}
})
})(jQuery);
/* 在textarea处插入文本--Ending */
使用方法是:$(文本域选择器).insertContent("插入的内容");
贴码:
$("#split").on("click",function(){
var splitArr=[];
$(".bd1").each(function(e){
splitArr.push(e);
});
if(splitArr.length>1){
alert("只能选择一个字符串拆分!");
$(this).removeClass("bd1");
return;
}else{
$(".bd1").each(function(e){
//inputVal是选中input框的value值
if(inputVal.length<2){
alert("字符数量必须大于两个!");
$(this).removeClass("bd1");
return;
}else{
if( $(this).hasClass("bd1")){
$(this).toggleClass("dw1");
$(this).removeAttr("readonly");
//console.log("sdasdsad");
$(this).keypress(function(event){
if ( $(this).hasClass('dw1')){
if (event.keyCode == 32) {
$(this).insertContent("#");
//console.log($(this).insertContent("#"))
var value1 = $(this).val();
console.log(value1.split("#"))
var valueone = value1.split("#")[0];
var valuetwo = value1.split("#")[1];
$(this).eq(e).before($('<input type="text" readonly>').val(valueone));
$(this).eq(e).after($('<input type="text" readonly>').val(valuetwo));
$(this).remove();
}
}
})
}
}
});
}
});
这里用到了字符串分割成数组的split()方法,js文档中有详细介绍,在这里就不说明了。
后记:内容虽然很少,可我偏偏整理了将近一天的时间 ,真的是哭笑不得啊~
2017.12.19