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;
        }
      };
    }
  };
});

posted @ 2020-08-27 00:00  少年小白  阅读(190)  评论(0编辑  收藏  举报