在内容可编辑div中的新行上触发事件

时间:2015-08-05 11:00:29

标签: jquery html css angularjs contenteditable

我正在尝试侦听一个事件,该事件表示已在内容可编辑div中创建了新行。目的是最终在每次创建新的空行并且插入符号位于该行上时,或者如果用户将插入符号位置单击到当前空行时,向用户显示一些选项。

在我的书中,似乎有四个事件会导致用户在一个可疑的div中处于新的界限:

  • 按回车
  • 粘贴末尾有空行的内容
  • 点击导致插入符号(闪烁的行)将位置移动到空行
  • 使用箭头键移动到新行

当然,在一个可疑的div中,新行对不同的浏览器意味着不同的东西,在chrome中它似乎创建了<div><br/></div>标签,但是浏览了足够的东西似乎其他浏览器可能会创建<div><p></p></div>或者<span>标签。

我现在试图解决这个问题几次,只需要完成它。是否真的是倾听在该div下添加的新元素的最佳方式,和/或检查插入位置当前是否在空的“新行”中。标签。检查每次插入符号的效率似乎非常低效 - 有更好的方法吗?

总结tldr;人

  • 有没有更好的方法来检查内容可编辑div中的新行?
  • 我将如何有效地触发事件?

只是fyi这是在Angular上下文中我也有jQuery(答案可以选择使用或不使用这些库)。

-----编辑-----

到目前为止,答案主要集中在新线路事件的创建上。并监测这些事件,也许是对插入符号位置进行轮询是确定插入符号是否在空行中的更可靠方法。

4 个答案:

答案 0 :(得分:11)

到目前为止,其他答案讨论了监视在内容可编辑div中创建换行符的事件。然而,从迄今为止的努力来看,这似乎不是监测用户是否已将插入符号放在新行上的可靠方法。

尽管有人担心setInterval事件很笨重并增加了开销,但这可能只是我的看法。我已经在OSX上的Firefox和Chrome中测试了以下内容。

&#13;
&#13;
function getNewLines() {
  console.log(document.getSelection());
  if (document.getSelection().anchorNode) {
    var node = document.getSelection().anchorNode;
    var nodeContents = "";
    if (node.innerHTML) {
      nodeContents = node.innerHTML.toLowerCase();
    } else {
      nodeContents = node.innerHTML;
    }
    if (nodeContents !== undefined) {
      if (nodeContents === "" || nodeContents == "<br>" || nodeContents ==
        "<br/>" || nodeContents.substr(nodeContents.length - 5) == "<br/>" ||
        nodeContents.substr(nodeContents.length - 4) == "<br>") {
        console.log("you are on a new line :]");
      } else {
        console.log('nope not a new line');
      }
    } else {
      console.log('nice try, but no not a new line');
    }
  }
}
setInterval(getNewLines, 100);
&#13;
<div contenteditable="true">
  <p>Lets get started!</p>
</div>
&#13;
&#13;
&#13;

See Fiddle Here

旁注: 内容可编辑中换行符的行为似乎有所不同,但我在firefox中注意到它将模仿该字段中的现有元素。即如果您使用的是<div></div>,则firefox将使用<div></div>,如果您使用<p></p>,则Firefox将执行相同的操作

答案 1 :(得分:9)

这就是我所做的:

$("#main").keyup(function (e) {
    if (e.which == 13) {
        doSomething();
    }
});
$("#main").on("click", "div:has(br)", function () {
    doSomething();
});
$("#main").on("paste", function () {
    setTimeout(function () {
        debugger;
        if ($('#main').children().last().children().last().has('br').length >0) {
            doSomething();
        }
    }, 100);
});

function doSomething(){
   alert("new line...");
}

Here is the JSFiddle demo

答案 2 :(得分:1)

我在Chrome和Edge上测试了这段代码。 当我从记事本中复制并粘贴时,Edge删除了空行。

http://codepen.io/tzach/pen/XbGWjZ?editors=101

angular
    .module('app', [])
    .directive('contenteditable', function ($timeout) {
        return {
            link: function($scope, element, attrs) {

                element.css('white-space', 'pre');

                element.on('keypress', function (e) {
                    if (e.keyCode === 13) {
                        $timeout(function () {
                            onNewLine();
                        }, 100);
                    }
                });

                element.on('paste', function (e) {
                    $timeout(function () {
                        var text = element.text();
                        var textRows = text.split('\n');

                        var html = element.html();
                        var htmlRows = html.split('<br>');

                        if (textRows[textRows.length - 1].trim() == '' ||
                            htmlRows[htmlRows.length - 1].trim() == '') {
                                onNewLine();
                        }
                    },0);
                });

                element.on('click', function(e) {
                    var html = e.target.innerHTML;
                    var text = e.target.innerText;
                    if (text === '\n' || html.toLowerCase() === '<br>') {
                        onNewLine();
                    }
                });

                function onNewLine() {
                    alert('new empty line');
                }
            }
        }
    });

答案 3 :(得分:1)

这是一个开始。我甚至不愿意尝试猜测不同的浏览器实现。相反,通过将焦点推到隐藏的文本区域然后根据​​其中的换行符进行测试(例如textarea.value.match(/\n$/))来填充它。

这应该处理所有用例,其余的只是伪造插入符号并通过范围进行选择。为此目的存在插件。

<强>的JavaScript

var contentEditable = document.querySelector('.content pre'),
    textarea = document.querySelector('.content textarea');

contentEditable.addEventListener('click', function() {
    textarea.focus();
    contentEditable.classList.add('pseudo-focus');
});
textarea.addEventListener('keyup', function(e) {
    contentEditable.innerText = textarea.value;

    if (textarea.value.match(/\n$/)) {
        alert('newline');
    }
});

<强> HTML

<div class="content">
    <pre id="editable" contenteditable></pre>
    <textarea></textarea>
</div>

JSFiddle Example