classList.toggle() 表示多个 div



我有 3 个div 作为颜色可供选择,还有 3 个空白div。我希望让用户能够:

(1( 单击彩色div,然后单击空白div,然后将空白div 着色为用户选择的颜色。代码似乎有效。

(2(我希望用户能够再次单击彩色空白div,它变为白色。代码似乎有效。

问题是,如果空白div 是彩色的,并且用户选择另一种颜色并再次单击彩色空白div,则会向div 添加更新的颜色类,并且事情变得不可预测。您可以打开控制台并跟踪空白div 类的混乱更改。

如何解决这个问题?我只希望空白div 在两个类之间切换。

var chosenColor;
function pickColor(arg){
chosenColor=arg.id;
}
function draw(id){
document.getElementById(id).classList.toggle("white");
document.getElementById(id).classList.toggle(chosenColor);
}
.box{
width: 100px;
height: 100px;
border: 1px solid black;
display: inline-block;

}
.red{background: red}
.blue{background: blue;}
.yellow{background: yellow;}
.white{background: white;}
<html>
<body>
<div class="box red" id="red" onclick="pickColor(this)">1</div>
<div class="box blue" id="blue" onclick="pickColor(this)">2</div>
<div class="box yellow" id="yellow" onclick="pickColor(this)">3</div>
<br><br>
<div class="box white" id="4" onclick="draw(4)">4</div>
<div class="box white" id="5" onclick="draw(5)">5</div>
<div class="box white" id="6" onclick="draw(6)">6</div>
</body>
</html>

而不是使用类并遇到分配多个嵌套类或不得不使用复杂的白色逻辑的问题......

我会使用data-*属性:

var chosenColor;
function pick(el) {
chosenColor = el.dataset.color;
}
function draw(el) {
el.dataset.color = el.dataset.color ? "" : chosenColor;
}
body { background: #eee; }
.box {
width: 100px;
height: 100px;
border: 1px solid black;
display: inline-block;
background: white;         /* BY DEFAULT !!! */
}
[data-color=red]    { background: red; }
[data-color=blue]   { background: blue; }
[data-color=yellow] { background: yellow; }
<div class="box" onclick="pick(this)" data-color="red">1</div>
<div class="box" onclick="pick(this)" data-color="blue">2</div>
<div class="box" onclick="pick(this)" data-color="yellow">3</div>
<br><br>
<div class="box" onclick="draw(this)">4</div>
<div class="box" onclick="draw(this)">5</div>
<div class="box" onclick="draw(this)">6</div>

三元el.dataset.color = el.dataset.color ? "" : chosenColor;的作用是:

  • 如果元素已经有任何data-color设置为data-color""(无(
  • 否则,将data-color设置为预选chosenColor

检查元素的classname是否white。如果没有,请将其类名设置为white- 否则,将其设置为所选颜色。您可以将盒子放在容器中并使用.container > div选择器,无需为盒子提供.box类。此外,在侦听器中,this将引用单击的元素 - 当您已经引用该元素时,无需使用getElementById

var chosenColor;
function pickColor(arg) {
chosenColor = arg.id;
}
function draw(element, id) {
if (element.className !== 'white') element.className = 'white';
else element.className = chosenColor;
}
.container > div {
width: 100px;
height: 100px;
border: 1px solid black;
display: inline-block;
}
.red {
background: red
}
.blue {
background: blue;
}
.yellow {
background: yellow;
}
.white {
background: white;
}
<div class="container">
<div class="red" id="red" onclick="pickColor(this)">1</div>
<div class="blue" id="blue" onclick="pickColor(this)">2</div>
<div class="yellow" id="yellow" onclick="pickColor(this)">3</div>
<br><br>
<div class="white" id="4" onclick="draw(this, 4)">4</div>
<div class="white" id="5" onclick="draw(this, 5)">5</div>
<div class="white" id="6" onclick="draw(this, 6)">6</div>
</div>

答案

请参阅 - https://codepen.io/stephanieschellin/pen/xyYxrj/(注释代码(

或。。。

var activeColor
function setPickerColor(event) {
activeColor = event.target.dataset.boxColorIs
}
function setThisBoxColor(event) {
let element = event.target
let the_existing_color_of_this_box = element.dataset.boxColorIs
if (the_existing_color_of_this_box == activeColor) {
delete element.dataset.boxColorIs
} else {
element.dataset.boxColorIs = activeColor
}
}
.box {
width: 100px;
height: 100px;
border: 1px solid black;
display: inline-block;
background: white;
}
[data-box-color-is="red"] {
background: red
}
[data-box-color-is="blue"] {
background: blue;
}
[data-box-color-is="yellow"] {
background: yellow;
}
<html>
<body>
<div id="box-1" class="box" data-box-color-is="red" onclick="setPickerColor(event)">1</div>
<div id="box-2" class="box" data-box-color-is="blue" onclick="setPickerColor(event)">2</div>
<div id="box-3" class="box" data-box-color-is="yellow" onclick="setPickerColor(event)">3</div>
<br>
<br>
<div id="box-4" class="box" onclick="setThisBoxColor(event)">4</div>
<div id="box-5" class="box" onclick="setThisBoxColor(event)">5</div>
<div id="box-6" class="box" onclick="setThisBoxColor(event)">6</div>
</body>
</html>

使用data-属性,您可以从CSS类中分离JavaScript功能问题。这简化了您的逻辑,但最重要的是,它允许设置应用程序样式的人独立于添加JS功能的人工作。当您的团队使用 BEM 或 OOCSS 模式时,这种解耦变得非常重要。

理想情况下,不要将样式附加到data-属性,而是使用data-维护"状态",并具有另一个基于data-状态设置classList的函数。允许你100%确定你所做的样式更改永远不会影响JS功能(QA会喜欢你(。但这是超越这篇文章的演变。

通过此设置,我们不使用id的,但我将它们保留了下来,因为它是一个重要的最佳实践。此代码很可能会演变为具有侦听器的组件,而不是内联onClick调用。JavaScript 选择器应该始终附加到iddata-变量,而不是类。此外,ID 应始终存在,供 QA 团队在其脚本中使用。您可能会冒着有人更改类名或删除它以调整样式并无意中破坏 JS 侦听器的风险。

我切换了参数以传递"事件"而不是元素"this"。任何使用 JS 事件函数的人都会期望事件对象作为第一个参数。如果你愿意,你可以传递"this"作为第二个参数,但event.target会给你同样的东西。

需要注意的另一件事是声明data-变量和从 JS 调用它之间的语法变化。

网页<div data-box-color-is="red">1</div>

JSevent.target.dataset.boxColorIs

无论您如何格式化数据属性名称,在 JS 中引用它时,它总是会被解析为 camelCase ...data-box_color--IS仍然会变成...dataset.boxColorIs

此外,作为代码的演变,您可以删除全局 JS var 并使用data-将值存储在页面上的<body>或其他元素上。这将为您提供一个单一的事实或"状态"来源,多个功能/组件可以引用该来源,而不会使全局空间混乱。

延伸阅读

https://css-tricks.com/bem-101/

https://en.bem.info/

https://philipwalton.com/articles/side-effects-in-css/

https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/

https://philipwalton.com/articles/decoupling-html-css-and-javascript/

最新更新