在 Chrome 中将文件拖放到文本区域时获取光标位置
Get cursor position when a file is dropped in textarea in Chrome
当您将文件从 OS 文件系统拖动到文本区域或文本输入上时,光标会出现在鼠标指针附近(这与 positionStart
不同),向用户显示拖动位置将插入内容。
更新:这是一张图片,我正在将文件 (test.sh) 拖到文本输入上。如果“文本”字样的中间,您可以看到放置光标。选择光标在字符串的末尾(在这张图片上看不到)。
(Chrome 的默认行为是打开拖放的文件,但我在 drop
事件中覆盖了这个行为。我想在文本区域中插入文件名.)
我试图在 drop
发生时获得此位置(根据文本区域值字符串中的索引)。有什么想法吗?
这只是部分答案:以下在 IE11 中有效,但在 Chrome 中无效(未在其他浏览器中测试)。
只是 select 上面 input
的一些字母,然后将它们拖到下面的字母中:
let to = document.getElementById("to");
to.addEventListener("dragover", function (e) {
if (e.target.selectionStart) {
console.log(e.target.selectionStart);
}
});
<input type="text" id="from" value="select some letters from this sentence, and drag them into the other input element"/ style="width: 500px;"><br/>
<input type="text" id="to" value="drag over here"/>
未来研究的一些注意事项:
在 Chrome 中,只有在 input
元素内首次设置焦点后才会触发 dragover
事件。
在Chrome中,selectionStart
的值是目标输入中最后selected文本位置的值(换句话说:最后位置目标输入内的光标)。
设置 type="number"
触发 selectionStart
在 Chrome 中分配给 null
,但在 IE11 中不会。
呸,你想做的事情并不容易,因为没有办法引用这个特定的插入符号!
在我的脑海中,你只能通过繁重的变通方法来实现:drop
发生时你可以获得的是鼠标光标位置。
您必须制作一个不可见的 div-克隆,在形状、文本大小、边距等方面与文本区域相同,自动填充文本区域中的文本。
接下来,您必须在 div 中为每个可能的插入符位置创建一个跨度(即文本的每个字符 1 个跨度),并获取每个跨度的 x 和 y 坐标并将它们保存到一个数组中.
.txtarea {
width: 300px;
height: 150px;
font-size: 12px;
font-family: Arial;
padding: 5px;
text-align: left;
border: 1px solid red;
}
<textarea class="txtarea">Mytext</textarea>
<!--just an example, auto-fill this content through a JS oninput event -->
<div class="txtarea"><span>M</span><span>y</span><span>t</span><span>e</span><span>x</span><span>t</span></div>
然后,在 drop
发生时,获取事件的鼠标坐标,将它们与坐标数组进行比较,approximate the closest x/y position 并在基于文本的文本区域中设置一个新的 selectionStart
索引在那上面,插入文件名,然后恢复之前的选择开始。
从你的图片来看,它看起来像一个输入文本(我承认,我懒得为 textarea
... 编写代码)但是 - 无论如何 - 这是一个很好的问题。
要获得文本宽度,您需要克隆原始元素并逐个字符地遍历文本。仅举一个例子,请在此处查看有关主题的一些答案:“如何使用 JavaScript”设置 ellipsis 文本。
我还注意到,通过将鼠标指针移到文本上,插入符号会从每个字符的中心左右移动。最后,这里的主要问题是:如何找到每个字符中间的x。
因此,我的代码分为两部分:文本输入克隆和字符位置。之后,要定位插入符号,您可以使用这样的现有库:jQuery Caret Plugin or jQuery Caret - 由您决定 - 我会跳过这部分问题。
我在 FF、Safari、IE 和 Chrome 中测试了下面的代码,这些浏览器的拖放行为显然存在一些小而烦人的问题,但在我看来它们无关紧要。
function getCaretPos(target, x) {
var txt = target.value, doc = target.ownerDocument,
clone = doc.createElement('span'), /* Make a clone */
style = doc.defaultView.getComputedStyle(target, null),
mL = style.getPropertyValue('margin-left'),
pL = style.getPropertyValue('padding-left'),
mouseX = x - parseFloat(mL) - parseFloat(pL);
clone.style.fontFamily = style.getPropertyValue('font-family');
clone.style.fontSize = style.getPropertyValue('font-size');
clone.style.fontWeight = style.getPropertyValue('font-weight');
clone.style.position = 'absolute'; /* Keep layout */
clone.style.left = -9999;
target.parentNode.appendChild(clone);
clone.style.width = 'auto';
clone.style.whiteSpace = 'pre'; /* Keep whitespaces */
clone.style.marginLeft = 0;
clone.style.paddingLeft = 0;
clone.innerText = txt; /* Start from full length */
var i = txt.length, pos = -1, xL = 0, xC = 0, xR = clone.clientWidth;
while (i--) { /* Find the caret pos */
clone.innerText = txt.slice(0, i);
xL = clone.clientWidth;
xC = (0.5 * (xR + xL)) | 0; /* We need the center */
if (xC < mouseX) { pos = i; break }
xR = xL;
}
pos++; /* Restore the correct index */
target.parentNode.removeChild(clone); /* Clean up */
clone = null;
return pos;
}
function onFileDragOver(e) {
if(!window.chrome) e.preventDefault(); /* Show the caret in Chromium */
}
function onFileDrop(e) {
e.preventDefault();
var target = e.currentTarget, txt = target.value,
pos = getCaretPos(target, e.offsetX),
tok1 = txt.substr(0, pos), tok2 = txt.substr(pos);
/* Get the drop-action result */
var result = '', files = e.dataTransfer.files,
data = e.dataTransfer.getData('text');
for (var i = 0, f; (f = files[i]); i++) { result += f.name }
target.value = tok1 + result + tok2;
target.focus();
/* Up to You how to position the caret */
if(target.setSelectionRange) target.setSelectionRange(pos, pos);
//$(target).caret(pos);
}
$(document).ready(function () {
var target = document.getElementById('search-input');
target.addEventListener('dragover', onFileDragOver);
target.addEventListener('drop', onFileDrop);
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<link rel="stylesheet" href="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.2/jquery.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="header"><h1>Caret Position</h1></div>
<div data-role="content">
<div class="ui-field-contain">
<label for="search-input">Products</label>
<input type="search" name="search-input" id="search-input" value="target text box"
spellcheck="false" autocomplete="off" autocorrect="off" autocapitalize="none"/>
</div>
</div>
</div>
</body>
</html>
尝试jQuery。您要做的是获取带有查询选择器的文本框,然后将其绑定到 mousemove
并获取 $(this).caret().start
.
示例:
let cursorPosition = 0;
$("#textinput").bind("mousemove", function() {
cursorPosition = $(this).caret().start;
});
// Do what you want with cursorPosition when file is dropped
我想这就是您需要做的所有事情。
只要你肯用jQuery就可以了
当您将文件从 OS 文件系统拖动到文本区域或文本输入上时,光标会出现在鼠标指针附近(这与 positionStart
不同),向用户显示拖动位置将插入内容。
更新:这是一张图片,我正在将文件 (test.sh) 拖到文本输入上。如果“文本”字样的中间,您可以看到放置光标。选择光标在字符串的末尾(在这张图片上看不到)。
(Chrome 的默认行为是打开拖放的文件,但我在 drop
事件中覆盖了这个行为。我想在文本区域中插入文件名.)
我试图在 drop
发生时获得此位置(根据文本区域值字符串中的索引)。有什么想法吗?
这只是部分答案:以下在 IE11 中有效,但在 Chrome 中无效(未在其他浏览器中测试)。
只是 select 上面 input
的一些字母,然后将它们拖到下面的字母中:
let to = document.getElementById("to");
to.addEventListener("dragover", function (e) {
if (e.target.selectionStart) {
console.log(e.target.selectionStart);
}
});
<input type="text" id="from" value="select some letters from this sentence, and drag them into the other input element"/ style="width: 500px;"><br/>
<input type="text" id="to" value="drag over here"/>
未来研究的一些注意事项:
在 Chrome 中,只有在
input
元素内首次设置焦点后才会触发dragover
事件。在Chrome中,
selectionStart
的值是目标输入中最后selected文本位置的值(换句话说:最后位置目标输入内的光标)。设置
type="number"
触发selectionStart
在 Chrome 中分配给null
,但在 IE11 中不会。
呸,你想做的事情并不容易,因为没有办法引用这个特定的插入符号!
在我的脑海中,你只能通过繁重的变通方法来实现:drop
发生时你可以获得的是鼠标光标位置。
您必须制作一个不可见的 div-克隆,在形状、文本大小、边距等方面与文本区域相同,自动填充文本区域中的文本。
接下来,您必须在 div 中为每个可能的插入符位置创建一个跨度(即文本的每个字符 1 个跨度),并获取每个跨度的 x 和 y 坐标并将它们保存到一个数组中.
.txtarea {
width: 300px;
height: 150px;
font-size: 12px;
font-family: Arial;
padding: 5px;
text-align: left;
border: 1px solid red;
}
<textarea class="txtarea">Mytext</textarea>
<!--just an example, auto-fill this content through a JS oninput event -->
<div class="txtarea"><span>M</span><span>y</span><span>t</span><span>e</span><span>x</span><span>t</span></div>
然后,在 drop
发生时,获取事件的鼠标坐标,将它们与坐标数组进行比较,approximate the closest x/y position 并在基于文本的文本区域中设置一个新的 selectionStart
索引在那上面,插入文件名,然后恢复之前的选择开始。
从你的图片来看,它看起来像一个输入文本(我承认,我懒得为 textarea
... 编写代码)但是 - 无论如何 - 这是一个很好的问题。
要获得文本宽度,您需要克隆原始元素并逐个字符地遍历文本。仅举一个例子,请在此处查看有关主题的一些答案:“如何使用 JavaScript”设置 ellipsis 文本。
我还注意到,通过将鼠标指针移到文本上,插入符号会从每个字符的中心左右移动。最后,这里的主要问题是:如何找到每个字符中间的x。
因此,我的代码分为两部分:文本输入克隆和字符位置。之后,要定位插入符号,您可以使用这样的现有库:jQuery Caret Plugin or jQuery Caret - 由您决定 - 我会跳过这部分问题。
我在 FF、Safari、IE 和 Chrome 中测试了下面的代码,这些浏览器的拖放行为显然存在一些小而烦人的问题,但在我看来它们无关紧要。
function getCaretPos(target, x) {
var txt = target.value, doc = target.ownerDocument,
clone = doc.createElement('span'), /* Make a clone */
style = doc.defaultView.getComputedStyle(target, null),
mL = style.getPropertyValue('margin-left'),
pL = style.getPropertyValue('padding-left'),
mouseX = x - parseFloat(mL) - parseFloat(pL);
clone.style.fontFamily = style.getPropertyValue('font-family');
clone.style.fontSize = style.getPropertyValue('font-size');
clone.style.fontWeight = style.getPropertyValue('font-weight');
clone.style.position = 'absolute'; /* Keep layout */
clone.style.left = -9999;
target.parentNode.appendChild(clone);
clone.style.width = 'auto';
clone.style.whiteSpace = 'pre'; /* Keep whitespaces */
clone.style.marginLeft = 0;
clone.style.paddingLeft = 0;
clone.innerText = txt; /* Start from full length */
var i = txt.length, pos = -1, xL = 0, xC = 0, xR = clone.clientWidth;
while (i--) { /* Find the caret pos */
clone.innerText = txt.slice(0, i);
xL = clone.clientWidth;
xC = (0.5 * (xR + xL)) | 0; /* We need the center */
if (xC < mouseX) { pos = i; break }
xR = xL;
}
pos++; /* Restore the correct index */
target.parentNode.removeChild(clone); /* Clean up */
clone = null;
return pos;
}
function onFileDragOver(e) {
if(!window.chrome) e.preventDefault(); /* Show the caret in Chromium */
}
function onFileDrop(e) {
e.preventDefault();
var target = e.currentTarget, txt = target.value,
pos = getCaretPos(target, e.offsetX),
tok1 = txt.substr(0, pos), tok2 = txt.substr(pos);
/* Get the drop-action result */
var result = '', files = e.dataTransfer.files,
data = e.dataTransfer.getData('text');
for (var i = 0, f; (f = files[i]); i++) { result += f.name }
target.value = tok1 + result + tok2;
target.focus();
/* Up to You how to position the caret */
if(target.setSelectionRange) target.setSelectionRange(pos, pos);
//$(target).caret(pos);
}
$(document).ready(function () {
var target = document.getElementById('search-input');
target.addEventListener('dragover', onFileDragOver);
target.addEventListener('drop', onFileDrop);
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<link rel="stylesheet" href="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.2/jquery.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="header"><h1>Caret Position</h1></div>
<div data-role="content">
<div class="ui-field-contain">
<label for="search-input">Products</label>
<input type="search" name="search-input" id="search-input" value="target text box"
spellcheck="false" autocomplete="off" autocorrect="off" autocapitalize="none"/>
</div>
</div>
</div>
</body>
</html>
尝试jQuery。您要做的是获取带有查询选择器的文本框,然后将其绑定到 mousemove
并获取 $(this).caret().start
.
示例:
let cursorPosition = 0;
$("#textinput").bind("mousemove", function() {
cursorPosition = $(this).caret().start;
});
// Do what you want with cursorPosition when file is dropped
我想这就是您需要做的所有事情。
只要你肯用jQuery就可以了