@mpxjs/webpack-plugin 2.9.40 → 2.9.41-react.0
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/config.js +63 -97
- package/lib/dependencies/{RecordVueContentDependency.js → RecordLoaderContentDependency.js} +5 -5
- package/lib/dependencies/ResolveDependency.js +2 -2
- package/lib/helpers.js +5 -1
- package/lib/index.js +26 -21
- package/lib/loader.js +43 -97
- package/lib/native-loader.js +0 -1
- package/lib/platform/index.js +3 -0
- package/lib/platform/style/wx/index.js +414 -0
- package/lib/platform/template/wx/component-config/button.js +36 -0
- package/lib/platform/template/wx/component-config/image.js +15 -0
- package/lib/platform/template/wx/component-config/input.js +41 -0
- package/lib/platform/template/wx/component-config/scroll-view.js +27 -1
- package/lib/platform/template/wx/component-config/swiper-item.js +13 -1
- package/lib/platform/template/wx/component-config/swiper.js +25 -1
- package/lib/platform/template/wx/component-config/text.js +15 -0
- package/lib/platform/template/wx/component-config/textarea.js +39 -0
- package/lib/platform/template/wx/component-config/unsupported.js +18 -0
- package/lib/platform/template/wx/component-config/view.js +14 -0
- package/lib/platform/template/wx/index.js +88 -4
- package/lib/react/index.js +104 -0
- package/lib/react/processJSON.js +361 -0
- package/lib/react/processMainScript.js +21 -0
- package/lib/react/processScript.js +70 -0
- package/lib/react/processStyles.js +69 -0
- package/lib/react/processTemplate.js +153 -0
- package/lib/react/script-helper.js +133 -0
- package/lib/react/style-helper.js +91 -0
- package/lib/resolver/PackageEntryPlugin.js +1 -0
- package/lib/runtime/components/react/event.config.ts +32 -0
- package/lib/runtime/components/react/getInnerListeners.ts +289 -0
- package/lib/runtime/components/react/getInnerListeners.type.ts +68 -0
- package/lib/runtime/components/react/mpx-button.tsx +402 -0
- package/lib/runtime/components/react/mpx-image/index.tsx +351 -0
- package/lib/runtime/components/react/mpx-image/svg.tsx +21 -0
- package/lib/runtime/components/react/mpx-input.tsx +389 -0
- package/lib/runtime/components/react/mpx-scroll-view.tsx +412 -0
- package/lib/runtime/components/react/mpx-swiper/carouse.tsx +398 -0
- package/lib/runtime/components/react/mpx-swiper/index.tsx +68 -0
- package/lib/runtime/components/react/mpx-swiper/type.ts +69 -0
- package/lib/runtime/components/react/mpx-swiper-item.tsx +42 -0
- package/lib/runtime/components/react/mpx-text.tsx +106 -0
- package/lib/runtime/components/react/mpx-textarea.tsx +46 -0
- package/lib/runtime/components/react/mpx-view.tsx +397 -0
- package/lib/runtime/components/react/useNodesRef.ts +39 -0
- package/lib/runtime/components/react/utils.ts +92 -0
- package/lib/runtime/optionProcessorReact.d.ts +9 -0
- package/lib/runtime/optionProcessorReact.js +21 -0
- package/lib/runtime/stringify.wxs +3 -8
- package/lib/style-compiler/index.js +2 -1
- package/lib/template-compiler/compiler.js +287 -36
- package/lib/template-compiler/gen-node-react.js +95 -0
- package/lib/template-compiler/index.js +15 -24
- package/lib/utils/env.js +17 -0
- package/lib/utils/make-map.js +1 -1
- package/lib/utils/shallow-stringify.js +12 -12
- package/lib/web/index.js +123 -0
- package/lib/web/processJSON.js +3 -3
- package/lib/web/processMainScript.js +25 -23
- package/lib/web/processScript.js +12 -16
- package/lib/web/processTemplate.js +13 -12
- package/lib/web/script-helper.js +14 -22
- package/package.json +4 -3
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* swiper 实现
|
|
3
|
+
*/
|
|
4
|
+
import { View, ScrollView, Dimensions, LayoutChangeEvent, NativeSyntheticEvent, NativeScrollEvent, NativeScrollPoint } from 'react-native'
|
|
5
|
+
import React, { forwardRef, useState, useRef, useEffect, ReactNode } from 'react'
|
|
6
|
+
import { CarouseProps, CarouseState } from './type'
|
|
7
|
+
import { getCustomEvent } from '../getInnerListeners'
|
|
8
|
+
import useNodesRef, { HandlerRef } from '../useNodesRef' // 引入辅助函数
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 默认的Style类型
|
|
12
|
+
*/
|
|
13
|
+
const styles: { [key: string]: Object } = {
|
|
14
|
+
container_x: {
|
|
15
|
+
position: 'relative',
|
|
16
|
+
},
|
|
17
|
+
container_y: {
|
|
18
|
+
position: 'relative',
|
|
19
|
+
},
|
|
20
|
+
pagination_x: {
|
|
21
|
+
position: 'absolute',
|
|
22
|
+
bottom: 25,
|
|
23
|
+
left: 0,
|
|
24
|
+
right: 0,
|
|
25
|
+
flexDirection: 'row',
|
|
26
|
+
flex: 1,
|
|
27
|
+
justifyContent: 'center',
|
|
28
|
+
alignItems: 'center',
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
pagination_y: {
|
|
32
|
+
position: 'absolute',
|
|
33
|
+
right: 15,
|
|
34
|
+
top: 0,
|
|
35
|
+
bottom: 0,
|
|
36
|
+
flexDirection: 'column',
|
|
37
|
+
flex: 1,
|
|
38
|
+
justifyContent: 'center',
|
|
39
|
+
alignItems: 'center',
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
const _Carouse = forwardRef<HandlerRef<ScrollView, CarouseProps>, CarouseProps>((props , ref): React.JSX.Element => {
|
|
45
|
+
// 默认取水平方向的width
|
|
46
|
+
const { width } = Dimensions.get('window')
|
|
47
|
+
const defaultHeight = 150
|
|
48
|
+
const dir = props.horizontal === false ? 'y' : 'x'
|
|
49
|
+
// state的offset默认值
|
|
50
|
+
const defaultX = width * (props.circular ? props.current + 1 : props.current) || 0
|
|
51
|
+
const defaultY = defaultHeight * (props.circular ? props.current + 1 : props.current) || 0
|
|
52
|
+
// 内部存储上一次的offset值
|
|
53
|
+
const newChild = Array.isArray(props.children) ? props.children.filter(child => child) : props.children
|
|
54
|
+
// 默认设置为初次渲染
|
|
55
|
+
const initRenderRef = useRef(true)
|
|
56
|
+
const autoplayTimerRef = useRef<ReturnType <typeof setTimeout> | null>(null)
|
|
57
|
+
let loopJumpTimerRef = useRef<ReturnType <typeof setTimeout> | null>(null)
|
|
58
|
+
const { nodeRef: scrollViewRef } = useNodesRef<ScrollView, CarouseProps>(props, ref, {
|
|
59
|
+
})
|
|
60
|
+
const autoplayEndRef = useRef(false)
|
|
61
|
+
// 存储layout布局信息
|
|
62
|
+
const layoutRef = useRef({})
|
|
63
|
+
// 内部存储上一次的偏移量
|
|
64
|
+
const internalsRef = useRef({
|
|
65
|
+
offset: {
|
|
66
|
+
x: defaultX || 0,
|
|
67
|
+
y: defaultY || 0
|
|
68
|
+
},
|
|
69
|
+
isScrolling: false
|
|
70
|
+
})
|
|
71
|
+
const [state, setState] = useState({
|
|
72
|
+
children: newChild,
|
|
73
|
+
width: width || 375,
|
|
74
|
+
height: defaultHeight,
|
|
75
|
+
index: 0,
|
|
76
|
+
total: Array.isArray(newChild) ? newChild.length : ( newChild ? 1 : 0),
|
|
77
|
+
offset: {
|
|
78
|
+
x: dir === 'x' ? defaultX : 0,
|
|
79
|
+
y: dir === 'y' ? defaultY: 0
|
|
80
|
+
},
|
|
81
|
+
loopJump: false,
|
|
82
|
+
dir
|
|
83
|
+
} as CarouseState);
|
|
84
|
+
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
// 确认这个是变化的props变化的时候才执行,还是初始化的时候就执行
|
|
87
|
+
if (props.autoplay) {
|
|
88
|
+
startAutoPlay()
|
|
89
|
+
} else {
|
|
90
|
+
startSwiperLoop()
|
|
91
|
+
}
|
|
92
|
+
}, [props.autoplay, props.current, state.index]);
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 更新index,以视图的offset计算当前的索引
|
|
96
|
+
*/
|
|
97
|
+
function updateIndex (scrollViewOffset: NativeScrollPoint) {
|
|
98
|
+
const diff = scrollViewOffset[dir] - internalsRef.current.offset[state.dir]
|
|
99
|
+
if (!diff) return
|
|
100
|
+
|
|
101
|
+
const step = dir === 'x' ? state.width : state.height
|
|
102
|
+
let loopJump = false
|
|
103
|
+
let newIndex = state.index + Math.round(diff / step)
|
|
104
|
+
// 若是循环circular
|
|
105
|
+
// 1. 当前索引-1, 初始化为最后一个索引, 且scrollView的偏移量设置为 每个元素的步长 * 一共多少个元素, 这里为什么不减一呢
|
|
106
|
+
// 2. 当前索引>total, 初始化为第一个元素,且scrollView的偏移量设置为一个元素的步长
|
|
107
|
+
if (props.circular) {
|
|
108
|
+
if (state.index <= -1) {
|
|
109
|
+
newIndex = state.total - 1
|
|
110
|
+
scrollViewOffset[state.dir] = step * state.total
|
|
111
|
+
loopJump = true
|
|
112
|
+
} else if (newIndex >= state.total) {
|
|
113
|
+
newIndex = 0
|
|
114
|
+
scrollViewOffset[state.dir] = step
|
|
115
|
+
loopJump = true
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// 存储当前的偏移量
|
|
119
|
+
internalsRef.current.offset = scrollViewOffset
|
|
120
|
+
// 这里需不需要区分是否loop,初始化????
|
|
121
|
+
setState((preState) => {
|
|
122
|
+
const newState = {
|
|
123
|
+
...preState,
|
|
124
|
+
index: newIndex,
|
|
125
|
+
offset: scrollViewOffset,
|
|
126
|
+
loopJump
|
|
127
|
+
}
|
|
128
|
+
return newState
|
|
129
|
+
})
|
|
130
|
+
internalsRef.current.isScrolling = false
|
|
131
|
+
// getCustomEvent
|
|
132
|
+
const eventData = getCustomEvent('change', {}, { detail: {current: newIndex, source: 'touch' }, layoutRef: layoutRef })
|
|
133
|
+
props.bindchange && props.bindchange(eventData)
|
|
134
|
+
// 更新完状态之后, 开启新的loop
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* 用户手动点击播放
|
|
139
|
+
* 触发scrollView的onScrollEnd事件 => 然后更新索引 => 通过useEffect事件 => startSwiperLoop => 主动更新scrollView到指定的位置
|
|
140
|
+
* 若是circular, 到最后一个索引会更新为0,但是视觉要scrollView到下一个
|
|
141
|
+
* 若是circular, 到第一个再往前索引会更新为total-1, 但是视觉是展示的最后一个
|
|
142
|
+
*/
|
|
143
|
+
function startSwiperLoop () {
|
|
144
|
+
loopJumpTimerRef.current = setTimeout(() => {
|
|
145
|
+
let offset = { x: 0, y: 0, animated: false}
|
|
146
|
+
if (state.index > 0){
|
|
147
|
+
offset = props.horizontal ? { x: state.width * state.index, y: 0, animated: false } : { x: 0, y: state.height * state.index, animated: false }
|
|
148
|
+
}
|
|
149
|
+
if (props.circular) {
|
|
150
|
+
offset = props.horizontal ? { x: state.width * (state.index + 1), y: 0, animated: false } : { x: 0, y: state.height * (state.index + 1), animated: false }
|
|
151
|
+
}
|
|
152
|
+
scrollViewRef.current?.scrollTo(offset)
|
|
153
|
+
internalsRef.current.offset = offset
|
|
154
|
+
}, props.duration || 500)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* 开启自动轮播
|
|
159
|
+
* 每间隔interval scrollView的offset更改到下一个位置,通过onScrollEnd来获取contentOffset再计算要更新的索引index
|
|
160
|
+
*/
|
|
161
|
+
function startAutoPlay () {
|
|
162
|
+
// 已经开启过autopaly则不重新创建
|
|
163
|
+
if (!Array.isArray(state.children) || !props.autoplay || internalsRef.current.isScrolling || autoplayEndRef.current) {
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
autoplayTimerRef.current && clearTimeout(autoplayTimerRef.current)
|
|
167
|
+
// 非循环自动播放的形式下 到最后一帧 结束自动播放
|
|
168
|
+
if (!props.circular && state.index === state.total -1) {
|
|
169
|
+
autoplayEndRef.current = true
|
|
170
|
+
return
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// 开启自动播放
|
|
174
|
+
autoplayTimerRef.current = setTimeout(() => {
|
|
175
|
+
if (state.total < 2) return
|
|
176
|
+
const nexStep = 1
|
|
177
|
+
const toIndex = (props.circular ? 1 : 0) + nexStep + state.index
|
|
178
|
+
let x = 0
|
|
179
|
+
let y = 0
|
|
180
|
+
if (state.dir === 'x') x = toIndex * state.width
|
|
181
|
+
if (state.dir === 'y') y = toIndex * state.height
|
|
182
|
+
// animated会影响切换的offset,先改为false
|
|
183
|
+
scrollViewRef.current?.scrollTo({ x, y, animated: false })
|
|
184
|
+
|
|
185
|
+
internalsRef.current.isScrolling = true
|
|
186
|
+
|
|
187
|
+
autoplayEndRef.current = false
|
|
188
|
+
updateIndex({ x, y })
|
|
189
|
+
}, props.interval || 5000)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* 当用户开始拖动此视图时调用此函数, 更新当前在滚动态
|
|
194
|
+
*/
|
|
195
|
+
function onScrollBegin () {
|
|
196
|
+
internalsRef.current.isScrolling = true
|
|
197
|
+
}
|
|
198
|
+
function onScrollEnd (event: NativeSyntheticEvent<NativeScrollEvent>) {
|
|
199
|
+
internalsRef.current.isScrolling = false
|
|
200
|
+
|
|
201
|
+
// 用户手动滑动更新索引后,如果开启了自动轮播等重新开始
|
|
202
|
+
updateIndex(event.nativeEvent.contentOffset)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* 当拖拽结束时,检测是否可滚动
|
|
207
|
+
*/
|
|
208
|
+
function onScrollEndDrag (event: NativeSyntheticEvent<NativeScrollEvent>) {
|
|
209
|
+
const { contentOffset } = event.nativeEvent
|
|
210
|
+
const { index, total } = state
|
|
211
|
+
|
|
212
|
+
const internalOffset = internalsRef.current.offset
|
|
213
|
+
const previousOffset = props.horizontal ? internalOffset.x : internalOffset.y
|
|
214
|
+
const newOffset = props.horizontal ? contentOffset.x : contentOffset.y
|
|
215
|
+
|
|
216
|
+
if (previousOffset === newOffset && (index === 0 || index === total - 1)) {
|
|
217
|
+
internalsRef.current.isScrolling = false
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* 垂直方向时,获取单个元素的布局,更新
|
|
222
|
+
*/
|
|
223
|
+
function onItemLayout (event: LayoutChangeEvent) {
|
|
224
|
+
if (!initRenderRef.current || state.dir === 'x') return
|
|
225
|
+
const { width, height } = event.nativeEvent.layout
|
|
226
|
+
if (state.total > 1) {
|
|
227
|
+
internalsRef.current.offset[state.dir] = (state.dir === 'y' ? height * state.index : state.width * state.index)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (!state.offset.x && !state.offset.y) {
|
|
231
|
+
state.offset = internalsRef.current.offset
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (initRenderRef.current && state.total > 1) {
|
|
235
|
+
scrollViewRef.current?.scrollTo({ ...internalsRef.current.offset, animated: false })
|
|
236
|
+
initRenderRef.current = false
|
|
237
|
+
}
|
|
238
|
+
setState((preState) => {
|
|
239
|
+
return {
|
|
240
|
+
...preState,
|
|
241
|
+
height
|
|
242
|
+
}
|
|
243
|
+
})
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* 水平方向时,获取单个元素的布局,更新
|
|
247
|
+
*/
|
|
248
|
+
function onWrapperLayout () {
|
|
249
|
+
if (props.enableOffset) {
|
|
250
|
+
// @ts-ignore
|
|
251
|
+
scrollViewRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => {
|
|
252
|
+
layoutRef.current = { x, y, width, height, offsetLeft, offsetTop }
|
|
253
|
+
props.getInnerLayout && props.getInnerLayout(layoutRef)
|
|
254
|
+
})
|
|
255
|
+
}
|
|
256
|
+
if (state.dir === 'y') return
|
|
257
|
+
if (!state.offset.x && !state.offset.y) {
|
|
258
|
+
state.offset = internalsRef.current.offset
|
|
259
|
+
}
|
|
260
|
+
if (!initRenderRef.current && state.total > 1) {
|
|
261
|
+
scrollViewRef.current?.scrollTo({ ...state.offset, animated: false })
|
|
262
|
+
initRenderRef.current = false
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function renderScrollView (pages: ReactNode) {
|
|
267
|
+
let scrollElementProps = {
|
|
268
|
+
ref: scrollViewRef,
|
|
269
|
+
horizontal: props.horizontal,
|
|
270
|
+
pagingEnabled: true,
|
|
271
|
+
showsHorizontalScrollIndicator: false,
|
|
272
|
+
showsVerticalScrollIndicator: false,
|
|
273
|
+
bounces: false,
|
|
274
|
+
scrollsToTop: false,
|
|
275
|
+
removeClippedSubviews: true,
|
|
276
|
+
automaticallyAdjustContentInsets: false
|
|
277
|
+
}
|
|
278
|
+
return (
|
|
279
|
+
<ScrollView
|
|
280
|
+
{...scrollElementProps}
|
|
281
|
+
overScrollMode="always"
|
|
282
|
+
contentOffset={state.offset}
|
|
283
|
+
onScrollBeginDrag={onScrollBegin}
|
|
284
|
+
onMomentumScrollEnd={onScrollEnd}
|
|
285
|
+
onScrollEndDrag={onScrollEndDrag}
|
|
286
|
+
>
|
|
287
|
+
{pages}
|
|
288
|
+
</ScrollView>
|
|
289
|
+
)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function renderPagination () {
|
|
293
|
+
if (state.total <= 1) return null
|
|
294
|
+
let dots: Array<ReactNode> = []
|
|
295
|
+
const activeDotStyle = [ {
|
|
296
|
+
backgroundColor: props.activeDotColor || '#007aff',
|
|
297
|
+
width: 8,
|
|
298
|
+
height: 8,
|
|
299
|
+
borderRadius: 4,
|
|
300
|
+
marginLeft: 3,
|
|
301
|
+
marginRight: 3,
|
|
302
|
+
marginTop: 3,
|
|
303
|
+
marginBottom: 3
|
|
304
|
+
}]
|
|
305
|
+
const dotStyle = [{
|
|
306
|
+
backgroundColor: props.dotColor || 'rgba(0,0,0,.2)',
|
|
307
|
+
width: 8,
|
|
308
|
+
height: 8,
|
|
309
|
+
borderRadius: 4,
|
|
310
|
+
marginLeft: 3,
|
|
311
|
+
marginRight: 3,
|
|
312
|
+
marginTop: 3,
|
|
313
|
+
marginBottom: 3
|
|
314
|
+
}]
|
|
315
|
+
for (let i = 0; i < state.total; i++) {
|
|
316
|
+
if (i === state.index) {
|
|
317
|
+
dots.push(<View style={activeDotStyle} key={i}></View>)
|
|
318
|
+
} else {
|
|
319
|
+
dots.push(<View style={dotStyle} key={i}></View>)
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return (
|
|
323
|
+
<View
|
|
324
|
+
pointerEvents="none"
|
|
325
|
+
style={[styles['pagination_' + state.dir]]}
|
|
326
|
+
>
|
|
327
|
+
{dots}
|
|
328
|
+
</View>
|
|
329
|
+
)
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function renderPages () {
|
|
333
|
+
const { width, height, total, children } = state
|
|
334
|
+
const { circular, previousMargin, nextMargin, innerProps } = props
|
|
335
|
+
const pageStyle = { width: width, height: height }
|
|
336
|
+
if (total > 1 && Array.isArray(children)) {
|
|
337
|
+
let arrElements: (Array<ReactNode>) = []
|
|
338
|
+
// pages = ["2", "0", "1", "2", "0"]
|
|
339
|
+
let pages = Array.isArray(children) && Object.keys(children) || []
|
|
340
|
+
/* 无限循环的时候 */
|
|
341
|
+
if (circular) {
|
|
342
|
+
pages.unshift(total - 1 + '')
|
|
343
|
+
pages.push('0')
|
|
344
|
+
}
|
|
345
|
+
arrElements = pages.map((page, i) => {
|
|
346
|
+
let pageStyle2 = { width: width, height: height }
|
|
347
|
+
const extraStyle = {} as {
|
|
348
|
+
left? : number;
|
|
349
|
+
marginLeft?: number;
|
|
350
|
+
paddingLeft?: number
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (previousMargin) {
|
|
354
|
+
extraStyle.left = +previousMargin
|
|
355
|
+
}
|
|
356
|
+
if (nextMargin && state.index === i - 1) {
|
|
357
|
+
const half = Math.floor(+nextMargin / 2)
|
|
358
|
+
extraStyle.marginLeft = - half
|
|
359
|
+
extraStyle.paddingLeft = half
|
|
360
|
+
}
|
|
361
|
+
return (
|
|
362
|
+
<View style={[pageStyle2, extraStyle]} key={ 'page' + i} onLayout={onItemLayout}>
|
|
363
|
+
{children[+page]}
|
|
364
|
+
</View>
|
|
365
|
+
)
|
|
366
|
+
})
|
|
367
|
+
return arrElements
|
|
368
|
+
} else {
|
|
369
|
+
return (
|
|
370
|
+
<View style={pageStyle} key={0}>
|
|
371
|
+
{children}
|
|
372
|
+
</View>
|
|
373
|
+
)
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const vStyle = {} as { height: number }
|
|
378
|
+
if (dir === 'y') {
|
|
379
|
+
vStyle.height = defaultHeight
|
|
380
|
+
}
|
|
381
|
+
const pages: Array<ReactNode> | ReactNode = renderPages()
|
|
382
|
+
const strStyle: string = 'container_' + state.dir
|
|
383
|
+
const eventProps = props.innerProps || {}
|
|
384
|
+
|
|
385
|
+
return (
|
|
386
|
+
<View
|
|
387
|
+
style={[styles[strStyle], vStyle]}
|
|
388
|
+
{...eventProps}
|
|
389
|
+
onLayout={onWrapperLayout}>
|
|
390
|
+
{renderScrollView(pages)}
|
|
391
|
+
{props.showsPagination && renderPagination()}
|
|
392
|
+
</View>)
|
|
393
|
+
|
|
394
|
+
})
|
|
395
|
+
|
|
396
|
+
_Carouse.displayName = '_Carouse';
|
|
397
|
+
|
|
398
|
+
export default _Carouse
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { View, ScrollView } from 'react-native'
|
|
2
|
+
import React, { forwardRef, useRef } from 'react'
|
|
3
|
+
import { default as Carouse } from './carouse'
|
|
4
|
+
import { SwiperProps } from './type'
|
|
5
|
+
import useInnerProps from '../getInnerListeners'
|
|
6
|
+
import useNodesRef, { HandlerRef } from '../useNodesRef' // 引入辅助函数
|
|
7
|
+
/**
|
|
8
|
+
* ✔ indicator-dots
|
|
9
|
+
* ✔ indicator-color
|
|
10
|
+
* ✔ indicator-active-color
|
|
11
|
+
* ✔ autoplay
|
|
12
|
+
* ✔ current
|
|
13
|
+
* ✔ interval
|
|
14
|
+
* ✔ duration
|
|
15
|
+
* ✔ circular
|
|
16
|
+
* ✔ vertical
|
|
17
|
+
* ✘ display-multiple-items
|
|
18
|
+
* ✔ previous-margin
|
|
19
|
+
* ✔ next-margin
|
|
20
|
+
* ✘ snap-to-edge
|
|
21
|
+
*/
|
|
22
|
+
const _SwiperWrapper = forwardRef<HandlerRef<ScrollView, SwiperProps>, SwiperProps>((props: SwiperProps, ref): React.JSX.Element => {
|
|
23
|
+
const { children } = props
|
|
24
|
+
let innerLayout = useRef({})
|
|
25
|
+
const swiperProp = {
|
|
26
|
+
circular: props.circular || false,
|
|
27
|
+
current: props.current || 0,
|
|
28
|
+
autoplay: props.autoplay || false,
|
|
29
|
+
duration: props.duration || 500,
|
|
30
|
+
interval: props.interval || 5000,
|
|
31
|
+
showsPagination: props['indicator-dots'],
|
|
32
|
+
dotColor: props['indicator-color'] || "rgba(0, 0, 0, .3)",
|
|
33
|
+
activeDotColor: props['indicator-active-color'] || '#000000',
|
|
34
|
+
horizontal: props.vertical !== undefined ? !props.vertical : true,
|
|
35
|
+
style: props.style,
|
|
36
|
+
previousMargin: props['previous-margin'] ? parseInt(props['previous-margin']) : 0,
|
|
37
|
+
nextMargin: props['next-margin'] ? parseInt(props['next-margin']) : 0,
|
|
38
|
+
enableOffset: props['enable-offset'] || false,
|
|
39
|
+
bindchange: props.bindchange
|
|
40
|
+
}
|
|
41
|
+
const { nodeRef } = useNodesRef<ScrollView, SwiperProps>(props, ref, {
|
|
42
|
+
})
|
|
43
|
+
const innerProps = useInnerProps(props, {
|
|
44
|
+
ref: nodeRef
|
|
45
|
+
}, [
|
|
46
|
+
'indicator-dots',
|
|
47
|
+
'indicator-color',
|
|
48
|
+
'indicator-active-color',
|
|
49
|
+
'previous-margin',
|
|
50
|
+
'next-margin'
|
|
51
|
+
], { layoutRef: innerLayout })
|
|
52
|
+
|
|
53
|
+
const getInnerLayout = (layout: React.MutableRefObject<{}>) => {
|
|
54
|
+
innerLayout.current = layout.current
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return <Carouse
|
|
58
|
+
getInnerLayout={getInnerLayout}
|
|
59
|
+
innerProps={innerProps}
|
|
60
|
+
{...swiperProp}
|
|
61
|
+
{...innerProps}>
|
|
62
|
+
{children}
|
|
63
|
+
</Carouse>
|
|
64
|
+
|
|
65
|
+
})
|
|
66
|
+
_SwiperWrapper.displayName = 'mpx-swiper';
|
|
67
|
+
|
|
68
|
+
export default _SwiperWrapper
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { ReactNode } from 'react'
|
|
2
|
+
import { NativeSyntheticEvent } from 'react-native'
|
|
3
|
+
export interface SwiperProps {
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
circular?: boolean;
|
|
6
|
+
current?: number;
|
|
7
|
+
interval?: number;
|
|
8
|
+
autoplay?: boolean;
|
|
9
|
+
duration?: number;
|
|
10
|
+
'indicator-dots'?: boolean;
|
|
11
|
+
'indicator-color'?: string;
|
|
12
|
+
'indicator-active-color'?: string;
|
|
13
|
+
vertical?: boolean;
|
|
14
|
+
style?: string;
|
|
15
|
+
easingFunction?: string;
|
|
16
|
+
'previous-margin'?: string;
|
|
17
|
+
'next-margin'?: string;
|
|
18
|
+
'enable-offset'?: boolean;
|
|
19
|
+
bindchange?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface CarouseProps {
|
|
23
|
+
children?: ReactNode;
|
|
24
|
+
circular?: boolean;
|
|
25
|
+
current: number;
|
|
26
|
+
autoplay?: boolean;
|
|
27
|
+
duration?: number;
|
|
28
|
+
interval?: number;
|
|
29
|
+
showsPagination?: boolean;
|
|
30
|
+
dotColor?: string;
|
|
31
|
+
activeDotColor?: string;
|
|
32
|
+
horizontal?: boolean;
|
|
33
|
+
style?: string;
|
|
34
|
+
easingFunction?: string;
|
|
35
|
+
previousMargin?: number;
|
|
36
|
+
nextMargin?: number;
|
|
37
|
+
enableOffset?: boolean;
|
|
38
|
+
bindchange?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void;
|
|
39
|
+
getInnerLayout: Function,
|
|
40
|
+
innerProps: Object;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface CarouseState {
|
|
44
|
+
children: Array<ReactNode> | ReactNode,
|
|
45
|
+
width: number;
|
|
46
|
+
height: number;
|
|
47
|
+
index: number;
|
|
48
|
+
total: number;
|
|
49
|
+
// 设置scrollView初始的滚动坐标,contentOffset
|
|
50
|
+
offset: {
|
|
51
|
+
x: number,
|
|
52
|
+
y: number
|
|
53
|
+
};
|
|
54
|
+
// 是否结束自动轮播,手动设置滚动到具体位置时结束
|
|
55
|
+
autoplayEnd: boolean;
|
|
56
|
+
loopJump: boolean;
|
|
57
|
+
dir: 'x' | 'y';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface ScrollElementProps {
|
|
61
|
+
pagingEnabled: boolean,
|
|
62
|
+
showsHorizontalScrollIndicator: boolean,
|
|
63
|
+
showsVerticalScrollIndicator: boolean,
|
|
64
|
+
bounces: boolean,
|
|
65
|
+
scrollsToTop: boolean,
|
|
66
|
+
removeClippedSubviews: boolean,
|
|
67
|
+
automaticallyAdjustContentInsets: boolean,
|
|
68
|
+
horizontal: boolean
|
|
69
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { View } from 'react-native'
|
|
2
|
+
import React, { forwardRef, useRef } from 'react'
|
|
3
|
+
import useInnerProps from './getInnerListeners'
|
|
4
|
+
import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数
|
|
5
|
+
|
|
6
|
+
interface SwiperItemProps {
|
|
7
|
+
'item-id'?: string;
|
|
8
|
+
'enable-offset'?: boolean;
|
|
9
|
+
children?: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const _SwiperItem = forwardRef<HandlerRef<View, SwiperItemProps>, SwiperItemProps>((props: SwiperItemProps, ref) => {
|
|
13
|
+
const { children, 'enable-offset': enableOffset } = props
|
|
14
|
+
const layoutRef = useRef({})
|
|
15
|
+
const { nodeRef } = useNodesRef(props, ref, {})
|
|
16
|
+
|
|
17
|
+
const onLayout = () => {
|
|
18
|
+
nodeRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => {
|
|
19
|
+
layoutRef.current = { x, y, width, height, offsetLeft, offsetTop }
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const innerProps = useInnerProps(props, {
|
|
24
|
+
...(enableOffset ? { onLayout } : {}),
|
|
25
|
+
}, [
|
|
26
|
+
'children',
|
|
27
|
+
'enable-offset'
|
|
28
|
+
], { layoutRef })
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<View
|
|
32
|
+
ref={nodeRef}
|
|
33
|
+
data-itemId={props['item-id']}
|
|
34
|
+
{...innerProps}>
|
|
35
|
+
{children}
|
|
36
|
+
</View>
|
|
37
|
+
)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
_SwiperItem.displayName = 'mpx-swiper-item';
|
|
41
|
+
|
|
42
|
+
export default _SwiperItem
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* ✔ selectable
|
|
4
|
+
* ✘ space
|
|
5
|
+
* ✘ decode
|
|
6
|
+
*/
|
|
7
|
+
import { Text, TextStyle, TextProps, StyleSheet } from 'react-native'
|
|
8
|
+
import { useRef, useEffect, forwardRef, ReactNode, ForwardedRef, JSX } from 'react';
|
|
9
|
+
import useInnerProps from './getInnerListeners'
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数
|
|
12
|
+
import { PERCENT_REGX } from './utils'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
interface _TextProps extends TextProps {
|
|
16
|
+
style?: TextStyle
|
|
17
|
+
children?: ReactNode
|
|
18
|
+
selectable?: boolean
|
|
19
|
+
'enable-offset'?: boolean
|
|
20
|
+
'user-select'?: boolean
|
|
21
|
+
userSelect?: boolean
|
|
22
|
+
['disable-default-style']?: boolean
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const DEFAULT_STYLE = {
|
|
26
|
+
fontSize: 16
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const transformStyle = (styleObj: TextStyle) => {
|
|
30
|
+
let { lineHeight } = styleObj
|
|
31
|
+
if (typeof lineHeight === 'string' && PERCENT_REGX.test(lineHeight)) {
|
|
32
|
+
lineHeight = (parseFloat(lineHeight)/100) * (styleObj.fontSize || DEFAULT_STYLE.fontSize)
|
|
33
|
+
styleObj.lineHeight = lineHeight
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const _Text = forwardRef<HandlerRef<Text, _TextProps>, _TextProps>((props, ref): JSX.Element => {
|
|
38
|
+
const {
|
|
39
|
+
style = [],
|
|
40
|
+
children,
|
|
41
|
+
selectable,
|
|
42
|
+
'enable-offset': enableOffset,
|
|
43
|
+
'user-select': userSelect,
|
|
44
|
+
'disable-default-style': disableDefaultStyle = false,
|
|
45
|
+
} = props
|
|
46
|
+
|
|
47
|
+
const layoutRef = useRef({})
|
|
48
|
+
|
|
49
|
+
const styleObj: TextStyle = StyleSheet.flatten<TextStyle>(style)
|
|
50
|
+
|
|
51
|
+
let defaultStyle = {}
|
|
52
|
+
|
|
53
|
+
if (!disableDefaultStyle) {
|
|
54
|
+
defaultStyle = DEFAULT_STYLE
|
|
55
|
+
transformStyle(styleObj)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const { nodeRef } = useNodesRef<Text, _TextProps>(props, ref, {
|
|
59
|
+
defaultStyle
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
const innerProps = useInnerProps(props, {
|
|
63
|
+
ref: nodeRef
|
|
64
|
+
}, [
|
|
65
|
+
'style',
|
|
66
|
+
'children',
|
|
67
|
+
'selectable',
|
|
68
|
+
'user-select',
|
|
69
|
+
'useInherit',
|
|
70
|
+
'enable-offset'
|
|
71
|
+
], {
|
|
72
|
+
layoutRef
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
let measureTimeout: ReturnType<typeof setTimeout> | null = null
|
|
77
|
+
if (enableOffset) {
|
|
78
|
+
measureTimeout = setTimeout(() => {
|
|
79
|
+
nodeRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => {
|
|
80
|
+
layoutRef.current = { x, y, width, height, offsetLeft, offsetTop }
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
return () => {
|
|
84
|
+
if (measureTimeout) {
|
|
85
|
+
clearTimeout(measureTimeout)
|
|
86
|
+
measureTimeout = null
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}, [])
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<Text
|
|
95
|
+
style={{...defaultStyle, ...styleObj}}
|
|
96
|
+
selectable={!!selectable || !!userSelect}
|
|
97
|
+
{...innerProps}
|
|
98
|
+
>
|
|
99
|
+
{children}
|
|
100
|
+
</Text>
|
|
101
|
+
)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
_Text.displayName = 'mpx-text'
|
|
105
|
+
|
|
106
|
+
export default _Text
|