如何通过单个处理程序函数处理来自各种按钮的 DOM 事件

如何解决如何通过单个处理程序函数处理来自各种按钮的 DOM 事件

我不确定是否可行,但我想使用一个独特的功能来触发 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>

解决方法

由于Jojo先生已经perfectly answered event delegation based approach没有什么可添加的,因此我将重点介绍一种查看和处理重复使用的方法DOM 结构以特定行为作为组件

至于 OP 的示例,将只有一个 Score Item 组件,它只实现一次特定行为并且独立于底层 HTML/CSS 的语义。

与这样一个Score Item 组件的实际能力相比,实现/使用的 JavaScript 代码的数量仍然足够少。

识别组件结构依赖于 data 属性,该属性将该任务与任何提供的 HTML 和 CSS 代码/环境分离。

每个组件在初始化/创建时封装其状态;因此它不会从 DOM 中读取数据(它只会写入到后者),但它会从/向其封装状态读取和写入数据。

组件还可以通过组件特定的 data 属性配置为初始显示的值以及不同的递增/递减值。

正值、负值或值的颜色模式由特定于组件和基于 data 属性的 CSS 规则描述;没有理由与布局相关的脚本开销......

function incrementBoundItemScore() {
  const { outputControl: ctrl,currentValue,incrementValue } = this;
  ctrl.textContent = ctrl.dataset.currentValue = this.currentValue = (currentValue + incrementValue);
}
function decrementBoundItemScore() {
  const { outputControl: ctrl,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>

,

是的,有事件委托

这样:

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>

关于

的说明
if (!e.target.matches('div.scoreItem > button.btn')) return  

首先,事件处理程序 scoreDiv.onclick = e => 关注内部的一切

<div class="scoreDiv"> 
  // everything inside
</div>

所以这个空间中的任何点击事件都由这个箭头函数处理。
可能是点击:
在 H3 元素上
,或 span 元素之一
,或任何 H4 元素
,一切!
,甚至任何元素之间的空格。

事件 [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')

将返回一个布尔值值(真或假)

现在有一个策略:而不是做大

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 中)有自己的 click eventHandler 的情况下快速释放事件管理器。

,

我查找了如何直接通过 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">&#69717;</button>
    <button data-increase="-1">&#69714;</button>
  </fieldset>
  <fieldset>
    <legend>Town</legend>
    <output data-value="0"></output>
    <button data-increase="+1">&#69717;</button>
    <button data-increase="-1">&#69714;</button>
  </fieldset>
  <fieldset>
    <legend>Production</legend>
    <output data-value="-7"></output>
    <button data-increase="+1">&#69717;</button>
    <button data-increase="-1">&#69714;</button>
  </fieldset>
  <fieldset>
    <legend>Factory</legend>
    <output data-value="5"></output>
    <button data-increase="+1">&#69717;</button>
    <button data-increase="-1">&#69714;</button>
  </fieldset>
</section>

,

// 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>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-