Skip to content

Commit 1f09212

Browse files
authored
react:重构sticky组件示例
* feat:新增吸顶容器 Sticky组件 * refact:将top属性的单位修改为rpx * react:重构sticky组件示例
1 parent 9c1af0f commit 1f09212

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1892
-19
lines changed

dist/sticky-item/index.js

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
Component({
2+
externalClasses: ["l-class", "l-header-wrapper-class", "l-header-class", "l-header-sticky-class", "l-body-class"],
3+
options: {
4+
multipleSlots: true
5+
},
6+
7+
relations: {
8+
"../sticky/index": {
9+
type: "parent"
10+
}
11+
},
12+
13+
properties: {
14+
/**
15+
* 吸顶容器吸顶后距离视窗 顶部的距离
16+
*/
17+
top: {
18+
type: Number,
19+
value: 0
20+
}
21+
},
22+
23+
data: {
24+
/**
25+
* 显示模式
26+
*/
27+
mode: undefined,
28+
/**
29+
* 当前sticky-item的索引值
30+
*/
31+
index: undefined,
32+
33+
/**
34+
* sticky-item是否固定到页面顶部
35+
*/
36+
isFixedTop: false,
37+
38+
/**
39+
* sticky-item组件距离页面顶部的高度
40+
*/
41+
stickyItemTop: 0,
42+
43+
/**
44+
* sticky-item组件自身的高度
45+
*/
46+
stickyItemHeight: 0,
47+
48+
/**
49+
* sticky-item组件包装高度
50+
*/
51+
stickyItemWrapperHeight: undefined
52+
},
53+
54+
lifetimes: {
55+
ready: function () {
56+
// 设置显示模式
57+
const parent = this.getParentComponet()
58+
const mode = parent.data.mode
59+
this.setData({ mode })
60+
}
61+
},
62+
63+
methods: {
64+
65+
/**
66+
* 更新sticky-item组件的position属性
67+
* 判断sticky-item组件是否固定到顶部
68+
* @param {Number} scrollTop 页面垂直滚动距离
69+
*/
70+
updateStickyItemPosition(scrollTop) {
71+
const parent = this.getParentComponet()
72+
const { index, stickyItemTop, stickyItemHeight, top } = this.data
73+
const isFixedTop = scrollTop > stickyItemTop - top && scrollTop < stickyItemHeight + stickyItemTop - top
74+
75+
// 避免频繁setData
76+
if (this.data.isFixedTop === isFixedTop) {
77+
return
78+
}
79+
80+
if (isFixedTop) {
81+
// 触发吸附事件
82+
parent.triggerEvent("linsticky", { index })
83+
} else {
84+
// 触发脱落事件
85+
parent.triggerEvent("linunsticky", { index })
86+
}
87+
88+
this.setData({ isFixedTop })
89+
},
90+
91+
92+
/**
93+
* 更新sticky-item组件的基础数据
94+
* @param {Number} index 当前sticky-item的索引值
95+
*/
96+
updateStickyItemBaseData(index) {
97+
// 设置索引值
98+
this.setData({ index })
99+
// 从父级组件获取页面垂直滚动距离
100+
const parent = this.getParentComponet()
101+
const scrollTop = parent.data.scrollTop
102+
103+
104+
const query = wx.createSelectorQuery().in(this)
105+
106+
/**
107+
* 设置sticky-item组件距页面顶部的距离
108+
* 和sticky-item组件的高度
109+
*/
110+
query
111+
.select(".l-sticky-item")
112+
.boundingClientRect((res) => {
113+
this.setData({
114+
stickyItemTop: res.top + scrollTop,
115+
stickyItemHeight: res.height
116+
})
117+
}).exec()
118+
119+
// 设置sticky-item-header外层容器高度
120+
query
121+
.select(".l-sticky-item-header")
122+
.boundingClientRect((res) => {
123+
this.setData({
124+
stickyItemWrapperHeight: res.height
125+
})
126+
}).exec()
127+
},
128+
129+
/**
130+
* 获取父级组件-sticky实例
131+
*/
132+
getParentComponet() {
133+
const stickys = this.getRelationNodes("../sticky/index")
134+
if (stickys.length === 0) {
135+
return
136+
}
137+
return stickys[0]
138+
}
139+
}
140+
})

dist/sticky-item/index.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"component": true,
3+
"usingComponents": {}
4+
}

dist/sticky-item/index.wxml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<view class="l-sticky-item l-class">
2+
<!-- sticky-item-header-wrapper用于占位,因为sticky-item-header吸顶后脱离文档流,导致sticky-item组件高度减小 -->
3+
<view
4+
class="l-sticky-item-header-wrapper l-header-wrapper-class"
5+
style="height:{{isFixedTop&&stickyItemWrapperHeight?stickyItemWrapperHeight+'px':'auto'}}"
6+
></view>
7+
<view
8+
style="{{mode==='js'?(isFixedTop?'position:fixed;':''):''}} top:{{top}}rpx"
9+
class="l-sticky-item-header l-sticky-item-header{{mode==='js'?(isFixedTop?'-fixed l-header-sticky-class':''):(mode==='css'?'-sticky l-header-sticky-class':'')}} l-header-class"
10+
>
11+
<slot name="header"></slot>
12+
</view>
13+
<view class="l-sticky-item-body l-body-class">
14+
<slot name="body"></slot>
15+
</view>
16+
</view>

