Align.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import _extends from 'babel-runtime/helpers/extends';
  2. import _typeof from 'babel-runtime/helpers/typeof';
  3. import PropTypes from '../_util/vue-types';
  4. import { alignElement, alignPoint } from 'dom-align';
  5. import addEventListener from '../vc-util/Dom/addEventListener';
  6. import { isWindow, buffer, isSamePoint, isSimilarValue, restoreFocus } from './util';
  7. import { cloneElement } from '../_util/vnode.js';
  8. import clonedeep from 'lodash/cloneDeep';
  9. import { getSlot, getListeners } from '../_util/props-util';
  10. function getElement(func) {
  11. if (typeof func !== 'function' || !func) return null;
  12. return func();
  13. }
  14. function getPoint(point) {
  15. if ((typeof point === 'undefined' ? 'undefined' : _typeof(point)) !== 'object' || !point) return null;
  16. return point;
  17. }
  18. export default {
  19. props: {
  20. childrenProps: PropTypes.object,
  21. align: PropTypes.object.isRequired,
  22. target: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).def(function () {
  23. return window;
  24. }),
  25. monitorBufferTime: PropTypes.number.def(50),
  26. monitorWindowResize: PropTypes.bool.def(false),
  27. disabled: PropTypes.bool.def(false)
  28. },
  29. data: function data() {
  30. this.aligned = false;
  31. return {};
  32. },
  33. mounted: function mounted() {
  34. var _this = this;
  35. this.$nextTick(function () {
  36. _this.prevProps = _extends({}, _this.$props);
  37. var props = _this.$props;
  38. // if parent ref not attached .... use document.getElementById
  39. !_this.aligned && _this.forceAlign();
  40. if (!props.disabled && props.monitorWindowResize) {
  41. _this.startMonitorWindowResize();
  42. }
  43. });
  44. },
  45. updated: function updated() {
  46. var _this2 = this;
  47. this.$nextTick(function () {
  48. var prevProps = _this2.prevProps;
  49. var props = _this2.$props;
  50. var reAlign = false;
  51. if (!props.disabled) {
  52. var source = _this2.$el;
  53. var sourceRect = source ? source.getBoundingClientRect() : null;
  54. if (prevProps.disabled) {
  55. reAlign = true;
  56. } else {
  57. var lastElement = getElement(prevProps.target);
  58. var currentElement = getElement(props.target);
  59. var lastPoint = getPoint(prevProps.target);
  60. var currentPoint = getPoint(props.target);
  61. if (isWindow(lastElement) && isWindow(currentElement)) {
  62. // Skip if is window
  63. reAlign = false;
  64. } else if (lastElement !== currentElement || // Element change
  65. lastElement && !currentElement && currentPoint || // Change from element to point
  66. lastPoint && currentPoint && currentElement || // Change from point to element
  67. currentPoint && !isSamePoint(lastPoint, currentPoint)) {
  68. reAlign = true;
  69. }
  70. // If source element size changed
  71. var preRect = _this2.sourceRect || {};
  72. if (!reAlign && source && (!isSimilarValue(preRect.width, sourceRect.width) || !isSimilarValue(preRect.height, sourceRect.height))) {
  73. reAlign = true;
  74. }
  75. }
  76. _this2.sourceRect = sourceRect;
  77. }
  78. if (reAlign) {
  79. _this2.forceAlign();
  80. }
  81. if (props.monitorWindowResize && !props.disabled) {
  82. _this2.startMonitorWindowResize();
  83. } else {
  84. _this2.stopMonitorWindowResize();
  85. }
  86. _this2.prevProps = _extends({}, _this2.$props, { align: clonedeep(_this2.$props.align) });
  87. });
  88. },
  89. beforeDestroy: function beforeDestroy() {
  90. this.stopMonitorWindowResize();
  91. },
  92. methods: {
  93. startMonitorWindowResize: function startMonitorWindowResize() {
  94. if (!this.resizeHandler) {
  95. this.bufferMonitor = buffer(this.forceAlign, this.$props.monitorBufferTime);
  96. this.resizeHandler = addEventListener(window, 'resize', this.bufferMonitor);
  97. }
  98. },
  99. stopMonitorWindowResize: function stopMonitorWindowResize() {
  100. if (this.resizeHandler) {
  101. this.bufferMonitor.clear();
  102. this.resizeHandler.remove();
  103. this.resizeHandler = null;
  104. }
  105. },
  106. forceAlign: function forceAlign() {
  107. var _$props = this.$props,
  108. disabled = _$props.disabled,
  109. target = _$props.target,
  110. align = _$props.align;
  111. if (!disabled && target) {
  112. var source = this.$el;
  113. var listeners = getListeners(this);
  114. var result = void 0;
  115. var element = getElement(target);
  116. var point = getPoint(target);
  117. // IE lose focus after element realign
  118. // We should record activeElement and restore later
  119. var activeElement = document.activeElement;
  120. if (element) {
  121. result = alignElement(source, element, align);
  122. } else if (point) {
  123. result = alignPoint(source, point, align);
  124. }
  125. restoreFocus(activeElement, source);
  126. this.aligned = true;
  127. listeners.align && listeners.align(source, result);
  128. }
  129. }
  130. },
  131. render: function render() {
  132. var childrenProps = this.$props.childrenProps;
  133. var child = getSlot(this)[0];
  134. if (child && childrenProps) {
  135. return cloneElement(child, { props: childrenProps });
  136. }
  137. return child;
  138. }
  139. };