123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- <template>
- <view class="">
- <view class="u-sticky-wrap" :class="[elClass]" :style="{
- height: fixed ? height + 'px' : 'auto',
- backgroundColor: bgColor
- }">
- <view class="u-sticky" :style="{
- position: fixed ? 'fixed' : 'static',
- top: stickyTop + 'px',
- left: left + 'px',
- width: width == 'auto' ? 'auto' : width + 'px',
- zIndex: uZIndex
- }">
- <slot></slot>
- </view>
- </view>
- </view>
- </template>
- <script>
- /**
- * sticky 吸顶
- * @description 该组件与CSS中position: sticky属性实现的效果一致,当组件达到预设的到顶部距离时, 就会固定在指定位置,组件位置大于预设的顶部距离时,会重新按照正常的布局排列。
- * @tutorial https://www.uviewui.com/components/sticky.html
- * @property {String Number} offset-top 吸顶时与顶部的距离,单位rpx(默认0)
- * @property {String Number} index 自定义标识,用于区分是哪一个组件
- * @property {Boolean} enable 是否开启吸顶功能(默认true)
- * @property {String} bg-color 组件背景颜色(默认#ffffff)
- * @property {String Number} z-index 吸顶时的z-index值(默认970)
- * @property {String Number} h5-nav-height 导航栏高度,自定义导航栏时(无导航栏时需设置为0),需要传入此值,单位px(默认44)
- * @event {Function} fixed 组件吸顶时触发
- * @event {Function} unfixed 组件取消吸顶时触发
- * @example <u-sticky offset-top="200"><view>塞下秋来风景异,衡阳雁去无留意</view></u-sticky>
- */
- export default {
- name: "u-sticky",
- props: {
- // 吸顶容器到顶部某个距离的时候,进行吸顶,在H5平台,NavigationBar为44px
- offsetTop: {
- type: [Number, String],
- default: 0
- },
- //列表中的索引值
- index: {
- type: [Number, String],
- default: ''
- },
- // 是否开启吸顶功能
- enable: {
- type: Boolean,
- default: true
- },
- // h5顶部导航栏的高度
- h5NavHeight: {
- type: [Number, String],
- default: 44
- },
- // 吸顶区域的背景颜色
- bgColor: {
- type: String,
- default: '#ffffff'
- },
- // z-index值
- zIndex: {
- type: [Number, String],
- default: ''
- }
- },
- data() {
- return {
- fixed: false,
- height: 'auto',
- stickyTop: 0,
- elClass: this.$u.guid(),
- left: 0,
- width: 'auto',
- };
- },
- watch: {
- offsetTop(val) {
- this.initObserver();
- },
- enable(val) {
- if (val == false) {
- this.fixed = false;
- this.disconnectObserver('contentObserver');
- } else {
- this.initObserver();
- }
- }
- },
- computed: {
- uZIndex() {
- return this.zIndex ? this.zIndex : this.$u.zIndex.sticky;
- }
- },
- mounted() {
- this.initObserver();
- },
- methods: {
- initObserver() {
- if (!this.enable) return;
- // #ifdef H5
- this.stickyTop = this.offsetTop != 0 ? uni.upx2px(this.offsetTop) + this.h5NavHeight : this.h5NavHeight;
- // #endif
- // #ifndef H5
- this.stickyTop = this.offsetTop != 0 ? uni.upx2px(this.offsetTop) : 0;
- // #endif
- this.disconnectObserver('contentObserver');
- this.$uGetRect('.' + this.elClass).then((res) => {
- this.height = res.height;
- this.left = res.left;
- this.width = res.width;
- this.$nextTick(() => {
- this.observeContent();
- });
- });
- },
- observeContent() {
- this.disconnectObserver('contentObserver');
- const contentObserver = this.createIntersectionObserver({
- thresholds: [0.95, 0.98, 1]
- });
- contentObserver.relativeToViewport({
- top: -this.stickyTop
- });
- contentObserver.observe('.' + this.elClass, res => {
- if (!this.enable) return;
- this.setFixed(res.boundingClientRect.top);
- });
- this.contentObserver = contentObserver;
- },
- setFixed(top) {
- const fixed = top < this.stickyTop;
- if (fixed) this.$emit('fixed', this.index);
- else if(this.fixed) this.$emit('unfixed', this.index);
- this.fixed = fixed;
- },
- disconnectObserver(observerName) {
- const observer = this[observerName];
- observer && observer.disconnect();
- },
- },
- beforeDestroy() {
- this.disconnectObserver('contentObserver');
- }
- };
- </script>
- <style scoped lang="scss">
- @import "../../libs/css/style.components.scss";
-
- .u-sticky {
- z-index: 9999999999;
- }
- </style>
|