VanillaJavaScript:如何动态创建一个按钮,在用户选择一些文本后显示,然后对该文本执行操作



我正在做一个小项目,在这个项目中,用户可以上传他们的.docx文件,然后在应用程序中读取这些文件(以及其他用户的文件(。为此,我从docx中提取了文本,并将其显示在单独视图和html页面的div中。现在,我想给我的用户一个选项,让他们从这个div(并且只有这个div(中选择一些文本,当他们选择了它时,我想显示一个悬停在他们可以点击的文本上的按钮。这个按钮将用于将所选文本添加到他们的笔记中,类似于MS Edge在我们选择一些文本时自动执行的操作(它会添加这三个点,然后打开一个菜单进行复制和其他操作(。或者更准确地说,如果你熟悉Coursera网站——当选择了课程中的一些文本时,会出现一个"保存笔记"按钮,点击它会将所选文本直接添加到你的笔记中,而无需用户做任何其他事情,用户在任何时候进入笔记时都可以找到保存的笔记(下面的照片显示了这个按钮的作用(。

Coursera"保存笔记"按钮示例

然而,我不确定如何实现这一点。我想我会使用window.getSelection,然后将选择存储在一些常量中,然后通过fetch发送到我的服务器,将其添加到Notes模型中(我使用的是Django(。但我不知道如何实现这一点,也不知道从哪里开始。如何让按钮悬停在其他文本上,只有当选择时?任何形式的帮助都非常感谢!!注意:如果可能的话,我希望在VanillaJS中这样做,因为我还不熟悉React或其他库/框架。

将问题分解为任务:

  1. 检测选择开始和结束-可以分别使用onmouseup和onmousedown完成
  • 使用EventHandler可用的事件对象来查找所选区域的坐标

  • onmousedown存储选择开始的坐标

  • onmouseup获取选择结束的坐标

  • 使用起始和结束坐标定位复制按钮(使用CSS(

  1. 获取所选文本-window.getSelection可用于在按下按钮时获取所选的文本

一旦检测到所选内容并且所选文本可用,就可以将其推送到服务器。

类似这样的东西:

const copyBtn = document.createElement("button");
copyBtn.innerHTML = "Press this button to log selected text";
copyBtn.style.position = "absolute";
copyBtn.style.display = "none";
copyBtn.onclick = function(evt) {
console.log(window.getSelection().toString())
}
document.body.appendChild(copyBtn);
const paragraph = document.querySelector('p');
let startX = 0;
let startY = 0;
function mouseDown(evt) {
console.log(`Selection started at : ${evt.clientX}, ${evt.clientY}`);
startX = evt.clientX;
startY = evt.clientY;
copyBtn.style.display = "none";
}
function mouseUp(evt) {
console.log(`Selection ended at : ${evt.clientX}, ${evt.clientY}`);
copyBtn.style.display = "block";
copyBtn.style.top = `${Math.min(startY, evt.clientY)}px`;
copyBtn.style.left = `${(startX + evt.clientX) / 2}px`;
}
paragraph.onmouseup = mouseUp;
paragraph.onmousedown = mouseDown
<!DOCTYPE html>
<html>
<body>
<p>
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
</p>
</body>
</html>

JavaScript中有一个函数可以检索当前选定的文本:

function getSelectionText() {
if (document.getSelection().toString().length === 0) {
//do nothing
} else if (document.getSelection().toString().length > 0) {
//fire button function
}
return text;
}

我相信没有一个函数只有在选择文本时才会触发,所以该函数应该一直运行,或者当有dom时;mouseup";事件

必须回答我自己的问题,以备将来参考多亏了Tyler Durden和Endoxos的解决方案,在玩了几个小时之后,这是(在大多数情况下(完成我希望它做的事情的代码(为了更容易理解,也对这个答案进行了注释(:

/* Read view - dynamically adding Save Note button after selection of text */
document.addEventListener('DOMContentLoaded', function() {
/* Use this functions only in a div that contains displayed contents of files */
const content = document.querySelector('#docContent');
/* Create and append button */
const noteBtn = document.createElement('button');
noteBtn.innerHTML = 'Save Note';
noteBtn.style.position = 'absolute';
noteBtn.style.display = 'none';
noteBtn.className = 'btn btn-sm btn-danger';
content.appendChild(noteBtn);
let startX = 0;
let startY = 0;
/* On mousedown only save starting X and Y, but relevant to entire page, 
not the client X and Y, which causes button to stay on top part of doc,
even if we want to select text from bottom part. */
content.addEventListener('mousedown', function(evt){
startX = evt.pageX;
startY = evt.pageY;
});

/* On mouse up, we check if the end X and Y differ from starting
and if, we place the button to the end of the selection, where user's
mouse will naturally be, after making the selection. This works on every
part of the page and dom, except on the far right side (if selection ends
on the endpoint on right side, that is), and for these cases one might make
calculations and for those cases just reverse the direction of button, but
I can't be bothered to do so today, maybe tomorrow... Also, if the start and
end X and Y do not differ, most likely user wanted to click somewhere to 'hide'
the popped up button, so we just set its display to none in such case*/
content.addEventListener('mouseup', function(evt) {  
if (evt.pageX != startX && evt.pageY != startY ) {
noteBtn.style.top = `${evt.pageY}px`;
noteBtn.style.left = `${evt.pageX}px`;
noteBtn.style.display = 'block';
} else {
noteBtn.style.display = 'none';
}
});
/* Finally, we add event listener for clicks on button, and when the button is
clicked we save the text to const, and pass that to our view in Django (in this 
case there is csrf_exempt, but normally one would do that too...) */
noteBtn.addEventListener('click', function() {
const note = document.getSelection().toString();
const id = content.querySelector('.reading_content_id').value;
fetch(`/add_note/${id}`, {
method: 'POST',
body: JSON.stringify({
note:`${note}`
})
}).then (function() {
document.getSelection().collapseToEnd();
noteBtn.style.display = 'none';
});
});
});

最新更新