now*_*iko 5 javascript range selection
我面临以下问题:当我尝试在contenteditable
元素中选择文本并且选择的结尾是元素内容的开头时,则不会触发select事件并且没有Selection
和Range
对象.
有人可以告诉我为什么会出现这种情况或如何防止这种情况?
负责获取选择范围的代码:
$('div[contenteditable="true"]').bind("mouseup keyup touchend", function() {
lastCaretIndex = getSelectionRange();
});
function getSelectionRange() {
var sel;
if (window.getSelection) {
sel = window.getSelection();
console.log(sel); // this doesn't print anything event empty string
if (sel.rangeCount) {
return sel.getRangeAt(0);
}
} else if (document.selection) {
return document.createRange();
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
<div id="main-input" contenteditable="true">Hello world!</div>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
Run Code Online (Sandbox Code Playgroud)
JSFiddle(打开浏览器控制台以确保不会记录选择).
问题是您只在contenteditable
元素上发生特定事件时记录选择更改.更具体地说,你有
$('div[contenteditable="true"]').bind("mouseup keyup touchend", // ...
Run Code Online (Sandbox Code Playgroud)
特别mouseup
是当选择改变时,通常会触发事件.除非它没有.当您将鼠标释放到可编辑范围之外时div
(在您的示例中执行!),那么div
将永远不会接收mouseup
事件,因此永远不会记录选择.
有两种方法:
body
.缺点是您收到的更多事件不会影响选择,并且仍然可以mouseup
在页面外获取事件.selectionchange
事件.document.addEventListener('selectionchange', function(event) {
console.log(event.type);
});
Run Code Online (Sandbox Code Playgroud)
<div contenteditable="true">Hello world!</div>
Run Code Online (Sandbox Code Playgroud)
您当然可以像在目前的事件处理程序中一样访问选择.每次选择更改时都会触发此事件,因此您可能希望对其进行限制.
完整实现可以在下面找到.
function handler() {
// do whatever you want here
// this shows the selection and all ranges it consists of
var sel = window.getSelection(),
ranges = Array(sel.rangeCount).fill(0).map((_, i) => sel.getRangeAt(i));
ranges = ranges.map((r) => `${r.startOffset}-${r.endOffset}`).join(';');
console.log(`Selection [${ranges}:"${sel.toString()}"]`);
}
function throttle(func) {
var timeoutId = false,
called = false,
wrap = function() {
if (!called) {
clearInterval(timeoutId);
timeoutId = false;
} else {
func();
}
called = false;
};
return function() {
if (timeoutId === false) {
func();
timeoutId = setInterval(wrap, 500);
} else {
called = true;
}
};
}
document.addEventListener('selectionchange', throttle(handler));
Run Code Online (Sandbox Code Playgroud)
<div contenteditable="true">Hello world!</div>
Run Code Online (Sandbox Code Playgroud)