UNPKG

ivue-material-plus

Version:

A high quality UI components Library with Vue.js

1 lines 13.2 kB
{"version":3,"file":"thumb.mjs","sources":["../../../../../src/components/ivue-scrollbar/thumb.vue"],"sourcesContent":["<template>\r\n <transition :name=\"`${prefixCls}-fade`\">\r\n <!-- v-show=\"always || visible\" -->\r\n <div\r\n :class=\"wrapperClasses\"\r\n @mousedown=\"handleThumbWrapperMousedown\"\r\n ref=\"thumbWrapper\"\r\n v-show=\"always || data.visible\"\r\n >\r\n <div\r\n :class=\"`${prefixCls}-thumb`\"\r\n :style=\"thumbStyles\"\r\n @mousedown=\"handleThumbMousedown\"\r\n ref=\"thumb\"\r\n ></div>\r\n </div>\r\n </transition>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport {\r\n computed,\r\n defineComponent,\r\n ref,\r\n reactive,\r\n inject,\r\n onBeforeUnmount,\r\n onMounted,\r\n} from 'vue';\r\nimport { useEventListener } from '@vueuse/core';\r\n\r\nimport { on, off } from '../../utils/dom';\r\n\r\n// type\r\nimport { ScrollbarContextKey, ScrollbarContext } from './types/scrollbar';\r\nimport type { Props, Data } from './types/thumb';\r\n\r\nconst prefixCls = 'ivue-scrollbar';\r\n\r\n// 鼠标按下\r\nlet mousedown = false;\r\n// 鼠标离开\r\nlet mouseLeave = false;\r\n\r\n// 开始选择任意文本内容时触发\r\nlet originalOnSelectStart = document.onselectstart;\r\n\r\nexport default defineComponent({\r\n name: 'ivue-scrollbar-thumb',\r\n props: {\r\n /**\r\n * 偏移位置\r\n *\r\n * @type {Number}\r\n */\r\n move: {\r\n type: Number,\r\n },\r\n /**\r\n * 轴滚动比率\r\n *\r\n * @type {Number}\r\n */\r\n ratio: {\r\n type: Number,\r\n default: 1,\r\n },\r\n /**\r\n * 滚动条总是显示\r\n *\r\n * @type {Boolean}\r\n */\r\n always: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n /**\r\n * 滚动条大小\r\n *\r\n * @type {String}\r\n */\r\n barSize: {\r\n type: String,\r\n default: '',\r\n },\r\n /**\r\n * 方向\r\n *\r\n * @type {Boolean}\r\n */\r\n vertical: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n },\r\n setup(props: Props) {\r\n // IvueScrollbar\r\n const IvueScrollbar = inject(ScrollbarContextKey) as ScrollbarContext;\r\n\r\n // dom\r\n const thumbWrapper = ref<HTMLDivElement>();\r\n const thumb = ref<HTMLDivElement>();\r\n\r\n // data\r\n const data = reactive<Data>({\r\n /**\r\n * 状态\r\n *\r\n * @type {Object}\r\n */\r\n thumbState: {},\r\n /**\r\n * 显示\r\n *\r\n * @type {Boolean}\r\n */\r\n visible: false,\r\n });\r\n\r\n // wrapperClasses\r\n const wrapperClasses = computed(() => {\r\n return [\r\n `${prefixCls}-bar`,\r\n props.vertical ? 'is-vertical' : 'is-horizontal',\r\n ];\r\n });\r\n\r\n // 滑动块样式\r\n const thumbStyles = computed(() => {\r\n let obj = {};\r\n\r\n // 垂直\r\n if (props.vertical) {\r\n obj = {\r\n height: props.barSize,\r\n transform: `translateY(${props.move}%)`,\r\n };\r\n }\r\n // 横向\r\n else {\r\n obj = {\r\n width: props.barSize,\r\n transform: `translateX(${props.move}%)`,\r\n };\r\n }\r\n\r\n return obj;\r\n });\r\n\r\n // 偏移比率\r\n const offsetRatio = computed(() => {\r\n // thumbWrapper height = scrollbarWrapper height - 4\r\n\r\n // 垂直\r\n // offsetRatioY = 滚动条的原始高度 / 表格滚动高度 / ratioY / 滚动块高度\r\n if (props.vertical) {\r\n return (\r\n thumbWrapper.value.offsetHeight ** 2 /\r\n IvueScrollbar.scrollbarWrapper.scrollHeight /\r\n props.ratio /\r\n thumb.value.offsetHeight\r\n );\r\n }\r\n\r\n // 横向\r\n // offsetRatioX = 滚动条的原始宽度 / 表格滚动宽度 / ratioX / 滚动块宽度\r\n if (!props.vertical) {\r\n return (\r\n thumbWrapper.value.offsetWidth ** 2 /\r\n IvueScrollbar.scrollbarWrapper.scrollWidth /\r\n props.ratio /\r\n thumb.value.offsetWidth\r\n );\r\n }\r\n\r\n return null;\r\n });\r\n\r\n // methods\r\n\r\n // 滑动块拖动\r\n const handleThumbMousedown = (event: MouseEvent) => {\r\n event.stopPropagation();\r\n\r\n // 防止中键和右键的点击事件;\r\n if (event.ctrlKey || [1, 2].includes(event.button)) {\r\n return;\r\n }\r\n\r\n // 取消所有选择\r\n window.getSelection()?.removeAllRanges();\r\n\r\n // 阻止监听同一事件的其他事件监听器被调用\r\n event.stopImmediatePropagation();\r\n\r\n // 鼠标按下\r\n mousedown = true;\r\n\r\n // 鼠标移动\r\n on(document, 'mousemove', handleMousemove);\r\n\r\n // 鼠标按下\r\n on(document, 'mouseup', handleMouseup);\r\n\r\n // 开始选择任意文本内容时触发\r\n originalOnSelectStart = document.onselectstart;\r\n\r\n // 禁止选中\r\n document.onselectstart = () => false;\r\n\r\n // 当前目标\r\n const target = event.currentTarget as HTMLDivElement;\r\n\r\n if (!target) {\r\n return;\r\n }\r\n\r\n // 垂直\r\n if (props.vertical) {\r\n // 可偏移高度\r\n data.thumbState['Y'] =\r\n target.offsetHeight -\r\n (event.clientY - target.getBoundingClientRect().top);\r\n }\r\n\r\n // 横向\r\n if (!props.vertical) {\r\n // 可偏移宽度\r\n data.thumbState['X'] =\r\n target.offsetWidth -\r\n (event.clientX - target.getBoundingClientRect().left);\r\n }\r\n };\r\n\r\n // 鼠标移动\r\n const handleMousemove = (event: MouseEvent) => {\r\n // 是否有dom\r\n if (!thumbWrapper.value || !thumb.value) {\r\n return;\r\n }\r\n\r\n // 鼠标按下\r\n if (mousedown === false) {\r\n return;\r\n }\r\n\r\n // 点击时的偏移位置\r\n let clickOffset = 0;\r\n\r\n // 拖动时的偏移位置\r\n let moveOffset = 0;\r\n\r\n // 点击位置\r\n let clickPosition = 0;\r\n\r\n // 垂直\r\n if (props.vertical) {\r\n // 是否可以偏移\r\n clickOffset = data.thumbState['Y'];\r\n\r\n if (!clickOffset) {\r\n return;\r\n }\r\n\r\n // 拖动时的偏移位置\r\n moveOffset =\r\n (thumbWrapper.value.getBoundingClientRect().top - event.clientY) * -1;\r\n\r\n // 在滚动条点击的位置\r\n clickPosition = thumb.value.offsetHeight - clickOffset;\r\n\r\n // 点击位置的百分比\r\n const clickPositionPercentage =\r\n // 拖动时的偏移位置 - 点击时的偏移位置 * 100 * 偏移比率\r\n ((moveOffset - clickPosition) * 100 * offsetRatio.value) /\r\n thumbWrapper.value.offsetHeight;\r\n\r\n // 设置滚动高度\r\n IvueScrollbar.scrollbarWrapper.scrollTop =\r\n (clickPositionPercentage *\r\n IvueScrollbar.scrollbarWrapper.scrollHeight) /\r\n 100;\r\n }\r\n\r\n // 横向\r\n if (!props.vertical) {\r\n // 是否可以偏移\r\n clickOffset = data.thumbState['X'];\r\n\r\n if (!clickOffset) {\r\n return;\r\n }\r\n\r\n // 拖动时的偏移位置\r\n moveOffset =\r\n (thumbWrapper.value.getBoundingClientRect().left - event.clientX) *\r\n -1;\r\n\r\n // 在滚动条点击的位置\r\n clickPosition = thumb.value.offsetWidth - clickOffset;\r\n\r\n // 点击位置的百分比\r\n const clickPositionPercentage =\r\n ((moveOffset - clickPosition) * 100 * offsetRatio.value) /\r\n thumbWrapper.value.offsetWidth;\r\n\r\n // 设置滚动宽度\r\n IvueScrollbar.scrollbarWrapper.scrollLeft =\r\n (clickPositionPercentage *\r\n IvueScrollbar.scrollbarWrapper.scrollWidth) /\r\n 100;\r\n }\r\n };\r\n\r\n // 鼠标按下\r\n const handleMouseup = () => {\r\n mousedown = false;\r\n\r\n // 垂直\r\n if (props.vertical) {\r\n data.thumbState['Y'] = 0;\r\n }\r\n\r\n // 横向\r\n if (!props.vertical) {\r\n data.thumbState['X'] = 0;\r\n }\r\n\r\n // 鼠标移动\r\n off(document, 'mousemove', handleMousemove);\r\n\r\n // 鼠标按下\r\n off(document, 'mouseup', handleMouseup);\r\n\r\n // 恢复选择任意文本内容时触发\r\n handleRestoreSelectStart();\r\n\r\n // 鼠标离开\r\n if (mouseLeave) {\r\n data.visible = false;\r\n }\r\n };\r\n\r\n // 恢复选择\r\n const handleRestoreSelectStart = () => {\r\n if (document.onselectstart !== originalOnSelectStart) {\r\n document.onselectstart = originalOnSelectStart;\r\n }\r\n };\r\n\r\n // 滚动条点击\r\n const handleThumbWrapperMousedown = (event: MouseEvent) => {\r\n if (\r\n !thumb.value ||\r\n !thumbWrapper.value ||\r\n !IvueScrollbar.scrollbarWrapper\r\n ) {\r\n return;\r\n }\r\n\r\n // 视口到鼠标点击的位置\r\n let offset = 0;\r\n // 滚动块的一半\r\n let thumbHalf = 0;\r\n\r\n // 元素的大小及其相对于视口的位置。\r\n const boundingClientRect = (\r\n event.target as HTMLElement\r\n ).getBoundingClientRect();\r\n\r\n // 滚动块的位置\r\n let thumbPositionPercentage = 0;\r\n\r\n // 垂直\r\n if (props.vertical) {\r\n // 视口到鼠标点击的位置\r\n offset = Math.abs(boundingClientRect.top - event.clientY);\r\n\r\n thumbHalf = thumb.value.offsetHeight / 2;\r\n\r\n thumbPositionPercentage =\r\n ((offset - thumbHalf) * 100 * offsetRatio.value) /\r\n thumbWrapper.value.offsetHeight;\r\n\r\n IvueScrollbar.scrollbarWrapper.scrollTop =\r\n (thumbPositionPercentage *\r\n IvueScrollbar.scrollbarWrapper.scrollHeight) /\r\n 100;\r\n }\r\n\r\n // 横向\r\n if (!props.vertical) {\r\n // 视口到鼠标点击的位置\r\n offset = Math.abs(boundingClientRect.left - event.clientX);\r\n\r\n thumbHalf = thumb.value.offsetWidth / 2;\r\n\r\n thumbPositionPercentage =\r\n ((offset - thumbHalf) * 100 * offsetRatio.value) /\r\n thumbWrapper.value.offsetWidth;\r\n\r\n IvueScrollbar.scrollbarWrapper.scrollLeft =\r\n (thumbPositionPercentage *\r\n IvueScrollbar.scrollbarWrapper.scrollWidth) /\r\n 100;\r\n }\r\n };\r\n\r\n // 鼠标移动到表格\r\n const handleMousemoveTable = () => {\r\n mouseLeave = false;\r\n\r\n data.visible = !!props.barSize;\r\n };\r\n\r\n // 鼠标移出到表格\r\n const handleMouseleaveTable = () => {\r\n mouseLeave = true;\r\n\r\n data.visible = mousedown;\r\n };\r\n\r\n // onBeforeUnmount\r\n onBeforeUnmount(() => {\r\n handleRestoreSelectStart();\r\n\r\n // 鼠标移动\r\n off(document, 'mousemove', handleMousemove);\r\n\r\n // 鼠标按下\r\n off(document, 'mouseup', handleMouseup);\r\n });\r\n\r\n // onMounted\r\n onMounted(() => {\r\n // mousemove\r\n useEventListener(\r\n IvueScrollbar.scrollbar,\r\n 'mousemove',\r\n handleMousemoveTable\r\n );\r\n\r\n // mouseleave\r\n useEventListener(\r\n IvueScrollbar.scrollbar,\r\n 'mouseleave',\r\n handleMouseleaveTable\r\n );\r\n });\r\n\r\n return {\r\n prefixCls,\r\n // dom\r\n thumbWrapper,\r\n thumb,\r\n\r\n // data\r\n data,\r\n\r\n // computed\r\n wrapperClasses,\r\n thumbStyles,\r\n\r\n // methods\r\n handleThumbMousedown,\r\n handleThumbWrapperMousedown,\r\n };\r\n },\r\n});\r\n</script>\r\n"],"names":["_openBlock","_createBlock","_Transition","_withCtx","_withDirectives","_createElementVNode","_normalizeClass","_normalizeStyle"],"mappings":";;;;AACmB,SAAA,YAAK,IAAS,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,OAAA,QAAA,EAAA;EAA/B,OAAAA,SAAA,EAea,EAAAC,WAAA,CAAAC,UAAA,EAAA;AAAA,IAAA,IAAA,EAAA,GAAA,IAAA,CAAA,SAAA,CAAA,KAAA,CAAA;AAAA;;IAZH,OAAA,EAAAC,QAAA,MAAA;AAAA,MACIC,cAAA,CAAAC,mBAAA,KAAA,EAAA;AAAA,QACV,KAAA,EAAIC,cAAc,CAAA,IAAA,CAAA,cAAA,CAAA;AAAA,QAAA,WAAA,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,KAAA,IAAA,CAAA,2BAAA,IAAA,IAAA,CAAA,2BAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,QAGlB,GAAA,EAAA,cAAA;AAAA,OAAA,EAAA;AAAA,2BAEQ,KAAE,EAAA;AAAA,UACP,KAAS,EAAAA,cAAA,CAAA,CAAA,EAAA,IAAA,CAAA,SAAA,CAAA,MAAA,CAAA,CAAA;AAAA,UACV,KAAA,EAAIC,cAAO,CAAA,IAAA,CAAA,WAAA,CAAA;AAAA,UAAA,WAAA,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,KAAA,IAAA,CAAA,oBAAA,IAAA,IAAA,CAAA,oBAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA;iBANL,EAAsB,CAAA;AAAA,OAAA,EAAA,EAAA,CAAA,EAAA;AAAA;;;;;;;;;;"}