[vue2]affix固钉组件的简单实现

290 阅读1分钟

网上看的几个固钉组件,感觉实现的比较复杂,所以决定简单实现一下,抛砖引玉

源码

<template>
  <div class="affix-placeholder" :style="styles">
    <slot></slot>
  </div>
</template>

<script>
// 固钉
export default {
  name: "Affix",
  data() {
    return {
      affixElTop: 0,
      scrollTop: 0,
      scrollEl: window,
    };
  },
  props: {
    // 固定时和滚动容器顶部的距离
    offset: { type: Number, default: 0 },
    // 固钉状态时的Z轴索引值
    zIndex: { type: [Number, String], default: 100 },
    // 目标滚动对象,默认为window
    target: {
      type: Function,
      default: () => window,
    },
  },
  computed: {
    styles() {
      const result = [];
      if (this.scrollTop - this.affixElTop >= this.offset) {
        result.push(
          { position: this.isWindow ? "fixed" : "sticky" },
          { zIndex: this.zIndex },
          { top: `${this.offset}px` }
        );
      }
      return result;
    },
    isWindow() {
      return this.scrollEl === window;
    },
  },
  methods: {
    handleScroll(e) {
      e.stopPropagation();
      if (this.isWindow) {
        this.scrollTop =
          document.documentElement.scrollTop || document.body.scrollTop;
      } else {
        this.scrollTop = this.scrollEl.scrollTop || 0;
      }
    },
  },
  mounted() {
    this.scrollEl = this.target();
    this.affixElTop = this.$el.getBoundingClientRect().top;
    this.scrollEl.addEventListener("scroll", this.handleScroll);
  },
  beforeDestroy() {
    this.scrollEl.removeEventListener("scroll", this.handleScroll);
  },
};
</script>

<style>
.affix-placeholder {
  min-height: 1px;
}
</style>

文档

Props

NameDescriptionTypeRequiredDefault
offset固定时和滚动容器顶部的距离Numberfalse0
zIndex固钉状态时的Z轴索引值Number / Stringfalse100
target目标滚动对象,默认为windowFunctionfalse() => window

Slots

NameDescriptionDefault Slot Content
default--

示例

<template>
  <div>
	<div style="height:100px;width:100%">header</div>
	<affix style="background:#199;width:100%;height:50px;">我是固钉</affix>
    <p v-for="i in 300" :key="i">{{i}}</p>
  </div>
</template>
<script>
import Affix from "./affix";
export default {
  components: {
    Affix,
  }
};
</script>