@mpxjs/webpack-plugin 2.10.17-beta.6 → 2.10.17-beta.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/index.js +1 -0
- package/lib/json-compiler/index.js +18 -1
- package/lib/platform/style/wx/index.js +1 -17
- package/lib/react/processJSON.js +20 -1
- package/lib/react/processScript.js +1 -0
- package/lib/react/script-helper.js +0 -1
- package/lib/runtime/components/ali/mpx-recycle-view.mpx +518 -0
- package/lib/runtime/components/ali/mpx-sticky-header.mpx +212 -0
- package/lib/runtime/components/ali/mpx-sticky-section.mpx +17 -0
- package/lib/runtime/components/react/animationHooks/useTransitionHooks.ts +34 -30
- package/lib/runtime/components/react/animationHooks/utils.ts +3 -2
- package/lib/runtime/components/react/dist/animationHooks/useTransitionHooks.js +38 -33
- package/lib/runtime/components/react/dist/animationHooks/utils.js +3 -2
- package/lib/runtime/components/react/dist/mpx-image.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-recycle-view.d.ts +45 -0
- package/lib/runtime/components/react/dist/mpx-recycle-view.jsx +272 -0
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +6 -5
- package/lib/runtime/components/react/dist/utils.d.ts +2 -1
- package/lib/runtime/components/react/dist/utils.jsx +15 -21
- package/lib/runtime/components/react/mpx-image.tsx +2 -2
- package/lib/runtime/components/react/mpx-recycle-view.tsx +398 -0
- package/lib/runtime/components/react/mpx-scroll-view.tsx +1 -0
- package/lib/runtime/components/react/mpx-sticky-section.tsx +1 -1
- package/lib/runtime/components/react/mpx-swiper.tsx +6 -5
- package/lib/runtime/components/react/utils.tsx +18 -23
- package/lib/runtime/components/web/mpx-recycle-view.vue +508 -0
- package/lib/runtime/components/wx/mpx-list-header-default.mpx +21 -0
- package/lib/runtime/components/wx/mpx-recycle-item-default.mpx +21 -0
- package/lib/runtime/components/wx/mpx-recycle-view.mpx +193 -0
- package/lib/runtime/components/wx/mpx-section-header-default.mpx +21 -0
- package/lib/template-compiler/compiler.js +8 -3
- package/lib/utils/const.js +17 -0
- package/lib/utils/process-extend-components.js +43 -0
- package/lib/web/processJSON.js +20 -2
- package/package.json +1 -1
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="mpx-sticky-header-container">
|
|
3
|
+
<view class="mpx-sticky-header" wx:ref="stickyHeader" wx:style="{{stickyHeaderStyle}}">
|
|
4
|
+
<slot></slot>
|
|
5
|
+
</view>
|
|
6
|
+
<view
|
|
7
|
+
class="mpx-sticky-header-placeholder"
|
|
8
|
+
id="{{stickyId}}"
|
|
9
|
+
wx:style="{{placeholderStyle}}"
|
|
10
|
+
></view>
|
|
11
|
+
</view>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script>
|
|
15
|
+
import mpx, { createComponent } from '@mpxjs/core'
|
|
16
|
+
|
|
17
|
+
createComponent({
|
|
18
|
+
properties: {
|
|
19
|
+
offsetTop: {
|
|
20
|
+
type: Number,
|
|
21
|
+
value: 0
|
|
22
|
+
},
|
|
23
|
+
scrollViewId: {
|
|
24
|
+
type: String,
|
|
25
|
+
value: ''
|
|
26
|
+
},
|
|
27
|
+
stickyId: {
|
|
28
|
+
type: String,
|
|
29
|
+
value: ''
|
|
30
|
+
},
|
|
31
|
+
padding: Array,
|
|
32
|
+
enablePolling: {
|
|
33
|
+
type: Boolean,
|
|
34
|
+
value: false
|
|
35
|
+
},
|
|
36
|
+
pollingDuration: {
|
|
37
|
+
type: Number,
|
|
38
|
+
value: 300
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
data: {
|
|
42
|
+
isStickOnTop: false,
|
|
43
|
+
scrollOffsetTop: 0,
|
|
44
|
+
headerHeight: 0,
|
|
45
|
+
stickyHeader: '',
|
|
46
|
+
headerTop: 0,
|
|
47
|
+
lastIntersectionRatio: -1,
|
|
48
|
+
pollingTimer: null
|
|
49
|
+
},
|
|
50
|
+
computed: {
|
|
51
|
+
paddingStyle() {
|
|
52
|
+
if (!this.padding || !Array.isArray(this.padding)) {
|
|
53
|
+
return ''
|
|
54
|
+
}
|
|
55
|
+
const [top = 0, right = 0, bottom = 0, left = 0] = this.padding
|
|
56
|
+
return `padding: ${top}px ${right}px ${bottom}px ${left}px;`
|
|
57
|
+
},
|
|
58
|
+
stickyHeaderStyle() {
|
|
59
|
+
const baseStyle = this.isStickOnTop
|
|
60
|
+
? `position: fixed;top: ${this.scrollOffsetTop + this.offsetTop}px;`
|
|
61
|
+
: ''
|
|
62
|
+
return baseStyle + this.paddingStyle
|
|
63
|
+
},
|
|
64
|
+
placeholderStyle() {
|
|
65
|
+
const position = this.isStickOnTop ? 'relative' : 'absolute'
|
|
66
|
+
return `position: ${position};height: ${this.headerHeight}px;`
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
ready() {
|
|
70
|
+
if (!this.scrollViewId) {
|
|
71
|
+
console.error('[mpx runtime error]: scroll-view-id is necessary property in ali environment')
|
|
72
|
+
}
|
|
73
|
+
if (!this.stickyId) {
|
|
74
|
+
console.error('[mpx runtime error]: sticky-id is necessary property in ali environment')
|
|
75
|
+
}
|
|
76
|
+
this.initStickyHeader()
|
|
77
|
+
// 启动轮询
|
|
78
|
+
if (this.enablePolling) {
|
|
79
|
+
this.startPolling()
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
methods: {
|
|
83
|
+
initStickyHeader() {
|
|
84
|
+
this.createSelectorQuery()
|
|
85
|
+
.select('.mpx-sticky-header')
|
|
86
|
+
.boundingClientRect()
|
|
87
|
+
.exec((rect = []) => {
|
|
88
|
+
this.headerHeight = rect[0]?.height || 0
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
mpx
|
|
92
|
+
.createSelectorQuery()
|
|
93
|
+
.select(`#${this.scrollViewId}`)
|
|
94
|
+
.boundingClientRect()
|
|
95
|
+
.exec((res) => {
|
|
96
|
+
if (!res) return
|
|
97
|
+
this.scrollOffsetTop = res[0]?.top || 0
|
|
98
|
+
this.stickyHeader = mpx.createIntersectionObserver({
|
|
99
|
+
thresholds: [0.1, 0.9]
|
|
100
|
+
})
|
|
101
|
+
this.initObserver()
|
|
102
|
+
})
|
|
103
|
+
},
|
|
104
|
+
initObserver() {
|
|
105
|
+
this.stickyHeader.relativeTo(`#${this.scrollViewId}`).observe(`#${this.stickyId}`, (res) => {
|
|
106
|
+
const { intersectionRatio, intersectionRect, relativeRect, boundingClientRect } = res
|
|
107
|
+
if (intersectionRatio < this.lastIntersectionRatio) {
|
|
108
|
+
// boundingClientRect.top < relativeRect.top fixed,否则默认布局
|
|
109
|
+
this.handleStickyStateChange(boundingClientRect.top < relativeRect.top)
|
|
110
|
+
} else if (intersectionRatio > this.lastIntersectionRatio) {
|
|
111
|
+
this.handleStickyStateChange(false)
|
|
112
|
+
}
|
|
113
|
+
this.lastIntersectionRatio = intersectionRatio
|
|
114
|
+
})
|
|
115
|
+
},
|
|
116
|
+
refresh() {
|
|
117
|
+
// 并行执行两个独立的查询
|
|
118
|
+
Promise.all([
|
|
119
|
+
// 查询1:组件内部元素
|
|
120
|
+
new Promise((resolve) => {
|
|
121
|
+
this.createSelectorQuery()
|
|
122
|
+
.select('.mpx-sticky-header')
|
|
123
|
+
.boundingClientRect()
|
|
124
|
+
.select('.mpx-sticky-header-placeholder')
|
|
125
|
+
.boundingClientRect()
|
|
126
|
+
.exec((results) => {
|
|
127
|
+
resolve(results)
|
|
128
|
+
})
|
|
129
|
+
}),
|
|
130
|
+
// 查询2:页面级scrollView
|
|
131
|
+
new Promise((resolve) => {
|
|
132
|
+
mpx.createSelectorQuery()
|
|
133
|
+
.select(`#${this.scrollViewId}`)
|
|
134
|
+
.boundingClientRect()
|
|
135
|
+
.select(`#${this.scrollViewId}`)
|
|
136
|
+
.scrollOffset()
|
|
137
|
+
.exec((results) => {
|
|
138
|
+
resolve(results)
|
|
139
|
+
})
|
|
140
|
+
})
|
|
141
|
+
]).then(([componentResults, scrollResults]) => {
|
|
142
|
+
const [stickyHeaderRect, placeholderRect] = componentResults
|
|
143
|
+
const [scrollViewRect, scrollOffsetData] = scrollResults
|
|
144
|
+
|
|
145
|
+
if (!stickyHeaderRect || !placeholderRect || !scrollViewRect || !scrollOffsetData) return
|
|
146
|
+
|
|
147
|
+
this.scrollOffsetTop = scrollViewRect.top || 0
|
|
148
|
+
this.headerHeight = stickyHeaderRect.height
|
|
149
|
+
|
|
150
|
+
// 模拟 offsetTop 计算:sticky placeholder具体顶部距离 - scrollView顶部 + scrollView滚动位置
|
|
151
|
+
// 必须用 placeholder 到顶部距离,用 sticky 如果刚好差值为 0, 区分不出是本身就在顶部还是 fixed 在顶部
|
|
152
|
+
this.headerTop = placeholderRect.top - this.scrollOffsetTop + scrollOffsetData.scrollTop
|
|
153
|
+
|
|
154
|
+
this.handleStickyStateChange(scrollOffsetData.scrollTop > this.headerTop)
|
|
155
|
+
})
|
|
156
|
+
},
|
|
157
|
+
handleStickyStateChange(shouldStick) {
|
|
158
|
+
// 如果状态没有变化,直接返回
|
|
159
|
+
if (shouldStick === this.isStickOnTop) {
|
|
160
|
+
return
|
|
161
|
+
}
|
|
162
|
+
// 更新状态
|
|
163
|
+
this.isStickOnTop = shouldStick
|
|
164
|
+
// 触发事件
|
|
165
|
+
this.triggerEvent('stickontopchange', {
|
|
166
|
+
isStickOnTop: shouldStick,
|
|
167
|
+
id: this.stickyId
|
|
168
|
+
})
|
|
169
|
+
},
|
|
170
|
+
// 启动轮询
|
|
171
|
+
startPolling() {
|
|
172
|
+
if (this.pollingTimer) {
|
|
173
|
+
clearInterval(this.pollingTimer)
|
|
174
|
+
}
|
|
175
|
+
this.pollingTimer = setInterval(() => {
|
|
176
|
+
this.refresh()
|
|
177
|
+
}, this.pollingDuration)
|
|
178
|
+
},
|
|
179
|
+
// 停止轮询
|
|
180
|
+
stopPolling() {
|
|
181
|
+
if (this.pollingTimer) {
|
|
182
|
+
clearInterval(this.pollingTimer)
|
|
183
|
+
this.pollingTimer = null
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
detached() {
|
|
188
|
+
// 清理观察器
|
|
189
|
+
if (this.stickyHeader) {
|
|
190
|
+
this.stickyHeader.disconnect()
|
|
191
|
+
}
|
|
192
|
+
// 清理轮询定时器
|
|
193
|
+
if (this.pollingTimer) {
|
|
194
|
+
clearInterval(this.pollingTimer)
|
|
195
|
+
this.pollingTimer = null
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
})
|
|
199
|
+
</script>
|
|
200
|
+
<style lang="stylus" scoped>
|
|
201
|
+
.mpx-sticky-header-container
|
|
202
|
+
position relative
|
|
203
|
+
.mpx-sticky-header-placeholder
|
|
204
|
+
position absolute
|
|
205
|
+
left 0
|
|
206
|
+
right 0
|
|
207
|
+
top 0
|
|
208
|
+
pointer-events none
|
|
209
|
+
.mpx-sticky-header
|
|
210
|
+
width 100%
|
|
211
|
+
box-sizing border-box
|
|
212
|
+
</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="mpx-sticky-section">
|
|
3
|
+
<slot></slot>
|
|
4
|
+
</view>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script>
|
|
8
|
+
import { createComponent } from '@mpxjs/core'
|
|
9
|
+
|
|
10
|
+
createComponent({
|
|
11
|
+
|
|
12
|
+
})
|
|
13
|
+
</script>
|
|
14
|
+
<style lang="stylus" scoped>
|
|
15
|
+
.mpx-sticky-section
|
|
16
|
+
position relative
|
|
17
|
+
</style>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { hasOwn, dash2hump, error } from '@mpxjs/utils'
|
|
1
|
+
import { hasOwn, dash2hump, error, warn } from '@mpxjs/utils'
|
|
2
2
|
import { useMemo, useRef, useEffect } from 'react'
|
|
3
3
|
import {
|
|
4
4
|
Easing,
|
|
@@ -169,10 +169,11 @@ export default function useTransitionHooks<T, P> (props: AnimationHooksPropsType
|
|
|
169
169
|
return parseTransitionStyle(originalStyle)
|
|
170
170
|
}, [])
|
|
171
171
|
// ** style prop sharedValue interpolateOutput: SharedValue<InterpolateOutput>
|
|
172
|
-
const { shareValMap, animatedKeys,
|
|
172
|
+
const { shareValMap, animatedKeys, animatedStyleKeys } = useMemo(() => {
|
|
173
173
|
// 记录需要执行动画的 propName
|
|
174
174
|
const animatedKeys = [] as string[]
|
|
175
|
-
|
|
175
|
+
// 有动画样式的 style key(useAnimatedStyle使用)
|
|
176
|
+
const animatedStyleKeys = [] as (string|string[])[]
|
|
176
177
|
const transforms = [] as string[]
|
|
177
178
|
const shareValMap = Object.keys(transitionMap).reduce((valMap, property) => {
|
|
178
179
|
// const { property } = transition || {}
|
|
@@ -189,20 +190,18 @@ export default function useTransitionHooks<T, P> (props: AnimationHooksPropsType
|
|
|
189
190
|
// console.log(`shareValMap property=${property} defaultVal=${defaultVal}`)
|
|
190
191
|
valMap[property] = makeMutable(defaultVal)
|
|
191
192
|
animatedKeys.push(property)
|
|
192
|
-
|
|
193
|
+
animatedStyleKeys.push(property)
|
|
193
194
|
}
|
|
194
195
|
// console.log('shareValMap = ', valMap)
|
|
195
196
|
return valMap
|
|
196
197
|
}, {} as { [propName: keyof ExtendedViewStyle]: SharedValue<string|number> })
|
|
197
|
-
if (transforms.length)
|
|
198
|
+
if (transforms.length) animatedStyleKeys.push(transforms)
|
|
198
199
|
return {
|
|
199
200
|
shareValMap,
|
|
200
201
|
animatedKeys,
|
|
201
|
-
|
|
202
|
+
animatedStyleKeys
|
|
202
203
|
}
|
|
203
204
|
}, [])
|
|
204
|
-
// 有动画样式的 style key(useAnimatedStyle使用)
|
|
205
|
-
const animatedStyleKeys = useSharedValue(animatedKeysShareVal)
|
|
206
205
|
const runOnJSCallbackRef = useRef({})
|
|
207
206
|
const runOnJSCallback = useRunOnJSCallback(runOnJSCallbackRef)
|
|
208
207
|
// 根据 animation action 创建&驱动动画
|
|
@@ -228,32 +227,37 @@ export default function useTransitionHooks<T, P> (props: AnimationHooksPropsType
|
|
|
228
227
|
toVal = `${toVal * 100}%`
|
|
229
228
|
} else if (typeof toVal !== typeof shareVal) {
|
|
230
229
|
// 动画起始值和终态值类型不一致报错提示一下
|
|
231
|
-
|
|
230
|
+
warn(`[Mpx runtime error]: Value types of property ${key} must be consistent during the animation`)
|
|
232
231
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
232
|
+
if ((toVal === 'auto' && !isNaN(+shareVal)) || (shareVal === 'auto' && !isNaN(+toVal))) {
|
|
233
|
+
// 有 auto 直接赋值不做动画
|
|
234
|
+
shareValMap[key].value = toVal
|
|
235
|
+
} else {
|
|
236
|
+
// console.log(`key=${key} oldVal=${shareValMap[key].value} newVal=${toVal}`)
|
|
237
|
+
const { delay = 0, duration, easing } = transitionMap[isTransformKey ? 'transform' : key]
|
|
238
|
+
// console.log('animationOptions=', { delay, duration, easing })
|
|
239
|
+
let callback
|
|
240
|
+
if (transitionend && (!isTransformKey || !transformTransitionendDone)) {
|
|
241
|
+
runOnJSCallbackRef.current = {
|
|
242
|
+
animationCallback: (duration: number, finished: boolean, current?: AnimatableValue) => {
|
|
243
|
+
transitionend(finished, current, duration)
|
|
244
|
+
}
|
|
241
245
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
246
|
+
callback = (finished?: boolean, current?: AnimatableValue) => {
|
|
247
|
+
'worklet'
|
|
248
|
+
// 动画结束后设置下一次transformOrigin
|
|
249
|
+
if (finished) {
|
|
250
|
+
runOnJS(runOnJSCallback)('animationCallback', duration, finished, current)
|
|
251
|
+
}
|
|
248
252
|
}
|
|
249
253
|
}
|
|
254
|
+
const animation = getAnimation({ key, value: toVal! }, { delay, duration, easing }, callback)
|
|
255
|
+
// Todo transform 有多个属性时也仅执行一次 transitionend(对齐wx)
|
|
256
|
+
if (isTransformKey) {
|
|
257
|
+
transformTransitionendDone = true
|
|
258
|
+
}
|
|
259
|
+
shareValMap[key].value = animation
|
|
250
260
|
}
|
|
251
|
-
const animation = getAnimation({ key, value: toVal! }, { delay, duration, easing }, callback)
|
|
252
|
-
// Todo transform 有多个属性时也仅执行一次 transitionend(对齐wx)
|
|
253
|
-
if (isTransformKey) {
|
|
254
|
-
transformTransitionendDone = true
|
|
255
|
-
}
|
|
256
|
-
shareValMap[key].value = animation
|
|
257
261
|
// console.log(`useTransitionHooks, ${key}=`, animation)
|
|
258
262
|
})
|
|
259
263
|
}
|
|
@@ -278,7 +282,7 @@ export default function useTransitionHooks<T, P> (props: AnimationHooksPropsType
|
|
|
278
282
|
// ** 生成动画样式
|
|
279
283
|
return useAnimatedStyle(() => {
|
|
280
284
|
// console.info(`useAnimatedStyle styles=`, originalStyle)
|
|
281
|
-
return animatedStyleKeys.
|
|
285
|
+
return animatedStyleKeys.reduce((styles, key) => {
|
|
282
286
|
if (Array.isArray(key)) {
|
|
283
287
|
const transformStyle = getTransformObj(originalStyle.transform || [])
|
|
284
288
|
key.forEach((transformKey) => {
|
|
@@ -94,8 +94,9 @@ export const transformInitial: ExtendedViewStyle = {
|
|
|
94
94
|
export const animationAPIInitialValue: ExtendedViewStyle = Object.assign({
|
|
95
95
|
opacity: 1,
|
|
96
96
|
backgroundColor: 'transparent',
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
// fixme 未设置 height 初始值定义了 transition-property height 时把动画高度值把原由子元素撑开的高度给覆盖的问题
|
|
98
|
+
width: 'auto',
|
|
99
|
+
height: 'auto',
|
|
99
100
|
top: 0,
|
|
100
101
|
right: 0,
|
|
101
102
|
bottom: 0,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { hasOwn, dash2hump, error } from '@mpxjs/utils';
|
|
1
|
+
import { hasOwn, dash2hump, error, warn } from '@mpxjs/utils';
|
|
2
2
|
import { useMemo, useRef, useEffect } from 'react';
|
|
3
|
-
import { Easing, makeMutable, runOnJS,
|
|
3
|
+
import { Easing, makeMutable, runOnJS, useAnimatedStyle, cancelAnimation } from 'react-native-reanimated';
|
|
4
4
|
import { easingKey, transitionSupportedProperty, transformInitial, cubicBezierExp, secondRegExp, percentExp, getTransformObj, getUnit, getInitialVal, getAnimation, isTransform } from './utils';
|
|
5
5
|
import { parseValues, useRunOnJSCallback } from '../utils';
|
|
6
6
|
const propName = {
|
|
@@ -141,10 +141,11 @@ export default function useTransitionHooks(props) {
|
|
|
141
141
|
return parseTransitionStyle(originalStyle);
|
|
142
142
|
}, []);
|
|
143
143
|
// ** style prop sharedValue interpolateOutput: SharedValue<InterpolateOutput>
|
|
144
|
-
const { shareValMap, animatedKeys,
|
|
144
|
+
const { shareValMap, animatedKeys, animatedStyleKeys } = useMemo(() => {
|
|
145
145
|
// 记录需要执行动画的 propName
|
|
146
146
|
const animatedKeys = [];
|
|
147
|
-
|
|
147
|
+
// 有动画样式的 style key(useAnimatedStyle使用)
|
|
148
|
+
const animatedStyleKeys = [];
|
|
148
149
|
const transforms = [];
|
|
149
150
|
const shareValMap = Object.keys(transitionMap).reduce((valMap, property) => {
|
|
150
151
|
// const { property } = transition || {}
|
|
@@ -162,21 +163,19 @@ export default function useTransitionHooks(props) {
|
|
|
162
163
|
// console.log(`shareValMap property=${property} defaultVal=${defaultVal}`)
|
|
163
164
|
valMap[property] = makeMutable(defaultVal);
|
|
164
165
|
animatedKeys.push(property);
|
|
165
|
-
|
|
166
|
+
animatedStyleKeys.push(property);
|
|
166
167
|
}
|
|
167
168
|
// console.log('shareValMap = ', valMap)
|
|
168
169
|
return valMap;
|
|
169
170
|
}, {});
|
|
170
171
|
if (transforms.length)
|
|
171
|
-
|
|
172
|
+
animatedStyleKeys.push(transforms);
|
|
172
173
|
return {
|
|
173
174
|
shareValMap,
|
|
174
175
|
animatedKeys,
|
|
175
|
-
|
|
176
|
+
animatedStyleKeys
|
|
176
177
|
};
|
|
177
178
|
}, []);
|
|
178
|
-
// 有动画样式的 style key(useAnimatedStyle使用)
|
|
179
|
-
const animatedStyleKeys = useSharedValue(animatedKeysShareVal);
|
|
180
179
|
const runOnJSCallbackRef = useRef({});
|
|
181
180
|
const runOnJSCallback = useRunOnJSCallback(runOnJSCallbackRef);
|
|
182
181
|
// 根据 animation action 创建&驱动动画
|
|
@@ -204,32 +203,38 @@ export default function useTransitionHooks(props) {
|
|
|
204
203
|
}
|
|
205
204
|
else if (typeof toVal !== typeof shareVal) {
|
|
206
205
|
// 动画起始值和终态值类型不一致报错提示一下
|
|
207
|
-
|
|
206
|
+
warn(`[Mpx runtime error]: Value types of property ${key} must be consistent during the animation`);
|
|
208
207
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
let callback;
|
|
213
|
-
if (transitionend && (!isTransformKey || !transformTransitionendDone)) {
|
|
214
|
-
runOnJSCallbackRef.current = {
|
|
215
|
-
animationCallback: (duration, finished, current) => {
|
|
216
|
-
transitionend(finished, current, duration);
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
callback = (finished, current) => {
|
|
220
|
-
'worklet';
|
|
221
|
-
// 动画结束后设置下一次transformOrigin
|
|
222
|
-
if (finished) {
|
|
223
|
-
runOnJS(runOnJSCallback)('animationCallback', duration, finished, current);
|
|
224
|
-
}
|
|
225
|
-
};
|
|
208
|
+
if ((toVal === 'auto' && !isNaN(+shareVal)) || (shareVal === 'auto' && !isNaN(+toVal))) {
|
|
209
|
+
// 有 auto 直接赋值不做动画
|
|
210
|
+
shareValMap[key].value = toVal;
|
|
226
211
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
212
|
+
else {
|
|
213
|
+
// console.log(`key=${key} oldVal=${shareValMap[key].value} newVal=${toVal}`)
|
|
214
|
+
const { delay = 0, duration, easing } = transitionMap[isTransformKey ? 'transform' : key];
|
|
215
|
+
// console.log('animationOptions=', { delay, duration, easing })
|
|
216
|
+
let callback;
|
|
217
|
+
if (transitionend && (!isTransformKey || !transformTransitionendDone)) {
|
|
218
|
+
runOnJSCallbackRef.current = {
|
|
219
|
+
animationCallback: (duration, finished, current) => {
|
|
220
|
+
transitionend(finished, current, duration);
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
callback = (finished, current) => {
|
|
224
|
+
'worklet';
|
|
225
|
+
// 动画结束后设置下一次transformOrigin
|
|
226
|
+
if (finished) {
|
|
227
|
+
runOnJS(runOnJSCallback)('animationCallback', duration, finished, current);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
const animation = getAnimation({ key, value: toVal }, { delay, duration, easing }, callback);
|
|
232
|
+
// Todo transform 有多个属性时也仅执行一次 transitionend(对齐wx)
|
|
233
|
+
if (isTransformKey) {
|
|
234
|
+
transformTransitionendDone = true;
|
|
235
|
+
}
|
|
236
|
+
shareValMap[key].value = animation;
|
|
231
237
|
}
|
|
232
|
-
shareValMap[key].value = animation;
|
|
233
238
|
// console.log(`useTransitionHooks, ${key}=`, animation)
|
|
234
239
|
});
|
|
235
240
|
}
|
|
@@ -254,7 +259,7 @@ export default function useTransitionHooks(props) {
|
|
|
254
259
|
// ** 生成动画样式
|
|
255
260
|
return useAnimatedStyle(() => {
|
|
256
261
|
// console.info(`useAnimatedStyle styles=`, originalStyle)
|
|
257
|
-
return animatedStyleKeys.
|
|
262
|
+
return animatedStyleKeys.reduce((styles, key) => {
|
|
258
263
|
if (Array.isArray(key)) {
|
|
259
264
|
const transformStyle = getTransformObj(originalStyle.transform || []);
|
|
260
265
|
key.forEach((transformKey) => {
|
|
@@ -47,8 +47,9 @@ export const transformInitial = {
|
|
|
47
47
|
export const animationAPIInitialValue = Object.assign({
|
|
48
48
|
opacity: 1,
|
|
49
49
|
backgroundColor: 'transparent',
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
// fixme 未设置 height 初始值定义了 transition-property height 时把动画高度值把原由子元素撑开的高度给覆盖的问题
|
|
51
|
+
width: 'auto',
|
|
52
|
+
height: 'auto',
|
|
52
53
|
top: 0,
|
|
53
54
|
right: 0,
|
|
54
55
|
bottom: 0,
|
|
@@ -16,7 +16,7 @@ import { noop } from '@mpxjs/utils';
|
|
|
16
16
|
import { SvgCssUri } from 'react-native-svg/css';
|
|
17
17
|
import useInnerProps, { getCustomEvent } from './getInnerListeners';
|
|
18
18
|
import useNodesRef from './useNodesRef';
|
|
19
|
-
import { SVG_REGEXP, useLayout, useTransformStyle, renderImage, extendObject } from './utils';
|
|
19
|
+
import { SVG_REGEXP, useLayout, useTransformStyle, renderImage, extendObject, isAndroid } from './utils';
|
|
20
20
|
import Portal from './mpx-portal';
|
|
21
21
|
const DEFAULT_IMAGE_WIDTH = 320;
|
|
22
22
|
const DEFAULT_IMAGE_HEIGHT = 240;
|
|
@@ -104,7 +104,7 @@ const Image = forwardRef((props, ref) => {
|
|
|
104
104
|
setLoaded(true);
|
|
105
105
|
}
|
|
106
106
|
};
|
|
107
|
-
const { hasPositionFixed, hasSelfPercent, normalStyle, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
|
|
107
|
+
const { hasPositionFixed, hasSelfPercent, normalStyle, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, isTransformBorderRadiusPercent: isAndroid && !isSvg && !isLayoutMode, externalVarContext, parentFontSize, parentWidth, parentHeight });
|
|
108
108
|
const { layoutRef, layoutStyle, layoutProps } = useLayout({
|
|
109
109
|
props,
|
|
110
110
|
hasSelfPercent,
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface ListItem {
|
|
3
|
+
isSectionHeader?: boolean;
|
|
4
|
+
_originalItemIndex?: number;
|
|
5
|
+
[key: string]: any;
|
|
6
|
+
}
|
|
7
|
+
interface ItemHeightType {
|
|
8
|
+
value?: number;
|
|
9
|
+
getter?: (item: any, index: number) => number;
|
|
10
|
+
}
|
|
11
|
+
interface RecycleViewProps {
|
|
12
|
+
enhanced?: boolean;
|
|
13
|
+
bounces?: boolean;
|
|
14
|
+
scrollEventThrottle?: number;
|
|
15
|
+
height?: number | string;
|
|
16
|
+
width?: number | string;
|
|
17
|
+
listData?: ListItem[];
|
|
18
|
+
generichash?: string;
|
|
19
|
+
style?: Record<string, any>;
|
|
20
|
+
itemHeight?: ItemHeightType;
|
|
21
|
+
sectionHeaderHeight?: ItemHeightType;
|
|
22
|
+
listHeaderData?: any;
|
|
23
|
+
listHeaderHeight?: ItemHeightType;
|
|
24
|
+
useListHeader?: boolean;
|
|
25
|
+
'genericrecycle-item'?: string;
|
|
26
|
+
'genericsection-header'?: string;
|
|
27
|
+
'genericlist-header'?: string;
|
|
28
|
+
'enable-var'?: boolean;
|
|
29
|
+
'external-var-context'?: any;
|
|
30
|
+
'parent-font-size'?: number;
|
|
31
|
+
'parent-width'?: number;
|
|
32
|
+
'parent-height'?: number;
|
|
33
|
+
'enable-sticky'?: boolean;
|
|
34
|
+
'enable-back-to-top'?: boolean;
|
|
35
|
+
'end-reached-threshold'?: number;
|
|
36
|
+
'refresher-enabled'?: boolean;
|
|
37
|
+
'show-scrollbar'?: boolean;
|
|
38
|
+
'refresher-triggered'?: boolean;
|
|
39
|
+
bindrefresherrefresh?: (event: any) => void;
|
|
40
|
+
bindscrolltolower?: (event: any) => void;
|
|
41
|
+
bindscroll?: (event: any) => void;
|
|
42
|
+
[key: string]: any;
|
|
43
|
+
}
|
|
44
|
+
declare const RecycleView: React.ForwardRefExoticComponent<Omit<RecycleViewProps, "ref"> & React.RefAttributes<any>>;
|
|
45
|
+
export default RecycleView;
|