【问题标题】:How can I know if an user deleted an element in a contenteditable div?我如何知道用户是否删除了 contenteditable div 中的元素?
【发布时间】:2021-03-20 02:41:56
【问题描述】:

我正在使用 jQuery 来检测 @ 符号是否已插入到 contenteditable div 中。当检测到这种情况时,将向服务器触发 ajax 请求以检索用户列表。用户然后单击用户名(函数 adduser 将触发),它将在 div 中创建一个禁用的文本区域。 然后我动态创建一个输入,将用户的 id 选为值(通知他们)

我遇到的问题是,如果用户使用键盘甚至鼠标从 contenteditable div 中删除了 textarea(用户名),我怎么知道它是哪个 textarea,所以也删除了具有用户 ID 的输入作为价值?

我的脚本:

function adduser(fname, lname, id, q)
    {
        var fname = fname;
        var lname = lname;
        var id = id;
        var word = '@' + q;
        var iid = 'id' + id;
    
      var old=$("#contentbox").html();
        var content=old.replace(word,""); 
        
    $("#contentbox").html(content);
        
    var E="<textarea class='textareamention' name="+id+" id="+iid+"  disabled >"+fname+"</textarea>";
                
    $("#contentbox").append(E);
                
      $('<input/>').attr({ type: 'text', name: 'mention[]', id: id, value: id}).appendTo('#post');
    }

【问题讨论】:

  • 循环遍历所有输入。如果相应的文本区域仍然存在,则保留输入;如果没有,则删除输入。
  • 听起来不错,但请问如何?

标签: javascript jquery html dom


【解决方案1】:

好的,这就去......

一个的方法——也许不是唯一的方法——是使用 Mutation Observers,尤其是 Mutation-summary,库——来观察你的 #contentbox 的变化。 Mutation-summary 文档甚至提到了这个特殊的用例 - 请参阅What is it useful for? 下的最后一个要点。

与事件处理相比,优势在于您无需预测可能导致删除文本区域的每种类型的事件。

虽然有一些警告:

  • 目前只有主流浏览器支持 Mutation Observers - Google Chrome、Firefox、Safari、Opera 和 IE11。有人告诉我们,“未来它将在其他浏览器中实现”。
  • Mutation-summary 已经有 3 年没有更新了。
  • 我实际上并没有在愤怒中使用 Mutation-summary - 我只阅读了文档。

一旦观察到突变,必须有多种方法来处理相应元素的删除。

正如我在上面的 cmets 中所建议的那样,一种方法是遍历所有输入并删除其中任何相应的 textarea 不再存在的输入。

但是,我认为有一种更清洁的方法。

首先,在页面上安装Mutation-summary 库(&lt;script src="..."&gt; 标记,如 jQuery)。

然后,修改 adduser() 以包含一个自定义事件侦听器 removeRelatedElements,附加到您的 &lt;textarea&gt; 元素:

function adduser(fname, lname, id, q) {
    $('<textarea class="textareamention" name=' + id + ' id=id' + id + ' disabled>' + fname + '</textarea>')
    .on('removeRelatedElements', function() {
        $input.remove(); // $input is held in a closure
    })
    .appendTo($("#contentbox").html($("#contentbox").html().replace('@' + q, '')));

    var $input = $('<input/>')
    .attr({
        'type': 'text',
        'name': 'mention[]',
        'id': id,
        'value': id
    })
    .appendTo('#post');
}

现在,您应该可以使用 Mutation-summary 来观察 #contentbox 的变化,并且在删除 textArea 时触发其自定义 removeRelatedElements 事件,从而导致相应的 &lt;input&gt; 元素也被删除。

var observer = new MutationSummary({
    queries: [
        { element: '#contentbox' } // jQuery-like selector
    ],
    callback: function(summaries) {
        summaries[0].removed.forEach(function(removedEl) {
            // Here, you should be able to write POJS or jQuery, or a mixture
            if(removedEl.tagName.toUpperCase() === 'TEXTAREA') {
                $(removedEl).trigger('removeRelatedElements').off('removeRelatedElements'); // remove the corresponding input element and detatch the custom handler to keep things clean
            }
        });
    }
});

这就是它的要点。您可能需要进行一些调试。

编辑:

好的,由于$("#contentbox").html().replace('@' + q, ''),上述尝试不起作用,它替换了#contentbox 中的DOM 层次结构。在这个过程中,我们的.on('removeRelatedElements', ...) 事件处理程序被不可逆转地突袭,随后.trigger('removeRelatedElements') 默默地失败了。

