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

在Stimulus.js中如何实现原生JavaScript的.style.transform功能?——基于Rails复刻Javascript30时钟场景

在Rails Stimulus控制器中复刻JavaScript30的简易动画时钟

嘿,我完全懂你作为编程新手,想用熟悉的Stimulus在Rails应用里复刻JavaScript30课程里的时钟动画时遇到的卡点——尤其是不知道怎么在Stimulus里实现原生JS中element.style.transform那样的样式修改,对吧?别着急,咱们一步步把这个问题解决掉。

首先,先回顾你提供的可以正常运行的原生代码(方便对照):

<body>
  <div class="clock">
    <div class="clock-face">
      <div class="hand hour-hand"></div>
      <div class="hand min-hand"></div>
      <div class="hand second-hand"></div>
    </div>
  </div>
  <style>
    .clock { width: 30rem; height: 30rem; border: 20px solid white; border-radius: 50%; margin: 50px auto; position: relative; padding: 2rem; box-shadow: 0 0 0 4px rgba(0,0,0,0.1), inset 0 0 0 3px #EFEFEF, inset 0 0 10px black, 0 0 10px rgba(0,0,0,0.2); }
    .clock-face { position: relative; width: 100%; height: 100%; transform: translateY(-3px); /* account for the height of the clock hands */ }
    .hand { width: 50%; height: 6px; background: black; position: absolute; top: 50%; transform-origin: 100%; transform: rotate(90deg); transition: all 0.05s; transition-timing-function: cubic-bezier(0.1, 2.7, 0.58, 1); }
  </style>
  <script>
    const secondHand = document.querySelector('.second-hand');
    const minsHand = document.querySelector('.min-hand');
    const hourHand = document.querySelector('.hour-hand');
    function setDate() {
      const now = new Date();
      const seconds = now.getSeconds();
      const secondsDegrees = ((seconds / 60) * 360) + 90;
      secondHand.style.transform = `rotate(${secondsDegrees}deg)`;
      const mins = now.getMinutes();
      const minsDegrees = ((mins / 60) * 360) + ((seconds/60)*6) + 90;
      minsHand.style.transform = `rotate(${minsDegrees}deg)`;
      const hour = now.getHours();
      const hourDegrees = ((hour / 12) * 360) + ((mins/60)*30) + 90;
      hourHand.style.transform = `rotate(${hourDegrees}deg)`;
    }
    setInterval(setDate, 1000);
    setDate();
  </script>

接下来看你尝试的Stimulus代码,其实你已经走对了大部分路——Stimulus的目标对象(比如this.secTarget)本质上就是原生的DOM元素,所以你完全可以像原生JS那样直接修改它的style.transform属性!

下面是完善后的完整Stimulus控制器代码:

import { Controller } from "stimulus"

export default class extends Controller {
  static values = { refreshInterval: Number }
  static targets = [ "hour", "min", "sec" ]

  connect() {
    // 初始化时钟位置
    this.setDate();
    // 如果设置了刷新间隔,启动定时刷新
    if (this.hasRefreshIntervalValue) {
      this.startRefreshing()
    } else {
      // 默认每秒刷新一次
      this.startRefreshingWithDefault()
    }
  }

  setDate() {
    const now = new Date();
    
    // 计算秒针角度并更新样式
    const seconds = now.getSeconds();
    const secondsDegrees = ((seconds / 60) * 360) + 90;
    this.secTarget.style.transform = `rotate(${secondsDegrees}deg)`;
    
    // 计算分针角度并更新样式
    const mins = now.getMinutes();
    const minsDegrees = ((mins / 60) * 360) + ((seconds/60)*6) + 90;
    this.minTarget.style.transform = `rotate(${minsDegrees}deg)`;
    
    // 计算时针角度并更新样式
    const hour = now.getHours();
    const hourDegrees = ((hour / 12) * 360) + ((mins/60)*30) + 90;
    this.hourTarget.style.transform = `rotate(${hourDegrees}deg)`;
  }

  startRefreshing() {
    setInterval(() => { this.setDate() }, this.refreshIntervalValue)
  }

  startRefreshingWithDefault() {
    setInterval(() => { this.setDate() }, 1000)
  }
}

然后,你需要对应修改HTML结构,把Stimulus的控制器和目标属性加上:

<div class="clock" data-controller="clock" data-clock-refresh-interval-value="1000">
  <div class="clock-face">
    <div class="hand hour-hand" data-clock-target="hour"></div>
    <div class="hand min-hand" data-clock-target="min"></div>
    <div class="hand second-hand" data-clock-target="sec"></div>
  </div>
</div>
<!-- 你的CSS部分保持不变 -->

这里需要注意几个关键点:

  • data-controller="clock":对应你Stimulus控制器的文件名(比如控制器文件是clock_controller.js,这里就写clock)
  • data-clock-target="hour":格式是data-[控制器名称]-target="[目标名]",和你控制器里static targets定义的名字一一对应
  • data-clock-refresh-interval-value="1000":传递刷新间隔的数值,也可以不写,控制器里会自动使用默认的1秒刷新

另外,关于你提到的.classList修改属性的问题:如果不需要动态切换类的话,直接修改style属性就足够实现时钟的旋转效果;如果确实需要用类来控制样式(比如不同状态的时针样式),你可以用this.secTarget.classList.add('some-class')、remove或者toggle方法,和原生JS的用法完全一致哦。

这样一来,你的Stimulus时钟就能像原生JS版本一样正常运转啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 14:52:29