前端之路:contenteditable 换行踩坑心得

       因为项目需求,前台做一个聊天编辑器。

     由于需要插入表情,而非纯文本,textarea显然是不能支持。这种需求的。这种需求就我所知只能用div 来实现。

      一个div元素,要让其可编辑,也就是可读写,contenteditable属性是最常用方法,做前端的基本上都知道,原理就是在这个div 添加html。模拟展示。输入框。

项目需求大概是这样的

遇到的坑:

        然而,这个属性,除去兼容性不说,还是存在一些比较坑爹的小bug的。搜了不少文章,比如张鑫旭大神的纯文本方式输出div内容,链接狂戳以下,帮助还是很大的:

http://www.zhangxinxu.com/wordpress/2016/01/contenteditable-plaintext-only/

        但是在真正使用的时候,发现了一个很大很大的坑。一般的编辑器,都需要事实字数统计功能。在测试纯文本contenteditable时发现了如下几个坑人的问题:

        1、 换行时,字数+2,再次输入一个字符,字数不变,然后再逐渐+1。(字数统计方式当然是获取html然后计算length)。

              有的浏览器换行会加P元素,有的会加<div><br><div>,我遇到的就是这个,还是先加两个,然后才逐渐加1个。和上述一样。(ps:这种问题用shift+enter 是可以避免 直接加<br>的,但是显然这个不能解决根本问题,因为人的习惯就是enter换行,一但按enter后,你输入的文字,将在<div><br><div>下。个人感觉后续很难处理。)

        2、 在末尾换行的时候,会加出一个看不见br。按回车br出现但页面没换行,在按一次会在加一个br,行是换了。但是末尾这                个换行是存在2个br的。那个末尾多出的br.(死活干不掉,选了也选不着。注:别在末尾换行,可以避免这个坑。当然                  了,用户是不可能不踩这个坑的,随便打个字,在那个字前面换行。编辑结束在删掉即可。

        3、无法再光标处插入新加文字或者表情img标签。

        4、 删除字符后,在dom里会留下一堆双引号。(这个我不打算理会,因为输出的字符串是没有这些家伙的。)

网上查看了一下,没什么可用信息。于是自己想了一套方案处理这些坑。

方案:

主要方法。解决第三个坑的主要问题。在光标处插入表情的img标签

 /*光标处插入html代码,参数是String类型的html代码,例子:"<p>猪头诺</p>"*/
    function insertHtml(html) {
        var sel, range;
        if (window.getSelection) {
            // IE9 或 非IE浏览器
            sel = window.getSelection();
            if (sel.getRangeAt && sel.rangeCount) {
                range = sel.getRangeAt(0);
                range.deleteContents();
                // Range.createContextualFragment() would be useful here but is
                // non-standard and not supported in all browsers (IE9, for one)
                var el = document.createElement("div");
                el.innerHTML = html;
                var frag = document.createDocumentFragment(),
                    node, lastNode;
                while ((node = el.firstChild)) {
                    lastNode = frag.appendChild(node);
                }
                range.insertNode(frag);
                // Preserve the selection
                if (lastNode) {
                    range = range.cloneRange();
                    range.setStartAfter(lastNode);
                    range.collapse(true);
                    sel.removeAllRanges();
                    sel.addRange(range);
                }
            }
        } else if (document.selection && document.selection.type != "Control") {
            // IE < 9
            document.selection.createRange().pasteHTML(html);
        }
    }

  先介绍这个方法,是解决坑1也需要这个方法。

现在我将用他来解决坑1.

我的解决思路是,阻止回车事件。然后由自己写的逻辑来走。就是我让它回车加<br>就可以了。将它写在阻止事件中。

阻止事件。代码如下

    /*阻止回车事件*/
    $(window).keydown( function(e) {
        var key = window.event?e.keyCode:e.which;
        /*获取用户按键,如果是回车,则不执行任何*/
        if(key.toString() == "13"){
            /*调用光标插入方法,在光标处插入 换行*/
            insertHtml("<br>");
            return false;
        }
    });

如此一来就把坑1 给填了。回车之后只有<br>,而不会出现其他的标签了。

现在我们来解决坑2.末尾换行会多一个br。死活删不掉的一个<br>。不看代码是看不到的。但是是存在的。
我的解决思路是。这个家伙占据这个div输出框4个字节。我可以监听这个div内容。当它的length为4的时候,判断其html。如果为<br>则清空这个<div>。这个是解决删除全部文本。删不掉。它是在末尾,提交的时候可以获取br个数。干掉最后一个即可。不过末尾有个br,其实影响,个人感觉不大。所以我苦恼的是删除时候它占据了在内容里面

监听方法如下:

         /*
         * 输入框监听事件
         * */
        $('.js_edit_area').bind('input propertychange', function() {
            var  len =$(this).html().length;
            var  x = 600-len;
            /*限制只能输入600字*/
            if(x<=600){
               
            }
            /*判断长度,干掉多余的br*/
            if(len==4){
                var br = $('.js_edit_area').html();
                if(br=="<br>"){
                    $('.js_edit_area').html("");
                    $(".js_editor_tip em").html("600");
                }
            }
            /*也可以获取br元素,干掉最后一个br即可,逻辑写在提交那里*/
        });

以上是个人的一些解决方案。记录成长,也分享帮助需要的你们。

你可以通过 JavaScript 监听输入框的输入事件,然后获取输入框中的文本内容,再通过字符串的 `length` 属性获取当前输入的字符数,以此判断是否超出限制。如果超出限制,可以通过 `substring()` 方法截取字符串并更新输入框的内容,或者给出提示信息。以下是一个简单的示例代码: ```html <div contenteditable="true" id="input-box"></div> <div id="counter"></div> <script> const maxLength = 10; // 最大字符数 const inputBox = document.getElementById('input-box'); const counter = document.getElementById('counter'); inputBox.addEventListener('input', function() { const text = inputBox.innerText; const length = text.length; if (length > maxLength) { inputBox.innerText = text.substring(0, maxLength); counter.innerText = `已输入 ${maxLength} / ${maxLength} 个字符`; } else { counter.innerText = `已输入 ${length} / ${maxLength} 个字符`; } }); </script> ``` 在上面的示例中,我们首先定义了一个 `maxLength` 变量表示最大字符数,然后通过 `document.getElementById()` 方法获取输入框和计数器的元素对象。接着,我们给输入框添加了一个 `input` 事件监听器,每次输入框的内容发生变化时,就会触发该事件。在事件处理函数中,我们首先获取输入框中的文本内容,然后计算字符数并进行判断。如果超出了最大字符数,就使用 `substring()` 方法截取字符串并更新输入框的内容,同时显示计数器的文本为已输入的字符数与最大字符数。否则,就只显示已输入的字符数与最大字符数。 这只是一个简单的实现方式,你可以根据实际需求进行修改和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值