Vue Affix组件

在vue的项目中经常用到固钉,但是 element-ui 上并没有提供这样的组件可供使用,ant-design-vue 有提供,总不能为了这一个组件再去引入一个组件库吧

下面是一个封装好的 affix 组件,可以放到项目中直接使用

Affix.vue

复制代码
<template>
    <div class="affix-placeholder" :style="wrapStyle">
        <div :class="{'affix': affixed}" :style="styles">
            <slot></slot>
        </div>
    </div>
</template>
<script>
/**
* @file Affix.vue
* @author v_shenjieping@baidu.com
* @date 2018-12-11 10:09:50
*/
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 lang="sass">
.affix
    position: fixed
</style>
复制代码

使用方法也是非常简单

test.vue

复制代码
<template>
    <div class="test">
        <affix>
            <div>这是一个固钉组件</div>
        </affix>
        <affix :offset="40">
            <div>这是一个固钉组件</div>
        </affix>
    </div>
</template>

<script>
import Affix from '@/components/Affix';
export default {
    name: 'test',
    components: {
        Affix
    }
};
</script>
复制代码

API

参数 说明 类型 默认值
offset 距离窗口顶部达到指定偏移量后触发 Number 0
boundary 设置 Affix 的活动范围,值为affix上级元素的id(可以是父元素,也可以是父元素的父元素...) String(#parent)  
on-affix 固定状态改变时触发的回调函数 Function(affixed)

posted on   sjpqy  阅读(9910)  评论(1编辑  收藏  举报

编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示