当插入符号位于特定div / span / a标记内时,以及当插入符号离开标记时,触发事件

这个想法是这样的 – 有一个含有一些文本的满足要素。 我试图构建一个标记机制(类似于在键入’@’时twitter的人员标记)。 每当用户键入“@”时,它会在他们继续输入时显示带有建议和filter的弹出窗口。 直到这里它很容易,我已经弄清楚了。 如果/仅当插入符号位于包含标记的元素上时,我需要显示弹出窗口时出现问题。

Some random text before @samadams Some random text after

现在,每当用户将标签移动到标签/点击它时,我想触发一个显示弹出窗口的事件,并在插入符号离开标签时将其删除。 (有点像焦点/模糊,但它们似乎不起作用)。 onmousedown工作,但无法判断光标是否已通过键盘移动到锚标签中。

此外,我在angularjs中这样做,因此,任何针对此的解决方案都是优选的,但不是必需的。

一直试图让这个工作一天,任何帮助非常感谢。

当您的插入位置位于包含@的锚点节点时,这将告诉您

 $('#content').on('mouseup keydown keyup', function (event) { var sel = getSelection(); if (sel.type === "Caret") { var anchorNodeVal = sel.anchorNode.nodeValue; if ( anchorNodeVal.indexOf('@') >= 0) { $('#pop').show() } else { $('#pop').hide() } } }) 
  

Some random text before @samadams Some random text after

在下面的代码中使用RegExps和偏移计算有一个奇怪的举动,但让我解释为什么它是一个更好的解决方案。

大约一年前,我一直在使用contenteditable构建一个复杂的编辑器。 这不仅仅是一场灾难。 这是一场他妈的灾难 。 没有涵盖所有案例规范。 浏览器在每个可能的细节中表现不同,并且它经常变化。 在@ char之前放一个插入符号,你会得到这个是Gecko:

 |@name 

这在WebKit中:

 |@name 

好吧,除非是段落的第一个孩子。 然后结果与Gecko相同。 尝试将昵称放在昵称之后,两者都会告诉它在链接中。 开始输入,插入符号将弹出元素 – 一年前Gecko没有这样做。

我在这个例子中使用了原生的Selection&Range API,它们是IE9 +。 您可能想要使用Rangy 。

 $el = $('#content'); var showTip = function (nickname) { // ... console.log('Show: ' + nickname); }; var dismissTip = function () { // ... console.log('Hide'); }; // I'm sure there is a better RegExp for this :) var nicknameRegexp = /(^|\b|\s)\@(\w+)(\s|\b|$)/g; var trackSelection = function () { var selection = window.getSelection(), range = selection.rangeCount > 0 ? selection.getRangeAt(0) : null; if (range == null || $el[0].contains(range.commonAncestorContainer) == false) { return dismissTip(); } var comparer = range.cloneRange(); comparer.setStart($el[0], 0); var offset = comparer.toString().length; var match, from, to; while (match = nicknameRegexp.exec($el[0].textContent)) { from = match.index + match[1].length; to = match.index + match[1].length + match[2].length + 1; if (offset >= from && offset <= to) { // Force rewind, otherwise next time result might be incorrect nicknameRegexp.lastIndex = 0; return showTip(match[2]); } } return dismissTip(); }; $el.on({ // `mousedown` can happen outside #content 'mousedown': function (e) { $(document).one('mouseup', function (e) { // Calling function without a tiny delay will lead to a wrong selection info setTimeout(trackSelection, 5); }); }, 'keyup': trackSelection });