javascript - 单击侦听器上的 e.stopPropagation 不起作用
问题描述
我正在尝试构建随机颜色生成器。它为每种生成的颜色创建框。您可以将鼠标悬停在它们上,然后复制或锁定您喜欢的颜色。
当我点击复制按钮或背景部分时出现问题。它也会触发锁定按钮,锁定按钮也会触发复制按钮。
我不知道为什么会发生这种情况,因为e.stopPropagation)
使用了函数。
我是 js 世界的新手,所以如果你发现任何可以修复的东西,我会很感激让我知道如何改进它
完整代码:
//selecting JS OBJECTS
const background = document.querySelector('.background');
const copy = document.querySelector('#copy');
const p = document.querySelector('p');
const body = document.querySelector('body');
const colorContainer = document.querySelector('.color-container');
let spacebarFirstCount = 0;
body.addEventListener('keydown', (e) => {
if (e.key === " ") {
const color = generateRGB();
changeBackgroundColor(color);
p.innerText = color;
if (copy.innerText != "copy") {
copy.innerText = "copy";
}
addColorBox(color);
if (spacebarFirstCount !== 3) {
if (spacebarFirstCount === 2) {
document.querySelector('.spacebar').remove();
}
spacebarFirstCount++;
}
}
});
copy.addEventListener('click', () => {
navigator.clipboard.writeText(p.innerText);
copy.innerText = "done";
})
const addColorBox = (color) => {
const colorBox = document.createElement('div');
colorBox.style.backgroundColor = color;
colorBox.classList.toggle('color-box');
colorBox.addEventListener('mouseover', hover2)
fixBoxNumber();
colorContainer.append(colorBox);
}
const generate255 = () => {
return Math.floor(Math.random() * 255) + 1;
}
const generateRGB = () => {
const r = generate255();
const g = generate255();
const b = generate255();
const alpha = (Math.floor((Math.random() + 0.1) * 100) / 100);
return `rgb(${r},${g},${b},${alpha})`;
}
const changeBackgroundColor = (color) => {
background.style.backgroundColor = color;
}
function hover2() {
const copyText = document.createElement('span');
const lockText = document.createElement('span');
copyText.append("copy");
copyText.classList.toggle("hoverText");
lockText.classList.toggle("hoverText");
this.classList.toggle('box-animation');
this.removeEventListener('mouseover', hover2);
const currentColor = background.style.background;
changeBackgroundColor(this.style.backgroundColor);
function copyToClipboard(event) {
navigator.clipboard.writeText(this.style.backgroundColor);
copyText.innerText = "copied";
this.removeEventListener('click', copyToClipboard);
event.stopPropagation();
}
function leaving() {
copyText.remove();
lockText.remove();
this.classList.remove('box-animation');
this.addEventListener('mouseover', hover2);
this.removeEventListener('click', copyToClipboard);
this.removeEventListener('mouseleave', leaving);
this.removeEventListener('click', locking);
}
this.addEventListener('click', copyToClipboard);
this.addEventListener('mouseleave', leaving)
if (!this.hasAttribute('locked')) {
lockText.append("lock");
}
else {
lockText.append("locked");
}
// ! Stop propagation nie działa
function locking(e) {
if (!this.hasAttribute('locked')) {
this.setAttribute('locked', 'true');
lockText.innerText = "locked";
} else {
this.removeAttribute('locked');
lockText.innerText = "lock";
}
e.stopPropagation();
}
this.addEventListener('click', locking);
this.append(lockText);
this.append(copyText);
}
const fixBoxNumber = () => {
if (colorContainer.childElementCount >= 19) {
const deleteBoxes = Object.values(colorContainer.childNodes).filter((box) => !box.hasAttribute("locked"));
if (deleteBoxes.length < 12) {
for (let i = 0; i < deleteBoxes.length; i++) {
deleteBoxes[i].remove();
}
}
else {
for (let i = 0; i < 12; i++) {
deleteBoxes[i].remove();
}
}
}
}
解决方案
这是一个随机颜色的片段:
- 您可以锁定/解锁颜色
- 你可以复制一种颜色(好的,
navigator.clipboard
这里禁止使用它) - 您可以重新随机化颜色(锁定颜色保持不变)
const colorSquare = document.getElementById('color-square')
const btnRandomizeColors = document.getElementById('btn-randomize-colors')
const copiedColor = document.getElementById('copied-hex-color')
const randomColor = () => {
return `#${Math.floor(Math.random()*16777215).toString(16)}`
}
// color object factory
const getRandomColor = () => ({
locked: false,
color: randomColor()
})
// init of color list
const initColorList = () => [...Array(16)].map(getRandomColor)
// color list class:
// - tracks state of colors (locked/not locked)
// - provides functions to manipulate color list
class ColorList {
constructor() {
this.colors = initColorList()
}
toggleLockedByIdx(idx) {
this.colors[idx].locked = !this.colors[idx].locked
}
randomizeColors() {
this.colors = this.colors.map(color => {
if (color.locked) {
return color
} else {
return getRandomColor()
}
})
}
}
const colorList = new ColorList()
// single color square presentation
const singleSquareHtml = ({
color,
idx,
locked
}) => {
let html = ''
html += `
<div class="single-color-square" style="background-color:${color};">
<button class="btn-ctrl btn-lock" data-idx="${idx}">${locked ? 'UNLOCK' : 'LOCK'}</button>
<button class="btn-ctrl btn-copy" data-hexcolor="${color}">COPY</button>
</div>
`
return html
}
// color square presentation
const colorSquareHtml = ({
colorList
}) => {
let html = ''
colorList.colors.forEach(({
color,
locked
}, idx) => {
html += singleSquareHtml({
color,
idx,
locked,
})
})
return html
}
function lockColor(idx, colorList) {
colorList.toggleLockedByIdx(idx)
// to update the button label:
updateColorSquareHTML({
colorList
})
}
function copyHexColor(hexColor) {
// copying to clipboard source:
// https://stackoverflow.com/questions/400212/how-do-i-copy-to-the-clipboard-in-javascript
// the fallback is not implemented here
navigator.clipboard.writeText(hexColor).then(function() {
console.log('Async: Copying to clipboard was successful!');
}, function(err) {
console.error('Async: Could not copy text: ', err);
});
}
// updating color square HTML
// - adding btn handlers
const updateColorSquareHTML = ({
colorList
}) => {
colorSquare.innerHTML = colorSquareHtml({
colorList
})
const lockBtns = document.querySelectorAll('.btn-lock')
lockBtns.forEach(btn => {
btn.addEventListener('click', function(e) {
e.stopPropagation()
const idx = Number(this.getAttribute('data-idx'))
lockColor(idx, colorList)
})
})
const copyBtns = document.querySelectorAll('.btn-copy')
copyBtns.forEach(btn => {
btn.addEventListener('click', function(e) {
e.stopPropagation()
const hexColor = this.getAttribute('data-hexcolor')
copyHexColor(hexColor)
// to display the color picked
copiedColor.textContent = hexColor
})
})
}
updateColorSquareHTML({
colorList: colorList
})
btnRandomizeColors.addEventListener('click', function() {
colorList.randomizeColors()
updateColorSquareHTML({
colorList
})
})
#container {
width: 100%;
height: 100%;
}
#color-square {
display: grid;
grid-template-columns: repeat(4, 80px);
grid-template-rows: repeat(4, 80px);
}
.single-color-square {
display: flex;
width: 100%;
height: 100%;
justify-content: center;
flex-direction: column;
align-items: center;
}
.btn-ctrl {
display: none;
margin: 4px;
}
.single-color-square:hover .btn-ctrl {
display: block;
}
<div id="container">
<div>
<button id="btn-randomize-colors">
RANDOMIZE COLORS
</button>
<br />
<div id="copied-hex-color"></div>
</div>
<div id="color-square"></div>
</div>
你可以看到
- 颜色列表操作被封装在
ColorList
类中:在该类之外没有任何变化或修改颜色列表。这意味着每次修改颜色列表后,都应该重新渲染视图(否则修改不会显示) eventListener
s 在每次重新渲染时添加:这在更大的范围内可能无效,但在这种大小下,它并没有真正的区别(浏览器倾向于删除不需要的侦听器,所以为什么要打扰?;))- 而不是
class
我本可以使用 afactory
(现在更流行),但这并没有什么区别(source 1,source 2等)
另外,我想说:在单独的文件中会更好 - 因此,如果您在这样的环境中工作,请尝试将其分解为更合理的块。
推荐阅读
- c# - Cefsharp 进程用户 ID 传递
- azure-active-directory - 用户帐户永远不会为空
- echarts - 如何在echarts中的条之间添加更多空间
- r - 在 r 中使用 sf 打开 shapefile 会出错
- c# - 如何在 SQLite Xamarin Android 中使用字符串变量作为表名
- java - 如何调用我创建的侦听器而不是 hiberante 侦听器?
- dax - 适用于 Excel SUMIFS 的 Powerpivot/DAX 等效项,其中查找字段包含来自另一个字段的部分文本
- reactjs - useState React 没有更新
- c# - 错误:在 ASP.NET Core MVC 项目中的 Controllers/HelloWorldControllers.cs 途中
- php - 未捕获的 Slim\Exception\HttpMethodNotAllowedException:方法不允许。必须是以下之一:GET