JQuery选中文本重复插入问题:多次选中文本后插入重复内容
多次选中文本后点击插入,重复插入所有选中内容的问题解决
我正在实现一个功能:用户从评论区选中文本后,点击插入按钮,就能把选中的内容以特定格式插入到textarea里。目前功能基本可用,但遇到一个奇怪的问题:多次选中文本(每次选中后点击别处取消选择),再点击插入按钮时,会把所有选中过的内容一并插入,而不是只插入最后一次选中的。比如重复选中"here"四次,点击插入就会出现四次带格式的内容。
我当前的代码:
获取选中文本的函数:
// selected text function getSelected() { var return_text = ''; if (window.getSelection) { return_text = window.getSelection(); } else if (document.getSelection) { return_text = document.getSelection(); } return return_text; }
处理选中文本和插入按钮的代码:
var quote_box = $('#selective-quote'); $(document).on('mouseup', ".comment-body div", function(e) { if ($('#comment').length) // only do this if comment box exists (logged in) { var selection = getSelected(); var selectedText = selection.toString(); if (typeof selection !== undefined && selectedText.length > 0 && selection.anchorNode.nodeName == '#text') { var container = $(this); var r=selection.getRangeAt(0).getBoundingClientRect(); var relative=document.body.parentNode.getBoundingClientRect(); // show the quote button box quote_box.css('position','absolute'); quote_box.css('top',r.bottom -relative.top - 45); quote_box.css('left',r.left); quote_box.css('height', 'auto'); quote_box.show(); var text_to_insert = ''; $(document).on('click', "#insert-selective-quote", function(e) { var username = container.parent().parent().children('.comment-meta').find('.username').text(); text_to_insert = '[quote='+username+']' + $.trim(selectedText) + '[/quote]'; console.log(text_to_insert); var current_text = $('#comment').val(); $('#comment').val(current_text + text_to_insert); quote_box.hide(); }); } else { quote_box.hide(); } } });
问题原因分析
核心问题出在事件绑定的时机:你每次触发mouseup事件(也就是每次选中文本后松开鼠标),都会给#insert-selective-quote按钮绑定一个新的click事件处理函数。
举个例子:
- 第一次选中文本:按钮绑定了1个click事件,点击会插入1次内容
- 第二次选中文本:按钮又绑定了1个新的click事件,现在总共有2个
- 重复四次后,按钮就有4个click事件处理函数,点击一次就会执行四次插入操作,所以你看到四次内容被插入。
解决方案
我给你两种解决思路,推荐第二种更优雅的方案:
方案1:绑定新事件前先解绑旧事件
在每次绑定click事件之前,先移除按钮上已有的同类型事件,避免重复绑定:
// 替换原来的点击事件绑定代码 $(document).off('click', "#insert-selective-quote").on('click', "#insert-selective-quote", function(e) { var username = container.parent().parent().children('.comment-meta').find('.username').text(); text_to_insert = '[quote='+username+']' + $.trim(selectedText) + '[/quote]'; console.log(text_to_insert); var current_text = $('#comment').val(); $('#comment').val(current_text + text_to_insert); quote_box.hide(); });
这里用.off('click', "#insert-selective-quote")先清除之前绑定的click事件,再绑定新的,确保按钮永远只有一个有效的click处理函数。
方案2:将点击事件绑定移到mouseup事件外部(更优)
把插入按钮的click事件绑定逻辑抽离出来,只在页面初始化时绑定一次,然后通过变量存储当前要插入的内容。这样就从根源上避免了重复绑定:
var quote_box = $('#selective-quote'); // 定义变量存储当前要插入的文本 var currentInsertContent = ''; // 只绑定一次插入按钮的点击事件 $(document).on('click', "#insert-selective-quote", function(e) { if (currentInsertContent) { var current_text = $('#comment').val(); $('#comment').val(current_text + currentInsertContent); quote_box.hide(); currentInsertContent = ''; // 插入后清空,避免重复插入 } }); // 处理选中文本的mouseup事件 $(document).on('mouseup', ".comment-body div", function(e) { if ($('#comment').length) { var selection = getSelected(); var selectedText = selection.toString(); if (selection && selectedText.length > 0 && selection.anchorNode.nodeName == '#text') { var container = $(this); var r=selection.getRangeAt(0).getBoundingClientRect(); var relative=document.body.parentNode.getBoundingClientRect(); // 显示按钮 quote_box.css({ 'position':'absolute', 'top': r.bottom - relative.top - 45, 'left': r.left, 'height': 'auto' }).show(); // 更新当前要插入的内容 var username = container.parent().parent().children('.comment-meta').find('.username').text(); currentInsertContent = '[quote='+username+']' + $.trim(selectedText) + '[/quote]'; } else { quote_box.hide(); currentInsertContent = ''; // 未选中有效文本时清空 } } });
这种方案的优势是事件只绑定一次,性能更好,逻辑也更清晰——mouseup事件只负责更新要插入的内容和显示按钮,click事件只负责执行插入操作。
内容的提问来源于stack exchange,提问作者NaughtySquid
相关产品推荐
相关产品推荐

