在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
相关产品推荐
相关产品推荐

