分享一个vue固钉组件

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

代码

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
<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>

使用

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

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


分享一个vue固钉组件
http://example.com/2021/04/13/分享一个vue固钉组件/
作者
shoukailiang
发布于
2021年4月13日
许可协议