index.js
4.47 KB
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import { VantComponent } from '../common/component';
const ROOT_ELEMENT = '.van-sticky';
VantComponent({
props: {
zIndex: {
type: Number,
value: 99
},
offsetTop: {
type: Number,
value: 0,
observer: 'observeContent'
},
disabled: {
type: Boolean,
observer(value) {
if (!this.mounted) {
return;
}
value ? this.disconnectObserver() : this.initObserver();
}
},
container: {
type: null,
observer(target) {
if (typeof target !== 'function' || !this.data.height) {
return;
}
this.observeContainer();
}
}
},
data: {
wrapStyle: '',
containerStyle: ''
},
methods: {
setStyle() {
const { offsetTop, height, fixed, zIndex } = this.data;
if (fixed) {
this.setData({
wrapStyle: `top: ${offsetTop}px;`,
containerStyle: `height: ${height}px; z-index: ${zIndex};`
});
}
else {
this.setData({
wrapStyle: '',
containerStyle: ''
});
}
},
getContainerRect() {
const nodesRef = this.data.container();
return new Promise(resolve => nodesRef.boundingClientRect(resolve).exec());
},
initObserver() {
this.disconnectObserver();
this.getRect(ROOT_ELEMENT).then((rect) => {
this.setData({ height: rect.height });
wx.nextTick(() => {
this.observeContent();
this.observeContainer();
});
});
},
disconnectObserver(observerName) {
if (observerName) {
const observer = this[observerName];
observer && observer.disconnect();
}
else {
this.contentObserver && this.contentObserver.disconnect();
this.containerObserver && this.containerObserver.disconnect();
}
},
observeContent() {
const { offsetTop } = this.data;
this.disconnectObserver('contentObserver');
const contentObserver = this.createIntersectionObserver({
thresholds: [0, 1]
});
this.contentObserver = contentObserver;
contentObserver.relativeToViewport({ top: -offsetTop });
contentObserver.observe(ROOT_ELEMENT, res => {
if (this.data.disabled) {
return;
}
this.setFixed(res.boundingClientRect.top);
});
},
observeContainer() {
if (typeof this.data.container !== 'function') {
return;
}
const { height } = this.data;
this.getContainerRect().then((rect) => {
this.containerHeight = rect.height;
this.disconnectObserver('containerObserver');
const containerObserver = this.createIntersectionObserver({
thresholds: [0, 1]
});
this.containerObserver = containerObserver;
containerObserver.relativeToViewport({
top: this.containerHeight - height
});
containerObserver.observe(ROOT_ELEMENT, res => {
if (this.data.disabled) {
return;
}
this.setFixed(res.boundingClientRect.top);
});
});
},
setFixed(top) {
const { offsetTop, height } = this.data;
const { containerHeight } = this;
const fixed = containerHeight && height
? top > height - containerHeight && top < offsetTop
: top < offsetTop;
this.$emit('scroll', {
scrollTop: top,
isFixed: fixed
});
this.setData({ fixed });
wx.nextTick(() => {
this.setStyle();
});
}
},
mounted() {
this.mounted = true;
if (!this.data.disabled) {
this.initObserver();
}
},
destroyed() {
this.disconnectObserver();
}
});