dist/sticky-item/index.wxss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.l-sticky-item{display:flex;flex-direction:column}.l-sticky-wrapper{overflow:visible}.l-sticky-item-header{width:100%}.l-sticky-item-header-fixed{position:fixed;top:0}@supports (position:sticky){.l-sticky-item-header-sticky{position:sticky}}

dist/sticky/index.js

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
Component({
2+
externalClasses: ["l-class"],
3+
4+
relations: {
5+
"../sticky-item/index": {
6+
type: "child",
7+
linked() {
8+
this.checkSupportCssSticky().then((isSupportCssSticky) => {
9+
if (!isSupportCssSticky) {
10+
this.updateStickyItemsSizeData()
11+
}
12+
})
13+
},
14+
linkChanged() {
15+
this.checkSupportCssSticky().then((isSupportCssSticky) => {
16+
if (!isSupportCssSticky) {
17+
this.updateStickyItemsSizeData()
18+
}
19+
})
20+
},
21+
unlinked() {
22+
this.checkSupportCssSticky().then((isSupportCssSticky) => {
23+
if (!isSupportCssSticky) {
24+
this.updateStickyItemsSizeData()
25+
}
26+
})
27+
}
28+
}
29+
},
30+
31+
properties: {
32+
/**
33+
* 吸顶容器实现模式
34+
* js - 使用js实现
35+
* css - 使用css实现,若不支持css,则回滚到js模式
36+
*/
37+
mode: {
38+
type: String,
39+
value: "js"
40+
},
41+
42+
/**
43+
* 页面垂直滚动的距离
44+
*/
45+
scrollTop: Number,
46+
},
47+
48+
observers: {
49+
/**
50+
* 监听页面滚动,实时更新吸顶容器位置
51+
*/
52+
"scrollTop": function () {
53+
this.checkSupportCssSticky().then((isSupportCssSticky) => {
54+
if (!isSupportCssSticky) {
55+
this.updateStickyItemsPosition()
56+
}
57+
})
58+
}
59+
},
60+
61+
lifetimes: {
62+
attached() {
63+
this.checkSupportCssSticky().then((isSupportCssSticky) => {
64+
if (!isSupportCssSticky) {
65+
this.initSticky()
66+
}
67+
})
68+
}
69+
},
70+
71+
methods: {
72+
73+
/**
74+
* 创建wx.lin函数
75+
*/
76+
initSticky() {
77+
wx.lin = wx.lin || {}
78+
wx.lin.flushSticky = () => {
79+
this.updateStickyItemsSizeData()
80+
}
81+
82+
// 传入scrollTop的值的函数
83+
wx.lin.setScrollTop = (scrollTop) => {
84+
this.data.scrollTop = scrollTop
85+
this.checkSupportCssSticky().then((isSupportCssSticky) => {
86+
if (!isSupportCssSticky) {
87+
this.updateStickyItemsPosition()
88+
}
89+
})
90+
}
91+
},
92+
93+
/**
94+
* 更新所有sticky-item组件的position属性
95+
*/
96+
updateStickyItemsPosition() {
97+
const stickyItemNodes = this.getStickyItemNodes()
98+
for (let stickyItemNode of stickyItemNodes) {
99+
stickyItemNode.updateStickyItemPosition(this.data.scrollTop)
100+
}
101+
},
102+
103+
/**
104+
* 更新所有sticky-item组件的基础数据
105+
*/
106+
updateStickyItemsSizeData() {
107+
const stickyItemNodes = this.getStickyItemNodes()
108+
stickyItemNodes.forEach((item, index) => {
109+
item.updateStickyItemBaseData(index)
110+
})
111+
},
112+
113+
/**
114+
* 获取所有的sticky-item组件
115+
* @return {Object} sticky-item组件集合
116+
*/
117+
getStickyItemNodes() {
118+
return this.getRelationNodes("../sticky-item/index")
119+
},
120+
121+
/**
122+
* 检测当前webview内核是否支持css设置sticky
123+
* @return {Boolean} css是否支持设置sticky
124+
*/
125+
checkSupportCssSticky() {
126+
return new Promise((resolve) => {
127+
const stickyItemNodes = this.getStickyItemNodes()
128+
if (stickyItemNodes.length == 0) {
129+
resolve(false)
130+
}
131+
132+
// 根据position判断是否支持position:sticky
133+
wx
134+
.createSelectorQuery()
135+
.in(stickyItemNodes[0])
136+
.select(".l-sticky-item-header")
137+
.fields({ computedStyle: ["position"] })
138+
.exec((res) => {
139+
if (res[0] === null) {
140+
resolve(false)
141+
} else {
142+
resolve(res[0].position === "sticky")
143+
}
144+
})
145+
})
146+
},
147+
}
148+
})

dist/sticky/index.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"component": true,
3+
"usingComponents": {}
4+
}

dist/sticky/index.wxml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<view class="l-sticky l-class">
2+
<slot></slot>
3+
</view>

dist/sticky/index.wxss

Whitespace-only changes.

examples/app.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,11 @@
107107
"pages/grid/index",
108108
"pages/card/index",
109109
"pages/water-flow/index",
110-
"pages/album/index"
110+
"pages/album/index",
111+
"pages/sticky/index",
112+
"pages/sticky/pages/sticky-base/index",
113+
"pages/sticky/pages/sticky-appoint/index",
114+
"pages/sticky/pages/sticky-dynamic/index"
111115
]
112116
},
113117
{

0 commit comments

Comments
 (0)