我们必须回到“A计划”。在.textareamention 的每个突变处,您需要查找并删除任何没有对应文本区域的输入。

很容易认为您可以像以前一样简单地使用summaries[0].removed,但事实并非如此。问题在于summaries[0].removed 包含对在replace('@' + q, '') 过程中删除的文本区域的引用。结果 所有 对应的输入元素被删除,包括刚刚添加的元素!净效应是预期的输入永远不会出现。

幸运的是,解决方法很简单。我们可以完全忽略summaries 并使用$("#contentbox textarea.textareamention") 作为每个观察到的突变的起点。如果您无法掌握这一点,请不要担心——这并不明显。我是通过反复试验发现的。

代码如下:

jQuery(function($) {
    var counter = 0; // integer, for associating each <textarea> with its <input>

    $('#button').click(function() {
        var q = " ";

        $('<textarea class="textareamention ' + counter + '" disabled></textarea>') // include `counter` as a className
        .text(counter)  // for demo purposes
        .appendTo($("#contentbox").html($("#contentbox").html().replace('@' + q, '')));

        var $input = $('<input/>').attr({
            'type': 'text',
            'name': 'mention[]',
            'value': counter // for demo purposes
        })
        .data('counter', counter) // bind the current counter value to this <input>
        .appendTo('#post');
        counter++;
    });

    var observer = new MutationSummary({
        'queries': [
            { element: '.textareamention' }
        ],
        'callback': function(summaries) {
            // Remove all inputs for which there is no corresponding textarea.
            var $textareas = $("#contentbox textarea.textareamention"); // all textareas
            $("#post input").filter(function(index, element) {
                return $textareas.filter('.' + $(element).data('counter')).length === 0;
            }) // filter to find any input for which there is no corresponding textarea ...
            .remove(); // ... and remove it/them.
        }
    });
});

DEMO。注意:在小提琴中,上述所有代码都出现在javascript框架的底部

【讨论】:

  • 您好,感谢您的解决方案。我试过了,但什么也没发生……我不明白事件 removeRelatedElements 的使用。我在提及摘要源中没有找到它
  • 我尝试调试,我注意到事件 removeRelatedElements 没有被触发...@Roamer-1888
  • jQuery 允许你“发明”事件。 removeRelatedElements 是我发明的自定义事件 - 你不会在任何地方找到它的文档。如果事件没有触发,那么我猜我的代码中存在未捕获的错误,或者事件处理程序在触发之前已从元素中删除。如果是后者,我将不得不修改流程。
  • 要调试,我会从“回调”函数开始。添加console.log(...) 语句,查看是否触发了“removeRelatedElements”。
  • 哦,哇,你太棒了!那行得通!太感谢了!!!!!!我真的很感激!
【解决方案2】:

尝试在删除textarea的时候注册一个回调函数,像这样:

<html>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
  function del(id) {
    if (event.keyCode == 8) {
      alert(id);
      $("#id"+id).remove();
    }
  }

  function adduser(fname, lname, id, q) {
    var fname = fname;
    var lname = lname;
    var id = id;
    var word = '@' + q;
    var iid = 'id' + id;

    var old=$("#contentbox").html();
    var content=old.replace(word,""); 

    $("#contentbox").html(content);

    var E="<textarea onkeydown='del("+id+")' class='textareamention' name="+id+" id="+iid+" >"+fname+"</textarea>";

    $("#contentbox").append(E);

    $('<input/>').attr({ type: 'text', name: 'mention[]', id: id, value: id}).appendTo('#post');
  }
</script>

<body>
<div id='contentbox'></div>

<button onclick="adduser(123, 123, 123, 123)">Click me</button>

</body>

</html>

【讨论】:

  • 当我点击 textarea 时有效,但是当我通过键盘键(退格键)删除它时,我怎么能做到呢?
  • @KhalidAskia 我已经更新了代码。您只需检测每个文本区域的 onkeydown 事件,并检查 del() 中哪个键被按下。
  • 我非常感谢您的帮助,但我接受了其他解决方案,这正是我想要的。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-27
  • 1970-01-01
  • 2016-12-27
  • 1970-01-01
  • 1970-01-01
  • 2011-01-11
  • 1970-01-01
相关资源
最近更新 更多