index.vue 5.0 KB

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