分享一个vue固钉组件

element 中没有vue固钉组件 ,而我发下ant-design-vue中做了相应的组件,总不能再element-ui的项目中再使用ant-design-vue吧,所以我抽离了组件出来。

代码

<template>
  <div class="affix-placeholder" :style="wrapStyle">
    <div :class="{ affix: affixed }" :style="styles">
      <slot></slot>
    </div>
  </div>
</template>
<script>
export default {
  props: {
    offset: {
      type: Number,
      default: 0,
    },
    onAffix: {
      type: Function,
      default() {},
    },
    boundary: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      affixed: false,
      styles: {},
      affixedClientHeight: 0,
      wrapStyle: {},
    };
  },
  methods: {
    getScroll(w, top) {
      let ret = w[`page${top ? "Y" : "X"}Offset`];
      const method = `scroll${top ? "Top" : "Left"}`;
      if (typeof ret !== "number") {
        const d = w.document;
        // ie6,7,8 standard mode
        ret = d.documentElement[method];
        if (typeof ret !== "number") {
          // quirks mode
          ret = d.body[method];
        }
      }
      return ret;
    },
    getOffset(element) {
      const rect = element.getBoundingClientRect();
      const body = document.body;
      const clientTop = element.clientTop || body.clientTop || 0;
      const clientLeft = element.clientLeft || body.clientLeft || 0;
      // const clientHeight = element.clientHeight || 0;
      const scrollTop = this.getScroll(window, true);
      const scrollLeft = this.getScroll(window);
      return {
        top: rect.bottom + scrollTop - clientTop - this.affixedClientHeight,
        left: rect.left + scrollLeft - clientLeft,
      };
    },
    handleScroll() {
      const scrollTop = this.getScroll(window, true) + this.offsets; // handle setting offset
      const elementOffset = this.getOffset(this.$el);
      if (!this.affixed && scrollTop > elementOffset.top) {
        this.affixed = true;
        this.styles = {
          top: `${this.offsets}px`,
          left: `${elementOffset.left}px`,
          width: `${this.$el.offsetWidth}px`,
        };
        this.onAffix(this.affixed);
      }
      // if setting boundary
      if (this.boundary && scrollTop > elementOffset.top) {
        const el = document.getElementById(this.boundary.slice(1));
        if (el) {
          const boundaryOffset = this.getOffset(el);
          if (scrollTop + this.offsets > boundaryOffset.top) {
            const top = scrollTop - boundaryOffset.top;
            this.styles.top = `-${top}px`;
          }
        }
      }
      if (this.affixed && scrollTop < elementOffset.top) {
        this.affixed = false;
        this.styles = {};
        this.onAffix(this.affixed);
      }
      if (this.affixed && this.boundary) {
        const el = document.getElementById(this.boundary.slice(1));
        if (el) {
          const boundaryOffset = this.getOffset(el);
          if (scrollTop + this.offsets <= boundaryOffset.top) {
            this.styles.top = 0;
          }
        }
      }
    },
  },
  computed: {
    offsets() {
      if (this.boundary) {
        return 0;
      }
      return this.offset;
    },
  },
  mounted() {
    this.affixedClientHeight = this.$el.children[0].clientHeight;
    this.wrapStyle = { height: `${this.affixedClientHeight}px` };
    window.addEventListener("scroll", this.handleScroll);
    window.addEventListener("resize", this.handleScroll);
  },
  beforeDestroy() {
    window.removeEventListener("scroll", this.handleScroll);
    window.removeEventListener("resize", this.handleScroll);
  },
};
</script>
<style >
.affix {
  position: fixed;
}
</style>

使用

<!-- 固钉距离 80px -->
        <my-affix :offset="80">
          <!-- parentClass 指定文章内容的父元素class值 -->
          <my-directory parentClass="article-content"></my-directory>
        </my-affix>

参考 https://2x.antdv.com/components/affix-cn

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值