做一个canvas时钟(六)
本帖最后由 马黑黑 于 2024-3-26 12:09 编辑 <br /><br /><style>.mama { font: normal 18px / 26px sans-serif; }
.mama p { margin: 12px 0; }
.mama mark { padding: 0 6px; background: lightblue; }
.mum { position: relative; margin: 0; padding: 10px; font: normal 16px/20px Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; color: black; background: rgba(240, 240, 240,.95); box-shadow: 2px 2px 4px gray; border: thick groove lightblue; border-radius: 6px; }
.mum ::selection { background-color: rgba(0,100,100,.35); }
.mum div { margin: 0; padding: 0; }
.mum cl-cd { display: block; position: relative; margin: 0 0 0 50px; padding: 0 0 0 10px; white-space: pre-wrap; overflow-wrap: break-word; border-left: 1px solid silver; }
.mum cl-cd::before { position: absolute; content: attr(data-idx); width: 50px; color: gray; text-align: right; transform: translate(-70px); }
.tRed { color: red; }
.tBlue { color: blue; }
.tGreen { color: green; }
.tDarkRed { color: darkred; }
.tMagenta { color: magenta; }
</style>
<div class="mama">
<p>到第五讲时,高颜值的时钟还不会走时,这是因为缺乏驱动。驱动将通过 requestAnimationFrame API 接口来实现。上一讲里,我们已经将画时钟的所有细节集中放到了一个函数里,函数名叫 render(),我们把 requestAnimationFrame(render)放入该函数内,函数自身只要从外部执行一次就会得到反复调用,直到手工停止它的执行或页面被关闭。代码结构如下:</p>
<div class='mum'>
<cl-cd data-idx="1"><span class="tGreen">//函数 :绘制时钟部件集合</span></cl-cd>
<cl-cd data-idx="2"><span class="tBlue">let</span> <span class="tRed">render</span> = () => {</cl-cd>
<cl-cd data-idx="3"> <span class="tGreen">//这里是绘制时钟具体部件的代码集群</span></cl-cd>
<cl-cd data-idx="4"> requestAnimationFrame(<span class="tRed">render</span>); <span class="tGreen">//请求关键帧动画从函数内部调用函数</span></cl-cd>
<cl-cd data-idx="5">};</cl-cd>
</div>
<p>requestAnimationFrame 其实也是一个定时器,它依据屏幕刷新率作为自己的执行频率,就是说,一秒钟里面它至少执行60次上下的任务,这取决于显示器的刷新频率的高低,频率越高,它执行任务的次数越多。</p>
<p>不过问题是,假如我们现在就将 requestAnimationFrame(render); 加入到函数 render() 中,情况和第五节的最终效果没什么两样,时钟还是没能走时。这又是为什么呢?请看三根指针的绘制代码:</p>
<div class='mum'>
<cl-cd data-idx="1">draw_rect(0, -3, 90, 6, 0, <span class="tMagenta">'lightgreen'</span>); <span class="tGreen">/* 时针 */</span></cl-cd>
<cl-cd data-idx="2">draw_rect(0, -2, 100, 4, 270 * <span class="tRed">Math</span>.PI/180, <span class="tMagenta">'lightgreen'</span>); <span class="tGreen">/* 分针 */</span></cl-cd>
<cl-cd data-idx="3">draw_rect(0, -1, 120, 2, 240 * <span class="tRed">Math</span>.PI/180, <span class="tMagenta">'lightgreen'</span>); <span class="tGreen">/* 秒针 */</span></cl-cd>
</div>
<p>以<span class="tRed">秒针</span>为例,它通过绘制矩形函数 draw_rect() 绘制出来,函数将画布坐标系移到了画布的中心,指针总是从圆心区域画起,向三点钟方向画一定宽高的矩形,requestAnimationFrame(render) 绘制秒钟就这么重复着画。要转动指针,实际上是转动画布坐标系,函数提供了一个 rad 参数,我们绘制的秒针传值是 240 * Math.PI/180 弧度,秒针定格在 11 点钟方向。这里,240是十一点钟方向的角度值,改变这个角度值,秒针的指向就会发生变化。所以,我们首先需要知道当下的秒数是多少,然后根据算法计算出这个秒数是多少度就可以将它替代 240 令秒针每一秒钟都指向正确的方向,秒钟就动起来了。</p>
<p>获得当下时间信息,需要用到JS的 Date 对象:通过声明一个变量将其实例化,就能从实例化变量中获得所需的年月日时分秒等具体时间信息:</p>
<div class='mum'>
<cl-cd data-idx="1"><span class="tGreen">// 将 <span class="tRed">Date</span> 对象实例化为 now</span></cl-cd>
<cl-cd data-idx="2"><span class="tBlue">let</span> now = <span class="tBlue">new</span> <span class="tRed">Date</span>();</cl-cd>
<cl-cd data-idx="3"> </cl-cd>
<cl-cd data-idx="4"><span class="tGreen">// 从 now 实例化对象中获取时间信息</span></cl-cd>
<cl-cd data-idx="5"><span class="tBlue">let</span> year = now.getFullYear(); <span class="tGreen">//年</span></cl-cd>
<cl-cd data-idx="6"><span class="tBlue">let</span> month = now.getMonth() + 1; <span class="tGreen">//月 加1的原因:getMonth() 返回 0~11 的数值</span></cl-cd>
<cl-cd data-idx="7"><span class="tBlue">let</span> date = now.getDate(); <span class="tGreen">//日</span></cl-cd>
<cl-cd data-idx="8"><span class="tBlue">let</span> day = now.getDay(); <span class="tGreen">// 星期几(返回 0~6 的数值)</span></cl-cd>
<cl-cd data-idx="9"><span class="tBlue">let</span> hour = now.getHour(); <span class="tGreen">//小时</span></cl-cd>
<cl-cd data-idx="10"><span class="tBlue">let</span> minute = now.getMinute(); <span class="tGreen">//分钟</span></cl-cd>
<cl-cd data-idx="11"><span class="tBlue">let</span> second = now.getSecond(); <span class="tGreen">//秒钟</span></cl-cd>
<cl-cd data-idx="12"><span class="tBlue">let</span> msec = now.getMilliseconds(); <span class="tGreen">//毫秒</span></cl-cd>
</div>
<p>通过上面的时间信息获取方法,我们用 now.getSecond() 就能拿到当下的秒数。那么,秒数和角度又有什么关系呢?秒针指向刻度,而时钟上的每一个刻度向圆心的延长线都会和指向三点钟方向的X轴形成一定角度的夹角。理论上,每一秒钟的行进距离就是一个刻度的距离,亦即,它走的角度值为 6 度,那么,假设现在的秒数是 sec 秒,则角度为 sec * 6,为了精准,还需要考虑毫秒数,假设现在的毫秒数为 msec,依据毫秒和秒的关系,其所在度数为 msec * 0.36 / 1000,这个要加到秒钟的偏移度数中。我们来看代码:</p>
<div class='mum'>
<cl-cd data-idx="1"><span class="tGreen">/* 获取时间信息 */</span></cl-cd>
<cl-cd data-idx="2"><span class="tBlue">let</span> now = <span class="tBlue">new</span> <span class="tRed">Date</span>();</cl-cd>
<cl-cd data-idx="3"> </cl-cd>
<cl-cd data-idx="4"><span class="tGreen">//获取秒数和毫秒数</span></cl-cd>
<cl-cd data-idx="5"><span class="tBlue">let</span> sec = now.getSeconds(),</cl-cd>
<cl-cd data-idx="6"> msec = now.getMilliseconds();</cl-cd>
<cl-cd data-idx="7"> </cl-cd>
<cl-cd data-idx="8"><span class="tGreen">//转换秒数毫秒数为角度</span></cl-cd>
<cl-cd data-idx="9"><span class="tBlue">let</span> sDeg = sec * 6 + (msec * 0.36 / 1000);</cl-cd>
<cl-cd data-idx="10"> </cl-cd>
<cl-cd data-idx="11"><span class="tGreen">//绘制秒针</span></cl-cd>
<cl-cd data-idx="12">draw_rect(0, -1, 120, 2, (sDeg - 90) * <span class="tRed">Math</span>.PI/180, <span class="tMagenta">'lightgreen'</span>);</cl-cd>
</div>
<p>其他指针同理获得角度,然后将角度转换成弧度作为传参调用 draw_rect 依次绘制出来。这些,统统加入到 render() 函数中来,连同时钟的其他所有元素的具体绘制封装在一起,render() 内部在最后通过 requestAnimationFrame 按屏幕的刷新率去驱动时钟。时钟的最终效果以及全部代码如下,代码中,尤其需要注意对时间信息和时针转动角度的处理,这可是本讲的核心:</p>
<div style="margin-top: 20px; text-align: center;">
<canvas id="canv" width="300" height="300"></canvas>
</div>
<p><br>全部代码:</p>
<div class='mum'>
<cl-cd data-idx="1"><<span class="tDarkRed">div</span> style=<span class="tMagenta">"<span class="tBlue">margin-top:</span> 20px; <span class="tBlue">text-align:</span> center;"</span>></cl-cd>
<cl-cd data-idx="2"> <<span class="tDarkRed">canvas</span> <span class="tRed">id</span>=<span class="tMagenta">"canv"</span> width=<span class="tMagenta">"300"</span> height=<span class="tMagenta">"300"</span>><<span class="tDarkRed">/canvas</span>></cl-cd>
<cl-cd data-idx="3"><<span class="tDarkRed">/div</span>></cl-cd>
<cl-cd data-idx="4"> </cl-cd>
<cl-cd data-idx="5"><<span class="tDarkRed">script</span>></cl-cd>
<cl-cd data-idx="6"> </cl-cd>
<cl-cd data-idx="7"><span class="tGreen">/* 获取画笔 */</span></cl-cd>
<cl-cd data-idx="8"><span class="tBlue">let</span> ctx = canv.getContext(<span class="tMagenta">'2d'</span>);</cl-cd>
<cl-cd data-idx="9"> </cl-cd>
<cl-cd data-idx="10"><span class="tGreen">/* 函数 :绘制矩形(指针) */</span></cl-cd>
<cl-cd data-idx="11"><span class="tBlue">let</span> draw_rect = (x, y, w, h, rad, color) => {</cl-cd>
<cl-cd data-idx="12"> ctx.save();</cl-cd>
<cl-cd data-idx="13"> ctx.fillStyle = color;</cl-cd>
<cl-cd data-idx="14"> ctx.translate(150,150);</cl-cd>
<cl-cd data-idx="15"> ctx.rotate(rad);</cl-cd>
<cl-cd data-idx="16"> ctx.fillRect(x,y,w,h);</cl-cd>
<cl-cd data-idx="17"> ctx.restore();</cl-cd>
<cl-cd data-idx="18">};</cl-cd>
<cl-cd data-idx="19"><span class="tGreen">/* 函数 :绘制圆(环) */</span></cl-cd>
<cl-cd data-idx="20"><span class="tBlue">let</span> draw_circle = (x,y,r,lw,color1,color2) => {</cl-cd>
<cl-cd data-idx="21"> ctx.save();</cl-cd>
<cl-cd data-idx="22"> ctx.fillStyle = color1;</cl-cd>
<cl-cd data-idx="23"> ctx.strokeStyle = color2;</cl-cd>
<cl-cd data-idx="24"> ctx.lineWidth = lw;</cl-cd>
<cl-cd data-idx="25"> ctx.beginPath();</cl-cd>
<cl-cd data-idx="26"> ctx.arc(x,y,r,0,<span class="tRed">Math</span>.PI * 2);</cl-cd>
<cl-cd data-idx="27"> ctx.fill();</cl-cd>
<cl-cd data-idx="28"> ctx.stroke();</cl-cd>
<cl-cd data-idx="29"> ctx.restore();</cl-cd>
<cl-cd data-idx="30">};</cl-cd>
<cl-cd data-idx="31"><span class="tGreen">/* 函数 :绘制文本 */</span></cl-cd>
<cl-cd data-idx="32"><span class="tBlue">let</span> draw_text = (txt,x,y,color,fontsize=18,b=<span class="tMagenta">"bold"</span>) => {</cl-cd>
<cl-cd data-idx="33"> ctx.save();</cl-cd>
<cl-cd data-idx="34"> ctx.translate(150,150);</cl-cd>
<cl-cd data-idx="35"> ctx.font = `${b} ${fontsize}px sans-serif`;</cl-cd>
<cl-cd data-idx="36"> ctx.textAlign = <span class="tMagenta">'center'</span>;</cl-cd>
<cl-cd data-idx="37"> ctx.textBaseline=<span class="tMagenta">"middle"</span>;</cl-cd>
<cl-cd data-idx="38"> ctx.fillStyle = color;</cl-cd>
<cl-cd data-idx="39"> ctx.fillText(txt,x,y);</cl-cd>
<cl-cd data-idx="40"> ctx.restore();</cl-cd>
<cl-cd data-idx="41">};</cl-cd>
<cl-cd data-idx="42"> </cl-cd>
<cl-cd data-idx="43"><span class="tBlue">let</span> render = () => {</cl-cd>
<cl-cd data-idx="44"> <span class="tGreen">/* 获取时间 */</span></cl-cd>
<cl-cd data-idx="45"> <span class="tBlue">let</span> now = <span class="tBlue">new</span> <span class="tRed">Date</span>();</cl-cd>
<cl-cd data-idx="46"> <span class="tBlue">let</span> hr = now.getHours() > 12 ? now.getHours() - 12 : now.getHours(),</cl-cd>
<cl-cd data-idx="47"> min = now.getMinutes(),</cl-cd>
<cl-cd data-idx="48"> sec = now.getSeconds(),</cl-cd>
<cl-cd data-idx="49"> msec = now.getMilliseconds();</cl-cd>
<cl-cd data-idx="50"> <span class="tBlue">let</span> hDeg = hr * 30 + (min * 6 / 12),</cl-cd>
<cl-cd data-idx="51"> mDeg = min * 6 + (sec * 6 / 60),</cl-cd>
<cl-cd data-idx="52"> sDeg = sec * 6 + (msec * 0.36 / 1000);</cl-cd>
<cl-cd data-idx="53"> </cl-cd>
<cl-cd data-idx="54"> ctx.clearRect(0,0,300,300); <span class="tGreen">/* 每一次绘制前都衔擦除画布 */</span></cl-cd>
<cl-cd data-idx="55"> draw_circle(150,150,140,10,<span class="tMagenta">'tan'</span>,<span class="tMagenta">'darkgreen'</span>); <span class="tGreen">/* 钟壳和钟面 */</span></cl-cd>
<cl-cd data-idx="56"> </cl-cd>
<cl-cd data-idx="57"> <span class="tGreen">/* 钟点 */</span></cl-cd>
<cl-cd data-idx="58"> <span class="tBlue">for</span>(<span class="tBlue">let</span> i = 0; i < 12; i ++) {</cl-cd>
<cl-cd data-idx="59"> <span class="tBlue">let</span> radian = <span class="tRed">Math</span>.PI/180*(i*30-60);</cl-cd>
<cl-cd data-idx="60"> <span class="tBlue">let</span> x = 115 * <span class="tRed">Math</span>.cos(radian), y = 115 * <span class="tRed">Math</span>.sin(radian);</cl-cd>
<cl-cd data-idx="61"> draw_text(i+1, x, y, <span class="tMagenta">'green'</span>);</cl-cd>
<cl-cd data-idx="62"> }</cl-cd>
<cl-cd data-idx="63"> <span class="tGreen">/* 刻度 */</span></cl-cd>
<cl-cd data-idx="64"> <span class="tBlue">for</span>(<span class="tBlue">let</span> i = 0; i < 60; i ++) {</cl-cd>
<cl-cd data-idx="65"> <span class="tBlue">let</span> radian = <span class="tRed">Math</span>.PI/180*(i*6);</cl-cd>
<cl-cd data-idx="66"> <span class="tBlue">let</span> x = 150 + 130 * <span class="tRed">Math</span>.cos(radian), y = 150 + 130 * <span class="tRed">Math</span>.sin(radian);</cl-cd>
<cl-cd data-idx="67"> draw_circle(x,y,1,2,<span class="tMagenta">'gray'</span>,<span class="tMagenta">'gray'</span>);</cl-cd>
<cl-cd data-idx="68"> }</cl-cd>
<cl-cd data-idx="69"> <span class="tGreen">/* 按一定次序绘制时钟各个元素 :确保指针、指针扣不会被遮挡 */</span></cl-cd>
<cl-cd data-idx="70"> draw_text(`${now.getFullYear()}年${now.getMonth() + 1}月${now.getDate()}日`,0,-50,<span class="tMagenta">'white'</span>, 15, <span class="tMagenta">'normal'</span>); <span class="tGreen">/* 日期 */</span></cl-cd>
<cl-cd data-idx="71"> draw_text(`星期${<span class="tMagenta">'日一二三四五六'</span>.substr(now.getDay(),1)}`,0,-25,<span class="tMagenta">'white'</span>, 15, <span class="tMagenta">'normal'</span>); <span class="tGreen">/* 星期 */</span></cl-cd>
<cl-cd data-idx="72"> draw_text(<span class="tMagenta">'HUACHAO'</span>,0,60,<span class="tMagenta">'gray'</span>); <span class="tGreen">/* Logo */</span></cl-cd>
<cl-cd data-idx="73"> draw_rect(0, -3, 90, 6, (hDeg - 90) * <span class="tRed">Math</span>.PI/180, <span class="tMagenta">'lightgreen'</span>); <span class="tGreen">/* 时针 */</span></cl-cd>
<cl-cd data-idx="74"> draw_rect(0, -2, 100, 4, (mDeg - 90) * <span class="tRed">Math</span>.PI/180, <span class="tMagenta">'lightgreen'</span>); <span class="tGreen">/* 分针 */</span></cl-cd>
<cl-cd data-idx="75"> draw_rect(0, -1, 120, 2, (sDeg - 90) * <span class="tRed">Math</span>.PI/180, <span class="tMagenta">'lightgreen'</span>); <span class="tGreen">/* 秒针 */</span></cl-cd>
<cl-cd data-idx="76"> draw_circle(150,150,6,6,<span class="tMagenta">'white'</span>,<span class="tMagenta">'lightgreen'</span>); <span class="tGreen">/* 指针扣 */</span></cl-cd>
<cl-cd data-idx="77"> </cl-cd>
<cl-cd data-idx="78"> requestAnimationFrame(render);</cl-cd>
<cl-cd data-idx="79">};</cl-cd>
<cl-cd data-idx="80"> </cl-cd>
<cl-cd data-idx="81">render();</cl-cd>
<cl-cd data-idx="82"> </cl-cd>
<cl-cd data-idx="83"><<span class="tDarkRed">/script</span>></cl-cd>
</div>
<p>《做一个canvas时钟》的课程至此结束。整体课程可能颇为抽象,尽管我已经极尽所能讲的很通俗了。时钟牵扯到的知识面很广,仅canvas画布的内容就相当不好理解,而且很多朋友此前对此没有什么基础。不过事在人为,能够消化这六个讲义,对提升编程水平和做帖能力等等都会有潜移默化的促进作用,甚至对改变自己的工作、学习和生活态度也会有正面的影响。谢谢大家!</p>
</div>
<script>
/* 获取画笔 */
let ctx = canv.getContext('2d');
/* 函数 :绘制矩形(指针) */
let draw_rect = (x, y, w, h, rad, color) => {
ctx.save();
ctx.fillStyle = color;
ctx.translate(150,150);
ctx.rotate(rad);
ctx.fillRect(x,y,w,h);
ctx.restore();
};
/* 函数 :绘制圆(环) */
let draw_circle = (x,y,r,lw,color1,color2) => {
ctx.save();
ctx.fillStyle = color1;
ctx.strokeStyle = color2;
ctx.lineWidth = lw;
ctx.beginPath();
ctx.arc(x,y,r,0,Math.PI * 2);
ctx.fill();
ctx.stroke();
ctx.restore();
};
/* 函数 :绘制文本 */
let draw_text = (txt,x,y,color,fontsize=18,b="bold") => {
ctx.save();
ctx.translate(150,150);
ctx.font = `${b} ${fontsize}px sans-serif`;
ctx.textAlign = 'center';
ctx.textBaseline="middle";
ctx.fillStyle = color;
ctx.fillText(txt,x,y);
ctx.restore();
};
let render = () => {
/* 获取时间 */
let now = new Date();
let hr = now.getHours() > 12 ? now.getHours() - 12 : now.getHours(),
min = now.getMinutes(),
sec = now.getSeconds(),
msec = now.getMilliseconds();
let hDeg = hr * 30 + (min * 6 / 12),
mDeg = min * 6 + (sec * 6 / 60),
sDeg = sec * 6 + (msec * 0.36 / 1000);
ctx.clearRect(0,0,300,300); /* 每一次绘制前都衔擦除画布 */
draw_circle(150,150,140,10,'tan','darkgreen'); /* 钟壳和钟面 */
/* 钟点 */
for(let i = 0; i < 12; i ++) {
let radian = Math.PI/180*(i*30-60);
let x = 115 * Math.cos(radian), y = 115 * Math.sin(radian);
draw_text(i+1, x, y, 'green');
}
/* 刻度 */
for(let i = 0; i < 60; i ++) {
let radian = Math.PI/180*(i*6);
let x = 150 + 130 * Math.cos(radian), y = 150 + 130 * Math.sin(radian);
draw_circle(x,y,1,2,'gray','gray');
}
/* 按一定次序绘制时钟各个元素 :确保指针、指针扣不会被遮挡 */
draw_text(`${now.getFullYear()}年${now.getMonth() + 1}月${now.getDate()}日`,0,-50,'white', 15, 'normal'); /* 日期 */
draw_text(`星期${'日一二三四五六'.substr(now.getDay(),1)}`,0,-25,'white', 15, 'normal'); /* 星期 */
draw_text('HUACHAO',0,60,'gray'); /* Logo */
draw_rect(0, -3, 90, 6, (hDeg - 90) * Math.PI/180, 'lightgreen'); /* 时针 */
draw_rect(0, -2, 100, 4, (mDeg - 90) * Math.PI/180, 'lightgreen'); /* 分针 */
draw_rect(0, -1, 120, 2, (sDeg - 90) * Math.PI/180, 'lightgreen'); /* 秒针 */
draw_circle(150,150,6,6,'white','lightgreen'); /* 指针扣 */
requestAnimationFrame(render);
};
render();
</script>
高手在花潮{:4_178:} 真是很实用的制作啊。 流水光阴 发表于 2024-3-26 14:25
高手在花潮
{:4_190:} 梦油 发表于 2024-3-26 16:16
真是很实用的制作啊。
这个时钟还不错吧 马黑黑 发表于 2024-3-26 17:36
这个时钟还不错吧
做贴者反馈,非常漂亮。。
使用实例在音画版,老师有空移步去瞧一眼。。
教程后半段还没啃下来,晚上继续。{:4_170:} 南无月 发表于 2024-3-26 18:20
教程后半段还没啃下来,晚上继续。
慢慢来不急。整体可能需要研究几次,最终可能可以发现讲义的错误 南无月 发表于 2024-3-26 18:19
做贴者反馈,非常漂亮。。
使用实例在音画版,老师有空移步去瞧一眼。。
{:4_191:} 马黑黑 发表于 2024-3-26 18:20
慢慢来不急。整体可能需要研究几次,最终可能可以发现讲义的错误
我不急的。。
教程多看几遍可以。。可我为啥要发现这个呢。。累呀累。。{:4_170:} 马黑黑 发表于 2024-3-26 18:21
今天白的。。晚上真喝了几口,有点晕。{:4_170:} 这个不能直接关联播放器吗 黑黑的改进版时钟,发现现在这款时钟,应该是第三版吧,前年一个,去年一个,今年又一个了 绿叶清舟 发表于 2024-3-26 20:29
这个不能直接关联播放器吗
为什么一定要关联音乐呢?制作成本太高赚不到钱钱的。看看 @南无月 肿么处理:
https://www.huachaowang.com/forum.php?mod=viewthread&tid=75123 小辣椒 发表于 2024-3-26 20:34
黑黑的改进版时钟,发现现在这款时钟,应该是第三版吧,前年一个,去年一个,今年又一个了
不知道是什么版本,应该不是出口非洲的吧 马黑黑 发表于 2024-3-26 20:36
不知道是什么版本,应该不是出口非洲的吧
因为我做过2个时钟的效果帖子,现在这个算上去就是三个了 南无月 发表于 2024-3-26 20:25
今天白的。。晚上真喝了几口,有点晕。
晕晕更健康 马黑黑 发表于 2024-3-26 20:34
为什么一定要关联音乐呢?制作成本太高赚不到钱钱的。看看 @南无月 肿么处理:
https://www.huachaowa ...
不加东西直接上去没反应啊,加了视频才行 绿叶清舟 发表于 2024-3-26 20:37
不加东西直接上去没反应啊,加了视频才行
该加啥加啥 小辣椒 发表于 2024-3-26 20:37
因为我做过2个时钟的效果帖子,现在这个算上去就是三个了
那不止的