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

如何在Vue.js中多次切换元素类实现骰子滚动动画

Fixing Dice Roll Animation in Vue.js Component

Got it, let's get that dice roll animation working in your Vue component! The problem boils down to three key missing pieces: you don't have the CSS that powers the 3D roll effect, you're trying to access DOM elements too early, and your current rollDice method only switches classes once instead of simulating a rolling sequence. Here's how to fix it step by step:

1. Add the Critical CSS for Animation

The original demo relies heavily on CSS 3D transforms and transitions to create the roll effect. Add this to your component's <style> section (you can keep scoped or remove it if you run into style specificity issues):

.container {
  padding-top: 3rem;
}

.card {
  border: none;
  border-radius: 1rem;
  box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);
}

.card-header {
  background-color: #fff;
  border-bottom: none;
  border-top-left-radius: 1rem;
  border-top-right-radius: 1rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.blink {
  animation: blink 1s infinite;
}

@keyframes blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}

.dice {
  display: flex;
  justify-content: center;
  gap: 2rem;
  padding: 2rem 0;
}

.die-list {
  list-style: none;
  padding: 0;
  margin: 0;
  width: 6rem;
  height: 6rem;
  position: relative;
  transform-style: preserve-3d;
  transition: transform 0.6s ease;
}

.die-item {
  position: absolute;
  width: 100%;
  height: 100%;
  background-color: white;
  border-radius: 0.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: inset 0 0 0.25rem rgba(0,0,0,0.2);
}

.dot {
  width: 1rem;
  height: 1rem;
  background-color: #333;
  border-radius: 50%;
  margin: 0.25rem;
}

/* Die face layouts */
.die-item[data-side="1"] .dot {
  margin: 0;
}

.die-item[data-side="2"] {
  justify-content: space-between;
}
.die-item[data-side="2"] .dot:first-child {
  align-self: flex-start;
}
.die-item[data-side="2"] .dot:last-child {
  align-self: flex-end;
}

.die-item[data-side="3"] {
  justify-content: space-between;
}
.die-item[data-side="3"] .dot:first-child {
  align-self: flex-start;
}
.die-item[data-side="3"] .dot:nth-child(2) {
  align-self: center;
}
.die-item[data-side="3"] .dot:last-child {
  align-self: flex-end;
}

.die-item[data-side="4"], .die-item[data-side="5"], .die-item[data-side="6"] {
  flex-wrap: wrap;
  padding: 0.5rem;
}

.die-item[data-side="4"] .dot {
  width: 45%;
  height: 45%;
}

.die-item[data-side="5"] .dot:nth-child(3) {
  width: 100%;
  height: 100%;
  margin: 0 auto;
}

.die-item[data-side="6"] .dot {
  width: 45%;
  height: 30%;
}

/* Roll animations */
.even-roll[data-roll="1"] { transform: rotateX(0deg) rotateY(0deg); }
.even-roll[data-roll="2"] { transform: rotateX(-90deg) rotateY(0deg); }
.even-roll[data-roll="3"] { transform: rotateX(0deg) rotateY(90deg); }
.even-roll[data-roll="4"] { transform: rotateX(0deg) rotateY(-90deg); }
.even-roll[data-roll="5"] { transform: rotateX(90deg) rotateY(0deg); }
.even-roll[data-roll="6"] { transform: rotateX(180deg) rotateY(0deg); }

.odd-roll[data-roll="1"] { transform: rotateX(0deg) rotateY(0deg); }
.odd-roll[data-roll="2"] { transform: rotateX(90deg) rotateY(0deg); }
.odd-roll[data-roll="3"] { transform: rotateX(0deg) rotateY(-90deg); }
.odd-roll[data-roll="4"] { transform: rotateX(0deg) rotateY(90deg); }
.odd-roll[data-roll="5"] { transform: rotateX(-90deg) rotateY(0deg); }
.odd-roll[data-roll="6"] { transform: rotateX(180deg) rotateY(0deg); }

2. Use Vue Refs Instead of DOM Queries

In Vue, it's better to use ref to access DOM elements instead of document.querySelectorAll. Update your template to add refs to the dice lists:

<template>
  <div class="container">
    <div class="row justify-content-center">
      <div class="col-md-6">
        <div class="card">
          <div class="card-header">
            Dice Game
            <h5 class="blink" style="color: red">* live</h5>
          </div>
          <div class="card-body" style="background-color: #3f0d12;background-image: linear-gradient(315deg, #3f0d12 0%, #a71d31 74%); ">
            <div class="dice">
              <ol class="die-list even-roll" data-roll="1" ref="dieList">
                <!-- Die 1 faces -->
                <li class="die-item" data-side="1">
                  <span class="dot"></span>
                </li>
                <li class="die-item" data-side="2">
                  <span class="dot"></span>
                  <span class="dot"></span>
                </li>
                <li class="die-item" data-side="3">
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                </li>
                <li class="die-item" data-side="4">
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                </li>
                <li class="die-item" data-side="5">
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                </li>
                <li class="die-item" data-side="6">
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                </li>
              </ol>
              <ol class="die-list odd-roll" data-roll="1" ref="dieList">
                <!-- Die 2 faces -->
                <li class="die-item" data-side="1">
                  <span class="dot"></span>
                </li>
                <li class="die-item" data-side="2">
                  <span class="dot"></span>
                  <span class="dot"></span>
                </li>
                <li class="die-item" data-side="3">
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                </li>
                <li class="die-item" data-side="4">
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                </li>
                <li class="die-item" data-side="5">
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                </li>
                <li class="die-item" data-side="6">
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                  <span class="dot"></span>
                </li>
              </ol>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

3. Update the Script to Simulate Rolling Animation

Modify your script to use refs, trigger the animation sequence properly, and wait for the DOM to be ready (use mounted instead of beforeMount):

<script>
export default {
  name: "Home",
  methods: {
    async rollDice() {
      const dice = this.$refs.dieList;
      if (!dice.length) return;

      // Simulate rolling for 1 second with rapid class/value changes
      const rollInterval = setInterval(() => {
        dice.forEach(die => {
          this.toggleClasses(die);
          die.dataset.roll = this.getRandomNumber(1, 6);
        });
      }, 100);

      // Stop rolling and set final random values
      setTimeout(() => {
        clearInterval(rollInterval);
        dice.forEach(die => {
          this.toggleClasses(die);
          die.dataset.roll = this.getRandomNumber(1, 6);
        });
      }, 1000);
    },
    toggleClasses(die) {
      die.classList.toggle("odd-roll");
      die.classList.toggle("even-roll");
    },
    getRandomNumber(min, max) {
      min = Math.ceil(min);
      max = Math.floor(max);
      return Math.floor(Math.random() * (max - min + 1)) + min;
    },
  },
  mounted() {
    this.rollDice();
  },
}
</script>

Key Changes Explained

  • CSS Added: The CSS provides the 3D transform rules, face layouts, and transition effects that make the dice roll look realistic.
  • Refs Used: this.$refs.dieList safely accesses the dice elements after the DOM is fully rendered, avoiding early DOM query issues.
  • Animation Sequence: The rollDice method uses setInterval to rapidly switch classes and random values for 1 second, creating the rolling effect, then stops on final random numbers.
  • Mounted Lifecycle: mounted ensures the DOM is ready before trying to interact with elements, which fixes the issue of querying elements too early.

Now your dice should roll smoothly when the component loads! You can also add a button to trigger rollDice on click if you want user-initiated rolls.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 17:58:10