index.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. 'use strict';
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. var _babelHelperVueJsxMergeProps = require('babel-helper-vue-jsx-merge-props');
  6. var _babelHelperVueJsxMergeProps2 = _interopRequireDefault(_babelHelperVueJsxMergeProps);
  7. var _defineProperty2 = require('babel-runtime/helpers/defineProperty');
  8. var _defineProperty3 = _interopRequireDefault(_defineProperty2);
  9. var _vueTypes = require('../_util/vue-types');
  10. var _vueTypes2 = _interopRequireDefault(_vueTypes);
  11. var _classnames = require('classnames');
  12. var _classnames2 = _interopRequireDefault(_classnames);
  13. var _omit = require('omit.js');
  14. var _omit2 = _interopRequireDefault(_omit);
  15. var _vcResizeObserver = require('../vc-resize-observer');
  16. var _vcResizeObserver2 = _interopRequireDefault(_vcResizeObserver);
  17. var _BaseMixin = require('../_util/BaseMixin');
  18. var _BaseMixin2 = _interopRequireDefault(_BaseMixin);
  19. var _throttleByAnimationFrame = require('../_util/throttleByAnimationFrame');
  20. var _throttleByAnimationFrame2 = _interopRequireDefault(_throttleByAnimationFrame);
  21. var _configConsumerProps = require('../config-provider/configConsumerProps');
  22. var _base = require('../base');
  23. var _base2 = _interopRequireDefault(_base);
  24. var _warning = require('../_util/warning');
  25. var _warning2 = _interopRequireDefault(_warning);
  26. var _utils = require('./utils');
  27. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  28. function getDefaultTarget() {
  29. return typeof window !== 'undefined' ? window : null;
  30. }
  31. // Affix
  32. var AffixProps = {
  33. /**
  34. * 距离窗口顶部达到指定偏移量后触发
  35. */
  36. offsetTop: _vueTypes2['default'].number,
  37. offset: _vueTypes2['default'].number,
  38. /** 距离窗口底部达到指定偏移量后触发 */
  39. offsetBottom: _vueTypes2['default'].number,
  40. /** 固定状态改变时触发的回调函数 */
  41. // onChange?: (affixed?: boolean) => void;
  42. /** 设置 Affix 需要监听其滚动事件的元素,值为一个返回对应 DOM 元素的函数 */
  43. target: _vueTypes2['default'].func.def(getDefaultTarget),
  44. prefixCls: _vueTypes2['default'].string
  45. };
  46. var AffixStatus = {
  47. None: 'none',
  48. Prepare: 'Prepare'
  49. };
  50. var Affix = {
  51. name: 'AAffix',
  52. props: AffixProps,
  53. mixins: [_BaseMixin2['default']],
  54. inject: {
  55. configProvider: { 'default': function _default() {
  56. return _configConsumerProps.ConfigConsumerProps;
  57. } }
  58. },
  59. data: function data() {
  60. return {
  61. affixStyle: undefined,
  62. placeholderStyle: undefined,
  63. status: AffixStatus.None,
  64. lastAffix: false,
  65. prevTarget: null
  66. };
  67. },
  68. beforeMount: function beforeMount() {
  69. this.updatePosition = (0, _throttleByAnimationFrame2['default'])(this.updatePosition);
  70. this.lazyUpdatePosition = (0, _throttleByAnimationFrame2['default'])(this.lazyUpdatePosition);
  71. },
  72. mounted: function mounted() {
  73. var _this = this;
  74. var target = this.target;
  75. if (target) {
  76. // [Legacy] Wait for parent component ref has its value.
  77. // We should use target as directly element instead of function which makes element check hard.
  78. this.timeout = setTimeout(function () {
  79. (0, _utils.addObserveTarget)(target(), _this);
  80. // Mock Event object.
  81. _this.updatePosition();
  82. });
  83. }
  84. },
  85. updated: function updated() {
  86. this.measure();
  87. },
  88. watch: {
  89. target: function target(val) {
  90. var newTarget = null;
  91. if (val) {
  92. newTarget = val() || null;
  93. }
  94. if (this.prevTarget !== newTarget) {
  95. (0, _utils.removeObserveTarget)(this);
  96. if (newTarget) {
  97. (0, _utils.addObserveTarget)(newTarget, this);
  98. // Mock Event object.
  99. this.updatePosition();
  100. }
  101. this.prevTarget = newTarget;
  102. }
  103. },
  104. offsetTop: function offsetTop() {
  105. this.updatePosition();
  106. },
  107. offsetBottom: function offsetBottom() {
  108. this.updatePosition();
  109. }
  110. },
  111. beforeDestroy: function beforeDestroy() {
  112. clearTimeout(this.timeout);
  113. (0, _utils.removeObserveTarget)(this);
  114. this.updatePosition.cancel();
  115. // https://github.com/ant-design/ant-design/issues/22683
  116. this.lazyUpdatePosition.cancel();
  117. },
  118. methods: {
  119. getOffsetTop: function getOffsetTop() {
  120. var offset = this.offset,
  121. offsetBottom = this.offsetBottom;
  122. var offsetTop = this.offsetTop;
  123. if (typeof offsetTop === 'undefined') {
  124. offsetTop = offset;
  125. (0, _warning2['default'])(typeof offset === 'undefined', 'Affix', '`offset` is deprecated. Please use `offsetTop` instead.');
  126. }
  127. if (offsetBottom === undefined && offsetTop === undefined) {
  128. offsetTop = 0;
  129. }
  130. return offsetTop;
  131. },
  132. getOffsetBottom: function getOffsetBottom() {
  133. return this.offsetBottom;
  134. },
  135. // =================== Measure ===================
  136. measure: function measure() {
  137. var status = this.status,
  138. lastAffix = this.lastAffix;
  139. var target = this.target;
  140. if (status !== AffixStatus.Prepare || !this.$refs.fixedNode || !this.$refs.placeholderNode || !target) {
  141. return;
  142. }
  143. var offsetTop = this.getOffsetTop();
  144. var offsetBottom = this.getOffsetBottom();
  145. var targetNode = target();
  146. if (!targetNode) {
  147. return;
  148. }
  149. var newState = {
  150. status: AffixStatus.None
  151. };
  152. var targetRect = (0, _utils.getTargetRect)(targetNode);
  153. var placeholderReact = (0, _utils.getTargetRect)(this.$refs.placeholderNode);
  154. var fixedTop = (0, _utils.getFixedTop)(placeholderReact, targetRect, offsetTop);
  155. var fixedBottom = (0, _utils.getFixedBottom)(placeholderReact, targetRect, offsetBottom);
  156. if (fixedTop !== undefined) {
  157. newState.affixStyle = {
  158. position: 'fixed',
  159. top: fixedTop,
  160. width: placeholderReact.width + 'px',
  161. height: placeholderReact.height + 'px'
  162. };
  163. newState.placeholderStyle = {
  164. width: placeholderReact.width + 'px',
  165. height: placeholderReact.height + 'px'
  166. };
  167. } else if (fixedBottom !== undefined) {
  168. newState.affixStyle = {
  169. position: 'fixed',
  170. bottom: fixedBottom,
  171. width: placeholderReact.width + 'px',
  172. height: placeholderReact.height + 'px'
  173. };
  174. newState.placeholderStyle = {
  175. width: placeholderReact.width + 'px',
  176. height: placeholderReact.height + 'px'
  177. };
  178. }
  179. newState.lastAffix = !!newState.affixStyle;
  180. if (lastAffix !== newState.lastAffix) {
  181. this.$emit('change', newState.lastAffix);
  182. }
  183. this.setState(newState);
  184. },
  185. // @ts-ignore TS6133
  186. prepareMeasure: function prepareMeasure() {
  187. this.setState({
  188. status: AffixStatus.Prepare,
  189. affixStyle: undefined,
  190. placeholderStyle: undefined
  191. });
  192. this.$forceUpdate();
  193. // Test if `updatePosition` called
  194. if (process.env.NODE_ENV === 'test') {
  195. this.$emit('testUpdatePosition');
  196. }
  197. },
  198. updatePosition: function updatePosition() {
  199. this.prepareMeasure();
  200. },
  201. lazyUpdatePosition: function lazyUpdatePosition() {
  202. var target = this.target;
  203. var affixStyle = this.affixStyle;
  204. // Check position change before measure to make Safari smooth
  205. if (target && affixStyle) {
  206. var offsetTop = this.getOffsetTop();
  207. var offsetBottom = this.getOffsetBottom();
  208. var targetNode = target();
  209. if (targetNode && this.$refs.placeholderNode) {
  210. var targetRect = (0, _utils.getTargetRect)(targetNode);
  211. var placeholderReact = (0, _utils.getTargetRect)(this.$refs.placeholderNode);
  212. var fixedTop = (0, _utils.getFixedTop)(placeholderReact, targetRect, offsetTop);
  213. var fixedBottom = (0, _utils.getFixedBottom)(placeholderReact, targetRect, offsetBottom);
  214. if (fixedTop !== undefined && affixStyle.top === fixedTop || fixedBottom !== undefined && affixStyle.bottom === fixedBottom) {
  215. return;
  216. }
  217. }
  218. }
  219. // Directly call prepare measure since it's already throttled.
  220. this.prepareMeasure();
  221. }
  222. },
  223. render: function render() {
  224. var _this2 = this;
  225. var h = arguments[0];
  226. var prefixCls = this.prefixCls,
  227. affixStyle = this.affixStyle,
  228. placeholderStyle = this.placeholderStyle,
  229. $slots = this.$slots,
  230. $props = this.$props;
  231. var getPrefixCls = this.configProvider.getPrefixCls;
  232. var className = (0, _classnames2['default'])((0, _defineProperty3['default'])({}, getPrefixCls('affix', prefixCls), affixStyle));
  233. var props = {
  234. attrs: (0, _omit2['default'])($props, ['prefixCls', 'offsetTop', 'offsetBottom', 'target'])
  235. };
  236. return h(
  237. _vcResizeObserver2['default'],
  238. {
  239. on: {
  240. 'resize': function resize() {
  241. _this2.updatePosition();
  242. }
  243. }
  244. },
  245. [h(
  246. 'div',
  247. (0, _babelHelperVueJsxMergeProps2['default'])([props, { style: placeholderStyle, ref: 'placeholderNode' }]),
  248. [h(
  249. 'div',
  250. { 'class': className, ref: 'fixedNode', style: affixStyle },
  251. [$slots['default']]
  252. )]
  253. )]
  254. );
  255. }
  256. };
  257. /* istanbul ignore next */
  258. Affix.install = function (Vue) {
  259. Vue.use(_base2['default']);
  260. Vue.component(Affix.name, Affix);
  261. };
  262. exports['default'] = Affix;