如何通过单个处理函数处理来自各种按钮的 DOM 事件
How does one handle DOM events from various buttons by a single handler function
我不确定这是否可行,但我想使用一个独特的功能来触发 4 个不同的按钮来计算一个值(+ 和 -)。但是有四个不同的跨度值,例如,如果我触发森林,它只会在森林中添加或从森林中删除,如果我在城镇中触发,它只会在城镇中触发,等等。
// set inital value to zero
let count = 0;
// select value and buttons
const valueForest = document.querySelector("#valueForest");
const btns = document.querySelectorAll(".btn");
btns.forEach(function (btn) {
btn.addEventListener("click", function (e) {
const styles = e.currentTarget.classList;
if (styles.contains("decrease")) {
count--;
} else if (styles.contains("increase")) {
count++;
} else {
count = 0;
}
if (count > 0) {
valueForest.style.color = "green";
}
if (count < 0) {
valueForest.style.color = "red";
}
if (count === 0) {
valueForest.style.color = "#222";
}
valueForest.textContent = count;
});
});
<div class="scoreDiv">
<h3>Input below the quantity of each tile in the end of the game:</h3>
<div class="scoreItem">
<h4>Forest</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueForest">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Town</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueTown">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Production</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueProduction">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Factory</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueFactory">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
</div>
是的,有事件委托
这样:
const scoreDiv = document.querySelector('div.scoreDiv') // the parent Div
scoreDiv.onclick = e => // get all clicks everywhere upon this parent Div
{
if (!e.target.matches('div.scoreItem > button.btn ')) return // ignore other clicks
let countEl = e.target.closest('div.scoreItem').querySelector('span.value')
, newVal = +countEl.textContent + (e.target.matches('.decrease') ? -1 : +1)
;
countEl.style.color = (newVal > 0) ? 'green' : (newVal < 0) ? 'red' : '#222'
countEl.textContent = newVal;
}
span.value {
display : inline-block;
width : 5em;
text-align : right;
padding-right : .5em;
font-weight : bold;
}
<div class="scoreDiv">
<h3>Input below the quantity of each tile in the end of the game:</h3>
<div class="scoreItem">
<h4>Forest</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueForest">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Town</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueTown">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Production</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueProduction">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Factory</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueFactory">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
</div>
Explanations about
if (!e.target.matches('div.scoreItem > button.btn')) return
首先事件处理器scoreDiv.onclick = e =>
关注里面的一切
<div class="scoreDiv">
// everything inside
</div>
所以这个 space 中的任何点击事件都是由这个箭头函数处理的。
可能是点击:
在 H3 元素上
,或跨度元素之一
, 或任何 H4 元素
, 一切!
,甚至任何元素之间的 spaces。
事件 [e] 具有不同的属性
e.currentTarget
--> 是调用者元素的引用(这里是scoreDiv [div.scoreItem])
e.target
--> 是对发生点击的元素的引用
对于这项工作,我们只需要进行递增/递减操作。
这意味着我们必须忽略任何点击事件 不在加号或减号按钮上。
8 按钮是:<button class="btn decrease">-</button>
或 <button class="btn increase">-</button>
所有这些按钮对应CSS = div.scoreItem > button.btn
在javascript测试的代码是
e.target.matches('div.scoreItem > button.btn')
将return一个布尔值值(真或假)
现在有攻略:而不是做大
if ( e.target.matches('div.scoreItem > button.btn') )
{
//...
// with many lines of code
//until the closing
}
// and then quit the function
因为这是一个函数,我们使用 Logical NOT (!)
从函数中直接 return
,编码如下:
if (!e.target.matches('div.scoreItem > button.btn')) return
主要兴趣是在另一个元素(存在于 scoreDiv 中)有自己的点击事件处理程序的情况下快速释放事件管理器。
// set inital value to zero
//let count = 0;
// select value and buttons
const btns = document.querySelectorAll(".btn");
btns.forEach(function (btn) {
btn.addEventListener("click", function (e) {
const styles = e.currentTarget.classList;
const SectionValue = e.currentTarget.parentNode.querySelector('span');
var count = Number( SectionValue.innerHTML );
if (styles.contains("decrease")) {
count--;
} else {
count++;
}
if (count > 0) {
SectionValue.style.color = "green";
} else if (count < 0) {
SectionValue.style.color = "red";
} else {
SectionValue.style.color = "#222";
}
SectionValue.innerHTML = count;
});
});
<div class="scoreDiv">
<h3>Input below the quantity of each tile in the end of the game:</h3>
<div class="scoreItem">
<h4>Forest</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueForest">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Town</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueTown">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Production</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueProduction">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Factory</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueFactory">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
</div>
由于 Jojo 先生 已经 没有什么可添加的了,我将专注于一种方法将具有特定行为的重复使用的DOM结构视为组件
至于 OP 的示例,将只有一个 Score Item 组件,它仅实现一次特定行为并且独立于底层 HTML/CSS 的语义。
implemented/used JavaScript 代码的数量与 分数项目 组件的实际能力相比仍然足够小。
识别组件结构依赖于 data
属性,这些属性将此任务与提供的任何内容分离 HTML- 和 CSS- code/environment.
每个组件在 initialization/creation 时间封装其状态;因此它不从 DOM 读取数据(它只写入后者),但它确实读取和写入数据 from/to 其封装状态。
还可以通过组件特定的 data
属性为初始显示值以及不同的 incrementing/decrementing 值配置组件。
正值、负值或零值的颜色模式由组件特定和基于data
属性的CSS规则描述;没有理由与布局相关的脚本开销...
function incrementBoundItemScore() {
const { outputControl: ctrl, currentValue, incrementValue } = this;
ctrl.textContent = ctrl.dataset.currentValue = this.currentValue = (currentValue + incrementValue);
}
function decrementBoundItemScore() {
const { outputControl: ctrl, currentValue, decrementValue } = this;
ctrl.textContent = ctrl.dataset.currentValue = this.currentValue = (currentValue + decrementValue);
}
function initializeScoreItem(rootNode) {
const incrementControl = rootNode.querySelector('[data-increase]');
const decrementControl = rootNode.querySelector('[data-decrease]');
const outputControl = rootNode.querySelector('[data-output]');
const incrementValue = parseFloat(incrementControl.dataset.value, 10);
const decrementValue = parseFloat(decrementControl.dataset.value, 10);
const initialValue = parseFloat(outputControl.dataset.initialValue, 10);
const scoreItem = {
outputControl,
currentValue: initialValue,
incrementValue,
decrementValue,
}
outputControl.textContent = outputControl.dataset.currentValue = initialValue;
incrementControl
.addEventListener('click', incrementBoundItemScore.bind(scoreItem));
decrementControl
.addEventListener('click', decrementBoundItemScore.bind(scoreItem));
}
function initialize() {
document
.querySelectorAll('[data-score-item-component]')
.forEach(initializeScoreItem);
}
initialize();
body {
zoom: .8;
margin: 0;
}
ul, li {
list-style: none;
}
ul {
margin: 0;
}
fieldset {
padding: 0px 10px;
}
.score-group {
margin: 4px 0;
}
.score-item {
margin: 0 0 5px 0;
}
.score-item legend {
font-weight: bold;
}
.score-item strong {
position: relative;
top: -2px;
font-weight: normal;
font-size: small;
text-transform: uppercase
}
[data-output][data-current-value] {
display: inline-block;
width: 3em;
text-align: center;
font-weight: bold;
color: green;
}
[data-output][data-current-value="0"] {
color: #222;
}
[data-output][data-current-value^="-"] {
color: red;
}
<section class="score-board">
<!--
<h3>Input below the quantity of each tile in the end of the game:</h3>
//-->
<ul>
<li class="score-item">
<fieldset data-score-item-component>
<legend>Forest</legend>
<div class="score-group">
<button
type="button"
data-decrease
data-value='-1'
class="btn decrease"
>-</button>
<output
name="forest-score"
data-output
data-initial-value="9"
></output>
<button
type="button"
data-increase
data-value='1'
class="btn increase"
>+</button>
</div>
<strong>Soma</strong>
</fieldset>
</li>
<li class="score-item">
<fieldset data-score-item-component>
<legend>Town</legend>
<div class="score-group">
<button
type="button"
data-decrease
data-value='-2'
class="btn decrease"
>-</button>
<output
name="town-score"
data-output
data-initial-value="0"
></output>
<button
type="button"
data-increase
data-value='2'
class="btn increase"
>+</button>
</div>
<strong>Soma</strong>
</fieldset>
</li>
<li class="score-item">
<fieldset data-score-item-component>
<legend>Production</legend>
<div class="score-group">
<button
type="button"
data-decrease
data-value='-5'
class="btn decrease"
>-</button>
<output
name="production-score"
data-output
data-initial-value="-10"
></output>
<button
type="button"
data-increase
data-value='5'
class="btn increase"
>+</button>
</div>
<strong>Soma</strong>
</fieldset>
</li>
<li class="score-item">
<fieldset data-score-item-component>
<legend>Factory</legend>
<div class="score-group">
<button
type="button"
data-decrease
data-value='-2'
class="btn decrease"
>-</button>
<output
name="factory-score"
data-output
data-initial-value="-5"
></output>
<button
type="button"
data-increase
data-value='1'
class="btn increase"
>+</button>
</div>
<strong>Soma</strong>
</fieldset>
</li>
</ul>
</section>
我查看了如何通过 css 直接更改颜色,幸运的是 Peter Seliger 展示了这一点。
我还在 css 中添加了一个 output::before {content: attr(data-value)}
允许直接在显示器上显示此值,无需 JS 代码
这进一步简化了 javascript 代码。
(我还冒昧地把界面改了一点,让它完全变亮,这对本次演示没有意义)
const scoreBoard = document.querySelector('#score-board')
scoreBoard.onclick = e =>
{
if (!e.target.matches('#score-board button')) return
let countEl = e.target.closest('fieldset')
.querySelector('output[data-value]')
countEl.dataset.value = +countEl.dataset.value
+ (+e.target.dataset.increase)
}
body, textarea, input {
font-family : Helvetica, Arial sans-serif;
font-size : 12px;
}
#score-board fieldset {
width : 20em;
margin : .5em 1em;
}
#score-board legend {
font-size : 1.4em;
padding : 0 .7em;
}
#score-board output {
display : inline-block;
font-size : 1.4em;
width : 5em;
text-align : right;
padding-right : .5em;
color : green;
font-weight : bold;
border-bottom : 1px solid grey;
margin : 0 .8em 0 .2em;
}
#score-board output::before {
content : attr(data-value)
}
#score-board output[data-value="0"] {
color: #222;
}
#score-board output[data-value^="-"] {
color: red;
}
<section id="score-board">
<fieldset>
<legend>Forest</legend>
<output data-value="-10"></output>
<button data-increase="+1">𑁕</button>
<button data-increase="-1">𑁒</button>
</fieldset>
<fieldset>
<legend>Town</legend>
<output data-value="0"></output>
<button data-increase="+1">𑁕</button>
<button data-increase="-1">𑁒</button>
</fieldset>
<fieldset>
<legend>Production</legend>
<output data-value="-7"></output>
<button data-increase="+1">𑁕</button>
<button data-increase="-1">𑁒</button>
</fieldset>
<fieldset>
<legend>Factory</legend>
<output data-value="5"></output>
<button data-increase="+1">𑁕</button>
<button data-increase="-1">𑁒</button>
</fieldset>
</section>
我不确定这是否可行,但我想使用一个独特的功能来触发 4 个不同的按钮来计算一个值(+ 和 -)。但是有四个不同的跨度值,例如,如果我触发森林,它只会在森林中添加或从森林中删除,如果我在城镇中触发,它只会在城镇中触发,等等。
// set inital value to zero
let count = 0;
// select value and buttons
const valueForest = document.querySelector("#valueForest");
const btns = document.querySelectorAll(".btn");
btns.forEach(function (btn) {
btn.addEventListener("click", function (e) {
const styles = e.currentTarget.classList;
if (styles.contains("decrease")) {
count--;
} else if (styles.contains("increase")) {
count++;
} else {
count = 0;
}
if (count > 0) {
valueForest.style.color = "green";
}
if (count < 0) {
valueForest.style.color = "red";
}
if (count === 0) {
valueForest.style.color = "#222";
}
valueForest.textContent = count;
});
});
<div class="scoreDiv">
<h3>Input below the quantity of each tile in the end of the game:</h3>
<div class="scoreItem">
<h4>Forest</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueForest">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Town</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueTown">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Production</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueProduction">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Factory</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueFactory">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
</div>
是的,有事件委托
这样:
const scoreDiv = document.querySelector('div.scoreDiv') // the parent Div
scoreDiv.onclick = e => // get all clicks everywhere upon this parent Div
{
if (!e.target.matches('div.scoreItem > button.btn ')) return // ignore other clicks
let countEl = e.target.closest('div.scoreItem').querySelector('span.value')
, newVal = +countEl.textContent + (e.target.matches('.decrease') ? -1 : +1)
;
countEl.style.color = (newVal > 0) ? 'green' : (newVal < 0) ? 'red' : '#222'
countEl.textContent = newVal;
}
span.value {
display : inline-block;
width : 5em;
text-align : right;
padding-right : .5em;
font-weight : bold;
}
<div class="scoreDiv">
<h3>Input below the quantity of each tile in the end of the game:</h3>
<div class="scoreItem">
<h4>Forest</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueForest">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Town</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueTown">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Production</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueProduction">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Factory</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueFactory">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
</div>
Explanations about
if (!e.target.matches('div.scoreItem > button.btn')) return
首先事件处理器scoreDiv.onclick = e =>
关注里面的一切
<div class="scoreDiv">
// everything inside
</div>
所以这个 space 中的任何点击事件都是由这个箭头函数处理的。
可能是点击:
在 H3 元素上
,或跨度元素之一
, 或任何 H4 元素
, 一切!
,甚至任何元素之间的 spaces。
事件 [e] 具有不同的属性
e.currentTarget
--> 是调用者元素的引用(这里是scoreDiv [div.scoreItem])
e.target
--> 是对发生点击的元素的引用
对于这项工作,我们只需要进行递增/递减操作。
这意味着我们必须忽略任何点击事件 不在加号或减号按钮上。
8 按钮是:<button class="btn decrease">-</button>
或 <button class="btn increase">-</button>
所有这些按钮对应CSS = div.scoreItem > button.btn
在javascript测试的代码是
e.target.matches('div.scoreItem > button.btn')
将return一个布尔值值(真或假)
现在有攻略:而不是做大
if ( e.target.matches('div.scoreItem > button.btn') )
{
//...
// with many lines of code
//until the closing
}
// and then quit the function
因为这是一个函数,我们使用 Logical NOT (!)
从函数中直接 return
,编码如下:
if (!e.target.matches('div.scoreItem > button.btn')) return
主要兴趣是在另一个元素(存在于 scoreDiv 中)有自己的点击事件处理程序的情况下快速释放事件管理器。
// set inital value to zero
//let count = 0;
// select value and buttons
const btns = document.querySelectorAll(".btn");
btns.forEach(function (btn) {
btn.addEventListener("click", function (e) {
const styles = e.currentTarget.classList;
const SectionValue = e.currentTarget.parentNode.querySelector('span');
var count = Number( SectionValue.innerHTML );
if (styles.contains("decrease")) {
count--;
} else {
count++;
}
if (count > 0) {
SectionValue.style.color = "green";
} else if (count < 0) {
SectionValue.style.color = "red";
} else {
SectionValue.style.color = "#222";
}
SectionValue.innerHTML = count;
});
});
<div class="scoreDiv">
<h3>Input below the quantity of each tile in the end of the game:</h3>
<div class="scoreItem">
<h4>Forest</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueForest">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Town</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueTown">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Production</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueProduction">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
<div class="scoreItem">
<h4>Factory</h4>
<button class="btn decrease">-</button>
<span class="value" id="valueFactory">0</span>
<button class="btn increase">+</button>
<h4>SOMA</h4>
</div>
</div>
由于 Jojo 先生 已经
至于 OP 的示例,将只有一个 Score Item 组件,它仅实现一次特定行为并且独立于底层 HTML/CSS 的语义。
implemented/used JavaScript 代码的数量与 分数项目 组件的实际能力相比仍然足够小。
识别组件结构依赖于 data
属性,这些属性将此任务与提供的任何内容分离 HTML- 和 CSS- code/environment.
每个组件在 initialization/creation 时间封装其状态;因此它不从 DOM 读取数据(它只写入后者),但它确实读取和写入数据 from/to 其封装状态。
还可以通过组件特定的 data
属性为初始显示值以及不同的 incrementing/decrementing 值配置组件。
正值、负值或零值的颜色模式由组件特定和基于data
属性的CSS规则描述;没有理由与布局相关的脚本开销...
function incrementBoundItemScore() {
const { outputControl: ctrl, currentValue, incrementValue } = this;
ctrl.textContent = ctrl.dataset.currentValue = this.currentValue = (currentValue + incrementValue);
}
function decrementBoundItemScore() {
const { outputControl: ctrl, currentValue, decrementValue } = this;
ctrl.textContent = ctrl.dataset.currentValue = this.currentValue = (currentValue + decrementValue);
}
function initializeScoreItem(rootNode) {
const incrementControl = rootNode.querySelector('[data-increase]');
const decrementControl = rootNode.querySelector('[data-decrease]');
const outputControl = rootNode.querySelector('[data-output]');
const incrementValue = parseFloat(incrementControl.dataset.value, 10);
const decrementValue = parseFloat(decrementControl.dataset.value, 10);
const initialValue = parseFloat(outputControl.dataset.initialValue, 10);
const scoreItem = {
outputControl,
currentValue: initialValue,
incrementValue,
decrementValue,
}
outputControl.textContent = outputControl.dataset.currentValue = initialValue;
incrementControl
.addEventListener('click', incrementBoundItemScore.bind(scoreItem));
decrementControl
.addEventListener('click', decrementBoundItemScore.bind(scoreItem));
}
function initialize() {
document
.querySelectorAll('[data-score-item-component]')
.forEach(initializeScoreItem);
}
initialize();
body {
zoom: .8;
margin: 0;
}
ul, li {
list-style: none;
}
ul {
margin: 0;
}
fieldset {
padding: 0px 10px;
}
.score-group {
margin: 4px 0;
}
.score-item {
margin: 0 0 5px 0;
}
.score-item legend {
font-weight: bold;
}
.score-item strong {
position: relative;
top: -2px;
font-weight: normal;
font-size: small;
text-transform: uppercase
}
[data-output][data-current-value] {
display: inline-block;
width: 3em;
text-align: center;
font-weight: bold;
color: green;
}
[data-output][data-current-value="0"] {
color: #222;
}
[data-output][data-current-value^="-"] {
color: red;
}
<section class="score-board">
<!--
<h3>Input below the quantity of each tile in the end of the game:</h3>
//-->
<ul>
<li class="score-item">
<fieldset data-score-item-component>
<legend>Forest</legend>
<div class="score-group">
<button
type="button"
data-decrease
data-value='-1'
class="btn decrease"
>-</button>
<output
name="forest-score"
data-output
data-initial-value="9"
></output>
<button
type="button"
data-increase
data-value='1'
class="btn increase"
>+</button>
</div>
<strong>Soma</strong>
</fieldset>
</li>
<li class="score-item">
<fieldset data-score-item-component>
<legend>Town</legend>
<div class="score-group">
<button
type="button"
data-decrease
data-value='-2'
class="btn decrease"
>-</button>
<output
name="town-score"
data-output
data-initial-value="0"
></output>
<button
type="button"
data-increase
data-value='2'
class="btn increase"
>+</button>
</div>
<strong>Soma</strong>
</fieldset>
</li>
<li class="score-item">
<fieldset data-score-item-component>
<legend>Production</legend>
<div class="score-group">
<button
type="button"
data-decrease
data-value='-5'
class="btn decrease"
>-</button>
<output
name="production-score"
data-output
data-initial-value="-10"
></output>
<button
type="button"
data-increase
data-value='5'
class="btn increase"
>+</button>
</div>
<strong>Soma</strong>
</fieldset>
</li>
<li class="score-item">
<fieldset data-score-item-component>
<legend>Factory</legend>
<div class="score-group">
<button
type="button"
data-decrease
data-value='-2'
class="btn decrease"
>-</button>
<output
name="factory-score"
data-output
data-initial-value="-5"
></output>
<button
type="button"
data-increase
data-value='1'
class="btn increase"
>+</button>
</div>
<strong>Soma</strong>
</fieldset>
</li>
</ul>
</section>
我查看了如何通过 css 直接更改颜色,幸运的是 Peter Seliger 展示了这一点。
我还在 css 中添加了一个 output::before {content: attr(data-value)}
允许直接在显示器上显示此值,无需 JS 代码
这进一步简化了 javascript 代码。
(我还冒昧地把界面改了一点,让它完全变亮,这对本次演示没有意义)
const scoreBoard = document.querySelector('#score-board')
scoreBoard.onclick = e =>
{
if (!e.target.matches('#score-board button')) return
let countEl = e.target.closest('fieldset')
.querySelector('output[data-value]')
countEl.dataset.value = +countEl.dataset.value
+ (+e.target.dataset.increase)
}
body, textarea, input {
font-family : Helvetica, Arial sans-serif;
font-size : 12px;
}
#score-board fieldset {
width : 20em;
margin : .5em 1em;
}
#score-board legend {
font-size : 1.4em;
padding : 0 .7em;
}
#score-board output {
display : inline-block;
font-size : 1.4em;
width : 5em;
text-align : right;
padding-right : .5em;
color : green;
font-weight : bold;
border-bottom : 1px solid grey;
margin : 0 .8em 0 .2em;
}
#score-board output::before {
content : attr(data-value)
}
#score-board output[data-value="0"] {
color: #222;
}
#score-board output[data-value^="-"] {
color: red;
}
<section id="score-board">
<fieldset>
<legend>Forest</legend>
<output data-value="-10"></output>
<button data-increase="+1">𑁕</button>
<button data-increase="-1">𑁒</button>
</fieldset>
<fieldset>
<legend>Town</legend>
<output data-value="0"></output>
<button data-increase="+1">𑁕</button>
<button data-increase="-1">𑁒</button>
</fieldset>
<fieldset>
<legend>Production</legend>
<output data-value="-7"></output>
<button data-increase="+1">𑁕</button>
<button data-increase="-1">𑁒</button>
</fieldset>
<fieldset>
<legend>Factory</legend>
<output data-value="5"></output>
<button data-increase="+1">𑁕</button>
<button data-increase="-1">𑁒</button>
</fieldset>
</section>