Anchor.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.default = exports.anchorProps = void 0;
  7. var _vue = require("vue");
  8. var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
  9. var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
  10. var _classNames3 = _interopRequireDefault(require("../_util/classNames"));
  11. var _addEventListener = _interopRequireDefault(require("../vc-util/Dom/addEventListener"));
  12. var _affix = _interopRequireDefault(require("../affix"));
  13. var _scrollTo = _interopRequireDefault(require("../_util/scrollTo"));
  14. var _getScroll = _interopRequireDefault(require("../_util/getScroll"));
  15. var _useConfigInject2 = _interopRequireDefault(require("../_util/hooks/useConfigInject"));
  16. var _context = _interopRequireDefault(require("./context"));
  17. function getDefaultContainer() {
  18. return window;
  19. }
  20. function getOffsetTop(element, container) {
  21. if (!element.getClientRects().length) {
  22. return 0;
  23. }
  24. var rect = element.getBoundingClientRect();
  25. if (rect.width || rect.height) {
  26. if (container === window) {
  27. container = element.ownerDocument.documentElement;
  28. return rect.top - container.clientTop;
  29. }
  30. return rect.top - container.getBoundingClientRect().top;
  31. }
  32. return rect.top;
  33. }
  34. var sharpMatcherRegx = /#([\S ]+)$/;
  35. var anchorProps = function anchorProps() {
  36. return {
  37. prefixCls: String,
  38. offsetTop: Number,
  39. bounds: Number,
  40. affix: {
  41. type: Boolean,
  42. default: true
  43. },
  44. showInkInFixed: {
  45. type: Boolean,
  46. default: false
  47. },
  48. getContainer: Function,
  49. wrapperClass: String,
  50. wrapperStyle: {
  51. type: Object,
  52. default: undefined
  53. },
  54. getCurrentAnchor: Function,
  55. targetOffset: Number,
  56. onChange: Function,
  57. onClick: Function
  58. };
  59. };
  60. exports.anchorProps = anchorProps;
  61. var _default2 = (0, _vue.defineComponent)({
  62. compatConfig: {
  63. MODE: 3
  64. },
  65. name: 'AAnchor',
  66. inheritAttrs: false,
  67. props: anchorProps(),
  68. setup: function setup(props, _ref) {
  69. var emit = _ref.emit,
  70. attrs = _ref.attrs,
  71. slots = _ref.slots,
  72. expose = _ref.expose;
  73. var _useConfigInject = (0, _useConfigInject2.default)('anchor', props),
  74. prefixCls = _useConfigInject.prefixCls,
  75. getTargetContainer = _useConfigInject.getTargetContainer,
  76. direction = _useConfigInject.direction;
  77. var inkNodeRef = (0, _vue.ref)();
  78. var anchorRef = (0, _vue.ref)();
  79. var state = (0, _vue.reactive)({
  80. links: [],
  81. scrollContainer: null,
  82. scrollEvent: null,
  83. animating: false
  84. });
  85. var activeLink = (0, _vue.ref)(null);
  86. var getContainer = (0, _vue.computed)(function () {
  87. var getContainer = props.getContainer;
  88. return getContainer || getTargetContainer.value || getDefaultContainer;
  89. });
  90. // func...
  91. var getCurrentAnchor = function getCurrentAnchor() {
  92. var offsetTop = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
  93. var bounds = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 5;
  94. var linkSections = [];
  95. var container = getContainer.value();
  96. state.links.forEach(function (link) {
  97. var sharpLinkMatch = sharpMatcherRegx.exec(link.toString());
  98. if (!sharpLinkMatch) {
  99. return;
  100. }
  101. var target = document.getElementById(sharpLinkMatch[1]);
  102. if (target) {
  103. var top = getOffsetTop(target, container);
  104. if (top < offsetTop + bounds) {
  105. linkSections.push({
  106. link: link,
  107. top: top
  108. });
  109. }
  110. }
  111. });
  112. if (linkSections.length) {
  113. var maxSection = linkSections.reduce(function (prev, curr) {
  114. return curr.top > prev.top ? curr : prev;
  115. });
  116. return maxSection.link;
  117. }
  118. return '';
  119. };
  120. var setCurrentActiveLink = function setCurrentActiveLink(link) {
  121. var getCurrentAnchor = props.getCurrentAnchor;
  122. if (activeLink.value === link) {
  123. return;
  124. }
  125. activeLink.value = typeof getCurrentAnchor === 'function' ? getCurrentAnchor() : link;
  126. emit('change', link);
  127. };
  128. var handleScrollTo = function handleScrollTo(link) {
  129. var offsetTop = props.offsetTop,
  130. targetOffset = props.targetOffset;
  131. setCurrentActiveLink(link);
  132. var container = getContainer.value();
  133. var scrollTop = (0, _getScroll.default)(container, true);
  134. var sharpLinkMatch = sharpMatcherRegx.exec(link);
  135. if (!sharpLinkMatch) {
  136. return;
  137. }
  138. var targetElement = document.getElementById(sharpLinkMatch[1]);
  139. if (!targetElement) {
  140. return;
  141. }
  142. var eleOffsetTop = getOffsetTop(targetElement, container);
  143. var y = scrollTop + eleOffsetTop;
  144. y -= targetOffset !== undefined ? targetOffset : offsetTop || 0;
  145. state.animating = true;
  146. (0, _scrollTo.default)(y, {
  147. callback: function callback() {
  148. state.animating = false;
  149. },
  150. getContainer: getContainer.value
  151. });
  152. };
  153. expose({
  154. scrollTo: handleScrollTo
  155. });
  156. var handleScroll = function handleScroll() {
  157. if (state.animating) {
  158. return;
  159. }
  160. var offsetTop = props.offsetTop,
  161. bounds = props.bounds,
  162. targetOffset = props.targetOffset;
  163. var currentActiveLink = getCurrentAnchor(targetOffset !== undefined ? targetOffset : offsetTop || 0, bounds);
  164. setCurrentActiveLink(currentActiveLink);
  165. };
  166. var updateInk = function updateInk() {
  167. var linkNode = anchorRef.value.getElementsByClassName("".concat(prefixCls.value, "-link-title-active"))[0];
  168. if (linkNode) {
  169. inkNodeRef.value.style.top = "".concat(linkNode.offsetTop + linkNode.clientHeight / 2 - 4.5, "px");
  170. }
  171. };
  172. (0, _context.default)({
  173. registerLink: function registerLink(link) {
  174. if (!state.links.includes(link)) {
  175. state.links.push(link);
  176. }
  177. },
  178. unregisterLink: function unregisterLink(link) {
  179. var index = state.links.indexOf(link);
  180. if (index !== -1) {
  181. state.links.splice(index, 1);
  182. }
  183. },
  184. activeLink: activeLink,
  185. scrollTo: handleScrollTo,
  186. handleClick: function handleClick(e, info) {
  187. emit('click', e, info);
  188. }
  189. });
  190. (0, _vue.onMounted)(function () {
  191. (0, _vue.nextTick)(function () {
  192. var container = getContainer.value();
  193. state.scrollContainer = container;
  194. state.scrollEvent = (0, _addEventListener.default)(state.scrollContainer, 'scroll', handleScroll);
  195. handleScroll();
  196. });
  197. });
  198. (0, _vue.onBeforeUnmount)(function () {
  199. if (state.scrollEvent) {
  200. state.scrollEvent.remove();
  201. }
  202. });
  203. (0, _vue.onUpdated)(function () {
  204. if (state.scrollEvent) {
  205. var currentContainer = getContainer.value();
  206. if (state.scrollContainer !== currentContainer) {
  207. state.scrollContainer = currentContainer;
  208. state.scrollEvent.remove();
  209. state.scrollEvent = (0, _addEventListener.default)(state.scrollContainer, 'scroll', handleScroll);
  210. handleScroll();
  211. }
  212. }
  213. updateInk();
  214. });
  215. return function () {
  216. var _slots$default;
  217. var offsetTop = props.offsetTop,
  218. affix = props.affix,
  219. showInkInFixed = props.showInkInFixed;
  220. var pre = prefixCls.value;
  221. var inkClass = (0, _classNames3.default)("".concat(pre, "-ink-ball"), {
  222. visible: activeLink.value
  223. });
  224. var wrapperClass = (0, _classNames3.default)(props.wrapperClass, "".concat(pre, "-wrapper"), (0, _defineProperty2.default)({}, "".concat(pre, "-rtl"), direction.value === 'rtl'));
  225. var anchorClass = (0, _classNames3.default)(pre, (0, _defineProperty2.default)({}, "".concat(pre, "-fixed"), !affix && !showInkInFixed));
  226. var wrapperStyle = (0, _objectSpread2.default)({
  227. maxHeight: offsetTop ? "calc(100vh - ".concat(offsetTop, "px)") : '100vh'
  228. }, props.wrapperStyle);
  229. var anchorContent = (0, _vue.createVNode)("div", {
  230. "class": wrapperClass,
  231. "style": wrapperStyle,
  232. "ref": anchorRef
  233. }, [(0, _vue.createVNode)("div", {
  234. "class": anchorClass
  235. }, [(0, _vue.createVNode)("div", {
  236. "class": "".concat(pre, "-ink")
  237. }, [(0, _vue.createVNode)("span", {
  238. "class": inkClass,
  239. "ref": inkNodeRef
  240. }, null)]), (_slots$default = slots.default) === null || _slots$default === void 0 ? void 0 : _slots$default.call(slots)])]);
  241. return !affix ? anchorContent : (0, _vue.createVNode)(_affix.default, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, attrs), {}, {
  242. "offsetTop": offsetTop,
  243. "target": getContainer.value
  244. }), {
  245. default: function _default() {
  246. return [anchorContent];
  247. }
  248. });
  249. };
  250. }
  251. });
  252. exports.default = _default2;