| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- <template>
- <div class="clock-board-wrapper" :class="{ selected }"
- :style="{ width: '100%', height: '100%', position: 'relative' }">
- <div class="clock-board" :style="clockStyle">{{ formattedTime }}</div>
- <template v-if="selected">
- <div v-for="dir in ['tr', 'tl', 'br', 'bl']" :key="dir" class="resize-handle" :class="dir"
- @mousedown.stop="onResizeMouseDown($event, dir)"></div>
- </template>
- </div>
- </template>
- <script setup lang="ts">
- import { ref, computed, onMounted, onUnmounted } from 'vue';
- const emit = defineEmits(['resize']);
- interface Props {
- color?: string;
- fontSize?: string | number;
- fontWeight?: string | number;
- align?: 'left' | 'center' | 'right';
- width?: number;
- height?: number;
- selected?: boolean;
- format?: '24h' | '12h' | 'date';
- }
- const props = defineProps<Props>();
- const selected = computed(() => !!props.selected);
- const clockStyle = computed(() => ({
- color: props.color || '#222',
- fontSize: typeof props.fontSize === 'number' ? props.fontSize + 'px' : props.fontSize || '24px',
- fontWeight: props.fontWeight || 'normal',
- textAlign: props.align || 'center',
- width: '100%',
- height: '100%',
- display: 'flex',
- alignItems: 'center',
- justifyContent: props.align === 'left' ? 'flex-start' : props.align === 'right' ? 'flex-end' : 'center',
- userSelect: 'none'
- }));
- const formats = {
- '24h': '24小时制 (HH:mm:ss)',
- '12h': '12小时制 (hh:mm:ss A)',
- 'date': '日期+时间 (YYYY-MM-DD HH:mm:ss)'
- };
- import { watch } from 'vue';
- const format = ref<'24h' | '12h' | 'date'>(props.format || '24h');
- // 保持 format 与 props.format 同步
- watch(
- () => props.format,
- (val) => {
- if (val && val !== format.value) {
- format.value = val;
- }
- }
- );
- watch(format, (val) => { });
- const now = ref(new Date());
- const formattedTime = computed(() => {
- const d = now.value;
- let result;
- if (format.value === '24h') {
- result = d.toLocaleTimeString('zh-CN', { hour12: false });
- } else if (format.value === '12h') {
- result = d.toLocaleTimeString('zh-CN', { hour12: true });
- } else {
- // 日期+时间
- const date = d.toLocaleDateString('zh-CN');
- const time = d.toLocaleTimeString('zh-CN', { hour12: false });
- result = `${date} ${time}`;
- }
- return result;
- });
- let timer: number | undefined;
- onMounted(() => {
- timer = window.setInterval(() => {
- now.value = new Date();
- }, 1000);
- });
- onUnmounted(() => {
- if (timer) clearInterval(timer);
- });
- function onResizeMouseDown(e: MouseEvent, dir: string) {
- e.stopPropagation();
- const startX = e.clientX,
- startY = e.clientY;
- const startWidth = Number(props.width) || 200;
- const startHeight = Number(props.height) || 40;
- function onMove(ev: MouseEvent) {
- let newWidth = startWidth,
- newHeight = startHeight;
- if (dir.includes('r')) newWidth += ev.clientX - startX;
- if (dir.includes('l')) newWidth -= ev.clientX - startX;
- if (dir.includes('b')) newHeight += ev.clientY - startY;
- if (dir.includes('t')) newHeight -= ev.clientY - startY;
- emit('resize', { width: Math.max(20, newWidth), height: Math.max(20, newHeight) });
- }
- function onUp() {
- document.removeEventListener('mousemove', onMove);
- document.removeEventListener('mouseup', onUp);
- }
- document.addEventListener('mousemove', onMove);
- document.addEventListener('mouseup', onUp);
- }
- </script>
- <style scoped>
- .clock-board-wrapper {
- width: 100%;
- height: 100%;
- position: relative;
- }
- .clock-board {
- width: 100%;
- height: 100%;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .resize-handle {
- position: absolute;
- width: 10px;
- height: 10px;
- background: #fff;
- border: 1px solid #aaa;
- z-index: 10;
- }
- .resize-handle.tr {
- top: -5px;
- right: -5px;
- cursor: ne-resize;
- }
- .resize-handle.tl {
- top: -5px;
- left: -5px;
- cursor: nw-resize;
- }
- .resize-handle.br {
- bottom: -5px;
- right: -5px;
- cursor: se-resize;
- }
- .resize-handle.bl {
- bottom: -5px;
- left: -5px;
- cursor: sw-resize;
- }
- .clock-format-selector {
- position: absolute;
- bottom: 8px;
- right: 8px;
- z-index: 20;
- background: rgba(255, 255, 255, 0.7);
- border-radius: 4px;
- padding: 2px 6px;
- }
- </style>
|