You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JS水平轮盘开发问题:单次转动保留15个对象并添加Active类

水平轮盘功能优化问题

我现在有一个水平轮盘,打开页面启动时控制台会通过getRandomItem()输出15次轮盘启动相关信息。我在generateItems()里生成了15个轮盘对象,但不知道怎么实现单次转动轮盘时保留这15个对象,同时在start()函数里给最终选中的对象添加active类。相关代码如下:

原JS代码

const items = [
    { name: 'flami', img: '', price: 100, priceCount: 0 },
    { name: 'flami', img: '', price: 100, priceCount: 0 },
    { name: 'flami', img: '', price: 100, priceCount: 0 },
    { name: 'flami', img: '', price: 200, priceCount: 0 },
    { name: 'flami', img: '', price: 250, priceCount: 0 },
  ];
  
let balance = 2000;
let countFlip = 0;

function getRandomItem() {
    let item;

    while(!item) {
        item = items[Math.floor(Math.random() * items.length)];

        if (item.price > balance * 0.20)  {
            return getRandomItem();
            } else {
            countFlip++;
            
            balance -= item.price;
            if (balance < 0) {
                console.log('Game over!');
                return;
            }
            if (countFlip % 10 === 0) {
                balance += 2000;
            }
            console.log(`You got ${item.name} for ${item.price}. Your balance is now ${balance}. ${countFlip}`);
            }
        return item;
    }
}

let isSpinning = false;

function generateItems() {
    if (isSpinning) {
        return;
    }
    isSpinning = true;

    document.querySelector('.list').innerHTML = '';
    document.querySelector('.scope').innerHTML = `<ul class="list"></ul>`;

    const list = document.querySelector('.list')
    list.innerHTML = ''

    for (let i = 0; i < 15; i++){
        item = getRandomItem()

        const li = document.createElement('li')
        li.classList.add('list_item')
        li.innerHTML = `
            <img src ="${item.img}" alt="" />
        `
        list.append(li)
    }
}

generateItems()


function start() {
    generateItems()
    const list = document.querySelector('.list')

    requestAnimationFrame(() => {
        list.style.left = '50%'
        list.style.transform = 'translate3d(-50%, 0, 0)'
    },0)

    const item = list.querySelectorAll('li')[7]

    list.addEventListener('transitionend', () =>{
        item.classList.add('active')
        isSpinning = false;
        
    })
}

原HTML代码

<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css" rel="stylesheet"/>
    <div class="app">
      <i class="pointer fa-solid fa-location-pin" style="font-size: 40px; color: rgb(163, 41, 41);"></i>
      <div class="scope">
        <ul class="list"></ul>
      </div>

      <button onclick="start()" class="start">Start</button>
    </div>

问题分析与修改方案

核心问题是getRandomItem()每次调用都会扣减余额、输出日志,导致生成15个对象时触发15次消费逻辑。下面是针对性修改:

1. 拆分逻辑,分离候选生成与消费处理

把原getRandomItem()拆成两个函数:一个只生成符合条件的候选对象,不碰余额;另一个在转动结束后处理选中对象的消费。

2. 保留轮盘对象集合

新增全局变量存储当前轮盘的15个对象,确保单次转动过程中对象不变。

3. 修正选中与动画逻辑

确保动画结束后只处理一次消费,且正确给选中项加active类。


修改后的完整代码

JS代码

const items = [
    { name: 'flami', img: '', price: 100, priceCount: 0 },
    { name: 'flami', img: '', price: 100, priceCount: 0 },
    { name: 'flami', img: '', price: 100, priceCount: 0 },
    { name: 'flami', img: '', price: 200, priceCount: 0 },
    { name: 'flami', img: '', price: 250, priceCount: 0 },
];

let balance = 2000;
let countFlip = 0;
let isSpinning = false;
let currentWheelItems = []; // 存储当前轮盘的15个对象

// 仅生成符合条件的候选对象,不处理余额
function getRandomCandidate() {
    let item;
    while (!item) {
        item = items[Math.floor(Math.random() * items.length)];
        // 过滤超出余额20%的选项
        if (item.price > balance * 0.20) {
            item = null;
        }
    }
    return item;
}

// 生成并渲染轮盘的15个候选对象
function generateWheelItems() {
    if (isSpinning) return;
    
    currentWheelItems = [];
    // 一次性生成15个候选
    for (let i = 0; i < 15; i++) {
        currentWheelItems.push(getRandomCandidate());
    }
    
    // 渲染到DOM
    const list = document.querySelector('.list');
    list.innerHTML = '';
    currentWheelItems.forEach(item => {
        const li = document.createElement('li');
        li.classList.add('list_item');
        li.innerHTML = `<img src="${item.img}" alt="${item.name}" />`;
        list.append(li);
    });
}

// 转动结束后处理选中对象的余额逻辑
function processSelectedItem(selectedItem) {
    countFlip++;
    balance -= selectedItem.price;
    
    if (balance < 0) {
        console.log('Game over!');
        return;
    }
    if (countFlip % 10 === 0) {
        balance += 2000;
    }
    console.log(`You got ${selectedItem.name} for ${selectedItem.price}. Your balance is now ${balance}. ${countFlip}`);
}

function start() {
    if (isSpinning) return;
    isSpinning = true;
    
    // 移除之前的active类
    document.querySelectorAll('.list_item.active').forEach(el => el.classList.remove('active'));
    
    // 生成新的轮盘候选(如果想固定候选池,注释掉这行)
    generateWheelItems();
    
    const list = document.querySelector('.list');
    // 触发转动动画
    requestAnimationFrame(() => {
        list.style.left = '50%';
        list.style.transform = 'translate3d(-50%, 0, 0)';
    });
    
    // 选中中间的第7个元素(索引7)
    const selectedLi = list.querySelectorAll('li')[7];
    const selectedItem = currentWheelItems[7];
    
    // 动画结束后执行
    const onTransitionEnd = () => {
        selectedLi.classList.add('active');
        processSelectedItem(selectedItem); // 仅处理一次消费
        isSpinning = false;
        list.removeEventListener('transitionend', onTransitionEnd); // 移除监听避免重复触发
    };
    list.addEventListener('transitionend', onTransitionEnd);
}

// 页面加载时初始化轮盘
generateWheelItems();

HTML代码(无需修改)

<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css" rel="stylesheet"/>
<div class="app">
  <i class="pointer fa-solid fa-location-pin" style="font-size: 40px; color: rgb(163, 41, 41);"></i>
  <div class="scope">
    <ul class="list"></ul>
  </div>
  <button onclick="start()" class="start">Start</button>
</div>

关键修改说明

  • 拆分逻辑后,生成15个对象时不会扣余额,只有转动结束选中后才处理一次消费,控制台只会输出1次结果。
  • currentWheelItems确保单次转动过程中轮盘对象固定不变。
  • 移除了原代码中重复创建<ul class="list">的冗余操作。
  • 给transitionend监听添加了移除逻辑,防止多次触发。

内容的提问来源于stack exchange,提问作者Twenix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 17:53:31