useTarget.js 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.default = useTarget;
  7. var _vue = require("vue");
  8. var _util = require("../util");
  9. var _useState = _interopRequireDefault(require("../../_util/hooks/useState"));
  10. function useTarget(target, open, gap, scrollIntoViewOptions) {
  11. // ========================= Target =========================
  12. // We trade `undefined` as not get target by function yet.
  13. // `null` as empty target.
  14. const [targetElement, setTargetElement] = (0, _useState.default)(undefined);
  15. (0, _vue.watchEffect)(() => {
  16. const nextElement = typeof target.value === 'function' ? target.value() : target.value;
  17. setTargetElement(nextElement || null);
  18. }, {
  19. flush: 'post'
  20. });
  21. // ========================= Align ==========================
  22. const [posInfo, setPosInfo] = (0, _useState.default)(null);
  23. const updatePos = () => {
  24. if (!open.value) {
  25. setPosInfo(null);
  26. return;
  27. }
  28. if (targetElement.value) {
  29. // Exist target element. We should scroll and get target position
  30. if (!(0, _util.isInViewPort)(targetElement.value) && open.value) {
  31. targetElement.value.scrollIntoView(scrollIntoViewOptions.value);
  32. }
  33. const {
  34. left,
  35. top,
  36. width,
  37. height
  38. } = targetElement.value.getBoundingClientRect();
  39. const nextPosInfo = {
  40. left,
  41. top,
  42. width,
  43. height,
  44. radius: 0
  45. };
  46. if (JSON.stringify(posInfo.value) !== JSON.stringify(nextPosInfo)) {
  47. setPosInfo(nextPosInfo);
  48. }
  49. } else {
  50. // Not exist target which means we just show in center
  51. setPosInfo(null);
  52. }
  53. };
  54. (0, _vue.onMounted)(() => {
  55. (0, _vue.watch)([open, targetElement], () => {
  56. updatePos();
  57. }, {
  58. flush: 'post',
  59. immediate: true
  60. });
  61. // update when window resize
  62. window.addEventListener('resize', updatePos);
  63. });
  64. (0, _vue.onBeforeUnmount)(() => {
  65. window.removeEventListener('resize', updatePos);
  66. });
  67. // ======================== PosInfo =========================
  68. const mergedPosInfo = (0, _vue.computed)(() => {
  69. var _a, _b;
  70. if (!posInfo.value) {
  71. return posInfo.value;
  72. }
  73. const gapOffset = ((_a = gap.value) === null || _a === void 0 ? void 0 : _a.offset) || 6;
  74. const gapRadius = ((_b = gap.value) === null || _b === void 0 ? void 0 : _b.radius) || 2;
  75. return {
  76. left: posInfo.value.left - gapOffset,
  77. top: posInfo.value.top - gapOffset,
  78. width: posInfo.value.width + gapOffset * 2,
  79. height: posInfo.value.height + gapOffset * 2,
  80. radius: gapRadius
  81. };
  82. });
  83. return [mergedPosInfo, targetElement];
  84. }