refactor(client): use setup syntax
This commit is contained in:
		| @@ -16,162 +16,126 @@ | |||||||
| </div> | </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script lang="ts"> | <script lang="ts" setup> | ||||||
| import { computed, defineAsyncComponent, defineComponent, onMounted, onUnmounted, ref, watch } from 'vue'; | import { computed, defineAsyncComponent, onMounted, onUnmounted, ref, watch } from 'vue'; | ||||||
| import * as os from '@/os'; | import * as os from '@/os'; | ||||||
|  |  | ||||||
| export default defineComponent({ | const props = withDefaults(defineProps<{ | ||||||
| 	props: { | 	modelValue: number; | ||||||
| 		modelValue: { | 	disabled?: boolean; | ||||||
| 			type: Number, | 	min: number; | ||||||
| 			required: false, | 	max: number; | ||||||
| 			default: 0, | 	step?: number; | ||||||
| 		}, | 	textConverter?: (value: number) => string, | ||||||
| 		disabled: { | }>(), { | ||||||
| 			type: Boolean, | 	step: 1, | ||||||
| 			required: false, | 	textConverter: (v) => v.toString(), | ||||||
| 			default: false, |  | ||||||
| 		}, |  | ||||||
| 		min: { |  | ||||||
| 			type: Number, |  | ||||||
| 			required: false, |  | ||||||
| 			default: 0, |  | ||||||
| 		}, |  | ||||||
| 		max: { |  | ||||||
| 			type: Number, |  | ||||||
| 			required: false, |  | ||||||
| 			default: 100, |  | ||||||
| 		}, |  | ||||||
| 		step: { |  | ||||||
| 			type: Number, |  | ||||||
| 			required: false, |  | ||||||
| 			default: 1, |  | ||||||
| 		}, |  | ||||||
| 		autofocus: { |  | ||||||
| 			type: Boolean, |  | ||||||
| 			required: false, |  | ||||||
| 		}, |  | ||||||
| 		textConverter: { |  | ||||||
| 			type: Function, |  | ||||||
| 			required: false, |  | ||||||
| 			default: (v) => v.toString(), |  | ||||||
| 		}, |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	setup(props, context) { |  | ||||||
| 		const containerEl = ref<HTMLElement>(); |  | ||||||
| 		const thumbEl = ref<HTMLElement>(); |  | ||||||
|  |  | ||||||
| 		const rawValue = ref((props.modelValue - props.min) / (props.max - props.min)); |  | ||||||
| 		const steppedRawValue = computed(() => { |  | ||||||
| 			if (props.step) { |  | ||||||
| 				const step = props.step / (props.max - props.min); |  | ||||||
| 				return (step * Math.round(rawValue.value / step)); |  | ||||||
| 			} else { |  | ||||||
| 				return rawValue.value; |  | ||||||
| 			} |  | ||||||
| 		}); |  | ||||||
| 		const finalValue = computed(() => { |  | ||||||
| 			if (Number.isInteger(props.step)) { |  | ||||||
| 				return Math.round((steppedRawValue.value * (props.max - props.min)) + props.min); |  | ||||||
| 			} else { |  | ||||||
| 				return (steppedRawValue.value * (props.max - props.min)) + props.min; |  | ||||||
| 			} |  | ||||||
| 		}); |  | ||||||
|  |  | ||||||
| 		const thumbWidth = computed(() => { |  | ||||||
| 			if (thumbEl.value == null) return 0; |  | ||||||
| 			return thumbEl.value!.offsetWidth; |  | ||||||
| 		}); |  | ||||||
| 		const thumbPosition = ref(0); |  | ||||||
| 		const calcThumbPosition = () => { |  | ||||||
| 			if (containerEl.value == null) { |  | ||||||
| 				thumbPosition.value = 0; |  | ||||||
| 			} else { |  | ||||||
| 				thumbPosition.value = (containerEl.value.offsetWidth - thumbWidth.value) * steppedRawValue.value; |  | ||||||
| 			} |  | ||||||
| 		}; |  | ||||||
| 		watch([steppedRawValue, containerEl], calcThumbPosition); |  | ||||||
|  |  | ||||||
| 		let ro: ResizeObserver | undefined; |  | ||||||
|  |  | ||||||
| 		onMounted(() => { |  | ||||||
| 			ro = new ResizeObserver((entries, observer) => { |  | ||||||
| 				calcThumbPosition(); |  | ||||||
| 			}); |  | ||||||
| 			ro.observe(containerEl.value); |  | ||||||
| 		}); |  | ||||||
| 		 |  | ||||||
| 		onUnmounted(() => { |  | ||||||
| 			if (ro) ro.disconnect(); |  | ||||||
| 		}); |  | ||||||
|  |  | ||||||
| 		const steps = computed(() => { |  | ||||||
| 			if (props.step) { |  | ||||||
| 				return (props.max - props.min) / props.step; |  | ||||||
| 			} else { |  | ||||||
| 				return 0; |  | ||||||
| 			} |  | ||||||
| 		}); |  | ||||||
|  |  | ||||||
| 		const onMousedown = (ev: MouseEvent | TouchEvent) => { |  | ||||||
| 			ev.preventDefault(); |  | ||||||
|  |  | ||||||
| 			const tooltipShowing = ref(true); |  | ||||||
| 			os.popup(defineAsyncComponent(() => import('@/components/ui/tooltip.vue')), { |  | ||||||
| 				showing: tooltipShowing, |  | ||||||
| 				text: computed(() => { |  | ||||||
| 					return props.textConverter(finalValue.value); |  | ||||||
| 				}), |  | ||||||
| 				targetElement: thumbEl, |  | ||||||
| 			}, {}, 'closed'); |  | ||||||
|  |  | ||||||
| 			const style = document.createElement('style'); |  | ||||||
| 			style.appendChild(document.createTextNode('* { cursor: grabbing !important; } body * { pointer-events: none !important; }')); |  | ||||||
| 			document.head.appendChild(style); |  | ||||||
|  |  | ||||||
| 			const onDrag = (ev: MouseEvent | TouchEvent) => { |  | ||||||
| 				ev.preventDefault(); |  | ||||||
| 				const containerRect = containerEl.value!.getBoundingClientRect(); |  | ||||||
| 				const pointerX = ev.touches && ev.touches.length > 0 ? ev.touches[0].clientX : ev.clientX; |  | ||||||
| 				const pointerPositionOnContainer = pointerX - (containerRect.left + (thumbWidth.value / 2)); |  | ||||||
| 				rawValue.value = Math.min(1, Math.max(0, pointerPositionOnContainer / (containerEl.value!.offsetWidth - thumbWidth.value))); |  | ||||||
| 			}; |  | ||||||
|  |  | ||||||
| 			let beforeValue = finalValue.value; |  | ||||||
|  |  | ||||||
| 			const onMouseup = () => { |  | ||||||
| 				document.head.removeChild(style); |  | ||||||
| 				tooltipShowing.value = false; |  | ||||||
| 				window.removeEventListener('mousemove', onDrag); |  | ||||||
| 				window.removeEventListener('touchmove', onDrag); |  | ||||||
| 				window.removeEventListener('mouseup', onMouseup); |  | ||||||
| 				window.removeEventListener('touchend', onMouseup); |  | ||||||
|  |  | ||||||
| 				// 値が変わってたら通知 |  | ||||||
| 				if (beforeValue !== finalValue.value) { |  | ||||||
| 					context.emit('update:modelValue', finalValue.value); |  | ||||||
| 				} |  | ||||||
| 			}; |  | ||||||
|  |  | ||||||
| 			window.addEventListener('mousemove', onDrag); |  | ||||||
| 			window.addEventListener('touchmove', onDrag); |  | ||||||
| 			window.addEventListener('mouseup', onMouseup, { once: true }); |  | ||||||
| 			window.addEventListener('touchend', onMouseup, { once: true }); |  | ||||||
| 		}; |  | ||||||
|  |  | ||||||
| 		return { |  | ||||||
| 			rawValue, |  | ||||||
| 			finalValue, |  | ||||||
| 			steppedRawValue, |  | ||||||
| 			onMousedown, |  | ||||||
| 			containerEl, |  | ||||||
| 			thumbEl, |  | ||||||
| 			thumbPosition, |  | ||||||
| 			steps, |  | ||||||
| 		}; |  | ||||||
| 	}, |  | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | const emit = defineEmits<{ | ||||||
|  | 	(ev: 'update:modelValue', value: number): void; | ||||||
|  | }>(); | ||||||
|  |  | ||||||
|  | const containerEl = ref<HTMLElement>(); | ||||||
|  | const thumbEl = ref<HTMLElement>(); | ||||||
|  |  | ||||||
|  | const rawValue = ref((props.modelValue - props.min) / (props.max - props.min)); | ||||||
|  | const steppedRawValue = computed(() => { | ||||||
|  | 	if (props.step) { | ||||||
|  | 		const step = props.step / (props.max - props.min); | ||||||
|  | 		return (step * Math.round(rawValue.value / step)); | ||||||
|  | 	} else { | ||||||
|  | 		return rawValue.value; | ||||||
|  | 	} | ||||||
|  | }); | ||||||
|  | const finalValue = computed(() => { | ||||||
|  | 	if (Number.isInteger(props.step)) { | ||||||
|  | 		return Math.round((steppedRawValue.value * (props.max - props.min)) + props.min); | ||||||
|  | 	} else { | ||||||
|  | 		return (steppedRawValue.value * (props.max - props.min)) + props.min; | ||||||
|  | 	} | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | const thumbWidth = computed(() => { | ||||||
|  | 	if (thumbEl.value == null) return 0; | ||||||
|  | 	return thumbEl.value!.offsetWidth; | ||||||
|  | }); | ||||||
|  | const thumbPosition = ref(0); | ||||||
|  | const calcThumbPosition = () => { | ||||||
|  | 	if (containerEl.value == null) { | ||||||
|  | 		thumbPosition.value = 0; | ||||||
|  | 	} else { | ||||||
|  | 		thumbPosition.value = (containerEl.value.offsetWidth - thumbWidth.value) * steppedRawValue.value; | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | watch([steppedRawValue, containerEl], calcThumbPosition); | ||||||
|  |  | ||||||
|  | let ro: ResizeObserver | undefined; | ||||||
|  |  | ||||||
|  | onMounted(() => { | ||||||
|  | 	ro = new ResizeObserver((entries, observer) => { | ||||||
|  | 		calcThumbPosition(); | ||||||
|  | 	}); | ||||||
|  | 	ro.observe(containerEl.value); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | onUnmounted(() => { | ||||||
|  | 	if (ro) ro.disconnect(); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | const steps = computed(() => { | ||||||
|  | 	if (props.step) { | ||||||
|  | 		return (props.max - props.min) / props.step; | ||||||
|  | 	} else { | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | const onMousedown = (ev: MouseEvent | TouchEvent) => { | ||||||
|  | 	ev.preventDefault(); | ||||||
|  |  | ||||||
|  | 	const tooltipShowing = ref(true); | ||||||
|  | 	os.popup(defineAsyncComponent(() => import('@/components/ui/tooltip.vue')), { | ||||||
|  | 		showing: tooltipShowing, | ||||||
|  | 		text: computed(() => { | ||||||
|  | 			return props.textConverter(finalValue.value); | ||||||
|  | 		}), | ||||||
|  | 		targetElement: thumbEl, | ||||||
|  | 	}, {}, 'closed'); | ||||||
|  |  | ||||||
|  | 	const style = document.createElement('style'); | ||||||
|  | 	style.appendChild(document.createTextNode('* { cursor: grabbing !important; } body * { pointer-events: none !important; }')); | ||||||
|  | 	document.head.appendChild(style); | ||||||
|  |  | ||||||
|  | 	const onDrag = (ev: MouseEvent | TouchEvent) => { | ||||||
|  | 		ev.preventDefault(); | ||||||
|  | 		const containerRect = containerEl.value!.getBoundingClientRect(); | ||||||
|  | 		const pointerX = ev.touches && ev.touches.length > 0 ? ev.touches[0].clientX : ev.clientX; | ||||||
|  | 		const pointerPositionOnContainer = pointerX - (containerRect.left + (thumbWidth.value / 2)); | ||||||
|  | 		rawValue.value = Math.min(1, Math.max(0, pointerPositionOnContainer / (containerEl.value!.offsetWidth - thumbWidth.value))); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	let beforeValue = finalValue.value; | ||||||
|  |  | ||||||
|  | 	const onMouseup = () => { | ||||||
|  | 		document.head.removeChild(style); | ||||||
|  | 		tooltipShowing.value = false; | ||||||
|  | 		window.removeEventListener('mousemove', onDrag); | ||||||
|  | 		window.removeEventListener('touchmove', onDrag); | ||||||
|  | 		window.removeEventListener('mouseup', onMouseup); | ||||||
|  | 		window.removeEventListener('touchend', onMouseup); | ||||||
|  |  | ||||||
|  | 		// 値が変わってたら通知 | ||||||
|  | 		if (beforeValue !== finalValue.value) { | ||||||
|  | 			emit('update:modelValue', finalValue.value); | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	window.addEventListener('mousemove', onDrag); | ||||||
|  | 	window.addEventListener('touchmove', onDrag); | ||||||
|  | 	window.addEventListener('mouseup', onMouseup, { once: true }); | ||||||
|  | 	window.addEventListener('touchend', onMouseup, { once: true }); | ||||||
|  | }; | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 syuilo
					syuilo