javascript - 带有 contenteditable 的真实计数器

标签 javascript html css angularjs contenteditable

几天来我一直在寻找解决方案,以添加与我的指令 contenteditable 关联的字符计数器。

很遗憾,我找不到解决方案。

为了突出这个问题,不同的浏览器对 contenteditable 有不同的行为。

这是我正在使用的指令:

var app = angular.module("App", []);
app.directive("contenteditable", function($timeout) {
  return {
    restrict: 'A',
    require : ['^?ngModel'],
    link : function(scope, element, attrs, args){
       var ngModel = args[0];
       if (ngModel === null) {
        return null;
       }

       var modelKey = getModelKey();
       opts = {
           onlyText: false,
           convertNewLines: false,
           noLf: false,
       };
        angular.forEach(['onlyText', 'convertNewLines', 'noLf'], function (opt) {
            if (attrs.hasOwnProperty(opt) && attrs[opt] && attrs[opt] !== 'false') {
                opts[opt] = true;
            }
        });

        $timeout(function () {
             return (opts.onlyText && opts.noLf) ? element.text(ngModel.$modelValue) : element.html(ngModel.$modelValue);
        });

        var validate = function (content) {
            var length = content.length;
            refreshFn = function(content) {
                if (content == undefined || content == null) {
                    content = '';
                }
                scope.maxCharacter= attrs.ngMaxlength;
                scope.remaining = (length);
            };
            scope.$watch('ngModel', function(content){
                refreshFn(content);
            }, true);

            if (length > attrs.ngMaxlength) {
                ngModel.$setValidity(modelKey, false);
                return element.addClass('-error');
            }

            if (element.hasClass('-error')) {
                ngModel.$setValidity(modelKey, true);
                return element.removeClass('-error');
            }
         };

        var read = function () {
            var content = '';
            if ((opts.onlyText && opts.noLf)) {
                content = element.text();
             } else {
                content = element.html();
                if (content) {
                    content = parseHtml(content);
                }
             }

             if (content !== '') {
                content = content.replace(/ /g, '');
                content = content.trim();
             }
            ngModel.$setViewValue(content);
            validate(content);
        };

        ngModel.$render = function () {
            if ((opts.onlyText && opts.noLf)) {
                element.text(ngModel.$viewValue || '');
             } else {
                element.html(ngModel.$viewValue || '');
             }
         };

        element.bind('blur keyup change focus', function (event) {
            scope.$apply(read);
            scope.displayCount = true;
            if (event.type === 'blur') {
                scope.$apply(ngModel.$render);
            }
        });

         function getModelKey() {
          if (typeof attrs.ngModel === 'undefined') {
            return null;
          }
          var split = attrs.ngModel.split('.');
          return split[split.length-1];
       }

        function parseHtml(html) {
            html = html.replace(/ /g, '');
            if (opts.convertNewLines || opts.noLf) {
                var lf = '\r\n',
                    rxl = /\r\n$/;

                if (opts.noLf) {
                    lf = ' ';
                    rxl = / $/;
                }

                html = html.replace(/<br(\s*)\/*>/ig, ''); // replace br for newlines
                html = html.replace(/<[div>]+>/ig, lf); // replace div for newlines
                html = html.replace(/<\/[div>]+>/gm, ''); // remove remaining divs
                html = html.replace(/&nbsp;/g, '');
                html = html.replace(/<[p>]+>/ig, lf); // replace p for newlines
                html = html.replace(/<\/[p>]+>/gm, ''); // remove remaining p
                html = html.replace(/<[span>]+>/ig, lf); // replace p for newlines
                html = html.replace(/<\/[span>]+>/gm, ''); // remove remaining p
                html = html.replace(rxl, ''); // remove last newline
                html = _.unescape(html); // replaces &amp;, &lt;, &gt;, &quot;, &#96; and &#x27; with their unescaped counterparts.
            }
            if (opts.onlyText) {
                html = html.replace(/<\S[^><]*>/g, '');
            }

            return html;
        }
    }
    };
 });

和 html 文件:

     <div class="content-editable" contenteditable="true"                                        
          ng-model="line.value"                                      
          ng-maxlength=255                                       
          only-text="true"               
          convert-new-lines="true"               
          no-lf="false">
     </div>
     <div ng-if="displayCount" class="ctn" ng-if="countChar">
       <span class="numberChar">
         <span class="italic" style="margin-right:5px;"> 
           <span ng-class="remaining>=maxCharacter ? 'errorMsg': ''">
             {{remaining}} 
           </span> / {{maxCharacter}}
         </span>   
         <span class="errorMsg error" ng-if="remaining>=maxCharacter"></span>
       </span>
    </div>                          
</div>

codepen 上的示例:https://codepen.io/gregand/pen/yLBjWYW

在 Chrome 和 Firefox 上,当我输入 6 个字符(包括换行符)时,计数器计数为 9 个字符

enter image description here

在 Edge 上,计数器很好

enter image description here

我尝试将 display: block 的 contenteditable css 更改为 inline-block,它纠正了 Chrome 上的问题,但在 Edge 上存在问题。

我试过

document.execCommand('defaultParagraphSeparator', false, 'p');

但没有成功。

如果有人知道适用于所有浏览器的解决方案,我会很感兴趣

最佳答案

我找到了解决方案,实际上问题来自下一行:

var lf = '\r\n'

我要求每个标签的替换为变量lf

html = html.replace(/<[div>]+>/ig, lf);

'\r\n'统计两个字符,一个为'\r',另一个为'\n'

而换行符应该只有一个字符。

因此,对于解决方案,我替换了变量 lf

 var lf = '\n'

它适用于多种浏览器

https://codepen.io/gregand/pen/yLBjWYW

关于javascript - 带有 contenteditable 的真实计数器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57926374/

相关文章:

javascript - 如何对 jQuery DataTables 中的列值进行后处理

c# - 在c#中以编程方式访问asp.net Label的值innerHtml值

javascript - 即使在我的服务器上的简单情况下,Express.js 路由器也无法工作

javascript - 页面加载时删除类并在离开页面时添加类

javascript - Firefox-Addon 如何找到 window.name ="mywindow"的选项卡?

javascript - Angular 2 组合表单验证

html - 站点菜单在 Windows 上的所有浏览器上看起来都不错,但在 Mac OS 上就坏了

html - CSS扩展div的宽度以覆盖左侧的div

javascript - 用 CSS 替换文本/图像 URL

php - 将 smarty 中的 url 连接到带有字符串的给定链接