@mpxjs/webpack-plugin 2.10.7 → 2.10.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/dependencies/RecordPageConfigsMapDependency.js +1 -1
- package/lib/dependencies/RequireExternalDependency.js +61 -0
- package/lib/file-loader.js +3 -2
- package/lib/index.js +55 -9
- package/lib/json-compiler/index.js +1 -0
- package/lib/parser.js +1 -1
- package/lib/platform/json/wx/index.js +43 -25
- package/lib/platform/style/wx/index.js +7 -0
- package/lib/platform/template/wx/component-config/fix-component-name.js +2 -2
- package/lib/platform/template/wx/component-config/index.js +5 -1
- package/lib/platform/template/wx/component-config/sticky-header.js +23 -0
- package/lib/platform/template/wx/component-config/sticky-section.js +23 -0
- package/lib/react/LoadAsyncChunkModule.js +74 -0
- package/lib/react/index.js +3 -1
- package/lib/react/processJSON.js +74 -13
- package/lib/react/processScript.js +6 -6
- package/lib/react/script-helper.js +100 -41
- package/lib/runtime/components/react/context.ts +12 -3
- package/lib/runtime/components/react/dist/context.js +4 -1
- package/lib/runtime/components/react/dist/mpx-async-suspense.jsx +135 -0
- package/lib/runtime/components/react/dist/mpx-button.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +8 -6
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +31 -15
- package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +117 -0
- package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +45 -0
- package/lib/runtime/components/react/mpx-async-suspense.tsx +180 -0
- package/lib/runtime/components/react/mpx-button.tsx +3 -2
- package/lib/runtime/components/react/mpx-movable-view.tsx +8 -4
- package/lib/runtime/components/react/mpx-scroll-view.tsx +84 -59
- package/lib/runtime/components/react/mpx-sticky-header.tsx +181 -0
- package/lib/runtime/components/react/mpx-sticky-section.tsx +96 -0
- package/lib/runtime/components/web/mpx-scroll-view.vue +18 -4
- package/lib/runtime/components/web/mpx-sticky-header.vue +99 -0
- package/lib/runtime/components/web/mpx-sticky-section.vue +15 -0
- package/lib/runtime/optionProcessorReact.d.ts +18 -0
- package/lib/runtime/optionProcessorReact.js +30 -0
- package/lib/script-setup-compiler/index.js +27 -5
- package/lib/template-compiler/bind-this.js +2 -1
- package/lib/template-compiler/compiler.js +4 -3
- package/lib/utils/dom-tag-config.js +17 -3
- package/lib/utils/trans-async-sub-rules.js +19 -0
- package/lib/web/script-helper.js +1 -1
- package/package.json +4 -4
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
* ✔ bindscroll
|
|
33
33
|
*/
|
|
34
34
|
import { ScrollView, RefreshControl, Gesture, GestureDetector } from 'react-native-gesture-handler'
|
|
35
|
-
import { View, NativeSyntheticEvent, NativeScrollEvent, LayoutChangeEvent, ViewStyle } from 'react-native'
|
|
35
|
+
import { View, NativeSyntheticEvent, NativeScrollEvent, LayoutChangeEvent, ViewStyle, Animated as RNAnimated } from 'react-native'
|
|
36
36
|
import { isValidElement, Children, JSX, ReactNode, RefObject, useRef, useState, useEffect, forwardRef, useContext, useMemo, createElement } from 'react'
|
|
37
37
|
import Animated, { useAnimatedRef, useSharedValue, withTiming, useAnimatedStyle, runOnJS } from 'react-native-reanimated'
|
|
38
38
|
import { warn, hasOwn } from '@mpxjs/utils'
|
|
@@ -43,48 +43,49 @@ import { IntersectionObserverContext, ScrollViewContext } from './context'
|
|
|
43
43
|
import Portal from './mpx-portal'
|
|
44
44
|
|
|
45
45
|
interface ScrollViewProps {
|
|
46
|
-
children?: ReactNode
|
|
47
|
-
enhanced?: boolean
|
|
48
|
-
bounces?: boolean
|
|
49
|
-
style?: ViewStyle
|
|
50
|
-
|
|
51
|
-
'scroll-
|
|
52
|
-
'
|
|
53
|
-
'
|
|
54
|
-
'
|
|
55
|
-
'
|
|
56
|
-
'
|
|
57
|
-
'
|
|
58
|
-
'
|
|
59
|
-
'refresher-
|
|
60
|
-
'refresher-
|
|
61
|
-
'refresher-
|
|
62
|
-
'refresher-
|
|
63
|
-
'
|
|
64
|
-
'scroll-
|
|
65
|
-
'
|
|
66
|
-
'
|
|
67
|
-
'
|
|
68
|
-
'enable-
|
|
69
|
-
'
|
|
70
|
-
'
|
|
71
|
-
'parent-
|
|
72
|
-
'parent-
|
|
73
|
-
'
|
|
74
|
-
'wait-for'?: Array<GestureHandler
|
|
75
|
-
'simultaneous-handlers'?: Array<GestureHandler
|
|
76
|
-
'scroll-event-throttle'?:
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
46
|
+
children?: ReactNode;
|
|
47
|
+
enhanced?: boolean;
|
|
48
|
+
bounces?: boolean;
|
|
49
|
+
style?: ViewStyle;
|
|
50
|
+
'scroll-x'?: boolean;
|
|
51
|
+
'scroll-y'?: boolean;
|
|
52
|
+
'enable-back-to-top'?: boolean;
|
|
53
|
+
'show-scrollbar'?: boolean;
|
|
54
|
+
'paging-enabled'?: boolean;
|
|
55
|
+
'upper-threshold'?: number;
|
|
56
|
+
'lower-threshold'?: number;
|
|
57
|
+
'scroll-with-animation'?: boolean;
|
|
58
|
+
'refresher-triggered'?: boolean;
|
|
59
|
+
'refresher-enabled'?: boolean;
|
|
60
|
+
'refresher-default-style'?: 'black' | 'white' | 'none';
|
|
61
|
+
'refresher-background'?: string;
|
|
62
|
+
'refresher-threshold'?: number;
|
|
63
|
+
'scroll-top'?: number;
|
|
64
|
+
'scroll-left'?: number;
|
|
65
|
+
'enable-offset'?: boolean;
|
|
66
|
+
'scroll-into-view'?: string;
|
|
67
|
+
'enable-trigger-intersection-observer'?: boolean;
|
|
68
|
+
'enable-var'?: boolean;
|
|
69
|
+
'external-var-context'?: Record<string, any>;
|
|
70
|
+
'parent-font-size'?: number;
|
|
71
|
+
'parent-width'?: number;
|
|
72
|
+
'parent-height'?: number;
|
|
73
|
+
'enable-sticky'?: boolean;
|
|
74
|
+
'wait-for'?: Array<GestureHandler>;
|
|
75
|
+
'simultaneous-handlers'?: Array<GestureHandler>;
|
|
76
|
+
'scroll-event-throttle'?:number;
|
|
77
|
+
'scroll-into-view-offset'?: number;
|
|
78
|
+
bindscrolltoupper?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
79
|
+
bindscrolltolower?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
80
|
+
bindscroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
81
|
+
bindrefresherrefresh?: (event: NativeSyntheticEvent<unknown>) => void;
|
|
82
|
+
binddragstart?: (event: NativeSyntheticEvent<DragEvent>) => void;
|
|
83
|
+
binddragging?: (event: NativeSyntheticEvent<DragEvent>) => void;
|
|
84
|
+
binddragend?: (event: NativeSyntheticEvent<DragEvent>) => void;
|
|
85
|
+
bindtouchstart?: (event: NativeSyntheticEvent<TouchEvent>) => void;
|
|
86
|
+
bindtouchmove?: (event: NativeSyntheticEvent<TouchEvent>) => void;
|
|
87
|
+
bindtouchend?: (event: NativeSyntheticEvent<TouchEvent>) => void;
|
|
88
|
+
bindscrollend?: (event: NativeSyntheticEvent<TouchEvent>) => void;
|
|
88
89
|
__selectRef?: (selector: string, nodeType: 'node' | 'component', all?: boolean) => HandlerRef<any, any>
|
|
89
90
|
}
|
|
90
91
|
type ScrollAdditionalProps = {
|
|
@@ -109,6 +110,8 @@ type ScrollAdditionalProps = {
|
|
|
109
110
|
onMomentumScrollEnd?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void
|
|
110
111
|
}
|
|
111
112
|
|
|
113
|
+
const AnimatedScrollView = RNAnimated.createAnimatedComponent(ScrollView) as React.ComponentType<any>
|
|
114
|
+
|
|
112
115
|
const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, ScrollViewProps>((scrollViewProps: ScrollViewProps = {}, ref): JSX.Element => {
|
|
113
116
|
const { textProps, innerProps: props = {} } = splitProps(scrollViewProps)
|
|
114
117
|
const {
|
|
@@ -145,10 +148,14 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
145
148
|
'parent-height': parentHeight,
|
|
146
149
|
'simultaneous-handlers': originSimultaneousHandlers,
|
|
147
150
|
'wait-for': waitFor,
|
|
151
|
+
'enable-sticky': enableSticky,
|
|
148
152
|
'scroll-event-throttle': scrollEventThrottle = 0,
|
|
153
|
+
'scroll-into-view-offset': scrollIntoViewOffset = 0,
|
|
149
154
|
__selectRef
|
|
150
155
|
} = props
|
|
151
156
|
|
|
157
|
+
const scrollOffset = useRef(new RNAnimated.Value(0)).current
|
|
158
|
+
|
|
152
159
|
const simultaneousHandlers = flatGesture(originSimultaneousHandlers)
|
|
153
160
|
const waitForHandlers = flatGesture(waitFor)
|
|
154
161
|
|
|
@@ -180,7 +187,7 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
180
187
|
const initialTimeout = useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
181
188
|
const intersectionObservers = useContext(IntersectionObserverContext)
|
|
182
189
|
|
|
183
|
-
const firstScrollIntoViewChange = useRef<boolean>(
|
|
190
|
+
const firstScrollIntoViewChange = useRef<boolean>(true)
|
|
184
191
|
|
|
185
192
|
const refreshColor = {
|
|
186
193
|
black: ['#000'],
|
|
@@ -213,19 +220,21 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
213
220
|
pagingEnabled,
|
|
214
221
|
fastDeceleration: false,
|
|
215
222
|
decelerationDisabled: false,
|
|
216
|
-
scrollTo
|
|
223
|
+
scrollTo,
|
|
224
|
+
scrollIntoView: handleScrollIntoView
|
|
217
225
|
},
|
|
218
226
|
gestureRef: scrollViewRef
|
|
219
227
|
})
|
|
220
228
|
|
|
229
|
+
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: scrollViewRef, onLayout })
|
|
230
|
+
|
|
221
231
|
const contextValue = useMemo(() => {
|
|
222
232
|
return {
|
|
223
|
-
gestureRef: scrollViewRef
|
|
233
|
+
gestureRef: scrollViewRef,
|
|
234
|
+
scrollOffset
|
|
224
235
|
}
|
|
225
236
|
}, [])
|
|
226
237
|
|
|
227
|
-
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: scrollViewRef, onLayout })
|
|
228
|
-
|
|
229
238
|
const hasRefresherLayoutRef = useRef(false)
|
|
230
239
|
|
|
231
240
|
// layout 完成前先隐藏,避免安卓闪烁问题
|
|
@@ -251,13 +260,15 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
251
260
|
|
|
252
261
|
useEffect(() => {
|
|
253
262
|
if (scrollIntoView && __selectRef) {
|
|
254
|
-
if (
|
|
255
|
-
setTimeout(
|
|
263
|
+
if (firstScrollIntoViewChange.current) {
|
|
264
|
+
setTimeout(() => {
|
|
265
|
+
handleScrollIntoView(scrollIntoView, { offset: scrollIntoViewOffset, animated: scrollWithAnimation })
|
|
266
|
+
})
|
|
256
267
|
} else {
|
|
257
|
-
handleScrollIntoView()
|
|
268
|
+
handleScrollIntoView(scrollIntoView, { offset: scrollIntoViewOffset, animated: scrollWithAnimation })
|
|
258
269
|
}
|
|
259
270
|
}
|
|
260
|
-
firstScrollIntoViewChange.current =
|
|
271
|
+
firstScrollIntoViewChange.current = false
|
|
261
272
|
}, [scrollIntoView])
|
|
262
273
|
|
|
263
274
|
useEffect(() => {
|
|
@@ -280,14 +291,16 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
280
291
|
scrollToOffset(left, top, animated)
|
|
281
292
|
}
|
|
282
293
|
|
|
283
|
-
function handleScrollIntoView () {
|
|
284
|
-
const refs = __selectRef!(`#${
|
|
294
|
+
function handleScrollIntoView (selector = '', { offset = 0, animated = true } = {}) {
|
|
295
|
+
const refs = __selectRef!(`#${selector}`, 'node')
|
|
285
296
|
if (!refs) return
|
|
286
297
|
const { nodeRef } = refs.getNodeInstance()
|
|
287
298
|
nodeRef.current?.measureLayout(
|
|
288
299
|
scrollViewRef.current,
|
|
289
300
|
(left: number, top: number) => {
|
|
290
|
-
|
|
301
|
+
const adjustedLeft = scrollX ? left + offset : left
|
|
302
|
+
const adjustedTop = scrollY ? top + offset : top
|
|
303
|
+
scrollToOffset(adjustedLeft, adjustedTop, animated)
|
|
291
304
|
}
|
|
292
305
|
)
|
|
293
306
|
}
|
|
@@ -487,6 +500,16 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
487
500
|
updateIntersection()
|
|
488
501
|
}
|
|
489
502
|
|
|
503
|
+
const scrollHandler = RNAnimated.event(
|
|
504
|
+
[{ nativeEvent: { contentOffset: { y: scrollOffset } } }],
|
|
505
|
+
{
|
|
506
|
+
useNativeDriver: true,
|
|
507
|
+
listener: (event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
508
|
+
onScroll(event)
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
)
|
|
512
|
+
|
|
490
513
|
function onScrollDragStart (e: NativeSyntheticEvent<NativeScrollEvent>) {
|
|
491
514
|
hasCallScrollToLower.current = false
|
|
492
515
|
hasCallScrollToUpper.current = false
|
|
@@ -661,7 +684,7 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
661
684
|
scrollEnabled: !enableScroll ? false : !!(scrollX || scrollY),
|
|
662
685
|
bounces: false,
|
|
663
686
|
ref: scrollViewRef,
|
|
664
|
-
onScroll: onScroll,
|
|
687
|
+
onScroll: enableSticky ? scrollHandler : onScroll,
|
|
665
688
|
onContentSizeChange: onContentSizeChange,
|
|
666
689
|
bindtouchstart: ((enhanced && binddragstart) || bindtouchstart) && onScrollTouchStart,
|
|
667
690
|
bindtouchmove: ((enhanced && binddragging) || bindtouchmove) && onScrollTouchMove,
|
|
@@ -716,11 +739,13 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
716
739
|
'bindrefresherrefresh'
|
|
717
740
|
], { layoutRef })
|
|
718
741
|
|
|
742
|
+
const ScrollViewComponent = enableSticky ? AnimatedScrollView : ScrollView
|
|
743
|
+
|
|
719
744
|
const withRefresherScrollView = createElement(
|
|
720
745
|
GestureDetector,
|
|
721
746
|
{ gesture: panGesture },
|
|
722
747
|
createElement(
|
|
723
|
-
|
|
748
|
+
ScrollViewComponent,
|
|
724
749
|
innerProps,
|
|
725
750
|
createElement(
|
|
726
751
|
Animated.View,
|
|
@@ -748,8 +773,8 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
748
773
|
)
|
|
749
774
|
|
|
750
775
|
const commonScrollView = createElement(
|
|
751
|
-
|
|
752
|
-
extendObject(innerProps, {
|
|
776
|
+
ScrollViewComponent,
|
|
777
|
+
extendObject({}, innerProps, {
|
|
753
778
|
refreshControl: refresherEnabled
|
|
754
779
|
? createElement(RefreshControl, extendObject({
|
|
755
780
|
progressBackgroundColor: refresherBackground,
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { useEffect, useRef, useContext, forwardRef, useMemo, createElement, ReactNode, useId } from 'react'
|
|
2
|
+
import { Animated, StyleSheet, View, NativeSyntheticEvent, ViewStyle, LayoutChangeEvent, useAnimatedValue } from 'react-native'
|
|
3
|
+
import { ScrollViewContext, StickyContext } from './context'
|
|
4
|
+
import useNodesRef, { HandlerRef } from './useNodesRef'
|
|
5
|
+
import { splitProps, splitStyle, useTransformStyle, wrapChildren, useLayout, extendObject } from './utils'
|
|
6
|
+
import { error } from '@mpxjs/utils'
|
|
7
|
+
import useInnerProps, { getCustomEvent } from './getInnerListeners'
|
|
8
|
+
|
|
9
|
+
interface StickyHeaderProps {
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
style?: ViewStyle;
|
|
12
|
+
padding?: [number, number, number, number];
|
|
13
|
+
'offset-top'?: number;
|
|
14
|
+
'enable-var'?: boolean;
|
|
15
|
+
'external-var-context'?: Record<string, any>;
|
|
16
|
+
'parent-font-size'?: number;
|
|
17
|
+
'parent-width'?: number;
|
|
18
|
+
'parent-height'?: number;
|
|
19
|
+
bindstickontopchange?: (e: NativeSyntheticEvent<unknown>) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const _StickyHeader = forwardRef<HandlerRef<View, StickyHeaderProps>, StickyHeaderProps>((stickyHeaderProps: StickyHeaderProps = {}, ref): JSX.Element => {
|
|
23
|
+
const { textProps, innerProps: props = {} } = splitProps(stickyHeaderProps)
|
|
24
|
+
const {
|
|
25
|
+
style,
|
|
26
|
+
bindstickontopchange,
|
|
27
|
+
padding = [0, 0, 0, 0],
|
|
28
|
+
'offset-top': offsetTop = 0,
|
|
29
|
+
'enable-var': enableVar,
|
|
30
|
+
'external-var-context': externalVarContext,
|
|
31
|
+
'parent-font-size': parentFontSize,
|
|
32
|
+
'parent-width': parentWidth,
|
|
33
|
+
'parent-height': parentHeight
|
|
34
|
+
} = props
|
|
35
|
+
|
|
36
|
+
const scrollViewContext = useContext(ScrollViewContext)
|
|
37
|
+
const stickyContext = useContext(StickyContext)
|
|
38
|
+
const { scrollOffset } = scrollViewContext
|
|
39
|
+
const { registerStickyHeader, unregisterStickyHeader } = stickyContext
|
|
40
|
+
const headerRef = useRef<View>(null)
|
|
41
|
+
const isStickOnTopRef = useRef(false)
|
|
42
|
+
const id = useId()
|
|
43
|
+
|
|
44
|
+
const {
|
|
45
|
+
normalStyle,
|
|
46
|
+
hasVarDec,
|
|
47
|
+
varContextRef,
|
|
48
|
+
hasSelfPercent,
|
|
49
|
+
setWidth,
|
|
50
|
+
setHeight
|
|
51
|
+
} = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
|
|
52
|
+
|
|
53
|
+
const { layoutRef, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: headerRef, onLayout })
|
|
54
|
+
|
|
55
|
+
const { textStyle, innerStyle = {} } = splitStyle(normalStyle)
|
|
56
|
+
|
|
57
|
+
const headerTopAnimated = useAnimatedValue(0)
|
|
58
|
+
// harmony animatedValue 不支持通过 _value 访问
|
|
59
|
+
const headerTopRef = useRef(0)
|
|
60
|
+
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
registerStickyHeader({ key: id, updatePosition })
|
|
63
|
+
return () => {
|
|
64
|
+
unregisterStickyHeader(id)
|
|
65
|
+
}
|
|
66
|
+
}, [])
|
|
67
|
+
|
|
68
|
+
function updatePosition () {
|
|
69
|
+
if (headerRef.current) {
|
|
70
|
+
const scrollViewRef = scrollViewContext.gestureRef
|
|
71
|
+
if (scrollViewRef && scrollViewRef.current) {
|
|
72
|
+
headerRef.current.measureLayout(
|
|
73
|
+
scrollViewRef.current,
|
|
74
|
+
(left: number, top: number) => {
|
|
75
|
+
Animated.timing(headerTopAnimated, {
|
|
76
|
+
toValue: top,
|
|
77
|
+
duration: 0,
|
|
78
|
+
useNativeDriver: true
|
|
79
|
+
}).start()
|
|
80
|
+
headerTopRef.current = top
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
} else {
|
|
84
|
+
error('StickyHeader measureLayout error: scrollViewRef is not a valid native component reference')
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function onLayout (e: LayoutChangeEvent) {
|
|
90
|
+
updatePosition()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
useNodesRef(props, ref, headerRef, {
|
|
94
|
+
style: normalStyle
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (!bindstickontopchange) return
|
|
99
|
+
|
|
100
|
+
const listener = scrollOffset.addListener((state: { value: number }) => {
|
|
101
|
+
const currentScrollValue = state.value
|
|
102
|
+
const newIsStickOnTop = currentScrollValue > headerTopRef.current
|
|
103
|
+
if (newIsStickOnTop !== isStickOnTopRef.current) {
|
|
104
|
+
isStickOnTopRef.current = newIsStickOnTop
|
|
105
|
+
bindstickontopchange(
|
|
106
|
+
getCustomEvent('stickontopchange', {}, {
|
|
107
|
+
detail: {
|
|
108
|
+
isStickOnTop: newIsStickOnTop
|
|
109
|
+
},
|
|
110
|
+
layoutRef
|
|
111
|
+
}, props))
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
return () => {
|
|
116
|
+
scrollOffset.removeListener(listener)
|
|
117
|
+
}
|
|
118
|
+
}, [])
|
|
119
|
+
|
|
120
|
+
const animatedStyle = useMemo(() => {
|
|
121
|
+
const translateY = Animated.subtract(scrollOffset, headerTopAnimated).interpolate({
|
|
122
|
+
inputRange: [0, 1],
|
|
123
|
+
outputRange: [0, 1],
|
|
124
|
+
extrapolateLeft: 'clamp',
|
|
125
|
+
extrapolateRight: 'extend'
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
const finalTranslateY = offsetTop === 0
|
|
129
|
+
? translateY
|
|
130
|
+
: Animated.add(
|
|
131
|
+
translateY,
|
|
132
|
+
Animated.subtract(scrollOffset, headerTopAnimated).interpolate({
|
|
133
|
+
inputRange: [0, 1],
|
|
134
|
+
outputRange: [0, offsetTop],
|
|
135
|
+
extrapolate: 'clamp'
|
|
136
|
+
})
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
transform: [{ translateY: finalTranslateY }]
|
|
141
|
+
}
|
|
142
|
+
}, [scrollOffset, headerTopAnimated, offsetTop])
|
|
143
|
+
|
|
144
|
+
const innerProps = useInnerProps(extendObject({}, props, {
|
|
145
|
+
ref: headerRef,
|
|
146
|
+
style: extendObject({}, styles.content, innerStyle, animatedStyle, {
|
|
147
|
+
paddingTop: padding[0] || 0,
|
|
148
|
+
paddingRight: padding[1] || 0,
|
|
149
|
+
paddingBottom: padding[2] || 0,
|
|
150
|
+
paddingLeft: padding[3] || 0
|
|
151
|
+
})
|
|
152
|
+
}, layoutProps), [], { layoutRef })
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
createElement(
|
|
156
|
+
Animated.View,
|
|
157
|
+
innerProps,
|
|
158
|
+
wrapChildren(
|
|
159
|
+
props,
|
|
160
|
+
{
|
|
161
|
+
hasVarDec,
|
|
162
|
+
varContext: varContextRef.current,
|
|
163
|
+
textStyle,
|
|
164
|
+
textProps
|
|
165
|
+
}
|
|
166
|
+
)
|
|
167
|
+
)
|
|
168
|
+
)
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
const styles = StyleSheet.create({
|
|
172
|
+
content: {
|
|
173
|
+
width: '100%',
|
|
174
|
+
zIndex: 10,
|
|
175
|
+
// harmony 需要手动设置 relative, zIndex 才生效
|
|
176
|
+
position: 'relative'
|
|
177
|
+
}
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
_StickyHeader.displayName = 'MpxStickyHeader'
|
|
181
|
+
export default _StickyHeader
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
|
|
2
|
+
import { useRef, forwardRef, createElement, ReactNode, useCallback, useMemo } from 'react'
|
|
3
|
+
import { View, ViewStyle } from 'react-native'
|
|
4
|
+
import useNodesRef, { HandlerRef } from './useNodesRef'
|
|
5
|
+
import { splitProps, splitStyle, useTransformStyle, wrapChildren, useLayout, extendObject } from './utils'
|
|
6
|
+
import { StickyContext } from './context'
|
|
7
|
+
import useInnerProps from './getInnerListeners'
|
|
8
|
+
|
|
9
|
+
interface StickySectionProps {
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
style?: ViewStyle;
|
|
12
|
+
'offset-top'?: number;
|
|
13
|
+
'enable-var'?: boolean;
|
|
14
|
+
'external-var-context'?: Record<string, any>;
|
|
15
|
+
'parent-font-size'?: number;
|
|
16
|
+
'parent-width'?: number;
|
|
17
|
+
'parent-height'?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const _StickySection = forwardRef<HandlerRef<View, StickySectionProps>, StickySectionProps>((stickySectionProps: StickySectionProps = {}, ref): JSX.Element => {
|
|
21
|
+
const { textProps, innerProps: props = {} } = splitProps(stickySectionProps)
|
|
22
|
+
const {
|
|
23
|
+
style,
|
|
24
|
+
'enable-var': enableVar,
|
|
25
|
+
'external-var-context': externalVarContext,
|
|
26
|
+
'parent-font-size': parentFontSize,
|
|
27
|
+
'parent-width': parentWidth,
|
|
28
|
+
'parent-height': parentHeight
|
|
29
|
+
} = props
|
|
30
|
+
const sectionRef = useRef<View>(null)
|
|
31
|
+
|
|
32
|
+
const {
|
|
33
|
+
normalStyle,
|
|
34
|
+
hasVarDec,
|
|
35
|
+
varContextRef,
|
|
36
|
+
hasSelfPercent,
|
|
37
|
+
setWidth,
|
|
38
|
+
setHeight
|
|
39
|
+
} = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
|
|
40
|
+
|
|
41
|
+
const { layoutRef, layoutProps, layoutStyle } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: sectionRef, onLayout })
|
|
42
|
+
|
|
43
|
+
const { textStyle, innerStyle = {} } = splitStyle(normalStyle)
|
|
44
|
+
|
|
45
|
+
const stickyHeaders = useRef<Map<string, any>>(new Map())
|
|
46
|
+
|
|
47
|
+
const registerStickyHeader = useCallback((item: { id: string, updatePosition: Function }) => {
|
|
48
|
+
stickyHeaders.current.set(item.id, item)
|
|
49
|
+
}, [])
|
|
50
|
+
|
|
51
|
+
const unregisterStickyHeader = useCallback((id: string) => {
|
|
52
|
+
stickyHeaders.current.delete(id)
|
|
53
|
+
}, [])
|
|
54
|
+
|
|
55
|
+
const contextValue = useMemo(() => ({
|
|
56
|
+
registerStickyHeader,
|
|
57
|
+
unregisterStickyHeader
|
|
58
|
+
}), [])
|
|
59
|
+
|
|
60
|
+
useNodesRef(props, ref, sectionRef, {
|
|
61
|
+
style: normalStyle
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
function onLayout () {
|
|
65
|
+
stickyHeaders.current.forEach(item => {
|
|
66
|
+
item.updatePosition()
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const innerProps = useInnerProps(extendObject({}, props, {
|
|
71
|
+
style: extendObject(innerStyle, layoutStyle),
|
|
72
|
+
ref: sectionRef
|
|
73
|
+
}, layoutProps), [], { layoutRef })
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
createElement(
|
|
77
|
+
View,
|
|
78
|
+
innerProps,
|
|
79
|
+
createElement(
|
|
80
|
+
StickyContext.Provider,
|
|
81
|
+
{ value: contextValue },
|
|
82
|
+
wrapChildren(
|
|
83
|
+
props,
|
|
84
|
+
{
|
|
85
|
+
hasVarDec,
|
|
86
|
+
varContext: varContextRef.current,
|
|
87
|
+
textStyle,
|
|
88
|
+
textProps
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
))
|
|
92
|
+
)
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
_StickySection.displayName = 'MpxStickySection'
|
|
96
|
+
export default _StickySection
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script>
|
|
2
|
+
import { computed } from 'vue'
|
|
2
3
|
import getInnerListeners, { getCustomEvent } from './getInnerListeners'
|
|
3
4
|
import { processSize } from '../../utils'
|
|
4
5
|
import BScroll from '@better-scroll/core'
|
|
@@ -44,6 +45,7 @@
|
|
|
44
45
|
enhanced: Boolean,
|
|
45
46
|
refresherEnabled: Boolean,
|
|
46
47
|
refresherTriggered: Boolean,
|
|
48
|
+
enableSticky: Boolean,
|
|
47
49
|
refresherThreshold: {
|
|
48
50
|
type: Number,
|
|
49
51
|
default: 45
|
|
@@ -57,6 +59,12 @@
|
|
|
57
59
|
default: ''
|
|
58
60
|
}
|
|
59
61
|
},
|
|
62
|
+
provide () {
|
|
63
|
+
return {
|
|
64
|
+
scrollOffset: computed(() => -this.lastY || 0),
|
|
65
|
+
refreshVersion: computed(() => this.refreshVersion || 0)
|
|
66
|
+
}
|
|
67
|
+
},
|
|
60
68
|
data () {
|
|
61
69
|
return {
|
|
62
70
|
isLoading: false,
|
|
@@ -68,7 +76,8 @@
|
|
|
68
76
|
lastContentWidth: 0,
|
|
69
77
|
lastContentHeight: 0,
|
|
70
78
|
lastWrapperWidth: 0,
|
|
71
|
-
lastWrapperHeight: 0
|
|
79
|
+
lastWrapperHeight: 0,
|
|
80
|
+
refreshVersion: 0
|
|
72
81
|
}
|
|
73
82
|
},
|
|
74
83
|
computed: {
|
|
@@ -222,6 +231,9 @@
|
|
|
222
231
|
stop: 56
|
|
223
232
|
}
|
|
224
233
|
}
|
|
234
|
+
if(this.enableSticky) {
|
|
235
|
+
originBsOptions.useTransition = false
|
|
236
|
+
}
|
|
225
237
|
const bsOptions = Object.assign({}, originBsOptions, this.scrollOptions, { observeDOM: false })
|
|
226
238
|
this.bs = new BScroll(this.$refs.wrapper, bsOptions)
|
|
227
239
|
this.lastX = -this.currentX
|
|
@@ -251,7 +263,7 @@
|
|
|
251
263
|
}
|
|
252
264
|
this.lastX = x
|
|
253
265
|
this.lastY = y
|
|
254
|
-
}, 30, {
|
|
266
|
+
}, this.enableSticky ? 0 : 30, {
|
|
255
267
|
leading: true,
|
|
256
268
|
trailing: true
|
|
257
269
|
}))
|
|
@@ -392,6 +404,7 @@
|
|
|
392
404
|
this.lastContentHeight = scrollContentHeight
|
|
393
405
|
this.lastWrapperWidth = scrollWrapperWidth
|
|
394
406
|
this.lastWrapperHeight = scrollWrapperHeight
|
|
407
|
+
this.refreshVersion++
|
|
395
408
|
if (this.bs) this.bs.refresh()
|
|
396
409
|
}
|
|
397
410
|
},
|
|
@@ -458,7 +471,8 @@
|
|
|
458
471
|
}
|
|
459
472
|
|
|
460
473
|
const innerWrapper = createElement('div', {
|
|
461
|
-
ref: 'innerWrapper'
|
|
474
|
+
ref: 'innerWrapper',
|
|
475
|
+
class: 'mpx-inner-wrapper'
|
|
462
476
|
}, this.$slots.default)
|
|
463
477
|
|
|
464
478
|
const pullDownContent = this.refresherDefaultStyle !== 'none' ? createElement('div', {
|
|
@@ -568,4 +582,4 @@
|
|
|
568
582
|
background: rgba(255, 255, 255, .7)
|
|
569
583
|
100%
|
|
570
584
|
background: rgba(255, 255, 255, .3)
|
|
571
|
-
</style>
|
|
585
|
+
</style>
|