x-clock.vue 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <template>
  2. <view class="clock-container">
  3. <view class="clock-face" :style="{width:`${size}rpx`,height:`${size}rpx`}">
  4. <!-- 时钟刻度 -->
  5. <view v-for="(item, index) in 12" :key="index" class="hour-marker"
  6. :style="{ transform: `rotate(${index * 30}deg) translateY(-${size * 0.44}rpx)` }"></view>
  7. <!-- 时针 -->
  8. <view class="hour-hand" :style="[hourHandStyle, { transform: `rotate(${hourDegree}deg)` }]"></view>
  9. <!-- 分针 -->
  10. <view class="minute-hand" :style="[minuteHandStyle, { transform: `rotate(${minuteDegree}deg)` }]"></view>
  11. <!-- 秒针 -->
  12. <view class="second-hand" :style="[secondHandStyle, { transform: `rotate(${secondDegree}deg)` }]"
  13. v-if="showSecond"></view>
  14. <!-- 中心点 -->
  15. <view class="center-point" :style="centerPointStyle"></view>
  16. </view>
  17. </view>
  18. </template>
  19. <script>
  20. export default {
  21. name: 'DynamicClock',
  22. props: {
  23. showSecond: {
  24. type: Boolean,
  25. default: true
  26. },
  27. size: {
  28. type: Number,
  29. default: 300 // 默认时钟大小,单位rpx
  30. }
  31. },
  32. data() {
  33. return {
  34. hourDegree: 0,
  35. minuteDegree: 0,
  36. secondDegree: 0,
  37. timer: null
  38. }
  39. },
  40. computed: {
  41. hourHandStyle() {
  42. return {
  43. width: `${this.size * 0.02}rpx`,
  44. height: `${this.size * 0.2}rpx`,
  45. marginLeft: `${-this.size * 0.01}rpx`
  46. }
  47. },
  48. minuteHandStyle() {
  49. return {
  50. width: `${this.size * 0.013}rpx`,
  51. height: `${this.size * 0.3}rpx`,
  52. marginLeft: `${-this.size * 0.0065}rpx`
  53. }
  54. },
  55. secondHandStyle() {
  56. return {
  57. width: `${this.size * 0.007}rpx`,
  58. height: `${this.size * 0.33}rpx`,
  59. marginLeft: `${-this.size * 0.0035}rpx`
  60. }
  61. },
  62. centerPointStyle() {
  63. return {
  64. width: `${this.size * 0.06}rpx`,
  65. height: `${this.size * 0.06}rpx`
  66. }
  67. }
  68. },
  69. mounted() {
  70. this.updateClock()
  71. this.startClock()
  72. },
  73. beforeDestroy() {
  74. this.stopClock()
  75. },
  76. methods: {
  77. updateClock() {
  78. const now = new Date()
  79. const hours = now.getHours() % 12
  80. const minutes = now.getMinutes()
  81. const seconds = now.getSeconds()
  82. // 计算指针角度
  83. // 时针:每小时旋转30度,每分钟额外旋转0.5度
  84. this.hourDegree = (hours * 30) + (minutes * 0.5)
  85. // 分针:每分钟旋转6度
  86. this.minuteDegree = minutes * 6
  87. // 秒针:每秒旋转6度
  88. this.secondDegree = seconds * 6
  89. },
  90. startClock() {
  91. // 每秒更新一次时钟
  92. this.timer = setInterval(() => {
  93. this.updateClock()
  94. }, 1000)
  95. },
  96. stopClock() {
  97. if (this.timer) {
  98. clearInterval(this.timer)
  99. this.timer = null
  100. }
  101. }
  102. }
  103. }
  104. </script>
  105. <style scoped>
  106. .clock-container {
  107. display: flex;
  108. justify-content: center;
  109. align-items: center;
  110. /* width: 100%; */
  111. }
  112. .clock-face {
  113. position: relative;
  114. border-radius: 50%;
  115. background-color: #ffffff;
  116. display: flex;
  117. justify-content: center;
  118. align-items: center;
  119. border: 6rpx solid #f5f5f5;
  120. }
  121. .hour-marker {
  122. position: absolute;
  123. width: 6rpx;
  124. height: 6rpx;
  125. border-radius: 50%;
  126. background-color: #aaa;
  127. top: 50%;
  128. left: 50%;
  129. transform-origin: center;
  130. }
  131. .hour-hand {
  132. position: absolute;
  133. background-color: #333;
  134. bottom: 50%;
  135. left: 50%;
  136. transform-origin: bottom center;
  137. border-radius: 6rpx;
  138. }
  139. .minute-hand {
  140. position: absolute;
  141. background-color: #333;
  142. bottom: 50%;
  143. left: 50%;
  144. transform-origin: bottom center;
  145. border-radius: 4rpx;
  146. }
  147. .second-hand {
  148. position: absolute;
  149. background-color: #666;
  150. bottom: 50%;
  151. left: 50%;
  152. transform-origin: bottom center;
  153. border-radius: 2rpx;
  154. }
  155. .center-point {
  156. position: absolute;
  157. background-color: #333;
  158. border-radius: 50%;
  159. z-index: 10;
  160. }
  161. </style>