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.
		
		
		
		
		
			
		
			
				
					
					
						
							217 lines
						
					
					
						
							4.6 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							217 lines
						
					
					
						
							4.6 KiB
						
					
					
				
								<template>
							 | 
						|
								  <view class="ui-fixed">
							 | 
						|
								    <view
							 | 
						|
								      class="ui-fixed-box"
							 | 
						|
								      :id="`fixed-${uuid}`"
							 | 
						|
								      :class="[{ fixed: state.fixed }]"
							 | 
						|
								      :style="[
							 | 
						|
								        {
							 | 
						|
								          left: sticky ? 'auto' : '0px',
							 | 
						|
								          top: state.fixed && !bottom ? (noNav ? val : val + sys_navBar) + 'px' : 'auto',
							 | 
						|
								          bottom: insetHeight,
							 | 
						|
								          zIndex: index + sheep.$zIndex.navbar,
							 | 
						|
								        },
							 | 
						|
								        !alway ? { opacity: state.opacityVal } : '',
							 | 
						|
								      ]"
							 | 
						|
								    >
							 | 
						|
								      <view
							 | 
						|
								        class="ui-fixed-content"
							 | 
						|
								        @tap="toTop"
							 | 
						|
								        :style="[{ zIndex: index + sheep.$zIndex.navbar }]"
							 | 
						|
								      >
							 | 
						|
								        <slot></slot>
							 | 
						|
								        <view
							 | 
						|
								          v-if="safeAreaInsets.bottom && bottom && isInset"
							 | 
						|
								          class="inset-bottom"
							 | 
						|
								          :style="[{ height: safeAreaInsets.bottom + 'px' }]"
							 | 
						|
								        ></view>
							 | 
						|
								      </view>
							 | 
						|
								      <view class="ui-fixed-bottom" :class="[bg]" v-if="bottom"></view>
							 | 
						|
								      <view
							 | 
						|
								        class="ui-fixed-bg"
							 | 
						|
								        :class="[ui, bg]"
							 | 
						|
								        :style="[
							 | 
						|
								          { zIndex: index + sheep.$zIndex.navbar - 1 },
							 | 
						|
								          bgStyles,
							 | 
						|
								          opacity ? { opacity: state.opacityVal } : '',
							 | 
						|
								        ]"
							 | 
						|
								      ></view>
							 | 
						|
								    </view>
							 | 
						|
								    <view
							 | 
						|
								      class="skeleton"
							 | 
						|
								      :style="[{ height: state.content.height + 'px', width: width + 'px' }]"
							 | 
						|
								      v-if="sticky ? state.fixed : placeholder && state.fixed"
							 | 
						|
								    ></view>
							 | 
						|
								  </view>
							 | 
						|
								</template>
							 | 
						|
								
							 | 
						|
								<script setup>
							 | 
						|
								  import { onPageScroll } from '@dcloudio/uni-app';
							 | 
						|
								  import { getCurrentInstance, unref, onMounted, reactive, nextTick, computed } from 'vue';
							 | 
						|
								  import sheep from '@/sheep';
							 | 
						|
								  const { safeAreaInsets } = sheep.$platform.device;
							 | 
						|
								
							 | 
						|
								  const vm = getCurrentInstance();
							 | 
						|
								
							 | 
						|
								  const uuid = sheep.$helper.guid();
							 | 
						|
								  const sys_navBar = sheep.$platform.navbar;
							 | 
						|
								  const state = reactive({
							 | 
						|
								    content: {},
							 | 
						|
								    fixed: true,
							 | 
						|
								    scrollTop: 0,
							 | 
						|
								    opacityVal: 0,
							 | 
						|
								  });
							 | 
						|
								  const insetHeight = computed(() => {
							 | 
						|
								    if (state.fixed && props.bottom) {
							 | 
						|
								      if (props.isInset) {
							 | 
						|
								        return props.val + 'px';
							 | 
						|
								      } else {
							 | 
						|
								        return props.val + safeAreaInsets.bottom + 'px';
							 | 
						|
								      }
							 | 
						|
								    } else {
							 | 
						|
								      return 'auto';
							 | 
						|
								    }
							 | 
						|
								  });
							 | 
						|
								  const props = defineProps({
							 | 
						|
								    noNav: {
							 | 
						|
								      type: Boolean,
							 | 
						|
								      default: false,
							 | 
						|
								    },
							 | 
						|
								    bottom: {
							 | 
						|
								      type: Boolean,
							 | 
						|
								      default: false,
							 | 
						|
								    },
							 | 
						|
								    bg: {
							 | 
						|
								      type: String,
							 | 
						|
								      default: '',
							 | 
						|
								    },
							 | 
						|
								    bgStyles: {
							 | 
						|
								      type: Object,
							 | 
						|
								      default() {},
							 | 
						|
								    },
							 | 
						|
								    val: {
							 | 
						|
								      type: Number,
							 | 
						|
								      default: 0,
							 | 
						|
								    },
							 | 
						|
								    width: {
							 | 
						|
								      type: [String, Number],
							 | 
						|
								      default: 0,
							 | 
						|
								    },
							 | 
						|
								    alway: {
							 | 
						|
								      type: Boolean,
							 | 
						|
								      default: true,
							 | 
						|
								    },
							 | 
						|
								    opacity: {
							 | 
						|
								      type: Boolean,
							 | 
						|
								      default: false,
							 | 
						|
								    },
							 | 
						|
								    index: {
							 | 
						|
								      type: [Number, String],
							 | 
						|
								      default: 0,
							 | 
						|
								    },
							 | 
						|
								    placeholder: {
							 | 
						|
								      type: [Boolean],
							 | 
						|
								      default: false,
							 | 
						|
								    },
							 | 
						|
								    sticky: {
							 | 
						|
								      type: [Boolean],
							 | 
						|
								      default: false,
							 | 
						|
								    },
							 | 
						|
								    noFixed: {
							 | 
						|
								      type: Boolean,
							 | 
						|
								      default: false,
							 | 
						|
								    },
							 | 
						|
								    ui: {
							 | 
						|
								      type: String,
							 | 
						|
								      default: '',
							 | 
						|
								    },
							 | 
						|
								    clickTo: {
							 | 
						|
								      type: Boolean,
							 | 
						|
								      default: false,
							 | 
						|
								    },
							 | 
						|
								    //是否需要安全区
							 | 
						|
								    isInset: {
							 | 
						|
								      type: Boolean,
							 | 
						|
								      default: true,
							 | 
						|
								    },
							 | 
						|
								  });
							 | 
						|
								
							 | 
						|
								  state.fixed = !unref(props.sticky);
							 | 
						|
								  onPageScroll((e) => {
							 | 
						|
								    let top = e.scrollTop;
							 | 
						|
								    state.scrollTop = top;
							 | 
						|
								    state.opacityVal = top > sheep.$platform.navbar ? 1 : top * 0.01;
							 | 
						|
								  });
							 | 
						|
								
							 | 
						|
								  onMounted(() => {
							 | 
						|
								    nextTick(() => {
							 | 
						|
								      computedQuery();
							 | 
						|
								    });
							 | 
						|
								  });
							 | 
						|
								
							 | 
						|
								  const computedQuery = () => {
							 | 
						|
								    uni.createSelectorQuery()
							 | 
						|
								      .in(vm)
							 | 
						|
								      .select(`#fixed-${uuid}`)
							 | 
						|
								      .boundingClientRect((data) => {
							 | 
						|
								        if (data != null) {
							 | 
						|
								          state.content = data;
							 | 
						|
								          if (unref(props.sticky)) {
							 | 
						|
								            setFixed(state.scrollTop);
							 | 
						|
								          }
							 | 
						|
								        }
							 | 
						|
								      })
							 | 
						|
								      .exec();
							 | 
						|
								  };
							 | 
						|
								
							 | 
						|
								  const setFixed = (value) => {
							 | 
						|
								    if (unref(props.bottom)) {
							 | 
						|
								      state.fixed =
							 | 
						|
								        value >=
							 | 
						|
								        state.content.bottom -
							 | 
						|
								          sheep.$platform.device.windowHeight +
							 | 
						|
								          state.content.height +
							 | 
						|
								          unref(props.val);
							 | 
						|
								    } else {
							 | 
						|
								      state.fixed =
							 | 
						|
								        value >=
							 | 
						|
								        state.content.top -
							 | 
						|
								          (unref(props.noNav) ? unref(props.val) : unref(props.val) + sheep.$platform.navbar);
							 | 
						|
								    }
							 | 
						|
								  };
							 | 
						|
								
							 | 
						|
								  const toTop = () => {
							 | 
						|
								    if (props.hasToTop) {
							 | 
						|
								      uni.pageScrollTo({
							 | 
						|
								        scrollTop: state.content.top,
							 | 
						|
								        duration: 100,
							 | 
						|
								      });
							 | 
						|
								    }
							 | 
						|
								  };
							 | 
						|
								</script>
							 | 
						|
								
							 | 
						|
								<style lang="scss">
							 | 
						|
								  .ui-fixed {
							 | 
						|
								    .ui-fixed-box {
							 | 
						|
								      position: relative;
							 | 
						|
								      width: 100%;
							 | 
						|
								      &.fixed {
							 | 
						|
								        position: fixed;
							 | 
						|
								      }
							 | 
						|
								      .ui-fixed-content {
							 | 
						|
								        position: relative;
							 | 
						|
								      }
							 | 
						|
								      .ui-fixed-bg {
							 | 
						|
								        position: absolute;
							 | 
						|
								        width: 100%;
							 | 
						|
								        height: 100%;
							 | 
						|
								        top: 0;
							 | 
						|
								        z-index: 1;
							 | 
						|
								        pointer-events: none;
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								  .inset-bottom {
							 | 
						|
								    background: #fff;
							 | 
						|
								  }
							 | 
						|
								</style>
							 |