stickyScrollBar.js 7.6 KB

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