在 Javascript 中,如何编写一个函数来影响多个按钮,每个按钮都有自己单独的数组?

In Javascript, how do I write one function that will effect multiple buttons, each with their own separate arrays?

我目前正在设置一个包含三个独立按钮的应用程序,每个按钮应该从特定于该按钮的数组中随机 select 一个元素。我已经成功地为每个按钮编写了单独的函数,但我想知道是否有办法将它压缩成一个可以应用于所有三个按钮的函数。

这是我现在的 Javascript:

const greyButton = document.querySelector('#grey');
greyButton.addEventListener('click', () => {
  let grey = ['Statblocks/Grey/badger.png', 'Statblocks/Grey/giantrat.png', 'Statblocks/Grey/badger.png', 'Statblocks/Grey/boar.png', 'Statblocks/Grey/panther.png', 'Statblocks/Grey/gitant badger.png', 'Statblocks/Grey/dire wolf.png', 'Statblocks/Grey/giant elk.png']
  
  for (i=0;i<grey.length;i++){
    let greyBalls = grey[Math.floor(Math.random() * grey.length)];
    document.getElementById('greyBall').src = greyBalls;
  }
});

const rustButton = document.querySelector('#rust');
rustButton.addEventListener('click', () => {
  let rust = ['Statblocks/Rust/rat.png', 'Statblocks/Rust/owl.png', 'Statblocks/Rust/mastiff.png', 'Statblocks/Rust/goat.png', 'Statblocks/Rust/giant goat.png', 'Statblocks/Rust/giant boar.png', 'Statblocks/Rust/lion.png', 'Statblocks/Rust/brown bear.png']
  
  for (i=0;i<rust.length;i++){
    let rustBalls = rust[Math.floor(Math.random() * rust.length)];
    document.getElementById('rustBall').src = rustBalls;
  }
});

const tanButton = document.querySelector('#tan');
tanButton.addEventListener('click', () => {
  let tan = ['Statblocks/Tan/jackal.png', 'Statblocks/Tan/ape.png', 'Statblocks/Tan/baboon.png', 'Statblocks/Tan/axe beak.png', 'Statblocks/Tan/black bear.png', 'Statblocks/Tan/giant weasel.png', 'Statblocks/Tan/giant hyena.png', 'Statblocks/Tan/tiger.png']
  
  for (i=0;i<tan.length;i++){
    let tanBalls = tan[Math.floor(Math.random() * tan.length)];
    document.getElementById('tanBall').src = tanBalls;
  }
});

和连接的HTML:

 <div class="row">
            <div class="column">
                <h1>Grey Bag of Tricks</h1>
                <button class="button" id='grey'>Draw from the Bag</button>
                <img src="" alt="" id="greyBall">
            </div>
            <div class="column">
                <h1>Rust Bag of Tricks</h1>
                <button class="button" id='rust'>Draw from the Bag</button>
                <img src="" alt="" id="rustBall">
            </div>
            <div class="column">
                <h1>Tan Bag of Tricks</h1>
                <button class="button" id='tan'>Draw from the Bag</button>
                <img src="" alt="" id="tanBall">
            </div>
        </div>

var urlsByColor = {
  grey: ['Statblocks/Grey/badger.png', 'Statblocks/Grey/giantrat.png', 'Statblocks/Grey/badger.png', 'Statblocks/Grey/boar.png', 'Statblocks/Grey/panther.png', 'Statblocks/Grey/gitant badger.png', 'Statblocks/Grey/dire wolf.png', 'Statblocks/Grey/giant elk.png'],
  rust: ['Statblocks/Rust/rat.png', 'Statblocks/Rust/owl.png', 'Statblocks/Rust/mastiff.png', 'Statblocks/Rust/goat.png', 'Statblocks/Rust/giant goat.png', 'Statblocks/Rust/giant boar.png', 'Statblocks/Rust/lion.png', 'Statblocks/Rust/brown bear.png'],
  tan: ['Statblocks/Tan/jackal.png', 'Statblocks/Tan/ape.png', 'Statblocks/Tan/baboon.png', 'Statblocks/Tan/axe beak.png', 'Statblocks/Tan/black bear.png', 'Statblocks/Tan/giant weasel.png', 'Statblocks/Tan/giant hyena.png', 'Statblocks/Tan/tiger.png']
};

function changeBall (e) {
  const urls = urlsByColor[e.target.id];
  const randomIndex = Math.floor(Math.random() * urls.length);
  const randomUrl = urls[randomIndex];
  const associatedBall = e.target.closest('.column').querySelector('.ball');
  
  console.log(`change ${e.target.id} to ${randomUrl}`);
  associatedBall.src = randomUrl;
  console.log(associatedBall);
}

