index.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import { VantComponent } from '../common/component';
  2. const ROOT_ELEMENT = '.van-sticky';
  3. VantComponent({
  4. props: {
  5. zIndex: {
  6. type: Number,
  7. value: 99
  8. },
  9. offsetTop: {
  10. type: Number,
  11. value: 0,
  12. observer: 'observeContent'
  13. },
  14. disabled: {
  15. type: Boolean,
  16. observer(value) {
  17. if (!this.mounted) {
  18. return;
  19. }
  20. value ? this.disconnectObserver() : this.initObserver();
  21. }
  22. },
  23. container: {
  24. type: null,
  25. observer(target) {
  26. if (typeof target !== 'function' || !this.data.height) {
  27. return;
  28. }
  29. this.observeContainer();
  30. }
  31. }
  32. },
  33. data: {
  34. wrapStyle: '',
  35. containerStyle: ''
  36. },
  37. methods: {
  38. setStyle() {
  39. const { offsetTop, height, fixed, zIndex } = this.data;
  40. if (fixed) {
  41. this.setData({
  42. wrapStyle: `top: ${offsetTop}px;`,
  43. containerStyle: `height: ${height}px; z-index: ${zIndex};`
  44. });
  45. }
  46. else {
  47. this.setData({
  48. wrapStyle: '',
  49. containerStyle: ''
  50. });
  51. }
  52. },
  53. getContainerRect() {
  54. const nodesRef = this.data.container();
  55. return new Promise(resolve => nodesRef.boundingClientRect(resolve).exec());
  56. },
  57. initObserver() {
  58. this.disconnectObserver();
  59. this.getRect(ROOT_ELEMENT).then((rect) => {
  60. this.setData({ height: rect.height });
  61. wx.nextTick(() => {
  62. this.observeContent();
  63. this.observeContainer();
  64. });
  65. });
  66. },
  67. disconnectObserver(observerName) {
  68. if (observerName) {
  69. const observer = this[observerName];
  70. observer && observer.disconnect();
  71. }
  72. else {
  73. this.contentObserver && this.contentObserver.disconnect();
  74. this.containerObserver && this.containerObserver.disconnect();
  75. }
  76. },
  77. observeContent() {
  78. const { offsetTop } = this.data;
  79. this.disconnectObserver('contentObserver');
  80. const contentObserver = this.createIntersectionObserver({
  81. thresholds: [0, 1]
  82. });
  83. this.contentObserver = contentObserver;
  84. contentObserver.relativeToViewport({ top: -offsetTop });
  85. contentObserver.observe(ROOT_ELEMENT, res => {
  86. if (this.data.disabled) {
  87. return;
  88. }
  89. this.setFixed(res.boundingClientRect.top);
  90. });
  91. },
  92. observeContainer() {
  93. if (typeof this.data.container !== 'function') {
  94. return;
  95. }
  96. const { height } = this.data;
  97. this.getContainerRect().then((rect) => {
  98. this.containerHeight = rect.height;
  99. this.disconnectObserver('containerObserver');
  100. const containerObserver = this.createIntersectionObserver({
  101. thresholds: [0, 1]
  102. });
  103. this.containerObserver = containerObserver;
  104. containerObserver.relativeToViewport({
  105. top: this.containerHeight - height
  106. });
  107. containerObserver.observe(ROOT_ELEMENT, res => {
  108. if (this.data.disabled) {
  109. return;
  110. }
  111. this.setFixed(res.boundingClientRect.top);
  112. });
  113. });
  114. },
  115. setFixed(top) {
  116. const { offsetTop, height } = this.data;
  117. const { containerHeight } = this;
  118. const fixed = containerHeight && height
  119. ? top > height - containerHeight && top < offsetTop
  120. : top < offsetTop;
  121. this.$emit('scroll', {
  122. scrollTop: top,
  123. isFixed: fixed
  124. });
  125. this.setData({ fixed });
  126. wx.nextTick(() => {
  127. this.setStyle();
  128. });
  129. }
  130. },
  131. mounted() {
  132. this.mounted = true;
  133. if (!this.data.disabled) {
  134. this.initObserver();
  135. }
  136. },
  137. destroyed() {
  138. this.disconnectObserver();
  139. }
  140. });