@will-ui/vue 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/btn/Btn.d.ts +4 -7
- package/dist/components/btn/Btn.js +1 -0
- package/dist/components/btn/Btn.js.map +1 -1
- package/dist/components/cascade/Cascade.d.ts +1 -1
- package/dist/components/choose/Choose.d.ts +4 -2
- package/dist/components/choose2/Choose2.d.ts +1 -1
- package/dist/components/confirm/index.d.ts +3 -4
- package/dist/components/confirm/index.js.map +1 -1
- package/dist/components/copy/Copy.d.ts +8 -8
- package/dist/components/copy/Copy.js +3 -2
- package/dist/components/copy/Copy.js.map +1 -1
- package/dist/components/cornerEars/CornerEars.d.ts +4 -7
- package/dist/components/cornerEars/CornerEars.js +1 -0
- package/dist/components/cornerEars/CornerEars.js.map +1 -1
- package/dist/components/date/DatePanel.d.ts +4 -0
- package/dist/components/date/DatePanel.js +2 -2
- package/dist/components/date/DatePanel.js.map +1 -1
- package/dist/components/date/DatePicker.d.ts +1 -1
- package/dist/components/date/DatePicker.js +4 -4
- package/dist/components/date/DatePicker.js.map +1 -1
- package/dist/components/date/Days.d.ts +2 -4
- package/dist/components/date/Days.js +1 -3
- package/dist/components/date/Days.js.map +1 -1
- package/dist/components/date/Months.d.ts +2 -4
- package/dist/components/date/Months.js +1 -3
- package/dist/components/date/Months.js.map +1 -1
- package/dist/components/date/QuickDate.d.ts +2 -12
- package/dist/components/date/QuickDate.js +1 -1
- package/dist/components/date/QuickDate.js.map +1 -1
- package/dist/components/date/Years.d.ts +3 -6
- package/dist/components/date/Years.js +1 -8
- package/dist/components/date/Years.js.map +1 -1
- package/dist/components/form/_use/formRules.d.ts +1 -1
- package/dist/components/form/_use/formRules.js.map +1 -1
- package/dist/components/formItem/FormItem.js.map +1 -1
- package/dist/components/image/Image.d.ts +5 -7
- package/dist/components/image/Image.js +3 -2
- package/dist/components/image/Image.js.map +1 -1
- package/dist/components/index.js +9 -9
- package/dist/components/modal/Modal.d.ts +1 -1
- package/dist/components/modal/Modal.js +29 -24
- package/dist/components/modal/Modal.js.map +1 -1
- package/dist/components/notice/src/_util/index.d.ts +1 -1
- package/dist/components/notice/src/_util/index.js.map +1 -1
- package/dist/components/number/Number copy.d.ts +1 -1
- package/dist/components/number/Number.d.ts +1 -1
- package/dist/components/pagination/src/Pagination.d.ts +6 -4
- package/dist/components/picture/Picture.d.ts +5 -7
- package/dist/components/picture/Picture.js +6 -5
- package/dist/components/picture/Picture.js.map +1 -1
- package/dist/components/picture/PictureViewport.js +22 -32
- package/dist/components/picture/PictureViewport.js.map +1 -1
- package/dist/components/progress/Progress.d.ts +1 -1
- package/dist/components/scrollbar/Scrollbar.js +61 -78
- package/dist/components/scrollbar/Scrollbar.js.map +1 -1
- package/dist/components/sheet/Sheet.d.ts +3 -1
- package/dist/components/sheet/_cell.js +16 -27
- package/dist/components/sheet/_cell.js.map +1 -1
- package/dist/components/slider/Slider.d.ts +2 -2
- package/dist/components/slider/Slider.js +24 -41
- package/dist/components/slider/Slider.js.map +1 -1
- package/dist/components/tab/Tab.d.ts +3 -3
- package/dist/components/tab/Tab.js +6 -0
- package/dist/components/tab/Tab.js.map +1 -1
- package/dist/components/textarea/Textarea.d.ts +5 -13
- package/dist/components/textarea/Textarea.js +3 -2
- package/dist/components/textarea/Textarea.js.map +1 -1
- package/dist/components/time/Dial.js.map +1 -1
- package/dist/components/time/Dial.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/time/TimePicker.d.ts +14 -2
- package/dist/components/tree-choose/TreeChoose.d.ts +1 -1
- package/dist/components/tree-choose/TreeChoose.js.map +1 -1
- package/dist/components/virtual/Virtual.d.ts +5 -5
- package/dist/components/virtual/Virtual.js +6 -0
- package/dist/components/virtual/Virtual.js.map +1 -1
- package/dist/index.d.ts +20 -15
- package/dist/index.js +6 -5
- package/dist/use/index.d.ts +2 -0
- package/dist/use/useChildComponentsCollector.d.ts +5 -0
- package/dist/use/useChildComponentsCollector.js.map +1 -1
- package/dist/use/usePercentDrag.d.ts +1 -1
- package/dist/use/usePercentDrag.js +19 -29
- package/dist/use/usePercentDrag.js.map +1 -1
- package/dist/use/usePointerDrag.d.ts +50 -0
- package/dist/use/usePointerDrag.js +143 -0
- package/dist/use/usePointerDrag.js.map +1 -0
- package/dist/use/useUII18n.d.ts +10 -0
- package/dist/use/useUII18n.js.map +1 -1
- package/dist/use/useUpload.js +1 -1
- package/dist/use/useUpload.js.map +1 -1
- package/package.json +79 -88
- package/dist/use/useDrag.d.ts +0 -17
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PictureViewport.js","names":["computed","defineComponent","onBeforeUnmount","onMounted","ref","shallowRef","watch","createVNode","_createVNode","createPictureViewport","PICTURE_VIEWPORT_ZOOM_STEP","useVisibleResize","PictureViewport","name","props","src","type","String","required","interact","Boolean","default","controller","Object","undefined","setup","expose","rootRef","wrapRef","imgRef","transformCss","useTransition","ready","dragging","canPan","natural","w","h","localApi","api","dragLast","unsub","syncFromApi","a","value","consumeTransition","getTransform","bindSubscribe","subscribe","measureViewport","el","width","height","getBoundingClientRect","setViewportSize","onImgLoad","img","naturalWidth","naturalHeight","setNaturalSize","prev","prepareImageChange","pointerFromCenter","clientX","clientY","x","y","r","left","top","onWheel","e","preventDefault","stopPropagation","factor","deltaY","p","zoomAt","onPointerDown","button","currentTarget","setPointerCapture","pointerId","onPointerMove","dx","dy","panBy","onPointerUp","releasePointerCapture","complete","methods","reset","fit","withTransition","oneToOne","zoomBy","rotateBy","delta","flip","axis","getFlipEl","getApi","rootClass","transform"],"sources":["../../../components/picture/PictureViewport.tsx"],"sourcesContent":["import {\r\n computed,\r\n defineComponent,\r\n onBeforeUnmount,\r\n onMounted,\r\n ref,\r\n shallowRef,\r\n watch,\r\n type PropType,\r\n} from 'vue'\r\nimport {\r\n createPictureViewport,\r\n PICTURE_VIEWPORT_ZOOM_STEP,\r\n type UsePictureViewport,\r\n} from '../../use/usePictureViewport'\r\nimport useVisibleResize from '../../use/useVisibleResize'\r\n\r\nexport type PictureViewportMethods = {\r\n reset: () => void\r\n fit: (withTransition?: boolean) => void\r\n oneToOne: () => void\r\n zoomBy: (factor: number) => void\r\n rotateBy: (delta: number) => void\r\n flip: (axis: 'x' | 'y') => void\r\n getFlipEl: () => HTMLElement | undefined\r\n getApi: () => UsePictureViewport\r\n}\r\n\r\nconst PictureViewport = defineComponent({\r\n name: 'PictureViewport',\r\n props: {\r\n src: { type: String, required: true },\r\n /** FLIP 结束后才为 true */\r\n interact: { type: Boolean, default: false },\r\n /** 与 Picture 共享,切图时保留缩放/旋转/翻转 */\r\n controller: {\r\n type: Object as PropType<UsePictureViewport>,\r\n default: undefined,\r\n },\r\n },\r\n setup(props, { expose }) {\r\n const rootRef = ref<HTMLElement>()\r\n const wrapRef = ref<HTMLElement>()\r\n const imgRef = ref<HTMLImageElement>()\r\n const transformCss = ref('translate(0px, 0px) rotate(0deg) scale(1, 1)')\r\n const useTransition = ref(false)\r\n const ready = ref(false)\r\n const dragging = ref(false)\r\n const canPan = ref(false)\r\n const natural = shallowRef({ w: 0, h: 0 })\r\n\r\n const localApi = createPictureViewport()\r\n const api = () => props.controller ?? localApi\r\n let dragLast: { x: number; y: number } | null = null\r\n let unsub: (() => void) | undefined\r\n\r\n const syncFromApi = () => {\r\n const a = api()\r\n useTransition.value = a.consumeTransition()\r\n transformCss.value = a.getTransform()\r\n canPan.value = a.canPan()\r\n }\r\n\r\n function bindSubscribe() {\r\n unsub?.()\r\n unsub = api().subscribe(syncFromApi)\r\n syncFromApi()\r\n }\r\n\r\n bindSubscribe()\r\n watch(\r\n () => props.controller,\r\n () => bindSubscribe(),\r\n )\r\n\r\n function measureViewport() {\r\n const el = rootRef.value\r\n if (!el) return\r\n const { width, height } = el.getBoundingClientRect()\r\n if (width < 1 || height < 1) return\r\n api().setViewportSize(width, height)\r\n syncFromApi()\r\n }\r\n\r\n useVisibleResize(rootRef, () => {\r\n measureViewport()\r\n })\r\n\r\n function onImgLoad() {\r\n const img = imgRef.value\r\n if (!img) return\r\n const w = img.naturalWidth\r\n const h = img.naturalHeight\r\n if (w < 1 || h < 1) return\r\n natural.value = { w, h }\r\n measureViewport()\r\n api().setNaturalSize(w, h)\r\n ready.value = true\r\n syncFromApi()\r\n }\r\n\r\n watch(\r\n () => props.src,\r\n (src, prev) => {\r\n if (prev == null || prev === src) return\r\n ready.value = false\r\n api().prepareImageChange()\r\n syncFromApi()\r\n },\r\n )\r\n\r\n function pointerFromCenter(clientX: number, clientY: number) {\r\n const el = rootRef.value\r\n if (!el) return { x: 0, y: 0 }\r\n const r = el.getBoundingClientRect()\r\n return {\r\n x: clientX - (r.left + r.width / 2),\r\n y: clientY - (r.top + r.height / 2),\r\n }\r\n }\r\n\r\n function onWheel(e: WheelEvent) {\r\n if (!props.interact || !ready.value) return\r\n e.preventDefault()\r\n e.stopPropagation()\r\n const factor =\r\n e.deltaY < 0\r\n ? PICTURE_VIEWPORT_ZOOM_STEP\r\n : 1 / PICTURE_VIEWPORT_ZOOM_STEP\r\n const p = pointerFromCenter(e.clientX, e.clientY)\r\n api().zoomAt(p.x, p.y, factor)\r\n }\r\n\r\n function onPointerDown(e: PointerEvent) {\r\n if (!props.interact || !ready.value) return\r\n if (e.button !== 0) return\r\n if (!api().canPan()) return\r\n e.preventDefault()\r\n dragging.value = true\r\n dragLast = { x: e.clientX, y: e.clientY }\r\n ;(e.currentTarget as HTMLElement).setPointerCapture?.(e.pointerId)\r\n }\r\n\r\n function onPointerMove(e: PointerEvent) {\r\n if (!dragging.value || !dragLast) return\r\n const dx = e.clientX - dragLast.x\r\n const dy = e.clientY - dragLast.y\r\n dragLast = { x: e.clientX, y: e.clientY }\r\n api().panBy(dx, dy)\r\n }\r\n\r\n function onPointerUp(e: PointerEvent) {\r\n if (!dragging.value) return\r\n dragging.value = false\r\n dragLast = null\r\n try {\r\n ;(e.currentTarget as HTMLElement).releasePointerCapture?.(e.pointerId)\r\n } catch {\r\n /* ignore */\r\n }\r\n }\r\n\r\n onMounted(() => {\r\n measureViewport()\r\n if (imgRef.value?.complete) onImgLoad()\r\n })\r\n\r\n onBeforeUnmount(() => {\r\n unsub?.()\r\n })\r\n\r\n const methods: PictureViewportMethods = {\r\n reset: () => {\r\n api().reset()\r\n syncFromApi()\r\n },\r\n fit: (withTransition = true) => {\r\n api().fit(withTransition)\r\n syncFromApi()\r\n },\r\n oneToOne: () => {\r\n api().oneToOne(true)\r\n syncFromApi()\r\n },\r\n zoomBy: (factor) => {\r\n api().zoomBy(factor)\r\n syncFromApi()\r\n },\r\n rotateBy: (delta) => {\r\n api().rotateBy(delta)\r\n syncFromApi()\r\n },\r\n flip: (axis) => {\r\n api().flip(axis)\r\n syncFromApi()\r\n },\r\n getFlipEl: () => wrapRef.value,\r\n getApi: () => api(),\r\n }\r\n\r\n expose(methods)\r\n\r\n const rootClass = computed(() => [\r\n 'w-picture-viewer__viewport',\r\n {\r\n 'is-panning': props.interact && canPan.value,\r\n 'is-dragging': dragging.value,\r\n },\r\n ])\r\n\r\n return () => (\r\n <div\r\n ref={rootRef}\r\n class={rootClass.value}\r\n onWheel={onWheel}\r\n onPointerdown={onPointerDown}\r\n onPointermove={onPointerMove}\r\n onPointerup={onPointerUp}\r\n onPointercancel={onPointerUp}>\r\n <div ref={wrapRef} class=\"w-picture-viewer__img-wrap\">\r\n <div\r\n class={[\r\n 'w-picture-viewer__transform',\r\n { 'is-transition': useTransition.value },\r\n ]}\r\n style={\r\n ready.value ? { transform: transformCss.value } : undefined\r\n }>\r\n <img\r\n ref={imgRef}\r\n class={[\r\n 'w-picture-viewer__img',\r\n { 'is-fit-css': !ready.value },\r\n ]}\r\n src={props.src}\r\n alt=\"\"\r\n draggable={false}\r\n width={ready.value && natural.value.w ? natural.value.w : undefined}\r\n height={\r\n ready.value && natural.value.h ? natural.value.h : undefined\r\n }\r\n onLoad={onImgLoad}\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n },\r\n})\r\n\r\nexport default PictureViewport\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PictureViewport.js","names":["computed","defineComponent","onBeforeUnmount","onMounted","ref","shallowRef","watch","createVNode","_createVNode","createPictureViewport","PICTURE_VIEWPORT_ZOOM_STEP","usePointerDrag","useVisibleResize","PictureViewport","name","props","src","type","String","required","interact","Boolean","default","controller","Object","undefined","setup","expose","rootRef","wrapRef","imgRef","transformCss","useTransition","ready","canPan","natural","w","h","localApi","api","unsub","syncFromApi","a","value","consumeTransition","getTransform","bindSubscribe","subscribe","measureViewport","el","width","height","getBoundingClientRect","setViewportSize","onImgLoad","img","naturalWidth","naturalHeight","setNaturalSize","prev","prepareImageChange","pointerFromCenter","clientX","clientY","x","y","r","left","top","onWheel","e","preventDefault","stopPropagation","factor","deltaY","p","zoomAt","dragging","onPointerDown","onPointerMove","onPointerUp","events","bind","disabled","onStart","ctx","button","data","lastX","lastY","onMove","dx","dy","panBy","complete","methods","reset","fit","withTransition","oneToOne","zoomBy","rotateBy","delta","flip","axis","getFlipEl","getApi","rootClass","transform"],"sources":["../../../components/picture/PictureViewport.tsx"],"sourcesContent":["import {\r\n computed,\r\n defineComponent,\r\n onBeforeUnmount,\r\n onMounted,\r\n ref,\r\n shallowRef,\r\n watch,\r\n type PropType,\r\n} from 'vue'\r\nimport {\r\n createPictureViewport,\r\n PICTURE_VIEWPORT_ZOOM_STEP,\r\n type UsePictureViewport,\r\n} from '../../use/usePictureViewport'\r\nimport usePointerDrag from '../../use/usePointerDrag'\r\nimport useVisibleResize from '../../use/useVisibleResize'\r\n\r\nexport type PictureViewportMethods = {\r\n reset: () => void\r\n fit: (withTransition?: boolean) => void\r\n oneToOne: () => void\r\n zoomBy: (factor: number) => void\r\n rotateBy: (delta: number) => void\r\n flip: (axis: 'x' | 'y') => void\r\n getFlipEl: () => HTMLElement | undefined\r\n getApi: () => UsePictureViewport\r\n}\r\n\r\nconst PictureViewport = defineComponent({\r\n name: 'PictureViewport',\r\n props: {\r\n src: { type: String, required: true },\r\n /** FLIP 结束后才为 true */\r\n interact: { type: Boolean, default: false },\r\n /** 与 Picture 共享,切图时保留缩放/旋转/翻转 */\r\n controller: {\r\n type: Object as PropType<UsePictureViewport>,\r\n default: undefined,\r\n },\r\n },\r\n setup(props, { expose }) {\r\n const rootRef = ref<HTMLElement>()\r\n const wrapRef = ref<HTMLElement>()\r\n const imgRef = ref<HTMLImageElement>()\r\n const transformCss = ref('translate(0px, 0px) rotate(0deg) scale(1, 1)')\r\n const useTransition = ref(false)\r\n const ready = ref(false)\r\n const canPan = ref(false)\r\n const natural = shallowRef({ w: 0, h: 0 })\r\n\r\n const localApi = createPictureViewport()\r\n const api = () => props.controller ?? localApi\r\n let unsub: (() => void) | undefined\r\n\r\n const syncFromApi = () => {\r\n const a = api()\r\n useTransition.value = a.consumeTransition()\r\n transformCss.value = a.getTransform()\r\n canPan.value = a.canPan()\r\n }\r\n\r\n function bindSubscribe() {\r\n unsub?.()\r\n unsub = api().subscribe(syncFromApi)\r\n syncFromApi()\r\n }\r\n\r\n bindSubscribe()\r\n watch(\r\n () => props.controller,\r\n () => bindSubscribe(),\r\n )\r\n\r\n function measureViewport() {\r\n const el = rootRef.value\r\n if (!el) return\r\n const { width, height } = el.getBoundingClientRect()\r\n if (width < 1 || height < 1) return\r\n api().setViewportSize(width, height)\r\n syncFromApi()\r\n }\r\n\r\n useVisibleResize(rootRef, () => {\r\n measureViewport()\r\n })\r\n\r\n function onImgLoad() {\r\n const img = imgRef.value\r\n if (!img) return\r\n const w = img.naturalWidth\r\n const h = img.naturalHeight\r\n if (w < 1 || h < 1) return\r\n natural.value = { w, h }\r\n measureViewport()\r\n api().setNaturalSize(w, h)\r\n ready.value = true\r\n syncFromApi()\r\n }\r\n\r\n watch(\r\n () => props.src,\r\n (src, prev) => {\r\n if (prev == null || prev === src) return\r\n ready.value = false\r\n api().prepareImageChange()\r\n syncFromApi()\r\n },\r\n )\r\n\r\n function pointerFromCenter(clientX: number, clientY: number) {\r\n const el = rootRef.value\r\n if (!el) return { x: 0, y: 0 }\r\n const r = el.getBoundingClientRect()\r\n return {\r\n x: clientX - (r.left + r.width / 2),\r\n y: clientY - (r.top + r.height / 2),\r\n }\r\n }\r\n\r\n function onWheel(e: WheelEvent) {\r\n if (!props.interact || !ready.value) return\r\n e.preventDefault()\r\n e.stopPropagation()\r\n const factor =\r\n e.deltaY < 0\r\n ? PICTURE_VIEWPORT_ZOOM_STEP\r\n : 1 / PICTURE_VIEWPORT_ZOOM_STEP\r\n const p = pointerFromCenter(e.clientX, e.clientY)\r\n api().zoomAt(p.x, p.y, factor)\r\n }\r\n\r\n // 平移用「相对上一帧」增量,与原先 dragLast 一致(非相对 start)\r\n const {\r\n dragging,\r\n onPointerDown,\r\n onPointerMove,\r\n onPointerUp,\r\n } = usePointerDrag({\r\n events: 'pointer',\r\n bind: 'capture',\r\n disabled: () => !props.interact || !ready.value,\r\n onStart: (e, ctx) => {\r\n if (e.button !== 0) return false\r\n if (!api().canPan()) return false\r\n e.preventDefault()\r\n ctx.data.lastX = e.clientX\r\n ctx.data.lastY = e.clientY\r\n },\r\n onMove: (e, ctx) => {\r\n const lastX = ctx.data.lastX as number\r\n const lastY = ctx.data.lastY as number\r\n const dx = e.clientX - lastX\r\n const dy = e.clientY - lastY\r\n ctx.data.lastX = e.clientX\r\n ctx.data.lastY = e.clientY\r\n api().panBy(dx, dy)\r\n },\r\n })\r\n\r\n onMounted(() => {\r\n measureViewport()\r\n if (imgRef.value?.complete) onImgLoad()\r\n })\r\n\r\n onBeforeUnmount(() => {\r\n unsub?.()\r\n })\r\n\r\n const methods: PictureViewportMethods = {\r\n reset: () => {\r\n api().reset()\r\n syncFromApi()\r\n },\r\n fit: (withTransition = true) => {\r\n api().fit(withTransition)\r\n syncFromApi()\r\n },\r\n oneToOne: () => {\r\n api().oneToOne(true)\r\n syncFromApi()\r\n },\r\n zoomBy: (factor) => {\r\n api().zoomBy(factor)\r\n syncFromApi()\r\n },\r\n rotateBy: (delta) => {\r\n api().rotateBy(delta)\r\n syncFromApi()\r\n },\r\n flip: (axis) => {\r\n api().flip(axis)\r\n syncFromApi()\r\n },\r\n getFlipEl: () => wrapRef.value,\r\n getApi: () => api(),\r\n }\r\n\r\n expose(methods)\r\n\r\n const rootClass = computed(() => [\r\n 'w-picture-viewer__viewport',\r\n {\r\n 'is-panning': props.interact && canPan.value,\r\n 'is-dragging': dragging.value,\r\n },\r\n ])\r\n\r\n return () => (\r\n <div\r\n ref={rootRef}\r\n class={rootClass.value}\r\n onWheel={onWheel}\r\n onPointerdown={onPointerDown}\r\n onPointermove={onPointerMove}\r\n onPointerup={onPointerUp}\r\n onPointercancel={onPointerUp}>\r\n <div ref={wrapRef} class=\"w-picture-viewer__img-wrap\">\r\n <div\r\n class={[\r\n 'w-picture-viewer__transform',\r\n { 'is-transition': useTransition.value },\r\n ]}\r\n style={\r\n ready.value ? { transform: transformCss.value } : undefined\r\n }>\r\n <img\r\n ref={imgRef}\r\n class={[\r\n 'w-picture-viewer__img',\r\n { 'is-fit-css': !ready.value },\r\n ]}\r\n src={props.src}\r\n alt=\"\"\r\n draggable={false}\r\n width={ready.value && natural.value.w ? natural.value.w : undefined}\r\n height={\r\n ready.value && natural.value.h ? natural.value.h : undefined\r\n }\r\n onLoad={onImgLoad}\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n },\r\n})\r\n\r\nexport default PictureViewport\r\n"],"mappings":"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"}
|
|
@@ -79,8 +79,8 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
|
|
|
79
79
|
}>> & Readonly<{
|
|
80
80
|
onChange?: (value: number) => any;
|
|
81
81
|
"onUpdate:modelValue"?: (value: number) => any;
|
|
82
|
-
"onDrag-start"?: (value: number) => any;
|
|
83
82
|
onDragging?: (value: number) => any;
|
|
83
|
+
"onDrag-start"?: (value: number) => any;
|
|
84
84
|
"onDrag-end"?: (value: number) => any;
|
|
85
85
|
}>, {
|
|
86
86
|
size: number;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isInvisible } from "../../util/dom.js";
|
|
2
2
|
import useVisibleResize from "../../use/useVisibleResize.js";
|
|
3
|
+
import usePointerDrag from "../../use/usePointerDrag.js";
|
|
3
4
|
import { computed, createVNode, defineComponent, nextTick, onMounted, onUnmounted, ref, watch } from "vue";
|
|
4
5
|
//#region components/scrollbar/Scrollbar.tsx
|
|
5
6
|
function toCssSize(v) {
|
|
@@ -68,12 +69,6 @@ var Scrollbar_default = /* @__PURE__ */ defineComponent({
|
|
|
68
69
|
const contentWidth = ref(0);
|
|
69
70
|
const vTrackHeight = ref(0);
|
|
70
71
|
const hTrackWidth = ref(0);
|
|
71
|
-
const isDraggingV = ref(false);
|
|
72
|
-
const isDraggingH = ref(false);
|
|
73
|
-
const dragStartY = ref(0);
|
|
74
|
-
const dragStartX = ref(0);
|
|
75
|
-
const dragStartScrollTop = ref(0);
|
|
76
|
-
const dragStartScrollLeft = ref(0);
|
|
77
72
|
const justDragged = ref(false);
|
|
78
73
|
const isProgrammaticScroll = ref(false);
|
|
79
74
|
const lastIsTop = ref(false);
|
|
@@ -299,78 +294,66 @@ var Scrollbar_default = /* @__PURE__ */ defineComponent({
|
|
|
299
294
|
const targetScrollLeft = leftPercent !== void 0 ? Math.max(0, Math.min(leftPercent / 100 * maxScrollLeft, maxScrollLeft)) : scrollLeft.value;
|
|
300
295
|
scrollTo(targetScrollTop, targetScrollLeft);
|
|
301
296
|
};
|
|
302
|
-
const handleVThumbMouseDown = (
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
};
|
|
362
|
-
const handleHThumbMouseUp = () => {
|
|
363
|
-
isDraggingH.value = false;
|
|
364
|
-
if (containerRef.value) containerRef.value.style.scrollBehavior = "";
|
|
365
|
-
document.removeEventListener("mousemove", handleHThumbMouseMove);
|
|
366
|
-
document.removeEventListener("mouseup", handleHThumbMouseUp);
|
|
367
|
-
document.body.style.userSelect = "";
|
|
368
|
-
document.body.style.cursor = "";
|
|
369
|
-
justDragged.value = true;
|
|
370
|
-
setTimeout(() => {
|
|
371
|
-
justDragged.value = false;
|
|
372
|
-
}, 0);
|
|
373
|
-
};
|
|
297
|
+
const { dragging: isDraggingV, onMouseDown: handleVThumbMouseDown } = usePointerDrag({
|
|
298
|
+
events: "mouse",
|
|
299
|
+
bind: "document",
|
|
300
|
+
cursor: "grabbing",
|
|
301
|
+
lockUserSelect: true,
|
|
302
|
+
onStart: (e, ctx) => {
|
|
303
|
+
e.preventDefault();
|
|
304
|
+
e.stopPropagation();
|
|
305
|
+
ctx.data.scrollStart = scrollTop.value;
|
|
306
|
+
if (containerRef.value) containerRef.value.style.scrollBehavior = "auto";
|
|
307
|
+
},
|
|
308
|
+
onMove: (e, ctx) => {
|
|
309
|
+
if (!containerRef.value) return;
|
|
310
|
+
e.preventDefault();
|
|
311
|
+
const deltaY = e.clientY - ctx.startY;
|
|
312
|
+
const maxScroll = contentHeight.value - containerHeight.value;
|
|
313
|
+
if (maxScroll <= 0 || vTrackHeight.value <= 0) return;
|
|
314
|
+
const maxThumbMove = vTrackHeight.value - vThumbHeight.value;
|
|
315
|
+
const scrollRatio = maxThumbMove > 0 ? maxScroll / maxThumbMove : 1;
|
|
316
|
+
const newScrollTop = ctx.data.scrollStart + deltaY * scrollRatio;
|
|
317
|
+
containerRef.value.scrollTop = Math.max(0, Math.min(newScrollTop, maxScroll));
|
|
318
|
+
},
|
|
319
|
+
onEnd: () => {
|
|
320
|
+
if (containerRef.value) containerRef.value.style.scrollBehavior = "";
|
|
321
|
+
justDragged.value = true;
|
|
322
|
+
setTimeout(() => {
|
|
323
|
+
justDragged.value = false;
|
|
324
|
+
}, 0);
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
const { dragging: isDraggingH, onMouseDown: handleHThumbMouseDown } = usePointerDrag({
|
|
328
|
+
events: "mouse",
|
|
329
|
+
bind: "document",
|
|
330
|
+
cursor: "grabbing",
|
|
331
|
+
lockUserSelect: true,
|
|
332
|
+
onStart: (e, ctx) => {
|
|
333
|
+
e.preventDefault();
|
|
334
|
+
e.stopPropagation();
|
|
335
|
+
ctx.data.scrollStart = scrollLeft.value;
|
|
336
|
+
if (containerRef.value) containerRef.value.style.scrollBehavior = "auto";
|
|
337
|
+
},
|
|
338
|
+
onMove: (e, ctx) => {
|
|
339
|
+
if (!containerRef.value) return;
|
|
340
|
+
e.preventDefault();
|
|
341
|
+
const deltaX = e.clientX - ctx.startX;
|
|
342
|
+
const maxScroll = contentWidth.value - containerWidth.value;
|
|
343
|
+
if (maxScroll <= 0 || hTrackWidth.value <= 0) return;
|
|
344
|
+
const maxThumbMove = hTrackWidth.value - hThumbWidth.value;
|
|
345
|
+
const scrollRatio = maxThumbMove > 0 ? maxScroll / maxThumbMove : 1;
|
|
346
|
+
const newScrollLeft = ctx.data.scrollStart + deltaX * scrollRatio;
|
|
347
|
+
containerRef.value.scrollLeft = Math.max(0, Math.min(newScrollLeft, maxScroll));
|
|
348
|
+
},
|
|
349
|
+
onEnd: () => {
|
|
350
|
+
if (containerRef.value) containerRef.value.style.scrollBehavior = "";
|
|
351
|
+
justDragged.value = true;
|
|
352
|
+
setTimeout(() => {
|
|
353
|
+
justDragged.value = false;
|
|
354
|
+
}, 0);
|
|
355
|
+
}
|
|
356
|
+
});
|
|
374
357
|
const handleVTrackClick = (e) => {
|
|
375
358
|
if (!containerRef.value || isDraggingV.value || justDragged.value) return;
|
|
376
359
|
const trackRect = vTrackRef.value?.getBoundingClientRect();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Scrollbar.js","names":["defineComponent","ref","computed","watch","onMounted","onUnmounted","nextTick","createVNode","_createVNode","useVisibleResize","isInvisible","toCssSize","v","undefined","name","props","direction","type","String","default","scrollStep","Number","visible","Boolean","minHeight","maxHeight","height","smooth","minThumbSize","bottomOffset","emits","setup","slots","emit","expose","containerRef","contentRef","vTrackRef","vThumbRef","hTrackRef","hThumbRef","scrollTop","scrollLeft","containerHeight","contentHeight","containerWidth","contentWidth","vTrackHeight","hTrackWidth","isDraggingV","isDraggingH","dragStartY","dragStartX","dragStartScrollTop","dragStartScrollLeft","justDragged","isProgrammaticScroll","lastIsTop","lastIsBottom","resolveWheelDelta","e","dx","deltaX","dy","deltaY","deltaMode","WheelEvent","DOM_DELTA_LINE","DOM_DELTA_PAGE","el","value","clientWidth","clientHeight","vThumbHeight","ratio","thumbH","Math","min","max","hThumbWidth","thumbW","vThumbTop","maxScroll","maxThumbMove","result","hThumbLeft","showVertical","showHorizontal","updateSize","scrollHeight","scrollWidth","computedStyle","getComputedStyle","paddingTop","parseFloat","paddingBottom","newVTrackHeight","paddingLeft","paddingRight","newHTrackWidth","handleScroll","target","isTop","maxScrollTop","maxScrollLeft","threshold","isBottom","distance","scrollTopPercent","round","scrollLeftPercent","scrollBottom","scrollRight","wheelSmoothRestoreTimer","pauseCssSmoothForWheel","style","scrollBehavior","clearTimeout","window","setTimeout","handleWheel","dir","eps","maxTop","maxLeft","canY","canX","stopPropagation","DOM_DELTA_PIXEL","preventDefault","scrollTo","top","left","behavior","scrollOptions","lastScrollTop","lastScrollLeft","stableFrames","checkScrollComplete","currentScrollTop","currentScrollLeft","requestAnimationFrame","scrollToTop","scrollToBottom","scrollToElement","element","scrollIntoView","block","scrollToPercent","topPercent","leftPercent","targetScrollTop","targetScrollLeft","handleVThumbMouseDown","clientY","document","addEventListener","handleVThumbMouseMove","handleVThumbMouseUp","body","userSelect","cursor","scrollRatio","newScrollTop","clampedScrollTop","removeEventListener","handleHThumbMouseDown","clientX","handleHThumbMouseMove","handleHThumbMouseUp","newScrollLeft","clampedScrollLeft","handleVTrackClick","trackRect","getBoundingClientRect","clickY","thumbCenter","handleHTrackClick","clickX","touchStartY","touchStartX","touchStartScrollTop","touchStartScrollLeft","handleTouchStart","touch","touches","handleTouchMove","handleTouchEnd","passive","exposeMethods","getScrollPosition","width"],"sources":["../../../components/scrollbar/Scrollbar.tsx"],"sourcesContent":["import {\r\n defineComponent,\r\n ref,\r\n computed,\r\n watch,\r\n onMounted,\r\n onUnmounted,\r\n nextTick,\r\n} from \"vue\"\r\nimport type { PropType } from \"vue\"\r\nimport useVisibleResize from \"../../use/useVisibleResize\"\r\nimport { isInvisible } from \"../../util\"\r\n\r\nfunction toCssSize(\r\n v: string | number | undefined\r\n): string | number | undefined {\r\n if (v === undefined) return undefined\r\n return typeof v === \"number\" ? `${v}px` : v\r\n}\r\n\r\nexport default defineComponent({\r\n name: \"Scrollbar\",\r\n props: {\r\n // 滚动方向:y(垂直), x(水平), both(双向)\r\n direction: {\r\n type: String as PropType<\"y\" | \"x\" | \"both\">,\r\n default: \"y\",\r\n },\r\n // 点击轨道的步长(px);滚轮在像素模式下跟随系统,LINE 模式才用此步长\r\n scrollStep: {\r\n type: Number,\r\n default: 60,\r\n },\r\n // 是否显示滚动条\r\n visible: {\r\n type: Boolean,\r\n default: true,\r\n },\r\n // 容器最小高度\r\n minHeight: {\r\n type: [String, Number],\r\n default: undefined,\r\n },\r\n // 容器最大高度\r\n maxHeight: {\r\n type: [String, Number],\r\n default: undefined,\r\n },\r\n // 容器高度\r\n height: {\r\n type: [String, Number],\r\n default: undefined,\r\n },\r\n // 是否启用平滑滚动\r\n smooth: {\r\n type: Boolean,\r\n default: true,\r\n },\r\n // 滑块最小尺寸(单位:px),默认 30px,防止内容过长时滑块过小难以拖拽\r\n minThumbSize: {\r\n type: Number,\r\n default: 30,\r\n },\r\n // 触底偏移量(单位:px),当距离底部还有多少像素时触发触底事件,默认 0\r\n bottomOffset: {\r\n type: Number,\r\n default: 0,\r\n },\r\n },\r\n emits: [\"scroll\", \"scroll-start\", \"scroll-end\", \"reach-top\", \"reach-bottom\"],\r\n setup(props, { slots, emit, expose }) {\r\n // 容器引用\r\n const containerRef = ref<HTMLElement | null>(null)\r\n // 内容引用\r\n const contentRef = ref<HTMLElement | null>(null)\r\n // 垂直滚动条引用\r\n const vTrackRef = ref<HTMLElement | null>(null)\r\n const vThumbRef = ref<HTMLElement | null>(null)\r\n // 水平滚动条引用\r\n const hTrackRef = ref<HTMLElement | null>(null)\r\n const hThumbRef = ref<HTMLElement | null>(null)\r\n\r\n // 滚动状态\r\n const scrollTop = ref(0)\r\n const scrollLeft = ref(0)\r\n const containerHeight = ref(0)\r\n const contentHeight = ref(0)\r\n const containerWidth = ref(0)\r\n const contentWidth = ref(0)\r\n\r\n // 轨道实际尺寸(通过测量得到)\r\n const vTrackHeight = ref(0)\r\n const hTrackWidth = ref(0)\r\n\r\n // 拖拽状态\r\n const isDraggingV = ref(false)\r\n const isDraggingH = ref(false)\r\n const dragStartY = ref(0)\r\n const dragStartX = ref(0)\r\n const dragStartScrollTop = ref(0)\r\n const dragStartScrollLeft = ref(0)\r\n\r\n // 刚结束拖拽的标志(用于防止 mouseup 后触发 click 事件)\r\n const justDragged = ref(false)\r\n\r\n // 是否是编程式滚动(外部调用方法触发的滚动)\r\n const isProgrammaticScroll = ref(false)\r\n\r\n // 触顶/触底状态(用于避免重复触发)\r\n const lastIsTop = ref(false)\r\n const lastIsBottom = ref(false)\r\n\r\n /**\r\n * 将 wheel 增量转为实际滚动像素。\r\n * 像素模式保留原生 delta(交给浏览器惯性,保证丝滑);\r\n * LINE/PAGE 才映射为 scrollStep / 一页高度。\r\n */\r\n const resolveWheelDelta = (e: WheelEvent) => {\r\n let dx = e.deltaX\r\n let dy = e.deltaY\r\n if (e.deltaMode === WheelEvent.DOM_DELTA_LINE) {\r\n dx *= props.scrollStep\r\n dy *= props.scrollStep\r\n } else if (e.deltaMode === WheelEvent.DOM_DELTA_PAGE) {\r\n const el = containerRef.value\r\n dx *= el?.clientWidth ?? 0\r\n dy *= el?.clientHeight ?? 0\r\n }\r\n return { dx, dy }\r\n }\r\n\r\n // 计算垂直滚动条滑块高度\r\n const vThumbHeight = computed(() => {\r\n if (contentHeight.value <= containerHeight.value) return 0\r\n\r\n // 滑块高度比例 = 可视区域 / 内容总高度\r\n const ratio = containerHeight.value / contentHeight.value\r\n\r\n // 滑块实际高度 = 轨道高度 × 比例\r\n const thumbH = vTrackHeight.value * ratio\r\n\r\n // 最小 minThumbSize px,最大不超过轨道高度\r\n return Math.min(Math.max(props.minThumbSize, thumbH), vTrackHeight.value)\r\n })\r\n\r\n // 计算水平滚动条滑块宽度\r\n const hThumbWidth = computed(() => {\r\n if (contentWidth.value <= containerWidth.value) return 0\r\n\r\n // 滑块宽度比例 = 可视区域 / 内容总宽度\r\n const ratio = containerWidth.value / contentWidth.value\r\n\r\n // 滑块实际宽度 = 轨道宽度 × 比例\r\n const thumbW = hTrackWidth.value * ratio\r\n\r\n // 最小 minThumbSize px,最大不超过轨道宽度\r\n return Math.min(Math.max(props.minThumbSize, thumbW), hTrackWidth.value)\r\n })\r\n\r\n // 计算垂直滚动条滑块位置\r\n const vThumbTop = computed(() => {\r\n if (contentHeight.value <= containerHeight.value) return 0\r\n const maxScroll = contentHeight.value - containerHeight.value\r\n if (maxScroll <= 0 || vTrackHeight.value <= 0) return 0\r\n\r\n const ratio = scrollTop.value / maxScroll\r\n\r\n // 滑块可移动的最大距离 = 轨道可用高度 - 滑块高度\r\n const maxThumbMove = vTrackHeight.value - vThumbHeight.value\r\n\r\n // 滑块位置(相对于轨道内容区域)\r\n const result = ratio * maxThumbMove\r\n\r\n // 确保在合理范围内\r\n return Math.max(0, Math.min(result, maxThumbMove))\r\n })\r\n\r\n // 计算水平滚动条滑块位置\r\n const hThumbLeft = computed(() => {\r\n if (contentWidth.value <= containerWidth.value) return 0\r\n const maxScroll = contentWidth.value - containerWidth.value\r\n if (maxScroll <= 0 || hTrackWidth.value <= 0) return 0\r\n\r\n const ratio = scrollLeft.value / maxScroll\r\n\r\n // 滑块可移动的最大距离 = 轨道可用宽度 - 滑块宽度\r\n const maxThumbMove = hTrackWidth.value - hThumbWidth.value\r\n\r\n // 滑块位置(相对于轨道内容区域)\r\n const result = ratio * maxThumbMove\r\n\r\n // 确保在合理范围内\r\n return Math.max(0, Math.min(result, maxThumbMove))\r\n })\r\n\r\n // 判断是否需要显示垂直滚动条\r\n const showVertical = computed(() => {\r\n return (\r\n props.visible &&\r\n (props.direction === \"y\" || props.direction === \"both\") &&\r\n contentHeight.value > containerHeight.value\r\n )\r\n })\r\n\r\n // 判断是否需要显示水平滚动条\r\n const showHorizontal = computed(() => {\r\n return (\r\n props.visible &&\r\n (props.direction === \"x\" || props.direction === \"both\") &&\r\n contentWidth.value > containerWidth.value\r\n )\r\n })\r\n\r\n // 更新尺寸信息\r\n const updateSize = () => {\r\n if (!containerRef.value || !contentRef.value) return\r\n if (isInvisible(containerRef.value)) return\r\n\r\n containerHeight.value = containerRef.value.clientHeight\r\n contentHeight.value = contentRef.value.scrollHeight\r\n containerWidth.value = containerRef.value.clientWidth\r\n contentWidth.value = contentRef.value.scrollWidth\r\n\r\n // 测量轨道实际尺寸(使用 offsetHeight/clientWidth 减去 padding,获取实际可移动区域)\r\n if (vTrackRef.value) {\r\n const computedStyle = getComputedStyle(vTrackRef.value)\r\n const paddingTop = parseFloat(computedStyle.paddingTop) || 0\r\n const paddingBottom = parseFloat(computedStyle.paddingBottom) || 0\r\n const newVTrackHeight =\r\n vTrackRef.value.clientHeight - paddingTop - paddingBottom\r\n if (newVTrackHeight > 0) {\r\n vTrackHeight.value = newVTrackHeight\r\n }\r\n }\r\n if (hTrackRef.value) {\r\n const computedStyle = getComputedStyle(hTrackRef.value)\r\n const paddingLeft = parseFloat(computedStyle.paddingLeft) || 0\r\n const paddingRight = parseFloat(computedStyle.paddingRight) || 0\r\n const newHTrackWidth =\r\n hTrackRef.value.clientWidth - paddingLeft - paddingRight\r\n if (newHTrackWidth > 0) {\r\n hTrackWidth.value = newHTrackWidth\r\n }\r\n }\r\n }\r\n\r\n useVisibleResize(containerRef, updateSize)\r\n useVisibleResize(contentRef, updateSize)\r\n watch([showVertical, showHorizontal], () => {\r\n nextTick(updateSize)\r\n })\r\n\r\n // 处理滚动事件\r\n const handleScroll = (e: Event) => {\r\n const target = e.target as HTMLElement\r\n\r\n // 更新滚动位置(总是更新,包括拖拽时)\r\n scrollTop.value = target.scrollTop\r\n scrollLeft.value = target.scrollLeft\r\n\r\n // 检测触顶\r\n const isTop = target.scrollTop <= 0\r\n if (isTop && !lastIsTop.value) {\r\n emit(\"reach-top\")\r\n }\r\n lastIsTop.value = isTop\r\n\r\n // 检测触底(考虑偏移量)\r\n const maxScrollTop = contentHeight.value - containerHeight.value\r\n const maxScrollLeft = contentWidth.value - containerWidth.value\r\n const threshold = maxScrollTop - props.bottomOffset\r\n const isBottom = maxScrollTop > 0 && target.scrollTop >= threshold\r\n if (isBottom && !lastIsBottom.value) {\r\n emit(\"reach-bottom\", { distance: maxScrollTop - target.scrollTop })\r\n }\r\n lastIsBottom.value = isBottom\r\n\r\n // 计算滚动百分比(0-100)\r\n const scrollTopPercent =\r\n maxScrollTop > 0\r\n ? Math.round((target.scrollTop / maxScrollTop) * 100)\r\n : 0\r\n const scrollLeftPercent =\r\n maxScrollLeft > 0\r\n ? Math.round((target.scrollLeft / maxScrollLeft) * 100)\r\n : 0\r\n\r\n // 如果是编程式滚动,不触发 scroll 事件\r\n if (!isProgrammaticScroll.value) {\r\n emit(\"scroll\", {\r\n scrollTop: target.scrollTop,\r\n scrollLeft: target.scrollLeft,\r\n // 距离底部的距离(垂直)\r\n scrollBottom: maxScrollTop - target.scrollTop,\r\n // 距离右侧的距离(水平)\r\n scrollRight: maxScrollLeft - target.scrollLeft,\r\n // 滚动百分比(0-100)\r\n scrollTopPercent,\r\n scrollLeftPercent,\r\n target,\r\n })\r\n }\r\n }\r\n\r\n // 连续像素流期间临时关掉 CSS smooth,避免跟浏览器惯性打架\r\n let wheelSmoothRestoreTimer: number | null = null\r\n const pauseCssSmoothForWheel = (el: HTMLElement) => {\r\n el.style.scrollBehavior = \"auto\"\r\n if (wheelSmoothRestoreTimer) clearTimeout(wheelSmoothRestoreTimer)\r\n wheelSmoothRestoreTimer = window.setTimeout(() => {\r\n if (props.smooth) el.style.scrollBehavior = \"\"\r\n wheelSmoothRestoreTimer = null\r\n }, 150)\r\n }\r\n\r\n /**\r\n * 滚轮:\r\n * - 本层还能顺着滚 → stopPropagation,避免外层 Scrollbar 抢走\r\n * - 像素模式 → 不 preventDefault,保留系统惯性(触摸板 / 现代鼠标)\r\n * - LINE/PAGE → preventDefault + 按 scrollStep / 页高步进\r\n * - 已到边界 → 不拦截,交给外层链式滚动\r\n */\r\n const handleWheel = (e: WheelEvent) => {\r\n const el = containerRef.value\r\n if (!el) return\r\n\r\n const { dx, dy } = resolveWheelDelta(e)\r\n const dir = props.direction\r\n const eps = 0.5\r\n\r\n const maxTop = el.scrollHeight - el.clientHeight\r\n const maxLeft = el.scrollWidth - el.clientWidth\r\n const canY =\r\n (dir === \"y\" || dir === \"both\") &&\r\n maxTop > 0 &&\r\n dy !== 0 &&\r\n ((dy > 0 && el.scrollTop < maxTop - eps) ||\r\n (dy < 0 && el.scrollTop > eps))\r\n const canX =\r\n (dir === \"x\" || dir === \"both\") &&\r\n maxLeft > 0 &&\r\n dx !== 0 &&\r\n ((dx > 0 && el.scrollLeft < maxLeft - eps) ||\r\n (dx < 0 && el.scrollLeft > eps))\r\n\r\n if (!canY && !canX) return\r\n\r\n // 挡住外层 Scrollbar 的 wheel 监听,否则嵌套时内层滚不动\r\n e.stopPropagation()\r\n pauseCssSmoothForWheel(el)\r\n\r\n // 像素模式交给浏览器(含惯性);scrollStep 主要作用于轨道点击与 LINE 模式\r\n if (e.deltaMode === WheelEvent.DOM_DELTA_PIXEL) return\r\n\r\n e.preventDefault()\r\n if (canY) {\r\n el.scrollTop = Math.max(0, Math.min(maxTop, el.scrollTop + dy))\r\n }\r\n if (canX) {\r\n el.scrollLeft = Math.max(0, Math.min(maxLeft, el.scrollLeft + dx))\r\n }\r\n }\r\n\r\n // 滚动到指定位置\r\n const scrollTo = (top?: number, left?: number) => {\r\n if (!containerRef.value) return\r\n\r\n // 设置编程式滚动标志\r\n isProgrammaticScroll.value = true\r\n\r\n const behavior = props.smooth ? \"smooth\" : \"auto\"\r\n\r\n // 将 top 和 left 合并到一个调用中,避免覆盖\r\n const scrollOptions: ScrollToOptions = { behavior }\r\n if (top !== undefined) scrollOptions.top = top\r\n if (left !== undefined) scrollOptions.left = left\r\n\r\n containerRef.value.scrollTo(scrollOptions)\r\n\r\n // 使用 requestAnimationFrame 检测滚动是否完成\r\n // 只有当滚动位置不再变化时才重置标志\r\n let lastScrollTop = containerRef.value.scrollTop\r\n let lastScrollLeft = containerRef.value.scrollLeft\r\n let stableFrames = 0\r\n\r\n const checkScrollComplete = () => {\r\n const currentScrollTop = containerRef.value?.scrollTop ?? lastScrollTop\r\n const currentScrollLeft = containerRef.value?.scrollLeft ?? lastScrollLeft\r\n\r\n if (currentScrollTop === lastScrollTop && currentScrollLeft === lastScrollLeft) {\r\n stableFrames++\r\n // 连续 3 帧位置不变,认为滚动已完成\r\n if (stableFrames >= 3) {\r\n isProgrammaticScroll.value = false\r\n return\r\n }\r\n } else {\r\n stableFrames = 0\r\n lastScrollTop = currentScrollTop\r\n lastScrollLeft = currentScrollLeft\r\n }\r\n\r\n // 最多检查 100 帧(约 1.6 秒),防止无限循环\r\n if (stableFrames < 100) {\r\n requestAnimationFrame(checkScrollComplete)\r\n } else {\r\n isProgrammaticScroll.value = false\r\n }\r\n }\r\n\r\n requestAnimationFrame(checkScrollComplete)\r\n }\r\n\r\n // 滚动到顶部\r\n const scrollToTop = () => {\r\n scrollTo(0)\r\n }\r\n\r\n // 滚动到底部\r\n const scrollToBottom = () => {\r\n if (!containerRef.value) return\r\n scrollTo(contentRef.value?.scrollHeight || 0)\r\n }\r\n\r\n // 滚动到指定元素\r\n const scrollToElement = (element: HTMLElement) => {\r\n // 设置编程式滚动标志\r\n isProgrammaticScroll.value = true\r\n\r\n element.scrollIntoView({\r\n behavior: props.smooth ? \"smooth\" : \"auto\",\r\n block: \"nearest\",\r\n })\r\n\r\n // 使用 requestAnimationFrame 检测滚动是否完成\r\n if (!containerRef.value) {\r\n setTimeout(() => { isProgrammaticScroll.value = false }, 100)\r\n return\r\n }\r\n\r\n let lastScrollTop = containerRef.value.scrollTop\r\n let lastScrollLeft = containerRef.value.scrollLeft\r\n let stableFrames = 0\r\n\r\n const checkScrollComplete = () => {\r\n const currentScrollTop = containerRef.value?.scrollTop ?? lastScrollTop\r\n const currentScrollLeft = containerRef.value?.scrollLeft ?? lastScrollLeft\r\n\r\n if (currentScrollTop === lastScrollTop && currentScrollLeft === lastScrollLeft) {\r\n stableFrames++\r\n if (stableFrames >= 3) {\r\n isProgrammaticScroll.value = false\r\n return\r\n }\r\n } else {\r\n stableFrames = 0\r\n lastScrollTop = currentScrollTop\r\n lastScrollLeft = currentScrollLeft\r\n }\r\n\r\n if (stableFrames < 100) {\r\n requestAnimationFrame(checkScrollComplete)\r\n } else {\r\n isProgrammaticScroll.value = false\r\n }\r\n }\r\n\r\n requestAnimationFrame(checkScrollComplete)\r\n }\r\n\r\n // 按百分比滚动到指定位置\r\n const scrollToPercent = (topPercent: number, leftPercent?: number) => {\r\n if (!containerRef.value) return\r\n\r\n const maxScrollTop = contentHeight.value - containerHeight.value\r\n const maxScrollLeft = contentWidth.value - containerWidth.value\r\n\r\n // 计算目标滚动位置\r\n const targetScrollTop = Math.max(\r\n 0,\r\n Math.min((topPercent / 100) * maxScrollTop, maxScrollTop)\r\n )\r\n const targetScrollLeft = leftPercent !== undefined\r\n ? Math.max(0, Math.min((leftPercent / 100) * maxScrollLeft, maxScrollLeft))\r\n : scrollLeft.value\r\n\r\n scrollTo(targetScrollTop, targetScrollLeft)\r\n }\r\n\r\n // 垂直滚动条拖拽开始\r\n const handleVThumbMouseDown = (e: MouseEvent) => {\r\n e.preventDefault()\r\n e.stopPropagation()\r\n isDraggingV.value = true\r\n dragStartY.value = e.clientY\r\n dragStartScrollTop.value = scrollTop.value\r\n\r\n // 拖拽时禁用平滑滚动,避免延迟感\r\n if (containerRef.value) {\r\n containerRef.value.style.scrollBehavior = \"auto\"\r\n }\r\n\r\n // 添加全局事件监听\r\n document.addEventListener(\"mousemove\", handleVThumbMouseMove)\r\n document.addEventListener(\"mouseup\", handleVThumbMouseUp)\r\n\r\n // 防止文本选择\r\n document.body.style.userSelect = \"none\"\r\n document.body.style.cursor = \"grabbing\"\r\n }\r\n\r\n // 垂直滚动条拖拽移动\r\n const handleVThumbMouseMove = (e: MouseEvent) => {\r\n if (!isDraggingV.value || !containerRef.value) return\r\n e.preventDefault()\r\n\r\n const deltaY = e.clientY - dragStartY.value\r\n const maxScroll = contentHeight.value - containerHeight.value\r\n\r\n // 防止除以零\r\n if (maxScroll <= 0 || vTrackHeight.value <= 0) return\r\n\r\n // 滑块可移动的最大距离 = 轨道高度 - 滑块高度\r\n const maxThumbMove = vTrackHeight.value - vThumbHeight.value\r\n\r\n // 计算滚动比例:每像素拖动对应的滚动距离\r\n const scrollRatio = maxThumbMove > 0 ? maxScroll / maxThumbMove : 1\r\n\r\n // 计算新的滚动位置\r\n const newScrollTop = dragStartScrollTop.value + deltaY * scrollRatio\r\n const clampedScrollTop = Math.max(0, Math.min(newScrollTop, maxScroll))\r\n\r\n // 直接设置滚动位置,Vue 会通过 scroll 事件自动更新滑块位置\r\n containerRef.value.scrollTop = clampedScrollTop\r\n }\r\n\r\n // 垂直滚动条拖拽结束\r\n const handleVThumbMouseUp = () => {\r\n isDraggingV.value = false\r\n\r\n // 恢复平滑滚动设置\r\n if (containerRef.value) {\r\n containerRef.value.style.scrollBehavior = \"\"\r\n }\r\n\r\n document.removeEventListener(\"mousemove\", handleVThumbMouseMove)\r\n document.removeEventListener(\"mouseup\", handleVThumbMouseUp)\r\n\r\n // 恢复样式\r\n document.body.style.userSelect = \"\"\r\n document.body.style.cursor = \"\"\r\n\r\n // 设置标志位,防止触发轨道 click 事件\r\n justDragged.value = true\r\n setTimeout(() => {\r\n justDragged.value = false\r\n }, 0)\r\n }\r\n\r\n // 水平滚动条拖拽开始\r\n const handleHThumbMouseDown = (e: MouseEvent) => {\r\n e.preventDefault()\r\n e.stopPropagation()\r\n isDraggingH.value = true\r\n dragStartX.value = e.clientX\r\n dragStartScrollLeft.value = scrollLeft.value\r\n\r\n // 拖拽时禁用平滑滚动,避免延迟感\r\n if (containerRef.value) {\r\n containerRef.value.style.scrollBehavior = \"auto\"\r\n }\r\n\r\n document.addEventListener(\"mousemove\", handleHThumbMouseMove)\r\n document.addEventListener(\"mouseup\", handleHThumbMouseUp)\r\n\r\n // 防止文本选择\r\n document.body.style.userSelect = \"none\"\r\n document.body.style.cursor = \"grabbing\"\r\n }\r\n\r\n // 水平滚动条拖拽移动\r\n const handleHThumbMouseMove = (e: MouseEvent) => {\r\n if (!isDraggingH.value || !containerRef.value) return\r\n e.preventDefault()\r\n\r\n const deltaX = e.clientX - dragStartX.value\r\n const maxScroll = contentWidth.value - containerWidth.value\r\n\r\n // 防止除以零\r\n if (maxScroll <= 0 || hTrackWidth.value <= 0) return\r\n\r\n // 滑块可移动的最大距离 = 轨道宽度 - 滑块宽度\r\n const maxThumbMove = hTrackWidth.value - hThumbWidth.value\r\n\r\n // 计算滚动比例:每像素拖动对应的滚动距离\r\n const scrollRatio = maxThumbMove > 0 ? maxScroll / maxThumbMove : 1\r\n\r\n // 计算新的滚动位置\r\n const newScrollLeft = dragStartScrollLeft.value + deltaX * scrollRatio\r\n const clampedScrollLeft = Math.max(0, Math.min(newScrollLeft, maxScroll))\r\n\r\n // 直接设置滚动位置,Vue 会通过 scroll 事件自动更新滑块位置\r\n containerRef.value.scrollLeft = clampedScrollLeft\r\n }\r\n\r\n // 水平滚动条拖拽结束\r\n const handleHThumbMouseUp = () => {\r\n isDraggingH.value = false\r\n\r\n // 恢复平滑滚动设置\r\n if (containerRef.value) {\r\n containerRef.value.style.scrollBehavior = \"\"\r\n }\r\n\r\n document.removeEventListener(\"mousemove\", handleHThumbMouseMove)\r\n document.removeEventListener(\"mouseup\", handleHThumbMouseUp)\r\n\r\n // 恢复样式\r\n document.body.style.userSelect = \"\"\r\n document.body.style.cursor = \"\"\r\n\r\n // 设置标志位,防止触发轨道 click 事件\r\n justDragged.value = true\r\n setTimeout(() => {\r\n justDragged.value = false\r\n }, 0)\r\n }\r\n\r\n // 点击垂直轨道\r\n const handleVTrackClick = (e: MouseEvent) => {\r\n if (!containerRef.value || isDraggingV.value || justDragged.value) return\r\n\r\n const trackRect = vTrackRef.value?.getBoundingClientRect()\r\n if (!trackRect) return\r\n\r\n // 计算点击位置相对于轨道顶部的位置\r\n const clickY = e.clientY - trackRect.top\r\n // 滑块中心位置\r\n const thumbCenter = vThumbTop.value + vThumbHeight.value / 2\r\n const maxScroll = contentHeight.value - containerHeight.value\r\n\r\n // 根据点击位置决定滚动方向\r\n let newScrollTop = scrollTop.value\r\n if (clickY < thumbCenter) {\r\n // 点击滑块上方,向上滚动\r\n newScrollTop = scrollTop.value - props.scrollStep\r\n } else {\r\n // 点击滑块下方,向下滚动\r\n newScrollTop = scrollTop.value + props.scrollStep\r\n }\r\n\r\n // 立即滚动,不使用平滑动画\r\n containerRef.value.scrollTop = Math.max(\r\n 0,\r\n Math.min(newScrollTop, maxScroll)\r\n )\r\n }\r\n\r\n // 点击水平轨道\r\n const handleHTrackClick = (e: MouseEvent) => {\r\n if (!containerRef.value || isDraggingH.value || justDragged.value) return\r\n\r\n const trackRect = hTrackRef.value?.getBoundingClientRect()\r\n if (!trackRect) return\r\n\r\n // 计算点击位置相对于轨道左侧的位置\r\n const clickX = e.clientX - trackRect.left\r\n // 滑块中心位置\r\n const thumbCenter = hThumbLeft.value + hThumbWidth.value / 2\r\n const maxScroll = contentWidth.value - containerWidth.value\r\n\r\n // 根据点击位置决定滚动方向\r\n let newScrollLeft = scrollLeft.value\r\n if (clickX < thumbCenter) {\r\n // 点击滑块左侧,向左滚动\r\n newScrollLeft = scrollLeft.value - props.scrollStep\r\n } else {\r\n // 点击滑块右侧,向右滚动\r\n newScrollLeft = scrollLeft.value + props.scrollStep\r\n }\r\n\r\n // 立即滚动,不使用平滑动画\r\n containerRef.value.scrollLeft = Math.max(\r\n 0,\r\n Math.min(newScrollLeft, maxScroll)\r\n )\r\n }\r\n\r\n // 触摸事件处理(移动端支持)\r\n const touchStartY = ref(0)\r\n const touchStartX = ref(0)\r\n const touchStartScrollTop = ref(0)\r\n const touchStartScrollLeft = ref(0)\r\n\r\n const handleTouchStart = (e: TouchEvent) => {\r\n const touch = e.touches[0]\r\n touchStartY.value = touch.clientY\r\n touchStartX.value = touch.clientX\r\n touchStartScrollTop.value = scrollTop.value\r\n touchStartScrollLeft.value = scrollLeft.value\r\n\r\n emit(\"scroll-start\")\r\n }\r\n\r\n const handleTouchMove = (e: TouchEvent) => {\r\n if (!containerRef.value) return\r\n\r\n const touch = e.touches[0]\r\n const deltaY = touchStartY.value - touch.clientY\r\n const deltaX = touchStartX.value - touch.clientX\r\n\r\n const maxScrollTop = contentHeight.value - containerHeight.value\r\n const maxScrollLeft = contentWidth.value - containerWidth.value\r\n\r\n const newScrollTop = touchStartScrollTop.value + deltaY\r\n const newScrollLeft = touchStartScrollLeft.value + deltaX\r\n\r\n // 使用 scrollTo,这会触发 scroll 事件,handleScroll 会更新状态\r\n scrollTo(\r\n Math.max(0, Math.min(newScrollTop, maxScrollTop)),\r\n Math.max(0, Math.min(newScrollLeft, maxScrollLeft))\r\n )\r\n }\r\n\r\n const handleTouchEnd = () => {\r\n emit(\"scroll-end\")\r\n }\r\n\r\n onMounted(() => {\r\n nextTick(() => {\r\n updateSize()\r\n\r\n // 再次延迟测量,确保轨道已渲染\r\n setTimeout(() => {\r\n updateSize()\r\n }, 100)\r\n\r\n // 需 preventDefault 才能接管离散滚轮步长,故 passive: false\r\n if (containerRef.value) {\r\n containerRef.value.addEventListener(\"wheel\", handleWheel, {\r\n passive: false,\r\n })\r\n }\r\n })\r\n })\r\n\r\n // 清理事件监听器\r\n onUnmounted(() => {\r\n if (containerRef.value) {\r\n containerRef.value.removeEventListener(\"wheel\", handleWheel)\r\n }\r\n\r\n if (wheelSmoothRestoreTimer) {\r\n clearTimeout(wheelSmoothRestoreTimer)\r\n wheelSmoothRestoreTimer = null\r\n }\r\n })\r\n\r\n // 暴露方法给父组件\r\n const exposeMethods = {\r\n scrollTo,\r\n scrollToTop,\r\n scrollToBottom,\r\n scrollToElement,\r\n scrollToPercent,\r\n updateSize,\r\n getScrollPosition: () => {\r\n const maxScrollTop = contentHeight.value - containerHeight.value\r\n const maxScrollLeft = contentWidth.value - containerWidth.value\r\n \r\n return {\r\n scrollTop: scrollTop.value,\r\n scrollLeft: scrollLeft.value,\r\n // 滚动百分比(0-100)\r\n scrollTopPercent: maxScrollTop > 0\r\n ? Math.round((scrollTop.value / maxScrollTop) * 100)\r\n : 0,\r\n scrollLeftPercent: maxScrollLeft > 0\r\n ? Math.round((scrollLeft.value / maxScrollLeft) * 100)\r\n : 0,\r\n }\r\n },\r\n }\r\n\r\n // 暴露方法\r\n expose(exposeMethods)\r\n\r\n return () => (\r\n <div\r\n class={[\r\n \"w-scrollbar\",\r\n // 将 direction 映射为 CSS class\r\n `w-scrollbar-${props.direction}`,\r\n {\r\n \"w-scrollbar-smooth\": props.smooth,\r\n },\r\n ]}\r\n style={{\r\n minHeight: toCssSize(props.minHeight),\r\n maxHeight: toCssSize(props.maxHeight),\r\n height: toCssSize(props.height),\r\n }}>\r\n {/* 滚动容器 */}\r\n <div\r\n ref={containerRef}\r\n class=\"w-scrollbar-container\"\r\n onScroll={handleScroll}\r\n onTouchstart={handleTouchStart}\r\n onTouchmove={handleTouchMove}\r\n onTouchend={handleTouchEnd}>\r\n <div ref={contentRef} class=\"w-scrollbar-content\">\r\n {slots.default?.()}\r\n </div>\r\n </div>\r\n\r\n {/* 垂直滚动条 */}\r\n {showVertical.value && (\r\n <div\r\n ref={vTrackRef}\r\n class=\"w-scrollbar-track w-scrollbar-track-y\"\r\n onClick={handleVTrackClick}>\r\n <div\r\n ref={vThumbRef}\r\n class={[\r\n \"w-scrollbar-thumb w-scrollbar-thumb-y\",\r\n { \"w-scrollbar-thumb-dragging\": isDraggingV.value },\r\n ]}\r\n style={{\r\n height: `${vThumbHeight.value}px`,\r\n top: `${vThumbTop.value}px`,\r\n }}\r\n onMousedown={handleVThumbMouseDown}\r\n onTouchstart={handleVThumbMouseDown as any}\r\n />\r\n </div>\r\n )}\r\n\r\n {/* 水平滚动条 */}\r\n {showHorizontal.value && (\r\n <div\r\n ref={hTrackRef}\r\n class=\"w-scrollbar-track w-scrollbar-track-x\"\r\n onClick={handleHTrackClick}>\r\n <div\r\n ref={hThumbRef}\r\n class={[\r\n \"w-scrollbar-thumb w-scrollbar-thumb-x\",\r\n { \"w-scrollbar-thumb-dragging\": isDraggingH.value },\r\n ]}\r\n style={{\r\n width: `${hThumbWidth.value}px`,\r\n left: `${hThumbLeft.value}px`,\r\n }}\r\n onMousedown={handleHThumbMouseDown}\r\n onTouchstart={handleHThumbMouseDown as any}\r\n />\r\n </div>\r\n )}\r\n </div>\r\n )\r\n },\r\n})\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Scrollbar.js","names":["defineComponent","ref","computed","watch","onMounted","onUnmounted","nextTick","createVNode","_createVNode","useVisibleResize","usePointerDrag","isInvisible","toCssSize","v","undefined","name","props","direction","type","String","default","scrollStep","Number","visible","Boolean","minHeight","maxHeight","height","smooth","minThumbSize","bottomOffset","emits","setup","slots","emit","expose","containerRef","contentRef","vTrackRef","vThumbRef","hTrackRef","hThumbRef","scrollTop","scrollLeft","containerHeight","contentHeight","containerWidth","contentWidth","vTrackHeight","hTrackWidth","justDragged","isProgrammaticScroll","lastIsTop","lastIsBottom","resolveWheelDelta","e","dx","deltaX","dy","deltaY","deltaMode","WheelEvent","DOM_DELTA_LINE","DOM_DELTA_PAGE","el","value","clientWidth","clientHeight","vThumbHeight","ratio","thumbH","Math","min","max","hThumbWidth","thumbW","vThumbTop","maxScroll","maxThumbMove","result","hThumbLeft","showVertical","showHorizontal","updateSize","scrollHeight","scrollWidth","computedStyle","getComputedStyle","paddingTop","parseFloat","paddingBottom","newVTrackHeight","paddingLeft","paddingRight","newHTrackWidth","handleScroll","target","isTop","maxScrollTop","maxScrollLeft","threshold","isBottom","distance","scrollTopPercent","round","scrollLeftPercent","scrollBottom","scrollRight","wheelSmoothRestoreTimer","pauseCssSmoothForWheel","style","scrollBehavior","clearTimeout","window","setTimeout","handleWheel","dir","eps","maxTop","maxLeft","canY","canX","stopPropagation","DOM_DELTA_PIXEL","preventDefault","scrollTo","top","left","behavior","scrollOptions","lastScrollTop","lastScrollLeft","stableFrames","checkScrollComplete","currentScrollTop","currentScrollLeft","requestAnimationFrame","scrollToTop","scrollToBottom","scrollToElement","element","scrollIntoView","block","scrollToPercent","topPercent","leftPercent","targetScrollTop","targetScrollLeft","dragging","isDraggingV","onMouseDown","handleVThumbMouseDown","events","bind","cursor","lockUserSelect","onStart","ctx","data","scrollStart","onMove","clientY","startY","scrollRatio","newScrollTop","onEnd","isDraggingH","handleHThumbMouseDown","clientX","startX","newScrollLeft","handleVTrackClick","trackRect","getBoundingClientRect","clickY","thumbCenter","handleHTrackClick","clickX","touchStartY","touchStartX","touchStartScrollTop","touchStartScrollLeft","handleTouchStart","touch","touches","handleTouchMove","handleTouchEnd","addEventListener","passive","removeEventListener","exposeMethods","getScrollPosition","width"],"sources":["../../../components/scrollbar/Scrollbar.tsx"],"sourcesContent":["import {\r\n defineComponent,\r\n ref,\r\n computed,\r\n watch,\r\n onMounted,\r\n onUnmounted,\r\n nextTick,\r\n} from \"vue\"\r\nimport type { PropType } from \"vue\"\r\nimport useVisibleResize from \"../../use/useVisibleResize\"\r\nimport usePointerDrag from \"../../use/usePointerDrag\"\r\nimport { isInvisible } from \"../../util\"\r\n\r\nfunction toCssSize(\r\n v: string | number | undefined\r\n): string | number | undefined {\r\n if (v === undefined) return undefined\r\n return typeof v === \"number\" ? `${v}px` : v\r\n}\r\n\r\nexport default defineComponent({\r\n name: \"Scrollbar\",\r\n props: {\r\n // 滚动方向:y(垂直), x(水平), both(双向)\r\n direction: {\r\n type: String as PropType<\"y\" | \"x\" | \"both\">,\r\n default: \"y\",\r\n },\r\n // 点击轨道的步长(px);滚轮在像素模式下跟随系统,LINE 模式才用此步长\r\n scrollStep: {\r\n type: Number,\r\n default: 60,\r\n },\r\n // 是否显示滚动条\r\n visible: {\r\n type: Boolean,\r\n default: true,\r\n },\r\n // 容器最小高度\r\n minHeight: {\r\n type: [String, Number],\r\n default: undefined,\r\n },\r\n // 容器最大高度\r\n maxHeight: {\r\n type: [String, Number],\r\n default: undefined,\r\n },\r\n // 容器高度\r\n height: {\r\n type: [String, Number],\r\n default: undefined,\r\n },\r\n // 是否启用平滑滚动\r\n smooth: {\r\n type: Boolean,\r\n default: true,\r\n },\r\n // 滑块最小尺寸(单位:px),默认 30px,防止内容过长时滑块过小难以拖拽\r\n minThumbSize: {\r\n type: Number,\r\n default: 30,\r\n },\r\n // 触底偏移量(单位:px),当距离底部还有多少像素时触发触底事件,默认 0\r\n bottomOffset: {\r\n type: Number,\r\n default: 0,\r\n },\r\n },\r\n emits: [\"scroll\", \"scroll-start\", \"scroll-end\", \"reach-top\", \"reach-bottom\"],\r\n setup(props, { slots, emit, expose }) {\r\n // 容器引用\r\n const containerRef = ref<HTMLElement | null>(null)\r\n // 内容引用\r\n const contentRef = ref<HTMLElement | null>(null)\r\n // 垂直滚动条引用\r\n const vTrackRef = ref<HTMLElement | null>(null)\r\n const vThumbRef = ref<HTMLElement | null>(null)\r\n // 水平滚动条引用\r\n const hTrackRef = ref<HTMLElement | null>(null)\r\n const hThumbRef = ref<HTMLElement | null>(null)\r\n\r\n // 滚动状态\r\n const scrollTop = ref(0)\r\n const scrollLeft = ref(0)\r\n const containerHeight = ref(0)\r\n const contentHeight = ref(0)\r\n const containerWidth = ref(0)\r\n const contentWidth = ref(0)\r\n\r\n // 轨道实际尺寸(通过测量得到)\r\n const vTrackHeight = ref(0)\r\n const hTrackWidth = ref(0)\r\n\r\n // 刚结束拖拽的标志(用于防止 mouseup 后触发 click 事件)\r\n const justDragged = ref(false)\r\n\r\n // 是否是编程式滚动(外部调用方法触发的滚动)\r\n const isProgrammaticScroll = ref(false)\r\n\r\n // 触顶/触底状态(用于避免重复触发)\r\n const lastIsTop = ref(false)\r\n const lastIsBottom = ref(false)\r\n\r\n /**\r\n * 将 wheel 增量转为实际滚动像素。\r\n * 像素模式保留原生 delta(交给浏览器惯性,保证丝滑);\r\n * LINE/PAGE 才映射为 scrollStep / 一页高度。\r\n */\r\n const resolveWheelDelta = (e: WheelEvent) => {\r\n let dx = e.deltaX\r\n let dy = e.deltaY\r\n if (e.deltaMode === WheelEvent.DOM_DELTA_LINE) {\r\n dx *= props.scrollStep\r\n dy *= props.scrollStep\r\n } else if (e.deltaMode === WheelEvent.DOM_DELTA_PAGE) {\r\n const el = containerRef.value\r\n dx *= el?.clientWidth ?? 0\r\n dy *= el?.clientHeight ?? 0\r\n }\r\n return { dx, dy }\r\n }\r\n\r\n // 计算垂直滚动条滑块高度\r\n const vThumbHeight = computed(() => {\r\n if (contentHeight.value <= containerHeight.value) return 0\r\n\r\n // 滑块高度比例 = 可视区域 / 内容总高度\r\n const ratio = containerHeight.value / contentHeight.value\r\n\r\n // 滑块实际高度 = 轨道高度 × 比例\r\n const thumbH = vTrackHeight.value * ratio\r\n\r\n // 最小 minThumbSize px,最大不超过轨道高度\r\n return Math.min(Math.max(props.minThumbSize, thumbH), vTrackHeight.value)\r\n })\r\n\r\n // 计算水平滚动条滑块宽度\r\n const hThumbWidth = computed(() => {\r\n if (contentWidth.value <= containerWidth.value) return 0\r\n\r\n // 滑块宽度比例 = 可视区域 / 内容总宽度\r\n const ratio = containerWidth.value / contentWidth.value\r\n\r\n // 滑块实际宽度 = 轨道宽度 × 比例\r\n const thumbW = hTrackWidth.value * ratio\r\n\r\n // 最小 minThumbSize px,最大不超过轨道宽度\r\n return Math.min(Math.max(props.minThumbSize, thumbW), hTrackWidth.value)\r\n })\r\n\r\n // 计算垂直滚动条滑块位置\r\n const vThumbTop = computed(() => {\r\n if (contentHeight.value <= containerHeight.value) return 0\r\n const maxScroll = contentHeight.value - containerHeight.value\r\n if (maxScroll <= 0 || vTrackHeight.value <= 0) return 0\r\n\r\n const ratio = scrollTop.value / maxScroll\r\n\r\n // 滑块可移动的最大距离 = 轨道可用高度 - 滑块高度\r\n const maxThumbMove = vTrackHeight.value - vThumbHeight.value\r\n\r\n // 滑块位置(相对于轨道内容区域)\r\n const result = ratio * maxThumbMove\r\n\r\n // 确保在合理范围内\r\n return Math.max(0, Math.min(result, maxThumbMove))\r\n })\r\n\r\n // 计算水平滚动条滑块位置\r\n const hThumbLeft = computed(() => {\r\n if (contentWidth.value <= containerWidth.value) return 0\r\n const maxScroll = contentWidth.value - containerWidth.value\r\n if (maxScroll <= 0 || hTrackWidth.value <= 0) return 0\r\n\r\n const ratio = scrollLeft.value / maxScroll\r\n\r\n // 滑块可移动的最大距离 = 轨道可用宽度 - 滑块宽度\r\n const maxThumbMove = hTrackWidth.value - hThumbWidth.value\r\n\r\n // 滑块位置(相对于轨道内容区域)\r\n const result = ratio * maxThumbMove\r\n\r\n // 确保在合理范围内\r\n return Math.max(0, Math.min(result, maxThumbMove))\r\n })\r\n\r\n // 判断是否需要显示垂直滚动条\r\n const showVertical = computed(() => {\r\n return (\r\n props.visible &&\r\n (props.direction === \"y\" || props.direction === \"both\") &&\r\n contentHeight.value > containerHeight.value\r\n )\r\n })\r\n\r\n // 判断是否需要显示水平滚动条\r\n const showHorizontal = computed(() => {\r\n return (\r\n props.visible &&\r\n (props.direction === \"x\" || props.direction === \"both\") &&\r\n contentWidth.value > containerWidth.value\r\n )\r\n })\r\n\r\n // 更新尺寸信息\r\n const updateSize = () => {\r\n if (!containerRef.value || !contentRef.value) return\r\n if (isInvisible(containerRef.value)) return\r\n\r\n containerHeight.value = containerRef.value.clientHeight\r\n contentHeight.value = contentRef.value.scrollHeight\r\n containerWidth.value = containerRef.value.clientWidth\r\n contentWidth.value = contentRef.value.scrollWidth\r\n\r\n // 测量轨道实际尺寸(使用 offsetHeight/clientWidth 减去 padding,获取实际可移动区域)\r\n if (vTrackRef.value) {\r\n const computedStyle = getComputedStyle(vTrackRef.value)\r\n const paddingTop = parseFloat(computedStyle.paddingTop) || 0\r\n const paddingBottom = parseFloat(computedStyle.paddingBottom) || 0\r\n const newVTrackHeight =\r\n vTrackRef.value.clientHeight - paddingTop - paddingBottom\r\n if (newVTrackHeight > 0) {\r\n vTrackHeight.value = newVTrackHeight\r\n }\r\n }\r\n if (hTrackRef.value) {\r\n const computedStyle = getComputedStyle(hTrackRef.value)\r\n const paddingLeft = parseFloat(computedStyle.paddingLeft) || 0\r\n const paddingRight = parseFloat(computedStyle.paddingRight) || 0\r\n const newHTrackWidth =\r\n hTrackRef.value.clientWidth - paddingLeft - paddingRight\r\n if (newHTrackWidth > 0) {\r\n hTrackWidth.value = newHTrackWidth\r\n }\r\n }\r\n }\r\n\r\n useVisibleResize(containerRef, updateSize)\r\n useVisibleResize(contentRef, updateSize)\r\n watch([showVertical, showHorizontal], () => {\r\n nextTick(updateSize)\r\n })\r\n\r\n // 处理滚动事件\r\n const handleScroll = (e: Event) => {\r\n const target = e.target as HTMLElement\r\n\r\n // 更新滚动位置(总是更新,包括拖拽时)\r\n scrollTop.value = target.scrollTop\r\n scrollLeft.value = target.scrollLeft\r\n\r\n // 检测触顶\r\n const isTop = target.scrollTop <= 0\r\n if (isTop && !lastIsTop.value) {\r\n emit(\"reach-top\")\r\n }\r\n lastIsTop.value = isTop\r\n\r\n // 检测触底(考虑偏移量)\r\n const maxScrollTop = contentHeight.value - containerHeight.value\r\n const maxScrollLeft = contentWidth.value - containerWidth.value\r\n const threshold = maxScrollTop - props.bottomOffset\r\n const isBottom = maxScrollTop > 0 && target.scrollTop >= threshold\r\n if (isBottom && !lastIsBottom.value) {\r\n emit(\"reach-bottom\", { distance: maxScrollTop - target.scrollTop })\r\n }\r\n lastIsBottom.value = isBottom\r\n\r\n // 计算滚动百分比(0-100)\r\n const scrollTopPercent =\r\n maxScrollTop > 0\r\n ? Math.round((target.scrollTop / maxScrollTop) * 100)\r\n : 0\r\n const scrollLeftPercent =\r\n maxScrollLeft > 0\r\n ? Math.round((target.scrollLeft / maxScrollLeft) * 100)\r\n : 0\r\n\r\n // 如果是编程式滚动,不触发 scroll 事件\r\n if (!isProgrammaticScroll.value) {\r\n emit(\"scroll\", {\r\n scrollTop: target.scrollTop,\r\n scrollLeft: target.scrollLeft,\r\n // 距离底部的距离(垂直)\r\n scrollBottom: maxScrollTop - target.scrollTop,\r\n // 距离右侧的距离(水平)\r\n scrollRight: maxScrollLeft - target.scrollLeft,\r\n // 滚动百分比(0-100)\r\n scrollTopPercent,\r\n scrollLeftPercent,\r\n target,\r\n })\r\n }\r\n }\r\n\r\n // 连续像素流期间临时关掉 CSS smooth,避免跟浏览器惯性打架\r\n let wheelSmoothRestoreTimer: number | null = null\r\n const pauseCssSmoothForWheel = (el: HTMLElement) => {\r\n el.style.scrollBehavior = \"auto\"\r\n if (wheelSmoothRestoreTimer) clearTimeout(wheelSmoothRestoreTimer)\r\n wheelSmoothRestoreTimer = window.setTimeout(() => {\r\n if (props.smooth) el.style.scrollBehavior = \"\"\r\n wheelSmoothRestoreTimer = null\r\n }, 150)\r\n }\r\n\r\n /**\r\n * 滚轮:\r\n * - 本层还能顺着滚 → stopPropagation,避免外层 Scrollbar 抢走\r\n * - 像素模式 → 不 preventDefault,保留系统惯性(触摸板 / 现代鼠标)\r\n * - LINE/PAGE → preventDefault + 按 scrollStep / 页高步进\r\n * - 已到边界 → 不拦截,交给外层链式滚动\r\n */\r\n const handleWheel = (e: WheelEvent) => {\r\n const el = containerRef.value\r\n if (!el) return\r\n\r\n const { dx, dy } = resolveWheelDelta(e)\r\n const dir = props.direction\r\n const eps = 0.5\r\n\r\n const maxTop = el.scrollHeight - el.clientHeight\r\n const maxLeft = el.scrollWidth - el.clientWidth\r\n const canY =\r\n (dir === \"y\" || dir === \"both\") &&\r\n maxTop > 0 &&\r\n dy !== 0 &&\r\n ((dy > 0 && el.scrollTop < maxTop - eps) ||\r\n (dy < 0 && el.scrollTop > eps))\r\n const canX =\r\n (dir === \"x\" || dir === \"both\") &&\r\n maxLeft > 0 &&\r\n dx !== 0 &&\r\n ((dx > 0 && el.scrollLeft < maxLeft - eps) ||\r\n (dx < 0 && el.scrollLeft > eps))\r\n\r\n if (!canY && !canX) return\r\n\r\n // 挡住外层 Scrollbar 的 wheel 监听,否则嵌套时内层滚不动\r\n e.stopPropagation()\r\n pauseCssSmoothForWheel(el)\r\n\r\n // 像素模式交给浏览器(含惯性);scrollStep 主要作用于轨道点击与 LINE 模式\r\n if (e.deltaMode === WheelEvent.DOM_DELTA_PIXEL) return\r\n\r\n e.preventDefault()\r\n if (canY) {\r\n el.scrollTop = Math.max(0, Math.min(maxTop, el.scrollTop + dy))\r\n }\r\n if (canX) {\r\n el.scrollLeft = Math.max(0, Math.min(maxLeft, el.scrollLeft + dx))\r\n }\r\n }\r\n\r\n // 滚动到指定位置\r\n const scrollTo = (top?: number, left?: number) => {\r\n if (!containerRef.value) return\r\n\r\n // 设置编程式滚动标志\r\n isProgrammaticScroll.value = true\r\n\r\n const behavior = props.smooth ? \"smooth\" : \"auto\"\r\n\r\n // 将 top 和 left 合并到一个调用中,避免覆盖\r\n const scrollOptions: ScrollToOptions = { behavior }\r\n if (top !== undefined) scrollOptions.top = top\r\n if (left !== undefined) scrollOptions.left = left\r\n\r\n containerRef.value.scrollTo(scrollOptions)\r\n\r\n // 使用 requestAnimationFrame 检测滚动是否完成\r\n // 只有当滚动位置不再变化时才重置标志\r\n let lastScrollTop = containerRef.value.scrollTop\r\n let lastScrollLeft = containerRef.value.scrollLeft\r\n let stableFrames = 0\r\n\r\n const checkScrollComplete = () => {\r\n const currentScrollTop = containerRef.value?.scrollTop ?? lastScrollTop\r\n const currentScrollLeft = containerRef.value?.scrollLeft ?? lastScrollLeft\r\n\r\n if (currentScrollTop === lastScrollTop && currentScrollLeft === lastScrollLeft) {\r\n stableFrames++\r\n // 连续 3 帧位置不变,认为滚动已完成\r\n if (stableFrames >= 3) {\r\n isProgrammaticScroll.value = false\r\n return\r\n }\r\n } else {\r\n stableFrames = 0\r\n lastScrollTop = currentScrollTop\r\n lastScrollLeft = currentScrollLeft\r\n }\r\n\r\n // 最多检查 100 帧(约 1.6 秒),防止无限循环\r\n if (stableFrames < 100) {\r\n requestAnimationFrame(checkScrollComplete)\r\n } else {\r\n isProgrammaticScroll.value = false\r\n }\r\n }\r\n\r\n requestAnimationFrame(checkScrollComplete)\r\n }\r\n\r\n // 滚动到顶部\r\n const scrollToTop = () => {\r\n scrollTo(0)\r\n }\r\n\r\n // 滚动到底部\r\n const scrollToBottom = () => {\r\n if (!containerRef.value) return\r\n scrollTo(contentRef.value?.scrollHeight || 0)\r\n }\r\n\r\n // 滚动到指定元素\r\n const scrollToElement = (element: HTMLElement) => {\r\n // 设置编程式滚动标志\r\n isProgrammaticScroll.value = true\r\n\r\n element.scrollIntoView({\r\n behavior: props.smooth ? \"smooth\" : \"auto\",\r\n block: \"nearest\",\r\n })\r\n\r\n // 使用 requestAnimationFrame 检测滚动是否完成\r\n if (!containerRef.value) {\r\n setTimeout(() => { isProgrammaticScroll.value = false }, 100)\r\n return\r\n }\r\n\r\n let lastScrollTop = containerRef.value.scrollTop\r\n let lastScrollLeft = containerRef.value.scrollLeft\r\n let stableFrames = 0\r\n\r\n const checkScrollComplete = () => {\r\n const currentScrollTop = containerRef.value?.scrollTop ?? lastScrollTop\r\n const currentScrollLeft = containerRef.value?.scrollLeft ?? lastScrollLeft\r\n\r\n if (currentScrollTop === lastScrollTop && currentScrollLeft === lastScrollLeft) {\r\n stableFrames++\r\n if (stableFrames >= 3) {\r\n isProgrammaticScroll.value = false\r\n return\r\n }\r\n } else {\r\n stableFrames = 0\r\n lastScrollTop = currentScrollTop\r\n lastScrollLeft = currentScrollLeft\r\n }\r\n\r\n if (stableFrames < 100) {\r\n requestAnimationFrame(checkScrollComplete)\r\n } else {\r\n isProgrammaticScroll.value = false\r\n }\r\n }\r\n\r\n requestAnimationFrame(checkScrollComplete)\r\n }\r\n\r\n // 按百分比滚动到指定位置\r\n const scrollToPercent = (topPercent: number, leftPercent?: number) => {\r\n if (!containerRef.value) return\r\n\r\n const maxScrollTop = contentHeight.value - containerHeight.value\r\n const maxScrollLeft = contentWidth.value - containerWidth.value\r\n\r\n // 计算目标滚动位置\r\n const targetScrollTop = Math.max(\r\n 0,\r\n Math.min((topPercent / 100) * maxScrollTop, maxScrollTop)\r\n )\r\n const targetScrollLeft = leftPercent !== undefined\r\n ? Math.max(0, Math.min((leftPercent / 100) * maxScrollLeft, maxScrollLeft))\r\n : scrollLeft.value\r\n\r\n scrollTo(targetScrollTop, targetScrollLeft)\r\n }\r\n\r\n const { dragging: isDraggingV, onMouseDown: handleVThumbMouseDown } =\r\n usePointerDrag({\r\n events: 'mouse',\r\n bind: 'document',\r\n cursor: 'grabbing',\r\n lockUserSelect: true,\r\n onStart: (e, ctx) => {\r\n e.preventDefault()\r\n e.stopPropagation()\r\n ctx.data.scrollStart = scrollTop.value\r\n if (containerRef.value) {\r\n containerRef.value.style.scrollBehavior = 'auto'\r\n }\r\n },\r\n onMove: (e, ctx) => {\r\n if (!containerRef.value) return\r\n e.preventDefault()\r\n const deltaY = e.clientY - ctx.startY\r\n const maxScroll = contentHeight.value - containerHeight.value\r\n if (maxScroll <= 0 || vTrackHeight.value <= 0) return\r\n const maxThumbMove = vTrackHeight.value - vThumbHeight.value\r\n const scrollRatio = maxThumbMove > 0 ? maxScroll / maxThumbMove : 1\r\n const newScrollTop =\r\n (ctx.data.scrollStart as number) + deltaY * scrollRatio\r\n containerRef.value.scrollTop = Math.max(\r\n 0,\r\n Math.min(newScrollTop, maxScroll),\r\n )\r\n },\r\n onEnd: () => {\r\n if (containerRef.value) {\r\n containerRef.value.style.scrollBehavior = ''\r\n }\r\n justDragged.value = true\r\n setTimeout(() => {\r\n justDragged.value = false\r\n }, 0)\r\n },\r\n })\r\n\r\n const { dragging: isDraggingH, onMouseDown: handleHThumbMouseDown } =\r\n usePointerDrag({\r\n events: 'mouse',\r\n bind: 'document',\r\n cursor: 'grabbing',\r\n lockUserSelect: true,\r\n onStart: (e, ctx) => {\r\n e.preventDefault()\r\n e.stopPropagation()\r\n ctx.data.scrollStart = scrollLeft.value\r\n if (containerRef.value) {\r\n containerRef.value.style.scrollBehavior = 'auto'\r\n }\r\n },\r\n onMove: (e, ctx) => {\r\n if (!containerRef.value) return\r\n e.preventDefault()\r\n const deltaX = e.clientX - ctx.startX\r\n const maxScroll = contentWidth.value - containerWidth.value\r\n if (maxScroll <= 0 || hTrackWidth.value <= 0) return\r\n const maxThumbMove = hTrackWidth.value - hThumbWidth.value\r\n const scrollRatio = maxThumbMove > 0 ? maxScroll / maxThumbMove : 1\r\n const newScrollLeft =\r\n (ctx.data.scrollStart as number) + deltaX * scrollRatio\r\n containerRef.value.scrollLeft = Math.max(\r\n 0,\r\n Math.min(newScrollLeft, maxScroll),\r\n )\r\n },\r\n onEnd: () => {\r\n if (containerRef.value) {\r\n containerRef.value.style.scrollBehavior = ''\r\n }\r\n justDragged.value = true\r\n setTimeout(() => {\r\n justDragged.value = false\r\n }, 0)\r\n },\r\n })\r\n\r\n // 点击垂直轨道\r\n const handleVTrackClick = (e: MouseEvent) => {\r\n if (!containerRef.value || isDraggingV.value || justDragged.value) return\r\n\r\n const trackRect = vTrackRef.value?.getBoundingClientRect()\r\n if (!trackRect) return\r\n\r\n // 计算点击位置相对于轨道顶部的位置\r\n const clickY = e.clientY - trackRect.top\r\n // 滑块中心位置\r\n const thumbCenter = vThumbTop.value + vThumbHeight.value / 2\r\n const maxScroll = contentHeight.value - containerHeight.value\r\n\r\n // 根据点击位置决定滚动方向\r\n let newScrollTop = scrollTop.value\r\n if (clickY < thumbCenter) {\r\n // 点击滑块上方,向上滚动\r\n newScrollTop = scrollTop.value - props.scrollStep\r\n } else {\r\n // 点击滑块下方,向下滚动\r\n newScrollTop = scrollTop.value + props.scrollStep\r\n }\r\n\r\n // 立即滚动,不使用平滑动画\r\n containerRef.value.scrollTop = Math.max(\r\n 0,\r\n Math.min(newScrollTop, maxScroll)\r\n )\r\n }\r\n\r\n // 点击水平轨道\r\n const handleHTrackClick = (e: MouseEvent) => {\r\n if (!containerRef.value || isDraggingH.value || justDragged.value) return\r\n\r\n const trackRect = hTrackRef.value?.getBoundingClientRect()\r\n if (!trackRect) return\r\n\r\n // 计算点击位置相对于轨道左侧的位置\r\n const clickX = e.clientX - trackRect.left\r\n // 滑块中心位置\r\n const thumbCenter = hThumbLeft.value + hThumbWidth.value / 2\r\n const maxScroll = contentWidth.value - containerWidth.value\r\n\r\n // 根据点击位置决定滚动方向\r\n let newScrollLeft = scrollLeft.value\r\n if (clickX < thumbCenter) {\r\n // 点击滑块左侧,向左滚动\r\n newScrollLeft = scrollLeft.value - props.scrollStep\r\n } else {\r\n // 点击滑块右侧,向右滚动\r\n newScrollLeft = scrollLeft.value + props.scrollStep\r\n }\r\n\r\n // 立即滚动,不使用平滑动画\r\n containerRef.value.scrollLeft = Math.max(\r\n 0,\r\n Math.min(newScrollLeft, maxScroll)\r\n )\r\n }\r\n\r\n // 触摸事件处理(移动端支持)\r\n const touchStartY = ref(0)\r\n const touchStartX = ref(0)\r\n const touchStartScrollTop = ref(0)\r\n const touchStartScrollLeft = ref(0)\r\n\r\n const handleTouchStart = (e: TouchEvent) => {\r\n const touch = e.touches[0]\r\n touchStartY.value = touch.clientY\r\n touchStartX.value = touch.clientX\r\n touchStartScrollTop.value = scrollTop.value\r\n touchStartScrollLeft.value = scrollLeft.value\r\n\r\n emit(\"scroll-start\")\r\n }\r\n\r\n const handleTouchMove = (e: TouchEvent) => {\r\n if (!containerRef.value) return\r\n\r\n const touch = e.touches[0]\r\n const deltaY = touchStartY.value - touch.clientY\r\n const deltaX = touchStartX.value - touch.clientX\r\n\r\n const maxScrollTop = contentHeight.value - containerHeight.value\r\n const maxScrollLeft = contentWidth.value - containerWidth.value\r\n\r\n const newScrollTop = touchStartScrollTop.value + deltaY\r\n const newScrollLeft = touchStartScrollLeft.value + deltaX\r\n\r\n // 使用 scrollTo,这会触发 scroll 事件,handleScroll 会更新状态\r\n scrollTo(\r\n Math.max(0, Math.min(newScrollTop, maxScrollTop)),\r\n Math.max(0, Math.min(newScrollLeft, maxScrollLeft))\r\n )\r\n }\r\n\r\n const handleTouchEnd = () => {\r\n emit(\"scroll-end\")\r\n }\r\n\r\n onMounted(() => {\r\n nextTick(() => {\r\n updateSize()\r\n\r\n // 再次延迟测量,确保轨道已渲染\r\n setTimeout(() => {\r\n updateSize()\r\n }, 100)\r\n\r\n // 需 preventDefault 才能接管离散滚轮步长,故 passive: false\r\n if (containerRef.value) {\r\n containerRef.value.addEventListener(\"wheel\", handleWheel, {\r\n passive: false,\r\n })\r\n }\r\n })\r\n })\r\n\r\n // 清理事件监听器\r\n onUnmounted(() => {\r\n if (containerRef.value) {\r\n containerRef.value.removeEventListener(\"wheel\", handleWheel)\r\n }\r\n\r\n if (wheelSmoothRestoreTimer) {\r\n clearTimeout(wheelSmoothRestoreTimer)\r\n wheelSmoothRestoreTimer = null\r\n }\r\n })\r\n\r\n // 暴露方法给父组件\r\n const exposeMethods = {\r\n scrollTo,\r\n scrollToTop,\r\n scrollToBottom,\r\n scrollToElement,\r\n scrollToPercent,\r\n updateSize,\r\n getScrollPosition: () => {\r\n const maxScrollTop = contentHeight.value - containerHeight.value\r\n const maxScrollLeft = contentWidth.value - containerWidth.value\r\n \r\n return {\r\n scrollTop: scrollTop.value,\r\n scrollLeft: scrollLeft.value,\r\n // 滚动百分比(0-100)\r\n scrollTopPercent: maxScrollTop > 0\r\n ? Math.round((scrollTop.value / maxScrollTop) * 100)\r\n : 0,\r\n scrollLeftPercent: maxScrollLeft > 0\r\n ? Math.round((scrollLeft.value / maxScrollLeft) * 100)\r\n : 0,\r\n }\r\n },\r\n }\r\n\r\n // 暴露方法\r\n expose(exposeMethods)\r\n\r\n return () => (\r\n <div\r\n class={[\r\n \"w-scrollbar\",\r\n // 将 direction 映射为 CSS class\r\n `w-scrollbar-${props.direction}`,\r\n {\r\n \"w-scrollbar-smooth\": props.smooth,\r\n },\r\n ]}\r\n style={{\r\n minHeight: toCssSize(props.minHeight),\r\n maxHeight: toCssSize(props.maxHeight),\r\n height: toCssSize(props.height),\r\n }}>\r\n {/* 滚动容器 */}\r\n <div\r\n ref={containerRef}\r\n class=\"w-scrollbar-container\"\r\n onScroll={handleScroll}\r\n onTouchstart={handleTouchStart}\r\n onTouchmove={handleTouchMove}\r\n onTouchend={handleTouchEnd}>\r\n <div ref={contentRef} class=\"w-scrollbar-content\">\r\n {slots.default?.()}\r\n </div>\r\n </div>\r\n\r\n {/* 垂直滚动条 */}\r\n {showVertical.value && (\r\n <div\r\n ref={vTrackRef}\r\n class=\"w-scrollbar-track w-scrollbar-track-y\"\r\n onClick={handleVTrackClick}>\r\n <div\r\n ref={vThumbRef}\r\n class={[\r\n \"w-scrollbar-thumb w-scrollbar-thumb-y\",\r\n { \"w-scrollbar-thumb-dragging\": isDraggingV.value },\r\n ]}\r\n style={{\r\n height: `${vThumbHeight.value}px`,\r\n top: `${vThumbTop.value}px`,\r\n }}\r\n onMousedown={handleVThumbMouseDown}\r\n onTouchstart={handleVThumbMouseDown as any}\r\n />\r\n </div>\r\n )}\r\n\r\n {/* 水平滚动条 */}\r\n {showHorizontal.value && (\r\n <div\r\n ref={hTrackRef}\r\n class=\"w-scrollbar-track w-scrollbar-track-x\"\r\n onClick={handleHTrackClick}>\r\n <div\r\n ref={hThumbRef}\r\n class={[\r\n \"w-scrollbar-thumb w-scrollbar-thumb-x\",\r\n { \"w-scrollbar-thumb-dragging\": isDraggingH.value },\r\n ]}\r\n style={{\r\n width: `${hThumbWidth.value}px`,\r\n left: `${hThumbLeft.value}px`,\r\n }}\r\n onMousedown={handleHThumbMouseDown}\r\n onTouchstart={handleHThumbMouseDown as any}\r\n />\r\n </div>\r\n )}\r\n </div>\r\n )\r\n },\r\n})\r\n"],"mappings":"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"}
|
|
@@ -1443,6 +1443,8 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
|
|
|
1443
1443
|
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
1444
1444
|
}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
1445
1445
|
}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
1446
|
-
Virtual: import('..').
|
|
1446
|
+
Virtual: new <T = any>() => import('..').VirtualListMethods & {
|
|
1447
|
+
$props: import('..').VirtualJSXProps<T>;
|
|
1448
|
+
};
|
|
1447
1449
|
}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
1448
1450
|
export default _default;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Icon_default from "../icon/Icon.js";
|
|
2
|
-
import
|
|
2
|
+
import usePointerDrag from "../../use/usePointerDrag.js";
|
|
3
|
+
import { computed, createVNode, defineComponent, inject, normalizeClass, normalizeStyle, ref } from "vue";
|
|
3
4
|
//#region components/sheet/_cell.tsx
|
|
4
5
|
var _cell_default = /* @__PURE__ */ defineComponent({
|
|
5
6
|
components: { Icon: Icon_default },
|
|
@@ -35,14 +36,6 @@ var _cell_default = /* @__PURE__ */ defineComponent({
|
|
|
35
36
|
},
|
|
36
37
|
setup(props, { slots }) {
|
|
37
38
|
const tdRoot = ref(null);
|
|
38
|
-
const start = reactive({
|
|
39
|
-
x: 0,
|
|
40
|
-
y: 0
|
|
41
|
-
});
|
|
42
|
-
const end = reactive({
|
|
43
|
-
x: 0,
|
|
44
|
-
y: 0
|
|
45
|
-
});
|
|
46
39
|
const beforeResize = inject("beforeResize");
|
|
47
40
|
const inResizing = inject("inResizing");
|
|
48
41
|
const afterResize = inject("afterResize");
|
|
@@ -74,32 +67,28 @@ var _cell_default = /* @__PURE__ */ defineComponent({
|
|
|
74
67
|
style: _s
|
|
75
68
|
};
|
|
76
69
|
});
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
70
|
+
const { onMouseDown: onResizeMouseDown } = usePointerDrag({
|
|
71
|
+
events: "mouse",
|
|
72
|
+
bind: "document",
|
|
73
|
+
onStart: (e) => {
|
|
74
|
+
beforeResize(tdRoot.value);
|
|
75
|
+
},
|
|
76
|
+
onMove: (e, ctx) => {
|
|
77
|
+
inResizing(props.colIndex, e.clientX - ctx.startX);
|
|
78
|
+
},
|
|
79
|
+
onEnd: (e, ctx) => {
|
|
80
|
+
if (e) afterResize(props.colIndex, e.clientX - ctx.startX);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
88
83
|
function toSort() {
|
|
89
84
|
updateSorter(props.col?.field);
|
|
90
85
|
}
|
|
91
|
-
onMounted(() => {});
|
|
92
86
|
return () => {
|
|
93
87
|
let line = null;
|
|
94
88
|
let sorter = null;
|
|
95
89
|
if (props.resizeWidth) line = createVNode("span", {
|
|
96
90
|
class: "w-cell-resize-line",
|
|
97
|
-
onMousedown:
|
|
98
|
-
start.x = e.clientX;
|
|
99
|
-
beforeResize(tdRoot.value);
|
|
100
|
-
document.addEventListener("mousemove", toResize);
|
|
101
|
-
document.addEventListener("mouseup", handleMouseup);
|
|
102
|
-
},
|
|
91
|
+
onMousedown: onResizeMouseDown,
|
|
103
92
|
onClick: (e) => {
|
|
104
93
|
e.preventDefault();
|
|
105
94
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_cell.js","names":["ref","computed","defineComponent","inject","
|
|
1
|
+
{"version":3,"file":"_cell.js","names":["ref","computed","defineComponent","inject","normalizeClass","normalizeStyle","createVNode","_createVNode","Icon","usePointerDrag","components","props","isInThead","Boolean","sorter","type","Number","default","undefined","tag","String","align","isNarrow","notBold","resizeWidth","colIndex","colSpan","rowSpan","col","Object","cellClass","Array","setup","slots","tdRoot","beforeResize","inResizing","afterResize","currentSorter","updateSorter","_style","width","restStyle","style","cellProps","_s","value","o","colspan","rowspan","class","onMouseDown","onResizeMouseDown","events","bind","onStart","e","onMove","ctx","clientX","startX","onEnd","toSort","field","line","lineProps","onMousedown","onClick","preventDefault","stopPropagation"],"sources":["../../../components/sheet/_cell.tsx"],"sourcesContent":["import {\r\n ref,\r\n computed,\r\n defineComponent,\r\n inject,\r\n normalizeClass,\r\n normalizeStyle,\r\n} from \"vue\"\r\nimport Icon from \"../icon/index\"\r\nimport usePointerDrag from \"../../use/usePointerDrag\"\r\nimport number from \"../number\"\r\nexport default defineComponent({\r\n components: { Icon },\r\n props: {\r\n isInThead: Boolean,\r\n\r\n sorter: { type: [Boolean, Number], default: undefined },\r\n tag: { type: String, default: \"td\" },\r\n align: { type: String }, //center\r\n isNarrow: Boolean,\r\n notBold: Boolean,\r\n resizeWidth: Boolean,\r\n colIndex: Number,\r\n colSpan: { type: Number, default: 1 },\r\n rowSpan: { type: Number, default: 1 },\r\n col: { type: Object },\r\n cellClass: { type: [Object, Array, String] },\r\n },\r\n setup(props, { slots }) {\r\n const tdRoot = ref(null)\r\n const beforeResize = inject(\"beforeResize\") as Function\r\n const inResizing = inject(\"inResizing\") as Function\r\n const afterResize = inject(\"afterResize\") as Function\r\n const currentSorter = inject(\"currentSorter\") as any\r\n const updateSorter = inject(\"updateSorter\") as Function\r\n const _style = computed(() => {\r\n if (!props.isInThead) {\r\n const { width, ...restStyle } = props.col?.style ?? {}\r\n return restStyle\r\n }\r\n })\r\n const cellProps = computed(() => {\r\n const _s = normalizeStyle(_style.value)\r\n let o: any = {\r\n ref: tdRoot,\r\n colspan: props.colSpan,\r\n rowspan: props.rowSpan,\r\n \"data-col-index\": props.colIndex,\r\n class: [\r\n \"w-cell\",\r\n {\r\n \"w-cell--center\": props.align === \"center\",\r\n \"w-cell--right\": props.align === \"right\",\r\n \"w-cell--narrow\": props.isNarrow,\r\n \"w-cell--not-bold\": props.notBold,\r\n },\r\n normalizeClass(props.cellClass),\r\n ],\r\n style: _s,\r\n }\r\n return o\r\n })\r\n\r\n const { onMouseDown: onResizeMouseDown } = usePointerDrag({\r\n events: \"mouse\",\r\n bind: \"document\",\r\n onStart: (e) => {\r\n beforeResize(tdRoot.value)\r\n },\r\n onMove: (e, ctx) => {\r\n inResizing(props.colIndex, e.clientX - ctx.startX)\r\n },\r\n onEnd: (e, ctx) => {\r\n if (e) afterResize(props.colIndex, e.clientX - ctx.startX)\r\n },\r\n })\r\n\r\n function toSort() {\r\n updateSorter(props.col?.field)\r\n }\r\n\r\n return () => {\r\n let line: any = null\r\n let sorter: any = null\r\n if (props.resizeWidth) {\r\n const lineProps = {\r\n class: \"w-cell-resize-line\",\r\n onMousedown: onResizeMouseDown,\r\n onClick: (e: MouseEvent) => {\r\n e.preventDefault()\r\n },\r\n }\r\n line = <span {...lineProps}></span>\r\n }\r\n if (props.sorter !== undefined) {\r\n sorter = (\r\n <div\r\n class=\"w-cell-sorter\"\r\n onClick={(e) => {\r\n toSort()\r\n e.preventDefault()\r\n e.stopPropagation()\r\n }}>\r\n <Icon\r\n name=\"w-icon-sort-down\"\r\n class={[\r\n \"w-cell-sorter-icon w-cell-sorter-up\",\r\n {\r\n \"w-cell-sorter--0\":\r\n currentSorter.field === props.col?.field &&\r\n currentSorter.sorter === 0,\r\n },\r\n ]}\r\n />\r\n <Icon\r\n name=\"w-icon-sort-down\"\r\n class={[\r\n \"w-cell-sorter-icon w-cell-sorter-down \",\r\n {\r\n \"w-cell-sorter--1\":\r\n currentSorter.field === props.col?.field &&\r\n currentSorter.sorter === 1,\r\n },\r\n ]}\r\n />\r\n </div>\r\n )\r\n }\r\n\r\n return (\r\n <props.tag {...cellProps.value}>\r\n {slots.default?.()}\r\n {line}\r\n {sorter}\r\n </props.tag>\r\n )\r\n }\r\n },\r\n})\r\n"],"mappings":"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"}
|