angularjs 用directive做一个 类似于maxlength的属性,支持汉字作为3个长度
index.html
<!doctype html>
<html lang="en" ng-app="phonecatApp">
<head>
<meta charset="utf-8">
<title>Google Phone Gallery</title>
<link rel="stylesheet" href="lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="app.css" />
<script src="lib/angular/angular.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="PhoneListController">
<ul>
<li ng-repeat="phone in phones">
<span>{{phone.name}}</span>
<p>{{phone.snippet}}</p>
</li>
</ul>
<input type="text" maxlength="5">
<input type="text" maxlengthCn="10">
<input type="text" inputCn="100">
<div my-customer></div>
</body>
</html>
app.js, 直接移步版本A++
'use strict';
// Define the `phonecatApp` module
var phonecatApp = angular.module('phonecatApp', []);
// Define the `PhoneListController` controller on the `phonecatApp` module
phonecatApp.controller('PhoneListController', function PhoneListController($scope) {
}).directive('maxlengthcnTest', function() {//版本A
return {//控制中英文混合输入的长度(一个中文字符算作三个);实现:控制maxlength属性。
//在有可能输入中文的时候,提前控制长度。中文输入时、ctrl v时
//中文输入后按enter或shift时取消控制
restrict: 'A',//只在作为属性时有效
// template: 'Name: {{customer.name}} Address: {{customer.address}}',
link: function (scope, element, attr) {
console.log("cnLength: " + attr.maxlengthcn);
var totalLength = parseInt(attr.maxlengthcn);
var opElement = element[0];
opElement.maxLength = totalLength;
element.on('input', function () {
if (opElement.comStart) return;
// inputEvt(opElement);
increaseLength(opElement);
}).on('compositionstart', function () {//中文输入开始
decreaseLength(opElement);//假设输入的都是中文,剩余长度除以3
opElement.comStart = true;
console.log("CN start");
}).on('compositionupdate', function () {
console.log("CN compositionupdate");
}).on('compositionend', function () {//中文输入结束
opElement.comStart = false;
console.log("CN end");
increaseLength(opElement);
}).on('keyup', function (event) {
if (event.which == 86) {//ctrl v
// inputEvt(opElement);
console.log("ctrl v");
// window.clipboardData.getData ("Text");
return;
}
console.log(event.which);
if (opElement.comStart) {//中文输入后按enter
if (event.which == 13) {
increaseLength(opElement);
console.log("enter");
} else if (event.which == 16) {//中文输入后按shift
increaseLength(opElement);
console.log("shift");
}
}
});
var inputEvt = function (element) {
if (element.comStart) return; // 中文输入过程中不截断
console.log("length: " + element.maxLength);
element.maxLength = 5;
console.log("text: " + element.value);
};
//剩余长度除3
var decreaseLength = function (opElement) {
var valueLen = validateTextLength(opElement.value);
opElement.maxLength = opElement.value.length + (totalLength - valueLen) / 3;
console.log("len: " + opElement.maxLength);
};
//剩余长度恢复
var increaseLength = function (opElement) {
var valueLen = validateTextLength(opElement.value);
opElement.maxLength = totalLength - valueLen + opElement.value.length;
console.log("len: " + opElement.maxLength);
};
var validateTextLength = function (value) {
// 中文、中文标点、全角字符按3长度,英文、英文符号、数字按1长度计算
let cnReg = /([\u4e00-\u9fa5]|[\u3000-\u303F]|[\uFF00-\uFF60])/g
let mat = value.match(cnReg)
let length;
if (mat) {
length = (mat.length * 3 + (value.length - mat.length))
return length;
} else {
return value.length;
}
};
}
};
}).directive('inputcn', function() {//测试用
return {
restrict: 'A',//只在作为属性时有效
// template: 'Name: {{customer.name}} Address: {{customer.address}}',
link: function (scope, element, attr) {
var opElement = element[0];
let str = "123";
element.on('input', function () {
//IE浏览器
if (document.selection) {
opElement.focus();
var sel = document.selection.createRange();
sel.text = str;
sel.select();
} //火狐/网景 浏览器
else if (opElement.selectionStart || opElement.selectionStart == '0')
{
//得到光标前的位置
var startPos = opElement.selectionStart;
//得到光标后的位置
var endPos = opElement.selectionEnd;
// 在加入数据之前获得滚动条的高度
var restoreTop = opElement.scrollTop;
opElement.value = opElement.value.substring(0, startPos) + str + opElement.value.substring(endPos, opElement.value.length);
//如果滚动条高度大于0
if (restoreTop > 0) {
// 返回
opElement.scrollTop = restoreTop;
}
opElement.focus();
opElement.selectionStart = startPos + str.length;
opElement.selectionEnd = startPos + str.length;
}
else {
opElement.value += str;
opElement.focus();
}
});
}
};
}).directive('maxlengthcnIE', function() {//版本A+ 最终版 问题:chrome中使用超长时会出现覆盖掉后面的字符的问题
//测试环境: ie11 chrome84
return {//控制中英文混合输入的长度(一个中文字符算作三个);实现:控制maxlength属性,
// 并且在有效输入(中、英、粘贴)后校验长度,并更正。
restrict: 'A',//只在作为属性时有效
link: function (scope, element, attr) {
console.log("cnLength: " + attr.maxlengthcn);
if (parseFloat(attr.maxlengthcn).toString() == "NaN") return;
var totalLength = parseInt(attr.maxlengthcn);
var opElement = element[0];
opElement.maxLength = totalLength;
element.on('input', function () {
console.log("input: " + opElement.value);
if (opElement.comStart) return;// 中文输入过程中不处理
inputEvt(opElement);
}).on('compositionstart', function () {//中文输入开始
opElement.comStart = true;
console.log("CN start");
}).on('compositionend', function () {//中文输入结束
opElement.comStart = false;
console.log("CN end");
inputEvt(opElement);//解决chrome执行顺序问题(compositionstart -- input -- compositionend)
});
var inputEvt = function (element) {
var valueLen = validateTextLength(opElement.value);
if (valueLen > totalLength) {
console.log("too long");
var diffLen = valueLen - totalLength;
//得到光标的位置
var startPos = opElement.selectionStart;
console.log("cursor pos: " + startPos);
var sumLen = 0;
let i = startPos - 1;
for (; i >= 0; i--) {
sumLen += validateTextLength(opElement.value.charAt(i));
if (sumLen >= diffLen) break;
}
console.log("last cursor pos: " + i);
//剪去多的字符
opElement.value = opElement.value.substring(0, i) + opElement.value.substring(startPos);
opElement.focus();
opElement.selectionStart = i;
opElement.selectionEnd = i;
valueLen -= sumLen;
}
if (totalLength >= valueLen) opElement.maxLength = totalLength - valueLen + opElement.value.length;
console.log("length: " + element.maxLength);
};
//得到字符长度
var validateTextLength = function (value) {
// 中文、中文标点、全角字符按3长度,英文、英文符号、数字按1长度计算
let cnReg = /([\u4e00-\u9fa5]|[\u3000-\u303F]|[\uFF00-\uFF60])/g
let mat = value.match(cnReg)
let length;
if (mat) {
length = (mat.length * 3 + (value.length - mat.length))
return length;
} else {
return value.length;
}
};
}
};
}).directive('maxlengthcn', function() {//版本A++ 最终版 放弃使用maxlength, 直接判断长度,删除光标前边的字符
//测试环境: ie11 chrome84
return {//控制中英文混合输入的长度(一个中文字符算作三个);
restrict: 'A',//只在作为属性时有效
link: function (scope, element, attr) {
console.log("cnLength: " + attr.maxlengthcn);
if (parseFloat(attr.maxlengthcn).toString() == "NaN") return;
var totalLength = parseInt(attr.maxlengthcn);
var opElement = element[0];
element.on('input', function () {
console.log("input: " + opElement.value);
if (opElement.comStart) return;// 中文输入过程中不处理
inputEvt(opElement);
}).on('compositionstart', function () {//中文输入开始
opElement.comStart = true;
console.log("CN start");
}).on('compositionend', function () {//中文输入结束
opElement.comStart = false;
console.log("CN end");
inputEvt(opElement);//解决chrome执行顺序问题(compositionstart -- input -- compositionend)
});
var inputEvt = function (element) {
var valueLen = validateTextLength(opElement.value);
if (valueLen > totalLength) {
console.log("too long");
var diffLen = valueLen - totalLength;
//得到光标的位置
var startPos = opElement.selectionStart;
console.log("cursor pos: " + startPos);
var sumLen = 0;
let i = startPos - 1;
for (; i >= 0; i--) {
sumLen += validateTextLength(opElement.value.charAt(i));
if (sumLen >= diffLen) break;
}
console.log("last cursor pos: " + i);
//剪去多的字符
opElement.value = opElement.value.substring(0, i) + opElement.value.substring(startPos);
opElement.focus();
opElement.selectionStart = i;
opElement.selectionEnd = i;
valueLen -= sumLen;
}
};
//得到字符长度
var validateTextLength = function (value) {
// 中文、中文标点、全角字符按3长度,英文、英文符号、数字按1长度计算
let cnReg = /([\u4e00-\u9fa5]|[\u3000-\u303F]|[\uFF00-\uFF60])/g
let mat = value.match(cnReg)
let length;
if (mat) {
length = (mat.length * 3 + (value.length - mat.length))
return length;
} else {
return value.length;
}
};
}
};
});