@mpxjs/webpack-plugin 2.10.15-5 → 2.10.15
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/LICENSE +433 -0
- package/lib/index.js +2 -5
- package/lib/platform/template/wx/component-config/progress.js +12 -0
- package/lib/platform/template/wx/component-config/unsupported.js +1 -1
- package/lib/platform/template/wx/index.js +3 -1
- package/lib/runtime/components/react/dist/getInnerListeners.js +35 -21
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +102 -34
- package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +3 -5
- package/lib/runtime/components/react/dist/mpx-progress.jsx +159 -0
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +38 -7
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +9 -16
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +20 -1
- package/lib/runtime/components/react/getInnerListeners.ts +41 -22
- package/lib/runtime/components/react/mpx-movable-view.tsx +156 -48
- package/lib/runtime/components/react/mpx-portal/portal-manager.tsx +4 -8
- package/lib/runtime/components/react/mpx-progress.tsx +257 -0
- package/lib/runtime/components/react/mpx-scroll-view.tsx +39 -7
- package/lib/runtime/components/react/mpx-swiper.tsx +9 -16
- package/lib/runtime/components/react/mpx-web-view.tsx +22 -1
- package/lib/runtime/components/react/types/getInnerListeners.d.ts +7 -2
- package/lib/runtime/components/web/mpx-movable-area.vue +43 -19
- package/lib/runtime/components/web/mpx-movable-view.vue +93 -3
- package/lib/runtime/components/web/mpx-swiper.vue +1 -2
- package/lib/runtime/components/web/mpx-web-view.vue +3 -3
- package/lib/template-compiler/compiler.js +61 -31
- package/lib/wxss/utils.js +1 -1
- package/package.json +3 -3
|
@@ -194,6 +194,8 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
194
194
|
white: ['#fff']
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
const isContentSizeChange = useRef(false)
|
|
198
|
+
|
|
197
199
|
const { refresherContent, otherContent } = getRefresherContent(props.children)
|
|
198
200
|
const hasRefresher = refresherContent && refresherEnabled
|
|
199
201
|
|
|
@@ -379,7 +381,22 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
379
381
|
}
|
|
380
382
|
|
|
381
383
|
function onContentSizeChange (width: number, height: number) {
|
|
382
|
-
|
|
384
|
+
isContentSizeChange.current = true
|
|
385
|
+
const newContentLength = selectLength({ height, width })
|
|
386
|
+
const oldContentLength = scrollOptions.current.contentLength
|
|
387
|
+
scrollOptions.current.contentLength = newContentLength
|
|
388
|
+
// 内容高度变化时,Animated.event 的映射可能会有不生效的场景,所以需要手动设置一下 scrollOffset 的值
|
|
389
|
+
if (enableSticky && (__mpx_mode__ === 'android' || __mpx_mode__ === 'ios')) {
|
|
390
|
+
// 当内容变少时,检查当前滚动位置是否超出新的内容范围
|
|
391
|
+
if (newContentLength < oldContentLength) {
|
|
392
|
+
const { visibleLength, offset } = scrollOptions.current
|
|
393
|
+
const maxOffset = Math.max(0, newContentLength - visibleLength)
|
|
394
|
+
// 如果当前滚动位置超出了新的内容范围,调整滚动offset
|
|
395
|
+
if (offset > maxOffset && scrollY) {
|
|
396
|
+
scrollOffset.setValue(maxOffset)
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
383
400
|
}
|
|
384
401
|
|
|
385
402
|
function onLayout (e: LayoutChangeEvent) {
|
|
@@ -402,8 +419,9 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
402
419
|
|
|
403
420
|
function onScroll (e: NativeSyntheticEvent<NativeScrollEvent>) {
|
|
404
421
|
const { bindscroll } = props
|
|
405
|
-
const {
|
|
406
|
-
const {
|
|
422
|
+
const { contentOffset, layoutMeasurement, contentSize } = e.nativeEvent
|
|
423
|
+
const { x: scrollLeft, y: scrollTop } = contentOffset
|
|
424
|
+
const { width: scrollWidth, height: scrollHeight } = contentSize
|
|
407
425
|
isAtTop.value = scrollTop <= 0
|
|
408
426
|
bindscroll &&
|
|
409
427
|
bindscroll(
|
|
@@ -414,7 +432,8 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
414
432
|
scrollHeight,
|
|
415
433
|
scrollWidth,
|
|
416
434
|
deltaX: scrollLeft - scrollOptions.current.scrollLeft,
|
|
417
|
-
deltaY: scrollTop - scrollOptions.current.scrollTop
|
|
435
|
+
deltaY: scrollTop - scrollOptions.current.scrollTop,
|
|
436
|
+
layoutMeasurement
|
|
418
437
|
},
|
|
419
438
|
layoutRef
|
|
420
439
|
}, props)
|
|
@@ -429,8 +448,9 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
429
448
|
|
|
430
449
|
function onScrollEnd (e: NativeSyntheticEvent<NativeScrollEvent>) {
|
|
431
450
|
const { bindscrollend } = props
|
|
432
|
-
const {
|
|
433
|
-
const {
|
|
451
|
+
const { contentOffset, layoutMeasurement, contentSize } = e.nativeEvent
|
|
452
|
+
const { x: scrollLeft, y: scrollTop } = contentOffset
|
|
453
|
+
const { width: scrollWidth, height: scrollHeight } = contentSize
|
|
434
454
|
isAtTop.value = scrollTop <= 0
|
|
435
455
|
bindscrollend &&
|
|
436
456
|
bindscrollend(
|
|
@@ -439,7 +459,8 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
439
459
|
scrollLeft,
|
|
440
460
|
scrollTop,
|
|
441
461
|
scrollHeight,
|
|
442
|
-
scrollWidth
|
|
462
|
+
scrollWidth,
|
|
463
|
+
layoutMeasurement
|
|
443
464
|
},
|
|
444
465
|
layoutRef
|
|
445
466
|
}, props)
|
|
@@ -494,6 +515,16 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
494
515
|
{
|
|
495
516
|
useNativeDriver: true,
|
|
496
517
|
listener: (event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
518
|
+
const y = event.nativeEvent.contentOffset.y || 0
|
|
519
|
+
// 内容高度变化时,鸿蒙中 listener 回调通过scrollOffset.__getValue获取值一直等于event.nativeEvent.contentOffset.y,值是正确的,但是无法触发 sticky 动画执行,所以需要手动再 set 一次
|
|
520
|
+
if (__mpx_mode__ === 'harmony') {
|
|
521
|
+
if (isContentSizeChange.current) {
|
|
522
|
+
scrollOffset.setValue(y)
|
|
523
|
+
setTimeout(() => {
|
|
524
|
+
isContentSizeChange.current = false
|
|
525
|
+
}, 100)
|
|
526
|
+
}
|
|
527
|
+
}
|
|
497
528
|
onScroll(event)
|
|
498
529
|
}
|
|
499
530
|
}
|
|
@@ -702,6 +733,7 @@ const _ScrollView = forwardRef<HandlerRef<ScrollView & View, ScrollViewProps>, S
|
|
|
702
733
|
showsVerticalScrollIndicator: scrollY && showScrollbar,
|
|
703
734
|
scrollEnabled: !enableScroll ? false : !!(scrollX || scrollY),
|
|
704
735
|
bounces: false,
|
|
736
|
+
overScrollMode: 'never',
|
|
705
737
|
ref: scrollViewRef,
|
|
706
738
|
onScroll: enableSticky ? scrollHandler : onScroll,
|
|
707
739
|
onContentSizeChange: onContentSizeChange,
|
|
@@ -207,8 +207,6 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
207
207
|
const strVelocity = 'velocity' + dir.toUpperCase() as StrVelocityType
|
|
208
208
|
// 标识手指触摸和抬起, 起点在onBegin
|
|
209
209
|
const touchfinish = useSharedValue(true)
|
|
210
|
-
// 记录onUpdate时的方向,用于进行onFinalize中的值修正
|
|
211
|
-
const preUpdateTransDir = useSharedValue(0)
|
|
212
210
|
// 记录上一帧的绝对定位坐标
|
|
213
211
|
const preAbsolutePos = useSharedValue(0)
|
|
214
212
|
// 记录从onBegin 到 onTouchesUp 时移动的距离
|
|
@@ -431,9 +429,11 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
431
429
|
}
|
|
432
430
|
}, [])
|
|
433
431
|
|
|
434
|
-
function handleSwiperChange (current: number) {
|
|
435
|
-
|
|
436
|
-
|
|
432
|
+
function handleSwiperChange (current: number, pCurrent: number) {
|
|
433
|
+
if (pCurrent !== currentIndex.value) {
|
|
434
|
+
const eventData = getCustomEvent('change', {}, { detail: { current, source: 'touch' }, layoutRef: layoutRef })
|
|
435
|
+
bindchange && bindchange(eventData)
|
|
436
|
+
}
|
|
437
437
|
}
|
|
438
438
|
|
|
439
439
|
const runOnJSCallbackRef = useRef({
|
|
@@ -482,7 +482,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
482
482
|
// 1. 用户在当前页切换选中项,动画;用户携带选中index打开到swiper页直接选中不走动画
|
|
483
483
|
useAnimatedReaction(() => currentIndex.value, (newIndex: number, preIndex: number) => {
|
|
484
484
|
// 这里必须传递函数名, 直接写()=> {}形式会报 访问了未sharedValue信息
|
|
485
|
-
if (newIndex !== preIndex &&
|
|
485
|
+
if (newIndex !== preIndex && bindchange) {
|
|
486
486
|
runOnJS(runOnJSCallback)('handleSwiperChange', newIndex, propCurrent)
|
|
487
487
|
}
|
|
488
488
|
})
|
|
@@ -517,9 +517,9 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
517
517
|
}, [children.length])
|
|
518
518
|
|
|
519
519
|
useEffect(() => {
|
|
520
|
-
// 1. 如果用户在touch的过程中, 外部更新了current
|
|
520
|
+
// 1. 如果用户在touch的过程中, 外部更新了current以外部为准(小程序表现)
|
|
521
521
|
// 2. 手指滑动过程中更新索引,外部会把current再传入进来,导致offset直接更新,增加判断不同才更新
|
|
522
|
-
if (propCurrent !== currentIndex.value
|
|
522
|
+
if (propCurrent !== currentIndex.value) {
|
|
523
523
|
updateCurrent(propCurrent, step.value)
|
|
524
524
|
}
|
|
525
525
|
}, [propCurrent])
|
|
@@ -757,7 +757,6 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
757
757
|
translation: moveDistance,
|
|
758
758
|
transdir: moveDistance
|
|
759
759
|
}
|
|
760
|
-
preUpdateTransDir.value = moveDistance
|
|
761
760
|
// 1. 支持滑动中超出一半更新索引的能力:只更新索引并不会影响onFinalize依据当前offset计算的索引
|
|
762
761
|
const { half } = computeHalf(eventData)
|
|
763
762
|
if (childrenLength.value > 1 && half) {
|
|
@@ -795,17 +794,11 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
795
794
|
'worklet'
|
|
796
795
|
if (touchfinish.value) return
|
|
797
796
|
touchfinish.value = true
|
|
798
|
-
/**
|
|
799
|
-
* 安卓修正
|
|
800
|
-
* 问题:部分安卓机型onFinalize中拿到的absoluteX 有问题
|
|
801
|
-
* 案例:比如手指从右向左滑的时候,onUpdate拿到的是241.64346313476562, 而onFinalize中拿到的是241.81817626953125,理论上onFinalize中应该比onUpdate小才对吧
|
|
802
|
-
* 解决方式:修正
|
|
803
|
-
*/
|
|
804
797
|
// 触发过onUpdate正常情况下e[strAbso] - preAbsolutePos.value=0; 未触发过onUpdate的情况下e[strAbso] - preAbsolutePos.value 不为0
|
|
805
798
|
const moveDistance = e[strAbso] - preAbsolutePos.value
|
|
806
799
|
const eventData = {
|
|
807
800
|
translation: moveDistance,
|
|
808
|
-
transdir:
|
|
801
|
+
transdir: moveDistance !== 0 ? moveDistance : e[strAbso] - moveTranstion.value
|
|
809
802
|
}
|
|
810
803
|
// 1. 只有一个元素:循环 和 非循环状态,都走回弹效果
|
|
811
804
|
if (childrenLength.value === 1) {
|
|
@@ -76,6 +76,7 @@ const styles = StyleSheet.create({
|
|
|
76
76
|
borderRadius: 10
|
|
77
77
|
}
|
|
78
78
|
})
|
|
79
|
+
|
|
79
80
|
const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((props, ref): JSX.Element | null => {
|
|
80
81
|
const { src, bindmessage, bindload, binderror } = props
|
|
81
82
|
const mpx = global.__mpx
|
|
@@ -126,10 +127,27 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
|
|
|
126
127
|
style: defaultWebViewStyle
|
|
127
128
|
})
|
|
128
129
|
|
|
130
|
+
const hostValidate = (url: string) => {
|
|
131
|
+
const host = url && new URL(url).host
|
|
132
|
+
const hostWhitelists = mpx.config.rnConfig?.webviewConfig?.hostWhitelists || []
|
|
133
|
+
if (hostWhitelists.length) {
|
|
134
|
+
return hostWhitelists.some((item: string) => {
|
|
135
|
+
return host.endsWith(item)
|
|
136
|
+
})
|
|
137
|
+
} else {
|
|
138
|
+
return true
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
129
142
|
if (!src) {
|
|
130
143
|
return null
|
|
131
144
|
}
|
|
132
145
|
|
|
146
|
+
if (!hostValidate(src)) {
|
|
147
|
+
console.error('访问页面域名不符合domainWhiteLists白名单配置,请确认是否正确配置该域名白名单')
|
|
148
|
+
return null
|
|
149
|
+
}
|
|
150
|
+
|
|
133
151
|
const _reload = function () {
|
|
134
152
|
if (__mpx_mode__ !== 'ios') {
|
|
135
153
|
fristLoaded.current = false // 安卓需要重新设置
|
|
@@ -182,6 +200,9 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
|
|
|
182
200
|
}
|
|
183
201
|
}
|
|
184
202
|
const _message = function (res: WebViewMessageEvent) {
|
|
203
|
+
if (!hostValidate(res.nativeEvent?.url)) {
|
|
204
|
+
return
|
|
205
|
+
}
|
|
185
206
|
let data: MessageData = {}
|
|
186
207
|
let asyncCallback
|
|
187
208
|
const navObj = promisify({ redirectTo, navigateTo, navigateBack, reLaunch, switchTab })
|
|
@@ -232,7 +253,7 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
|
|
|
232
253
|
break
|
|
233
254
|
default:
|
|
234
255
|
if (type) {
|
|
235
|
-
const implement = mpx.config.webviewConfig.apiImplementations && mpx.config.webviewConfig.apiImplementations[type]
|
|
256
|
+
const implement = mpx.config.rnConfig.webviewConfig && mpx.config.rnConfig.webviewConfig.apiImplementations && mpx.config.rnConfig.webviewConfig.apiImplementations[type]
|
|
236
257
|
if (isFunction(implement)) {
|
|
237
258
|
asyncCallback = Promise.resolve(implement(...params))
|
|
238
259
|
} else {
|
|
@@ -84,12 +84,16 @@ interface ExtendedNativeTouchEvent extends NativeTouchEvent {
|
|
|
84
84
|
_stoppedEventTypes?: Set<string>
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
interface GlobalEventState {
|
|
88
|
+
needPress: boolean
|
|
89
|
+
identifier: null | number
|
|
90
|
+
}
|
|
91
|
+
|
|
87
92
|
export {
|
|
88
93
|
NativeTouchEvent,
|
|
89
94
|
Props,
|
|
90
95
|
AdditionalProps,
|
|
91
96
|
RemoveProps,
|
|
92
|
-
UseInnerPropsConfig,
|
|
93
97
|
InnerRef,
|
|
94
98
|
LayoutRef,
|
|
95
99
|
PropsRef,
|
|
@@ -98,5 +102,6 @@ export {
|
|
|
98
102
|
ExtendedNativeTouchEvent,
|
|
99
103
|
EventConfig,
|
|
100
104
|
RawConfig,
|
|
101
|
-
EventType
|
|
105
|
+
EventType,
|
|
106
|
+
GlobalEventState
|
|
102
107
|
}
|
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
</div>
|
|
2
|
+
<div class="mpx-movable-area-container" ref="movableArea">
|
|
3
|
+
<div class="mpx-movable-scroll-wrapper" ref="scroll">
|
|
4
|
+
<slot></slot>
|
|
6
5
|
</div>
|
|
6
|
+
</div>
|
|
7
7
|
</template>
|
|
8
8
|
|
|
9
9
|
<script type="text/ecmascript-6">
|
|
10
10
|
export default {
|
|
11
|
-
data
|
|
12
|
-
return {
|
|
11
|
+
data() {
|
|
12
|
+
return {
|
|
13
|
+
isInited: false,
|
|
14
|
+
}
|
|
13
15
|
},
|
|
14
|
-
mounted
|
|
16
|
+
mounted() {
|
|
15
17
|
this.computedStyle()
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
if (!this.closeResizeObserver) {
|
|
19
|
+
this.createResizeObserver()
|
|
20
|
+
}
|
|
19
21
|
},
|
|
20
22
|
methods: {
|
|
21
23
|
computedStyle() {
|
|
@@ -26,17 +28,39 @@
|
|
|
26
28
|
if (!style.height) {
|
|
27
29
|
this.$refs.movableArea.style.height = '10px'
|
|
28
30
|
}
|
|
31
|
+
},
|
|
32
|
+
createResizeObserver() {
|
|
33
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
34
|
+
this.resizeObserver = new ResizeObserver(entries => {
|
|
35
|
+
if (!this.isInited) {
|
|
36
|
+
this.isInited = true
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
this.$children.forEach(child => {
|
|
40
|
+
if (child && child.refresh) {
|
|
41
|
+
child.refresh()
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
this.resizeObserver.observe(this.$refs.movableArea)
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
beforeDestroy () {
|
|
50
|
+
if (this.resizeObserver) {
|
|
51
|
+
this.resizeObserver.disconnect()
|
|
52
|
+
this.resizeObserver = null
|
|
29
53
|
}
|
|
30
|
-
}
|
|
54
|
+
},
|
|
31
55
|
}
|
|
32
56
|
</script>
|
|
33
57
|
<style lang="stylus" rel="stylesheet/stylus" scoped>
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
58
|
+
.mpx-movable-area-container
|
|
59
|
+
position: relative
|
|
60
|
+
.mpx-movable-scroll-wrapper
|
|
61
|
+
position: absolute
|
|
62
|
+
top: 0
|
|
63
|
+
left: 0
|
|
64
|
+
bottom: 0
|
|
65
|
+
right: 0
|
|
42
66
|
</style>
|
|
@@ -38,7 +38,13 @@ export default {
|
|
|
38
38
|
touchEvent: '',
|
|
39
39
|
isInited: false,
|
|
40
40
|
deactivatedX: 0,
|
|
41
|
-
deactivatedY: 0
|
|
41
|
+
deactivatedY: 0,
|
|
42
|
+
// 缓存高度,用于检测变化
|
|
43
|
+
cachedContentHeight: 0,
|
|
44
|
+
cachedWrapperHeight: 0,
|
|
45
|
+
// 缓存宽度,用于检测变化
|
|
46
|
+
cachedContentWidth: 0,
|
|
47
|
+
cachedWrapperWidth: 0
|
|
42
48
|
}
|
|
43
49
|
},
|
|
44
50
|
props: {
|
|
@@ -107,7 +113,24 @@ export default {
|
|
|
107
113
|
},
|
|
108
114
|
watch: {
|
|
109
115
|
x (newVal) {
|
|
116
|
+
if (this.direction === 'vertical' || this.direction === 'none') {
|
|
117
|
+
return
|
|
118
|
+
}
|
|
110
119
|
this.source = ''
|
|
120
|
+
// 检查宽度是否发生变化,只有在变化时才调用 refresh
|
|
121
|
+
const widthChanged = this.checkWidthChange()
|
|
122
|
+
let currentX = this.bs.x
|
|
123
|
+
|
|
124
|
+
if (widthChanged) {
|
|
125
|
+
// 兼容容器尺寸变化且同时改变x的场景,ResizeObserver回调是异步的,如果不直接refresh,minScrollX, maxScrollX 拿到的都是上一次的值
|
|
126
|
+
this.refresh()
|
|
127
|
+
// bs refresh 方法内会触发 resetPosition(),如果容器宽度从 100 - 50,y 从 100 - 50,这会导致位置立即跳转到边界内,没有动画效果,造成视觉突兀
|
|
128
|
+
// 如果 refresh 导致了位置变化,先恢复到原位置再动画滚动
|
|
129
|
+
if (this.bs.x !== currentX) {
|
|
130
|
+
this.bs.scrollTo(currentX, this.bs.y, 0)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
111
134
|
if (newVal > this.bs.minScrollX) {
|
|
112
135
|
newVal = this.bs.minScrollX
|
|
113
136
|
}
|
|
@@ -118,7 +141,24 @@ export default {
|
|
|
118
141
|
this.bs.scrollTo(newVal, this.bs.y, this.speed)
|
|
119
142
|
},
|
|
120
143
|
y (newVal) {
|
|
144
|
+
if (this.direction === 'horizontal' || this.direction === 'none') {
|
|
145
|
+
return
|
|
146
|
+
}
|
|
121
147
|
this.source = ''
|
|
148
|
+
// 检查高度是否发生变化,只有在变化时才调用 refresh
|
|
149
|
+
const heightChanged = this.checkHeightChange()
|
|
150
|
+
let currentY = this.bs.y
|
|
151
|
+
|
|
152
|
+
if (heightChanged) {
|
|
153
|
+
// 兼容容器尺寸变化且同时改变y的场景,ResizeObserver回调是异步的,如果不直接refresh,minScrollY, maxScrollY 拿到的都是上一次的值
|
|
154
|
+
this.refresh()
|
|
155
|
+
// bs refresh 方法内会触发 resetPosition(),如果容器高度从 100 - 50,y 从 100 - 50,这会导致位置立即跳转到边界内,没有动画效果,造成视觉突兀
|
|
156
|
+
// 如果 refresh 导致了位置变化,先恢复到原位置再动画滚动
|
|
157
|
+
if (this.bs.y !== currentY) {
|
|
158
|
+
this.bs.scrollTo(this.bs.x, currentY, 0)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
122
162
|
if (newVal > this.bs.minScrollY) {
|
|
123
163
|
newVal = this.bs.minScrollY
|
|
124
164
|
}
|
|
@@ -146,6 +186,10 @@ export default {
|
|
|
146
186
|
if (!this.scrollOptions.closeResizeObserver) {
|
|
147
187
|
this.createResizeObserver()
|
|
148
188
|
}
|
|
189
|
+
// 初始化尺寸缓存
|
|
190
|
+
this.$nextTick(() => {
|
|
191
|
+
this.initSizeCache()
|
|
192
|
+
})
|
|
149
193
|
this.init()
|
|
150
194
|
},
|
|
151
195
|
activated () {
|
|
@@ -178,13 +222,50 @@ export default {
|
|
|
178
222
|
}
|
|
179
223
|
this.refresh()
|
|
180
224
|
})
|
|
181
|
-
|
|
182
|
-
elementToObserve && this.resizeObserver.observe(elementToObserve)
|
|
225
|
+
this.resizeObserver.observe(this.$refs.scrollContent)
|
|
183
226
|
}
|
|
184
227
|
},
|
|
185
228
|
refresh () {
|
|
186
229
|
this.bs && this.bs.refresh()
|
|
187
230
|
},
|
|
231
|
+
// 检查高度是否发生变化
|
|
232
|
+
checkHeightChange () {
|
|
233
|
+
if (!this.$refs.scrollContent || !this.$parent.$refs.movableArea) {
|
|
234
|
+
return false
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const currentContentHeight = this.$refs.scrollContent.clientHeight
|
|
238
|
+
const currentWrapperHeight = this.$parent.$refs.movableArea.clientHeight
|
|
239
|
+
|
|
240
|
+
const heightChanged =
|
|
241
|
+
currentContentHeight !== this.cachedContentHeight ||
|
|
242
|
+
currentWrapperHeight !== this.cachedWrapperHeight
|
|
243
|
+
|
|
244
|
+
// 更新缓存的高度
|
|
245
|
+
this.cachedContentHeight = currentContentHeight
|
|
246
|
+
this.cachedWrapperHeight = currentWrapperHeight
|
|
247
|
+
|
|
248
|
+
return heightChanged
|
|
249
|
+
},
|
|
250
|
+
// 检查宽度是否发生变化
|
|
251
|
+
checkWidthChange () {
|
|
252
|
+
if (!this.$refs.scrollContent || !this.$parent.$refs.movableArea) {
|
|
253
|
+
return false
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const currentContentWidth = this.$refs.scrollContent.clientWidth
|
|
257
|
+
const currentWrapperWidth = this.$parent.$refs.movableArea.clientWidth
|
|
258
|
+
|
|
259
|
+
const widthChanged =
|
|
260
|
+
currentContentWidth !== this.cachedContentWidth ||
|
|
261
|
+
currentWrapperWidth !== this.cachedWrapperWidth
|
|
262
|
+
|
|
263
|
+
// 更新缓存的宽度
|
|
264
|
+
this.cachedContentWidth = currentContentWidth
|
|
265
|
+
this.cachedWrapperWidth = currentWrapperWidth
|
|
266
|
+
|
|
267
|
+
return widthChanged
|
|
268
|
+
},
|
|
188
269
|
destroyBs () {
|
|
189
270
|
if (!this.bs) return
|
|
190
271
|
this.bs.destroy()
|
|
@@ -364,6 +445,15 @@ export default {
|
|
|
364
445
|
}
|
|
365
446
|
extend(this.bsOptions, this.scrollOptions)
|
|
366
447
|
},
|
|
448
|
+
// 初始化尺寸缓存
|
|
449
|
+
initSizeCache () {
|
|
450
|
+
if (this.$refs.scrollContent && this.$parent.$refs.movableArea) {
|
|
451
|
+
this.cachedContentHeight = this.$refs.scrollContent.clientHeight
|
|
452
|
+
this.cachedWrapperHeight = this.$parent.$refs.movableArea.clientHeight
|
|
453
|
+
this.cachedContentWidth = this.$refs.scrollContent.clientWidth
|
|
454
|
+
this.cachedWrapperWidth = this.$parent.$refs.movableArea.clientWidth
|
|
455
|
+
}
|
|
456
|
+
},
|
|
367
457
|
// 处理小数点,四舍五入,默认保留一位小数
|
|
368
458
|
roundFun (value, n = 1) {
|
|
369
459
|
return Math.round(value * Math.pow(10, n)) / Math.pow(10, n)
|
|
@@ -124,7 +124,7 @@ export default {
|
|
|
124
124
|
case 'postMessage':
|
|
125
125
|
let data = {
|
|
126
126
|
type: 'message',
|
|
127
|
-
data: params[0]?.data
|
|
127
|
+
data: params[0]?.data || params[0] // 补充兜底逻辑
|
|
128
128
|
}
|
|
129
129
|
this.$emit(eventMessage, getCustomEvent(eventMessage, data, this))
|
|
130
130
|
asyncCallback = Promise.resolve({
|
|
@@ -148,7 +148,7 @@ export default {
|
|
|
148
148
|
break
|
|
149
149
|
default:
|
|
150
150
|
if (type) {
|
|
151
|
-
const implement = mpx.config.webviewConfig
|
|
151
|
+
const implement = mpx.config.webConfig?.webviewConfig?.apiImplementations?.[type]
|
|
152
152
|
if (isFunction(implement)) {
|
|
153
153
|
asyncCallback = Promise.resolve(implement(...params))
|
|
154
154
|
} else {
|
|
@@ -174,7 +174,7 @@ export default {
|
|
|
174
174
|
})
|
|
175
175
|
},
|
|
176
176
|
hostValidate (host) {
|
|
177
|
-
const hostWhitelists = mpx.config.webviewConfig
|
|
177
|
+
const hostWhitelists = mpx.config.webConfig?.webviewConfig?.hostWhitelists || []
|
|
178
178
|
if (hostWhitelists.length) {
|
|
179
179
|
return hostWhitelists.some((item) => {
|
|
180
180
|
return host.endsWith(item)
|
|
@@ -1333,8 +1333,35 @@ function processEventReact (el, options) {
|
|
|
1333
1333
|
// }
|
|
1334
1334
|
}
|
|
1335
1335
|
|
|
1336
|
+
function isNeedBind (configs, isProxy) {
|
|
1337
|
+
if (isProxy) return true
|
|
1338
|
+
if (configs.length > 1) return true
|
|
1339
|
+
if (configs.length === 1) return configs[0].hasArgs
|
|
1340
|
+
return false
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
function processEventBinding (el, configs) {
|
|
1344
|
+
let resultName
|
|
1345
|
+
configs.forEach(({ name }) => {
|
|
1346
|
+
if (name) {
|
|
1347
|
+
// 清空原始事件绑定
|
|
1348
|
+
let has
|
|
1349
|
+
do {
|
|
1350
|
+
has = getAndRemoveAttr(el, name).has
|
|
1351
|
+
} while (has)
|
|
1352
|
+
|
|
1353
|
+
if (!resultName) {
|
|
1354
|
+
// 清除修饰符
|
|
1355
|
+
resultName = name.replace(/\..*/, '')
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
})
|
|
1359
|
+
return { resultName }
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1336
1362
|
function processEvent (el, options) {
|
|
1337
1363
|
const eventConfigMap = {}
|
|
1364
|
+
const finalEventsMap = {}
|
|
1338
1365
|
el.attrsList.forEach(function ({ name, value }) {
|
|
1339
1366
|
const parsedEvent = config[mode].event.parseEvent(name)
|
|
1340
1367
|
|
|
@@ -1346,12 +1373,15 @@ function processEvent (el, options) {
|
|
|
1346
1373
|
const extraStr = runtimeCompile && prefix === 'catch' ? `, "__mpx_${prefix}"` : ''
|
|
1347
1374
|
const parsedFunc = parseFuncStr(value, extraStr)
|
|
1348
1375
|
if (parsedFunc) {
|
|
1376
|
+
const isCapture = /^capture/.test(prefix)
|
|
1349
1377
|
if (!eventConfigMap[type]) {
|
|
1350
1378
|
eventConfigMap[type] = {
|
|
1351
|
-
configs: []
|
|
1379
|
+
configs: [],
|
|
1380
|
+
captureConfigs: []
|
|
1352
1381
|
}
|
|
1353
1382
|
}
|
|
1354
|
-
eventConfigMap[type].
|
|
1383
|
+
const targetConfigs = isCapture ? eventConfigMap[type].captureConfigs : eventConfigMap[type].configs
|
|
1384
|
+
targetConfigs.push(Object.assign({ name }, parsedFunc))
|
|
1355
1385
|
if (modifiers.indexOf('proxy') > -1 || options.forceProxyEvent) {
|
|
1356
1386
|
eventConfigMap[type].proxy = true
|
|
1357
1387
|
}
|
|
@@ -1393,57 +1423,57 @@ function processEvent (el, options) {
|
|
|
1393
1423
|
}
|
|
1394
1424
|
|
|
1395
1425
|
for (const type in eventConfigMap) {
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
needBind = true
|
|
1401
|
-
} else if (configs.length > 1) {
|
|
1402
|
-
needBind = true
|
|
1403
|
-
} else if (configs.length === 1) {
|
|
1404
|
-
needBind = !!configs[0].hasArgs
|
|
1405
|
-
}
|
|
1426
|
+
const { configs = [], captureConfigs = [], proxy } = eventConfigMap[type]
|
|
1427
|
+
|
|
1428
|
+
let needBubblingBind = isNeedBind(configs, proxy)
|
|
1429
|
+
let needCaptureBind = isNeedBind(captureConfigs, proxy)
|
|
1406
1430
|
|
|
1407
1431
|
const escapedType = dash2hump(type)
|
|
1408
1432
|
// 排除特殊情况
|
|
1409
1433
|
if (!isValidIdentifierStr(escapedType)) {
|
|
1410
1434
|
warn$1(`EventName ${type} which need be framework proxy processed must be a valid identifier!`)
|
|
1411
|
-
|
|
1435
|
+
needBubblingBind = false
|
|
1436
|
+
needCaptureBind = false
|
|
1412
1437
|
}
|
|
1413
1438
|
|
|
1414
|
-
if (
|
|
1415
|
-
|
|
1416
|
-
configs.forEach(({ name }) => {
|
|
1417
|
-
if (name) {
|
|
1418
|
-
// 清空原始事件绑定
|
|
1419
|
-
let has
|
|
1420
|
-
do {
|
|
1421
|
-
has = getAndRemoveAttr(el, name).has
|
|
1422
|
-
} while (has)
|
|
1439
|
+
if (needBubblingBind) {
|
|
1440
|
+
const { resultName } = processEventBinding(el, configs)
|
|
1423
1441
|
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1442
|
+
addAttrs(el, [
|
|
1443
|
+
{
|
|
1444
|
+
name: resultName || config[mode].event.getEvent(type),
|
|
1445
|
+
value: '__invoke'
|
|
1428
1446
|
}
|
|
1447
|
+
])
|
|
1448
|
+
if (!finalEventsMap.bubble) {
|
|
1449
|
+
finalEventsMap.bubble = {}
|
|
1450
|
+
}
|
|
1451
|
+
finalEventsMap.bubble[escapedType] = configs.map((item) => {
|
|
1452
|
+
return item.expStr
|
|
1429
1453
|
})
|
|
1454
|
+
}
|
|
1430
1455
|
|
|
1456
|
+
if (needCaptureBind) {
|
|
1457
|
+
const { resultName } = processEventBinding(el, captureConfigs)
|
|
1431
1458
|
addAttrs(el, [
|
|
1432
1459
|
{
|
|
1433
1460
|
name: resultName || config[mode].event.getEvent(type),
|
|
1434
|
-
value: '
|
|
1461
|
+
value: '__captureInvoke'
|
|
1435
1462
|
}
|
|
1436
1463
|
])
|
|
1437
|
-
|
|
1464
|
+
if (!finalEventsMap.capture) {
|
|
1465
|
+
finalEventsMap.capture = {}
|
|
1466
|
+
}
|
|
1467
|
+
finalEventsMap.capture[escapedType] = captureConfigs.map((item) => {
|
|
1438
1468
|
return item.expStr
|
|
1439
1469
|
})
|
|
1440
1470
|
}
|
|
1441
1471
|
}
|
|
1442
1472
|
|
|
1443
|
-
if (!isEmptyObject(
|
|
1473
|
+
if (!isEmptyObject(finalEventsMap)) {
|
|
1444
1474
|
addAttrs(el, [{
|
|
1445
1475
|
name: 'data-eventconfigs',
|
|
1446
|
-
value: `{{${shallowStringify(
|
|
1476
|
+
value: `{{${shallowStringify(finalEventsMap, true)}}}`
|
|
1447
1477
|
}])
|
|
1448
1478
|
}
|
|
1449
1479
|
}
|
|
@@ -2737,8 +2767,8 @@ function processElement (el, root, options, meta) {
|
|
|
2737
2767
|
processIf(el)
|
|
2738
2768
|
processFor(el)
|
|
2739
2769
|
processRefReact(el, meta)
|
|
2770
|
+
processStyleReact(el, options)
|
|
2740
2771
|
if (!pass) {
|
|
2741
|
-
processStyleReact(el, options)
|
|
2742
2772
|
processEventReact(el, options)
|
|
2743
2773
|
processComponentGenerics(el, meta)
|
|
2744
2774
|
processComponentIs(el, options)
|
package/lib/wxss/utils.js
CHANGED
|
@@ -1052,7 +1052,7 @@ function getModuleCode (
|
|
|
1052
1052
|
`@import url(${url});`
|
|
1053
1053
|
)}${printedParam.length > 0 ? `, ${printedParam}` : ''}]);\n`
|
|
1054
1054
|
} else {
|
|
1055
|
-
// 符合css后缀名的文件经过mpx处理后会带上相应的后缀防止使用
|
|
1055
|
+
// 符合css后缀名的文件经过mpx处理后会带上相应的后缀防止使用 webpack 的默认解析规则,此时 require/import 相应路径时,导出的不是一段 css 代码了,事实上是一个文件路径。
|
|
1056
1056
|
const printedParam = printParams(media, dedupe, supports, layer)
|
|
1057
1057
|
const otherParams = printedParam.length > 0 ? printedParam : ''
|
|
1058
1058
|
beforeCode += `___CSS_LOADER_EXPORT___.push([module.id, '@import "' + ${item.importName} + '";', ${JSON.stringify(otherParams)} ]);\n`
|