我有一个任务,用户需要用光标突出显示部分文本。但是,我现在处理鼠标移动事件的方式仅允许用户在单个方向上突出显示文本 - 即,如果他们在移动事件中更改鼠标方向,则文本突出显示不会跟随他们的光标。
这个post与请求相关,但通过添加/切换类来处理文本突出显示,而我通过更改跨度元素的背景颜色来处理突出显示。这个post也非常相关,但我不知道如何实施。
我希望弄清楚如何在鼠标改变方向时删除突出显示。这可能吗?
// Initialize data structures and variables
var wordDictionary = {}; // Dictionary to store words
var selectedWords = {}; // Currently selected words
var isMouseDown = false; // Flag for mouse state
var currentColor = ''; // Current highlight color
var usedColors = new Set(); // Set of used colors
// Available highlight colors
var availableColors = ["yellow", "red", "blue", "green", "orange"];
var highlights = {}; // Store highlighted words for each event
var eventCounter = 0; // Counter for events
var text = "Pangolins, sometimes known as scaly anteaters, are mammals of the order Pholidota. \
The one extant family, the Manidae, has three genera: Manis, Phataginus, and Smutsia. \
Manis comprises four species found in Asia, while Phataginus and Smutsia include two species each, all found in sub-Saharan Africa. \
These species range in size from 30 to 100 cm (12 to 39 in). \
A number of extinct pangolin species are also known. \
In September 2023, nine species were reported.<br><br> \
Pangolins have large, protective keratin scales, similar in material to fingernails and toenails, covering their skin; \
they are the only known mammals with this feature. \
They live in hollow trees or burrows, depending on the species. \
Pangolins are nocturnal, and their diet consists of mainly ants and termites, which they capture using their long tongues. \
They tend to be solitary animals, meeting only to mate and produce a litter of one to three offspring, which they raise for about two years.";
var textParagraph = document.getElementById("textParagraph");
textParagraph.innerHTML = text;
// Execute when the window is loaded
window.onload = function () {
var contentDiv = document.getElementById('content');
let ptag = contentDiv.querySelector('p');
var text = ptag.innerHTML.trim();
var words = text.split(/\s+|(?=<br><br>)/);
// Populate wordDictionary with words and create span elements for each word
for (var i = 0; i < words.length; i++) {
wordDictionary[i] = words[i];
}
for (var i = 0; i < words.length; i++) {
var wordElement = document.createElement('span');
wordElement.textContent = words[i] + ' ';
wordElement.dataset.index = i;
wordElement.addEventListener('mousedown', handleMouseDown);
if (words[i] == '<br><br>') {
wordElement.textContent = ' ';
wordElement.classList.add('line-break')
}
contentDiv.appendChild(wordElement);
}
// Add mouseup event listener for handling mouse up events
document.addEventListener('mouseup', handleMouseUp);
};
// Function to get a random highlight color
function getRandomColor() {
if (availableColors.length === 0) {
availableColors = [...usedColors];
usedColors.clear();
}
var randomIndex = Math.floor(Math.random() * availableColors.length);
var color = availableColors.splice(randomIndex, 1)[0];
usedColors.add(color);
return color;
}
// Function to handle mouse down event on words
function handleMouseDown(event) {
isMouseDown = true;
var index = event.target.dataset.index;
var word = event.target.textContent.trim();
if (!isHighlighted(index)) {
selectedWords = {};
selectedWords.startIndex = index;
selectedWords.endIndex = index;
selectedWords[index] = word;
// console.log(selectedWords)
currentColor = getRandomColor();
event.target.style.backgroundColor = currentColor;
event.preventDefault();
document.addEventListener('mousemove', handleMouseMove);
}
}
// Function to handle mouse up event
function handleMouseUp(event) {
if (isMouseDown) {
document.removeEventListener('mousemove', handleMouseMove);
var highlightedWords = {};
for (var index in selectedWords) {
if (index !== 'startIndex' && index !== 'endIndex') {
highlightedWords[index] = selectedWords[index];
}
}
eventCounter++;
highlights[eventCounter] = highlightedWords;
// console.log(highlights);
}
isMouseDown = false;
}
// Function to handle mouse move event (word selection)
function handleMouseMove(event) {
if (isMouseDown) {
var currentIndex = event.target.dataset.index;
var startIndex = selectedWords.startIndex;
var endIndex = selectedWords.endIndex;
var contentDiv = document.getElementById('content');
var newStartIndex = Math.min(startIndex, currentIndex);
var newEndIndex = Math.max(endIndex, currentIndex);
clearPreviousSelection();
for (var i = newStartIndex; i <= newEndIndex; i++) {
selectedWords[i] = wordDictionary[i];
}
for (var i = newStartIndex + 1; i <= newEndIndex + 1; i++) {
contentDiv.children[i].style.backgroundColor = currentColor;
}
selectedWords.startIndex = newStartIndex;
selectedWords.endIndex = newEndIndex;
}
}
// Function to clear previously selected words
function clearPreviousSelection() {
var contentDiv = document.getElementById('content');
for (var i in selectedWords) {
if (i !== 'startIndex' && i !== 'endIndex') {
contentDiv.children[i].style.backgroundColor = '';
delete selectedWords[i];
}
}
}
// Function to check if a word is already highlighted
function isHighlighted(index) {
for (var eventKey in highlights) {
var highlightedWords = highlights[eventKey];
for (var wordIndex in highlightedWords) {
if (wordIndex === index) {
return true;
}
}
}
return false;
}
// Function to clear all selections and reset
function clearSelections() {
var contentDiv = document.getElementById('content');
var wordElements = contentDiv.getElementsByTagName('span');
for (var i = 0; i < wordElements.length; i++) {
wordElements[i].style.backgroundColor = '';
}
highlights = {};
eventCounter = 0;
}
// Function to undo the last selection
function undoSelection() {
if (eventCounter > 0) {
var lastHighlight = highlights[eventCounter];
for (var index in lastHighlight) {
var wordIndex = parseInt(index);
var contentDiv = document.getElementById('content');
if (!isNaN(wordIndex)) {
contentDiv.children[wordIndex + 1].style.backgroundColor = '';
}
}
delete highlights[eventCounter];
eventCounter--;
}
}
// Add event listeners to the clear and undo buttons
document.getElementById("removeHighlight").addEventListener("click", clearSelections);
document.getElementById("undoHighlight").addEventListener("click", undoSelection);
#buttons {
margin-top: 30px;
}
.line-break {
display: block;
margin: 15px;
}
#trial_display {
display: block;
padding: 50px;
}
#title{
text-align: center;
font-size: 20px;
}
#content {
display: block;
border: 2px solid gray;
padding: 50px;
}
<div id="trial_display">
<div id="content">
<p id="textParagraph" style="display: none"></p>
</div>
<div id="buttons">
<button id="removeHighlight">Clear</button>
<button id="undoHighlight">Undo</button>
</div>
</div>
看来你想要的,已经通过浏览器的选择API本地实现了。
因此,您可以通过选择来处理这一切,通过从中获取元素,然后通过其数据索引更改默认选择突出显示样式。
(注意:这里我没有实现undo和clear,因为它需要大量重构,但这应该不难,我也保留了整个原始代码,除了移动的window.onload和禁用的事件侦听器,所以现在应该完全重构)
试试这个:
从选择中提取元素
循环每个元素,获取索引,然后更改其背景
每次选择开始时,删除之前的选择规则,并添加新的颜色
从选择中提取元素
function getSelectionElements(e) {
const sel = window.getSelection();
if (sel.rangeCount) {
// container to store all seleccted elements
const container = document.createElement('div');
for (let i = 0, len = sel.rangeCount; i < len; ++i) {
// append elements
// if only single text node, then append element from event.target
if (sel.getRangeAt(i).cloneContents().childNodes.length > 1) {
container.appendChild(sel.getRangeAt(i).cloneContents());
} else {
container.appendChild(e.target.cloneNode());
}
}
return container;
}
}
循环每个元素,获取索引,然后更改其背景
// get elements from selection
// loop and add background color to each
document.addEventListener('mouseup', (e) => {
const selectedElements = getSelectionElements(e);
if (selectedElements)
selectedElements.childNodes.forEach(el => {
let index = el.dataset.index;
let word = el.textContent.trim();
if (!isHighlighted(index)) {
selectedWords = {};
selectedWords.startIndex = index;
selectedWords.endIndex = index;
selectedWords[index] = word;
document.querySelector(`[data-index="${index}"]`).style.backgroundColor = currentColor;
}
});
});
每次选择开始时,删除之前的选择规则,并添加新的颜色
// remove previous selection style
// add new highlight color
document.addEventListener('mousedown', (e) => {
const sheet = window.document.styleSheets[0];
const rules = document.styleSheets[0].cssRules;
for (let i = 0; i < rules.length; i++) {
const rule = rules[i];
if (rule.selectorText.includes('::selection')) sheet.deleteRule(i);
}
currentColor = getRandomColor();
sheet.insertRule(`#content span::selection { background-color: ${currentColor}; }`, sheet.cssRules.length);
});
// Execute when the window is loaded
window.onload = function() {
// Initialize data structures and variables
var wordDictionary = {}; // Dictionary to store words
var selectedWords = {}; // Currently selected words
var isMouseDown = false; // Flag for mouse state
var currentColor = ''; // Current highlight color
var usedColors = new Set(); // Set of used colors
// Available highlight colors
var availableColors = ["yellow", "red", "blue", "green", "orange"];
var highlights = {}; // Store highlighted words for each event
var eventCounter = 0; // Counter for events
var text = "Pangolins, sometimes known as scaly anteaters, are mammals of the order Pholidota. \
The one extant family, the Manidae, has three genera: Manis, Phataginus, and Smutsia. \
Manis comprises four species found in Asia, while Phataginus and Smutsia include two species each, all found in sub-Saharan Africa. \
These species range in size from 30 to 100 cm (12 to 39 in). \
A number of extinct pangolin species are also known. \
In September 2023, nine species were reported.<br><br> \
Pangolins have large, protective keratin scales, similar in material to fingernails and toenails, covering their skin; \
they are the only known mammals with this feature. \
They live in hollow trees or burrows, depending on the species. \
Pangolins are nocturnal, and their diet consists of mainly ants and termites, which they capture using their long tongues. \
They tend to be solitary animals, meeting only to mate and produce a litter of one to three offspring, which they raise for about two years.";
var textParagraph = document.getElementById("textParagraph");
textParagraph.innerHTML = text;
var contentDiv = document.getElementById('content');
let ptag = contentDiv.querySelector('p');
var text = ptag.innerHTML.trim();
var words = text.split(/\s+|(?=<br><br>)/);
// Populate wordDictionary with words and create span elements for each word
for (var i = 0; i < words.length; i++) {
wordDictionary[i] = words[i];
}
for (var i = 0; i < words.length; i++) {
var wordElement = document.createElement('span');
wordElement.textContent = words[i] + ' ';
wordElement.dataset.index = i;
//wordElement.addEventListener('mousedown', handleMouseDown);
if (words[i] == '<br><br>') {
wordElement.textContent = ' ';
wordElement.classList.add('line-break')
}
contentDiv.appendChild(wordElement);
}
// Add mouseup event listener for handling mouse up events
//document.addEventListener('mouseup', handleMouseUp);
// Function to get a random highlight color
function getRandomColor() {
if (availableColors.length === 0) {
availableColors = [...usedColors];
usedColors.clear();
}
var randomIndex = Math.floor(Math.random() * availableColors.length);
var color = availableColors.splice(randomIndex, 1)[0];
usedColors.add(color);
return color;
}
// Function to handle mouse down event on words
function handleMouseDown(event) {
isMouseDown = true;
var index = event.target.dataset.index;
var word = event.target.textContent.trim();
if (!isHighlighted(index)) {
selectedWords = {};
selectedWords.startIndex = index;
selectedWords.endIndex = index;
selectedWords[index] = word;
// console.log(selectedWords)
currentColor = getRandomColor();
event.target.style.backgroundColor = currentColor;
event.preventDefault();
//document.addEventListener('mousemove', handleMouseMove);
}
}
// Function to handle mouse up event
function handleMouseUp(event) {
if (isMouseDown) {
document.removeEventListener('mousemove', handleMouseMove);
var highlightedWords = {};
for (var index in selectedWords) {
if (index !== 'startIndex' && index !== 'endIndex') {
highlightedWords[index] = selectedWords[index];
}
}
eventCounter++;
highlights[eventCounter] = highlightedWords;
// console.log(highlights);
}
isMouseDown = false;
}
// Function to handle mouse move event (word selection)
function handleMouseMove(event) {
if (isMouseDown) {
var currentIndex = event.target.dataset.index;
var startIndex = selectedWords.startIndex;
var endIndex = selectedWords.endIndex;
var contentDiv = document.getElementById('content');
var newStartIndex = Math.min(startIndex, currentIndex);
var newEndIndex = Math.max(endIndex, currentIndex);
clearPreviousSelection();
for (var i = newStartIndex; i <= newEndIndex; i++) {
selectedWords[i] = wordDictionary[i];
}
for (var i = newStartIndex + 1; i <= newEndIndex + 1; i++) {
contentDiv.children[i].style.backgroundColor = currentColor;
}
selectedWords.startIndex = newStartIndex;
selectedWords.endIndex = newEndIndex;
}
}
// Function to clear previously selected words
function clearPreviousSelection() {
var contentDiv = document.getElementById('content');
for (var i in selectedWords) {
if (i !== 'startIndex' && i !== 'endIndex') {
contentDiv.children[i].style.backgroundColor = '';
delete selectedWords[i];
}
}
}
// Function to check if a word is already highlighted
function isHighlighted(index) {
for (var eventKey in highlights) {
var highlightedWords = highlights[eventKey];
for (var wordIndex in highlightedWords) {
if (wordIndex === index) {
return true;
}
}
}
return false;
}
// Function to clear all selections and reset
function clearSelections() {
var contentDiv = document.getElementById('content');
var wordElements = contentDiv.getElementsByTagName('span');
for (var i = 0; i < wordElements.length; i++) {
wordElements[i].style.backgroundColor = '';
}
highlights = {};
eventCounter = 0;
}
// Function to undo the last selection
function undoSelection() {
if (eventCounter > 0) {
var lastHighlight = highlights[eventCounter];
for (var index in lastHighlight) {
var wordIndex = parseInt(index);
var contentDiv = document.getElementById('content');
if (!isNaN(wordIndex)) {
contentDiv.children[wordIndex + 1].style.backgroundColor = '';
}
}
delete highlights[eventCounter];
eventCounter--;
}
}
// Add event listeners to the clear and undo buttons
document.getElementById("removeHighlight").addEventListener("click", clearSelections);
document.getElementById("undoHighlight").addEventListener("click", undoSelection);
function getSelectionElements(e) {
const sel = window.getSelection();
if (sel.rangeCount) {
// container to store all seleccted elements
const container = document.createElement('div');
for (let i = 0, len = sel.rangeCount; i < len; ++i) {
// append elements
// if only single text node, then append element from event.target
if (sel.getRangeAt(i).cloneContents().childNodes.length > 1) {
container.appendChild(sel.getRangeAt(i).cloneContents());
} else {
container.appendChild(e.target.cloneNode());
}
}
return container;
}
}
// remove previous selection style
// add new highlight color
document.addEventListener('mousedown', (e) => {
const sheet = window.document.styleSheets[0];
const rules = document.styleSheets[0].cssRules;
for (let i = 0; i < rules.length; i++) {
const rule = rules[i];
if (rule.selectorText.includes('::selection')) sheet.deleteRule(i);
}
currentColor = getRandomColor();
sheet.insertRule(`#content span::selection { background-color: ${currentColor}; }`, sheet.cssRules.length);
});
// get elements from selection
// loop and add background color to each
document.addEventListener('mouseup', (e) => {
const selectedElements = getSelectionElements(e);
if (selectedElements)
selectedElements.childNodes.forEach(el => {
let index = el.dataset.index;
let word = el.textContent.trim();
if (!isHighlighted(index)) {
selectedWords = {};
selectedWords.startIndex = index;
selectedWords.endIndex = index;
selectedWords[index] = word;
document.querySelector(`[data-index="${index}"]`).style.backgroundColor = currentColor;
}
});
});
};
#buttons {
margin-top: 30px;
}
.line-break {
display: block;
margin: 15px;
}
#trial_display {
display: block;
padding: 50px;
}
#title {
text-align: center;
font-size: 20px;
}
#content {
display: block;
border: 2px solid gray;
padding: 50px;
}
<div id="trial_display">
<div id="content">
<p id="textParagraph" style="display:none"></p>
</div>
<div id="buttons">
<button id="removeHighlight">Clear</button>
<button id="undoHighlight">Undo</button>
</div>
</div>