diff --git a/packages/components/color-picker/__tests__/color-picker.spec.ts b/packages/components/color-picker/__tests__/color-picker.spec.ts index c30907a933..c03b8837c8 100644 --- a/packages/components/color-picker/__tests__/color-picker.spec.ts +++ b/packages/components/color-picker/__tests__/color-picker.spec.ts @@ -21,11 +21,12 @@ const _mount = (template: string, data: () => { [key: string]: any }) => { type ColorPickerVM = ComponentPublicInstance<{ handleClick: (opt: { target: Nullable + type: string clientX: number clientY: number }) => void thumbTop: number - handleDrag: (opt: { clientX: number; clientY: number }) => void + handleDrag: (opt: { type: string; clientX: number; clientY: number }) => void }> describe('Color-picker', () => { @@ -188,6 +189,7 @@ describe('Color-picker', () => { .mockReturnValue(4) ;(hueSlideWrapper.vm as ColorPickerVM).handleClick({ target: null, + type: 'mouseup', clientX: 0, clientY: 100, }) @@ -229,6 +231,7 @@ describe('Color-picker', () => { .mockReturnValue(4) ;(hueSlideWrapper.vm as ColorPickerVM).handleClick({ target: null, + type: 'mouseup', clientX: 0, clientY: 100, }) @@ -268,6 +271,7 @@ describe('Color-picker', () => { .mockReturnValue(4) ;(alphaWrapper.vm as ColorPickerVM).handleClick({ target: null, + type: 'mouseup', clientX: 50, clientY: 0, }) @@ -289,7 +293,11 @@ describe('Color-picker', () => { await wrapper.find('.el-color-picker__trigger').trigger('click') const colorPickerWrapper = wrapper.findComponent(ColorPicker) const svPanelWrapper = colorPickerWrapper.findComponent({ ref: 'svPanel' }) - ;(svPanelWrapper.vm as ColorPickerVM).handleDrag({ clientX: 0, clientY: 0 }) + ;(svPanelWrapper.vm as ColorPickerVM).handleDrag({ + type: 'mousemove', + clientX: 0, + clientY: 0, + }) wrapper.vm.$nextTick(() => { expect(wrapper.vm.color._saturation !== 50).toBeTruthy() expect(wrapper.vm.color._value !== 50).toBeTruthy() @@ -404,6 +412,7 @@ describe('Color-picker', () => { .mockReturnValue(4) ;(hueSlideWrapper.vm as ColorPickerVM).handleClick({ target: null, + type: 'mouseup', clientX: 0, clientY: 1000, }) diff --git a/packages/components/color-picker/src/components/alpha-slider.vue b/packages/components/color-picker/src/components/alpha-slider.vue index 19ee84264b..ca30e74d3c 100644 --- a/packages/components/color-picker/src/components/alpha-slider.vue +++ b/packages/components/color-picker/src/components/alpha-slider.vue @@ -28,6 +28,7 @@ import { getCurrentInstance, shallowRef, } from 'vue' +import { getClientXY } from '@element-plus/utils/dom' import draggable from '../draggable' import type { PropType } from 'vue' @@ -112,9 +113,10 @@ export default defineComponent({ function handleDrag(event) { const el = instance.vnode.el as HTMLElement const rect = el.getBoundingClientRect() + const { clientX, clientY } = getClientXY(event) if (!props.vertical) { - let left = event.clientX - rect.left + let left = clientX - rect.left left = Math.max(thumb.value.offsetWidth / 2, left) left = Math.min(left, rect.width - thumb.value.offsetWidth / 2) @@ -127,7 +129,7 @@ export default defineComponent({ ) ) } else { - let top = event.clientY - rect.top + let top = clientY - rect.top top = Math.max(thumb.value.offsetHeight / 2, top) top = Math.min(top, rect.height - thumb.value.offsetHeight / 2) diff --git a/packages/components/color-picker/src/components/hue-slider.vue b/packages/components/color-picker/src/components/hue-slider.vue index 29dcee97a4..09e2246672 100644 --- a/packages/components/color-picker/src/components/hue-slider.vue +++ b/packages/components/color-picker/src/components/hue-slider.vue @@ -21,6 +21,7 @@ import { getCurrentInstance, defineComponent, } from 'vue' +import { getClientXY } from '@element-plus/utils/dom' import draggable from '../draggable' import type { PropType } from 'vue' @@ -56,6 +57,7 @@ export default defineComponent({ update() } ) + // methods function handleClick(event: Event) { const target = event.target @@ -64,13 +66,15 @@ export default defineComponent({ handleDrag(event) } } + function handleDrag(event) { const el = instance.vnode.el as HTMLElement const rect = el.getBoundingClientRect() + const { clientX, clientY } = getClientXY(event) let hue if (!props.vertical) { - let left = event.clientX - rect.left + let left = clientX - rect.left left = Math.min(left, rect.width - thumb.value.offsetWidth / 2) left = Math.max(thumb.value.offsetWidth / 2, left) @@ -80,7 +84,7 @@ export default defineComponent({ 360 ) } else { - let top = event.clientY - rect.top + let top = clientY - rect.top top = Math.min(top, rect.height - thumb.value.offsetHeight / 2) top = Math.max(thumb.value.offsetHeight / 2, top) @@ -92,6 +96,7 @@ export default defineComponent({ } props.color.set('hue', hue) } + function getThumbLeft() { const el = instance.vnode.el @@ -114,10 +119,12 @@ export default defineComponent({ (hue * (el.offsetHeight - thumb.value.offsetHeight / 2)) / 360 ) } + function update() { thumbLeft.value = getThumbLeft() thumbTop.value = getThumbTop() } + // mounded onMounted(() => { const dragConfig = { diff --git a/packages/components/color-picker/src/components/sv-panel.vue b/packages/components/color-picker/src/components/sv-panel.vue index 5861ed4113..e65ba63873 100644 --- a/packages/components/color-picker/src/components/sv-panel.vue +++ b/packages/components/color-picker/src/components/sv-panel.vue @@ -28,6 +28,7 @@ import { getCurrentInstance, onMounted, } from 'vue' +import { getClientXY } from '@element-plus/utils/dom' import draggable from '../draggable' import type { PropType } from 'vue' @@ -54,6 +55,7 @@ export default defineComponent({ const value = props.color.get('value') return { hue, value } }) + // methods function update() { const saturation = props.color.get('saturation') @@ -71,9 +73,10 @@ export default defineComponent({ function handleDrag(event) { const el = instance.vnode.el const rect = el.getBoundingClientRect() + const { clientX, clientY } = getClientXY(event) - let left = event.clientX - rect.left - let top = event.clientY - rect.top + let left = clientX - rect.left + let top = clientY - rect.top left = Math.max(0, left) left = Math.min(left, rect.width) @@ -87,6 +90,7 @@ export default defineComponent({ value: 100 - (top / rect.height) * 100, }) } + // watch watch( () => colorValue.value, diff --git a/packages/components/color-picker/src/draggable.ts b/packages/components/color-picker/src/draggable.ts index b4bf6487a7..94cef09afb 100644 --- a/packages/components/color-picker/src/draggable.ts +++ b/packages/components/color-picker/src/draggable.ts @@ -19,6 +19,8 @@ export default function (element: HTMLElement, options: IOptions) { const upFn = function (event: Event) { off(document, 'mousemove', moveFn) off(document, 'mouseup', upFn) + off(document, 'touchmove', moveFn) + off(document, 'touchend', upFn) document.onselectstart = null document.ondragstart = null @@ -27,15 +29,21 @@ export default function (element: HTMLElement, options: IOptions) { options.end?.(event) } - on(element, 'mousedown', function (event) { + const downFn = function (event: Event) { if (isDragging) return + event.preventDefault() document.onselectstart = () => false document.ondragstart = () => false on(document, 'mousemove', moveFn) on(document, 'mouseup', upFn) + on(document, 'touchmove', moveFn) + on(document, 'touchend', upFn) isDragging = true options.start?.(event) - }) + } + + on(element, 'mousedown', downFn) + on(element, 'touchstart', downFn) } diff --git a/packages/utils/dom.ts b/packages/utils/dom.ts index c54956b70e..3dee4c9048 100644 --- a/packages/utils/dom.ts +++ b/packages/utils/dom.ts @@ -234,3 +234,22 @@ export const getOffsetTopDistance = ( } export const stop = (e: Event) => e.stopPropagation() + +export const getClientXY = (event: MouseEvent | TouchEvent) => { + let clientX: number + let clientY: number + if (event.type === 'touchend') { + clientY = (event as TouchEvent).changedTouches[0].clientY + clientX = (event as TouchEvent).changedTouches[0].clientX + } else if (event.type.startsWith('touch')) { + clientY = (event as TouchEvent).touches[0].clientY + clientX = (event as TouchEvent).touches[0].clientX + } else { + clientY = (event as MouseEvent).clientY + clientX = (event as MouseEvent).clientX + } + return { + clientX, + clientY, + } +}