stickyScrollBar.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.default = void 0;
  7. var _vue = require("vue");
  8. var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
  9. var _addEventListener = _interopRequireDefault(require("../vc-util/Dom/addEventListener"));
  10. var _css = require("../vc-util/Dom/css");
  11. var _classNames = _interopRequireDefault(require("../_util/classNames"));
  12. var _getScrollBarSize = _interopRequireDefault(require("../_util/getScrollBarSize"));
  13. var _TableContext = require("./context/TableContext");
  14. var _useFrame = require("./hooks/useFrame");
  15. var _default = exports.default = (0, _vue.defineComponent)({
  16. name: 'StickyScrollBar',
  17. inheritAttrs: false,
  18. props: ['offsetScroll', 'container', 'scrollBodyRef', 'scrollBodySizeInfo'],
  19. emits: ['scroll'],
  20. setup(props, _ref) {
  21. let {
  22. emit,
  23. expose
  24. } = _ref;
  25. const tableContext = (0, _TableContext.useInjectTable)();
  26. const bodyScrollWidth = (0, _vue.shallowRef)(0);
  27. const bodyWidth = (0, _vue.shallowRef)(0);
  28. const scrollBarWidth = (0, _vue.shallowRef)(0);
  29. (0, _vue.watchEffect)(() => {
  30. bodyScrollWidth.value = props.scrollBodySizeInfo.scrollWidth || 0;
  31. bodyWidth.value = props.scrollBodySizeInfo.clientWidth || 0;
  32. scrollBarWidth.value = bodyScrollWidth.value && bodyWidth.value * (bodyWidth.value / bodyScrollWidth.value);
  33. }, {
  34. flush: 'post'
  35. });
  36. const scrollBarRef = (0, _vue.shallowRef)();
  37. const [scrollState, setScrollState] = (0, _useFrame.useLayoutState)({
  38. scrollLeft: 0,
  39. isHiddenScrollBar: true
  40. });
  41. const refState = (0, _vue.ref)({
  42. delta: 0,
  43. x: 0
  44. });
  45. const isActive = (0, _vue.shallowRef)(false);
  46. const onMouseUp = () => {
  47. isActive.value = false;
  48. };
  49. const onMouseDown = event => {
  50. refState.value = {
  51. delta: event.pageX - scrollState.value.scrollLeft,
  52. x: 0
  53. };
  54. isActive.value = true;
  55. event.preventDefault();
  56. };
  57. const onMouseMove = event => {
  58. // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons
  59. const {
  60. buttons
  61. } = event || (window === null || window === void 0 ? void 0 : window.event);
  62. if (!isActive.value || buttons === 0) {
  63. // If out body mouse up, we can set isActive false when mouse move
  64. if (isActive.value) {
  65. isActive.value = false;
  66. }
  67. return;
  68. }
  69. let left = refState.value.x + event.pageX - refState.value.x - refState.value.delta;
  70. if (left <= 0) {
  71. left = 0;
  72. }
  73. if (left + scrollBarWidth.value >= bodyWidth.value) {
  74. left = bodyWidth.value - scrollBarWidth.value;
  75. }
  76. emit('scroll', {
  77. scrollLeft: left / bodyWidth.value * (bodyScrollWidth.value + 2)
  78. });
  79. refState.value.x = event.pageX;
  80. };
  81. const onContainerScroll = () => {
  82. if (!props.scrollBodyRef.value) {
  83. return;
  84. }
  85. const tableOffsetTop = (0, _css.getOffset)(props.scrollBodyRef.value).top;
  86. const tableBottomOffset = tableOffsetTop + props.scrollBodyRef.value.offsetHeight;
  87. const currentClientOffset = props.container === window ? document.documentElement.scrollTop + window.innerHeight : (0, _css.getOffset)(props.container).top + props.container.clientHeight;
  88. if (tableBottomOffset - (0, _getScrollBarSize.default)() <= currentClientOffset || tableOffsetTop >= currentClientOffset - props.offsetScroll) {
  89. setScrollState(state => (0, _extends2.default)((0, _extends2.default)({}, state), {
  90. isHiddenScrollBar: true
  91. }));
  92. } else {
  93. setScrollState(state => (0, _extends2.default)((0, _extends2.default)({}, state), {
  94. isHiddenScrollBar: false
  95. }));
  96. }
  97. };
  98. const setScrollLeft = left => {
  99. setScrollState(state => {
  100. return (0, _extends2.default)((0, _extends2.default)({}, state), {
  101. scrollLeft: left / bodyScrollWidth.value * bodyWidth.value || 0
  102. });
  103. });
  104. };
  105. expose({
  106. setScrollLeft
  107. });
  108. let onMouseUpListener = null;
  109. let onMouseMoveListener = null;
  110. let onResizeListener = null;
  111. let onScrollListener = null;
  112. (0, _vue.onMounted)(() => {
  113. onMouseUpListener = (0, _addEventListener.default)(document.body, 'mouseup', onMouseUp, false);
  114. onMouseMoveListener = (0, _addEventListener.default)(document.body, 'mousemove', onMouseMove, false);
  115. onResizeListener = (0, _addEventListener.default)(window, 'resize', onContainerScroll, false);
  116. });
  117. (0, _vue.onActivated)(() => {
  118. (0, _vue.nextTick)(() => {
  119. onContainerScroll();
  120. });
  121. });
  122. (0, _vue.onMounted)(() => {
  123. setTimeout(() => {
  124. (0, _vue.watch)([scrollBarWidth, isActive], () => {
  125. onContainerScroll();
  126. }, {
  127. immediate: true,
  128. flush: 'post'
  129. });
  130. });
  131. });
  132. (0, _vue.watch)(() => props.container, () => {
  133. onScrollListener === null || onScrollListener === void 0 ? void 0 : onScrollListener.remove();
  134. onScrollListener = (0, _addEventListener.default)(props.container, 'scroll', onContainerScroll, false);
  135. }, {
  136. immediate: true,
  137. flush: 'post'
  138. });
  139. (0, _vue.onBeforeUnmount)(() => {
  140. onMouseUpListener === null || onMouseUpListener === void 0 ? void 0 : onMouseUpListener.remove();
  141. onMouseMoveListener === null || onMouseMoveListener === void 0 ? void 0 : onMouseMoveListener.remove();
  142. onScrollListener === null || onScrollListener === void 0 ? void 0 : onScrollListener.remove();
  143. onResizeListener === null || onResizeListener === void 0 ? void 0 : onResizeListener.remove();
  144. });
  145. (0, _vue.watch)(() => (0, _extends2.default)({}, scrollState.value), (newState, preState) => {
  146. if (newState.isHiddenScrollBar !== (preState === null || preState === void 0 ? void 0 : preState.isHiddenScrollBar) && !newState.isHiddenScrollBar) {
  147. setScrollState(state => {
  148. const bodyNode = props.scrollBodyRef.value;
  149. if (!bodyNode) {
  150. return state;
  151. }
  152. return (0, _extends2.default)((0, _extends2.default)({}, state), {
  153. scrollLeft: bodyNode.scrollLeft / bodyNode.scrollWidth * bodyNode.clientWidth
  154. });
  155. });
  156. }
  157. }, {
  158. immediate: true
  159. });
  160. const scrollbarSize = (0, _getScrollBarSize.default)();
  161. return () => {
  162. if (bodyScrollWidth.value <= bodyWidth.value || !scrollBarWidth.value || scrollState.value.isHiddenScrollBar) {
  163. return null;
  164. }
  165. const {
  166. prefixCls
  167. } = tableContext;
  168. return (0, _vue.createVNode)("div", {
  169. "style": {
  170. height: `${scrollbarSize}px`,
  171. width: `${bodyWidth.value}px`,
  172. bottom: `${props.offsetScroll}px`
  173. },
  174. "class": `${prefixCls}-sticky-scroll`
  175. }, [(0, _vue.createVNode)("div", {
  176. "onMousedown": onMouseDown,
  177. "ref": scrollBarRef,
  178. "class": (0, _classNames.default)(`${prefixCls}-sticky-scroll-bar`, {
  179. [`${prefixCls}-sticky-scroll-bar-active`]: isActive.value
  180. }),
  181. "style": {
  182. width: `${scrollBarWidth.value}px`,
  183. transform: `translate3d(${scrollState.value.scrollLeft}px, 0, 0)`
  184. }
  185. }, null)]);
  186. };
  187. }
  188. });