[...document.querySelectorAll('.color.button')].forEach(button =>
  button.addEventListener('click', changeBall)
);
<div class="row">
  <div class="column">
    <h1>Grey Bag of Tricks</h1>
    <button class="button color" id='grey'>Draw from the Bag</button>
    <img src="" alt="" class="ball" id="greyBall">
  </div>
  <div class="column">
    <h1>Rust Bag of Tricks</h1>
    <button class="button color" id='rust'>Draw from the Bag</button>
    <img src="" alt="" class="ball" id="rustBall">
  </div>
  <div class="column">
    <h1>Tan Bag of Tricks</h1>
    <button class="button color" id='tan'>Draw from the Bag</button>
    <img src="" alt="" class="ball" id="tanBall">
  </div>
</div>

好的,所以有一些事情发生了变化。

  • 我将 url 的列表提取到地图中,可以使用按钮的 ID 来查找 url 要使用的内容
  • 按钮和球的标记更改为具有用于查找和查找的通用 classes
  • 当点击发生时,我们通过按钮 id
  • 获取 urls
  • 然后我们得到一个随机索引,就像之前所做的那样
  • 我们得到该索引的随机关联 url
  • 我们通过父列 class
  • 找到与按钮上下文关联的球
  • 最后我们改变球的url

一般来说,你把相似的重复部分放在一个函数中,然后通过用函数的参数替换它们来抽象出每次用法中不同的部分:

function addHandler(buttonSelector, ballImages, ballId) {
  const button = document.querySelector(buttonSelector);
  button.addEventListener('click', e => {
    for (let i=0; i<ballImages.length; i++) {
      let ball = ballImages[Math.floor(Math.random() * ballImages.length)];
      document.getElementById(ballId).src = ball;
    }
  });
}

这样你就可以这样称呼它

addHandler('#grey', ['Statblocks/Grey/badger.png', 'Statblocks/Grey/giantrat.png', 'Statblocks/Grey/badger.png', 'Statblocks/Grey/boar.png', 'Statblocks/Grey/panther.png', 'Statblocks/Grey/gitant badger.png', 'Statblocks/Grey/dire wolf.png', 'Statblocks/Grey/giant elk.png'], 'greyBall');
addHandler('#rust', ['Statblocks/Rust/rat.png', 'Statblocks/Rust/owl.png', 'Statblocks/Rust/mastiff.png', 'Statblocks/Rust/goat.png', 'Statblocks/Rust/giant goat.png', 'Statblocks/Rust/giant boar.png', 'Statblocks/Rust/lion.png', 'Statblocks/Rust/brown bear.png'], 'rustBall');
addHandler('#tan', ['Statblocks/Tan/jackal.png', 'Statblocks/Tan/ape.png', 'Statblocks/Tan/baboon.png', 'Statblocks/Tan/axe beak.png', 'Statblocks/Tan/black bear.png', 'Statblocks/Tan/giant weasel.png', 'Statblocks/Tan/giant hyena.png', 'Statblocks/Tan/tiger.png'], 'tanBall');

虽然这仍然有些重复。我们可以通过对数据进行额外处理来避免这种情况,以便我们可以传递更简单的值:

function addHandler(id, imageNames) {
  const buttonSelector = '#' + id;
  const ballImages = imageNames.map(name => `Statblocks/${id[0].toUpperCase()+id.slice(1)}/${name}.png}`);
  const ballId = id + 'Ball';

  … // rest as before
}

addHandler('grey', ['badger', 'giantrat', 'badger', 'boar', 'panther', 'gitant badger', 'dire wolf', 'giant elk']);
addHandler('rust', ['rat', 'owl', 'mastiff', 'goat', 'giant goat', 'giant boar', 'lion', 'brown bear']);
addHandler('tan', ['jackal', 'ape', 'baboon', 'axe beak', 'black bear', 'giant weasel', 'giant hyena', 'tiger']);

最后我将 querySelector 更改为 getElementById 查找,并删除不必要的循环,然后我们到达

function addHandler(id, imageNames) {
  const ballImages = imageNames.map(name => `Statblocks/${id[0].toUpperCase()+id.slice(1)}/${name}.png}`);
  const button = document.getElementById(id);
  button.addEventListener('click', e => {
    let ball = ballImages[Math.floor(Math.random() * ballImages.length)];
    document.getElementById(id + 'Ball').src = ball;
  });
}

addHandler('grey', ['badger', 'giantrat', 'badger', 'boar', 'panther', 'gitant badger', 'dire wolf', 'giant elk']);
addHandler('rust', ['rat', 'owl', 'mastiff', 'goat', 'giant goat', 'giant boar', 'lion', 'brown bear']);
addHandler('tan', ['jackal', 'ape', 'baboon', 'axe beak', 'black bear', 'giant weasel', 'giant hyena', 'tiger']);