You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

157 lines
4.2 KiB

3 years ago
  1. <template>
  2. <view class="">
  3. <view class="u-sticky-wrap" :class="[elClass]" :style="{
  4. height: fixed ? height + 'px' : 'auto',
  5. backgroundColor: bgColor
  6. }">
  7. <view class="u-sticky" :style="{
  8. position: fixed ? 'fixed' : 'static',
  9. top: stickyTop + 'px',
  10. left: left + 'px',
  11. width: width == 'auto' ? 'auto' : width + 'px',
  12. zIndex: uZIndex
  13. }">
  14. <slot></slot>
  15. </view>
  16. </view>
  17. </view>
  18. </template>
  19. <script>
  20. /**
  21. * sticky 吸顶
  22. * @description 该组件与CSS中position: sticky属性实现的效果一致当组件达到预设的到顶部距离时 就会固定在指定位置组件位置大于预设的顶部距离时会重新按照正常的布局排列
  23. * @tutorial https://www.uviewui.com/components/sticky.html
  24. * @property {String Number} offset-top 吸顶时与顶部的距离单位rpx默认0
  25. * @property {String Number} index 自定义标识用于区分是哪一个组件
  26. * @property {Boolean} enable 是否开启吸顶功能默认true
  27. * @property {String} bg-color 组件背景颜色默认#ffffff
  28. * @property {String Number} z-index 吸顶时的z-index值默认970
  29. * @property {String Number} h5-nav-height 导航栏高度自定义导航栏时(无导航栏时需设置为0)需要传入此值单位px默认44
  30. * @event {Function} fixed 组件吸顶时触发
  31. * @event {Function} unfixed 组件取消吸顶时触发
  32. * @example <u-sticky offset-top="200"><view>塞下秋来风景异衡阳雁去无留意</view></u-sticky>
  33. */
  34. export default {
  35. name: "u-sticky",
  36. props: {
  37. // 吸顶容器到顶部某个距离的时候,进行吸顶,在H5平台,NavigationBar为44px
  38. offsetTop: {
  39. type: [Number, String],
  40. default: 0
  41. },
  42. //列表中的索引值
  43. index: {
  44. type: [Number, String],
  45. default: ''
  46. },
  47. // 是否开启吸顶功能
  48. enable: {
  49. type: Boolean,
  50. default: true
  51. },
  52. // h5顶部导航栏的高度
  53. h5NavHeight: {
  54. type: [Number, String],
  55. default: 44
  56. },
  57. // 吸顶区域的背景颜色
  58. bgColor: {
  59. type: String,
  60. default: '#ffffff'
  61. },
  62. // z-index值
  63. zIndex: {
  64. type: [Number, String],
  65. default: ''
  66. }
  67. },
  68. data() {
  69. return {
  70. fixed: false,
  71. height: 'auto',
  72. stickyTop: 0,
  73. elClass: this.$u.guid(),
  74. left: 0,
  75. width: 'auto',
  76. };
  77. },
  78. watch: {
  79. offsetTop(val) {
  80. this.initObserver();
  81. },
  82. enable(val) {
  83. if (val == false) {
  84. this.fixed = false;
  85. this.disconnectObserver('contentObserver');
  86. } else {
  87. this.initObserver();
  88. }
  89. }
  90. },
  91. computed: {
  92. uZIndex() {
  93. return this.zIndex ? this.zIndex : this.$u.zIndex.sticky;
  94. }
  95. },
  96. mounted() {
  97. this.initObserver();
  98. },
  99. methods: {
  100. initObserver() {
  101. if (!this.enable) return;
  102. // #ifdef H5
  103. this.stickyTop = this.offsetTop != 0 ? uni.upx2px(this.offsetTop) + this.h5NavHeight : this.h5NavHeight;
  104. // #endif
  105. // #ifndef H5
  106. this.stickyTop = this.offsetTop != 0 ? uni.upx2px(this.offsetTop) : 0;
  107. // #endif
  108. this.disconnectObserver('contentObserver');
  109. this.$uGetRect('.' + this.elClass).then((res) => {
  110. this.height = res.height;
  111. this.left = res.left;
  112. this.width = res.width;
  113. this.$nextTick(() => {
  114. this.observeContent();
  115. });
  116. });
  117. },
  118. observeContent() {
  119. this.disconnectObserver('contentObserver');
  120. const contentObserver = this.createIntersectionObserver({
  121. thresholds: [0.95, 0.98, 1]
  122. });
  123. contentObserver.relativeToViewport({
  124. top: -this.stickyTop
  125. });
  126. contentObserver.observe('.' + this.elClass, res => {
  127. if (!this.enable) return;
  128. this.setFixed(res.boundingClientRect.top);
  129. });
  130. this.contentObserver = contentObserver;
  131. },
  132. setFixed(top) {
  133. const fixed = top < this.stickyTop;
  134. if (fixed) this.$emit('fixed', this.index);
  135. else if(this.fixed) this.$emit('unfixed', this.index);
  136. this.fixed = fixed;
  137. },
  138. disconnectObserver(observerName) {
  139. const observer = this[observerName];
  140. observer && observer.disconnect();
  141. },
  142. },
  143. beforeDestroy() {
  144. this.disconnectObserver('contentObserver');
  145. }
  146. };
  147. </script>
  148. <style scoped lang="scss">
  149. @import "../../libs/css/style.components.scss";
  150. .u-sticky {
  151. z-index: 9999999999;
  152. }
  153. </style>