滑动吸顶源代码,使用npm 插件

91 阅读1分钟

滑动吸顶

场景:当滑动到一定高度,想要一部分固定,其他地方滑动

具体实现代码如下

stickySlot.vue


<template>
  <div class="sticky" :style="getPosition">
    <div class="sticky-warp">
      <slot></slot>
    </div>
  </div>
</template>

<script>
export default {
  computed: {
    getPosition() {
      const position = this.cssSupport('position', 'sticky') ? 'sticky' : 'relative'
      return 'position:' + position
    }
  },
  mounted() {
    this.init()
  },
  deactivated() {
    if (this.cssSupport('position', 'sticky')) {
      return
    }

    // 复位
    const elWarp = this.$el.querySelector('.sticky-warp')
    elWarp.position = 'absolute'
  },
  methods: {
    init() {
      if (this.cssSupport('position', 'sticky')) {
        return
      }

      const el = this.$el
      const target = this.$el.parentNode
      const elWarp = this.$el.querySelector('.sticky-warp')
      const top = this.getNumberValue(document.defaultView.getComputedStyle(el).top)

      this.addScrollListen(target, () => {
        if (el.getBoundingClientRect().top <= top) {
          elWarp.style.position = 'fixed'
        }

        if (el.getBoundingClientRect().top >= 0 && elWarp.style.position != 'absolute') {
          elWarp.style.position = 'absolute'
        }
      })
    },
    cssSupport(attr, value) {
      const element = document.createElement('div')

      if (attr in element.style) {
        element.style[attr] = value
        return element.style[attr] === value
      } else {
        return false
      }
    },
    getNumberValue(pxValue) {
      const value = String(pxValue).match(/^\-?\+?[0-9]+/g)
      return value ? Number(value) : undefined
    },
    addScrollListen(target, cb) {
      target.addEventListener('y-scroll', (event) => {
        cb && cb(event)
      })
    }
  }
}
</script>

<style>
.sticky {
  width: 100%;
}

.sticky .sticky-warp {
  width: 100%;
  background: inherit;
  will-change: change;
  height: inherit;
  top: inherit;
}
</style>

使用

<template>
  <div>
    <ul>
      <li v-for="(item, index) in headerData" :key="index">{{ item }}</li>
    </ul>
    <!-- 这里需要给组件添加一个class,用于控制固定的位置,看css注释部分 -->
    <!-- <sticky-slot class="stickyTop">
      <div class="tab">假装这是一个tab栏, 当页面滚动的时候要固定在顶部</div>
    </sticky-slot> -->
    <sticky-slot class="stickyTop">
      <div class="tab">假装这是一个tab栏, 当页面滚动的时候要固定在顶部</div>
    </sticky-slot>
    <ul>
      <li v-for="(item, index) in footerData" :key="index">{{ item }}</li>
    </ul>
  </div>
</template>

<script>
// import stickySlot from '@/components/stickySlot/stickySlot.vue'
import stickySlot from '@/package/stickySlot'

export default {
  components: {
    stickySlot
  },
  data() {
    return {
      headerData: [],
      footerData: []
    };
  },
  mounted() {
    // 使用假数据撑满屏幕
    for (let i = 0; i < 20; i++) {
      this.headerData.push('第' + i + '条数据')
    }
    for (let i = 20; i < 80; i++) {
      this.footerData.push('第' + i + '条数据')
    }
  }
}
</script>

<style scoped>
/* 通过设置top的值,控制需要固定在什么位置,0是顶部,值为number(px) */
.stickyTop {
  top: 0;
  z-index: 10;
}

.tab {
  height: 30px;
  line-height: 30px;
  background-color: greenyellow;
}
</style>

效果

_QQ录屏20231211091124_1.gif

封装成依赖,使用时npm一下

使用方法
npm i  webui-whm
import WebuiWhm from 'webui-whm'
Vue.use(WebuiWhm)
  <sticky-slot class="stickyTop">
          <aside class="section-aside  "  >
            <sectionAsideLeftVue :treeData='chapterTree ' :chapterCode='initChapterCode'  v-if="initChapterCode" @updateContent='chapterCode=>bookDetails(chapterCode)'></sectionAsideLeftVue>
          </aside>
          </sticky-slot>
          
css      
.stickyTop {
  top: 0;
  z-index: 10;
}