@mpxjs/webpack-plugin 2.10.6 → 2.10.7-beta.10
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/index.js +71 -51
- package/lib/parser.js +1 -1
- package/lib/platform/json/wx/index.js +0 -1
- package/lib/platform/style/wx/index.js +7 -0
- package/lib/platform/template/wx/component-config/button.js +1 -1
- package/lib/platform/template/wx/component-config/index.js +5 -1
- package/lib/platform/template/wx/component-config/input.js +1 -1
- package/lib/platform/template/wx/component-config/movable-view.js +1 -10
- 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/processJSON.js +2 -1
- package/lib/runtime/components/react/AsyncContainer.tsx +189 -0
- package/lib/runtime/components/react/context.ts +23 -4
- package/lib/runtime/components/react/dist/AsyncContainer.jsx +141 -0
- package/lib/runtime/components/react/dist/context.js +5 -2
- package/lib/runtime/components/react/dist/mpx-button.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-input.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-movable-area.jsx +64 -10
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +358 -98
- package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +3 -0
- 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/dist/mpx-swiper-item.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +53 -27
- package/lib/runtime/components/react/dist/mpx-view.jsx +21 -7
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +13 -13
- package/lib/runtime/components/react/dist/utils.jsx +94 -1
- package/lib/runtime/components/react/mpx-button.tsx +3 -2
- package/lib/runtime/components/react/mpx-input.tsx +1 -1
- package/lib/runtime/components/react/mpx-movable-area.tsx +99 -12
- package/lib/runtime/components/react/mpx-movable-view.tsx +413 -100
- package/lib/runtime/components/react/mpx-rich-text/index.tsx +3 -0
- 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/react/mpx-swiper-item.tsx +2 -2
- package/lib/runtime/components/react/mpx-swiper.tsx +53 -25
- package/lib/runtime/components/react/mpx-view.tsx +20 -7
- package/lib/runtime/components/react/mpx-web-view.tsx +12 -12
- package/lib/runtime/components/react/utils.tsx +93 -1
- 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/optionProcessor.js +0 -2
- 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/package.json +4 -4
- package/LICENSE +0 -433
|
@@ -23,6 +23,7 @@ import Portal from './mpx-portal'
|
|
|
23
23
|
* ✔ easing-function ="easeOutCubic"
|
|
24
24
|
* ✘ display-multiple-items
|
|
25
25
|
* ✘ snap-to-edge
|
|
26
|
+
* ✔ disableGesture
|
|
26
27
|
*/
|
|
27
28
|
type EaseType = 'default' | 'linear' | 'easeInCubic' | 'easeOutCubic' | 'easeInOutCubic'
|
|
28
29
|
type StrAbsoType = 'absoluteX' | 'absoluteY'
|
|
@@ -206,6 +207,10 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
206
207
|
const moveTranstion = useSharedValue(0)
|
|
207
208
|
// 记录从onBegin 到 onTouchesUp 的时间
|
|
208
209
|
const moveTime = useSharedValue(0)
|
|
210
|
+
// 记录从onBegin 到 onTouchesCancelled 另外一个方向移动的距离
|
|
211
|
+
const anotherDirectionMove = useSharedValue(0)
|
|
212
|
+
// 另一个方向的
|
|
213
|
+
const anotherAbso = 'absolute' + (dir === 'x' ? 'y' : 'x').toUpperCase() as StrAbsoType
|
|
209
214
|
const timerId = useRef(0 as number | ReturnType<typeof setTimeout>)
|
|
210
215
|
const intervalTimer = props.interval || 500
|
|
211
216
|
|
|
@@ -504,7 +509,11 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
504
509
|
}, [children.length])
|
|
505
510
|
|
|
506
511
|
useEffect(() => {
|
|
507
|
-
|
|
512
|
+
// 1. 如果用户在touch的过程中, 外部更新了current以外部为准(小程序表现)
|
|
513
|
+
// 2. 手指滑动过程中更新索引,外部会把current再穿进来,导致offset直接更新了
|
|
514
|
+
if (props.current !== currentIndex.value) {
|
|
515
|
+
updateCurrent(props.current || 0, step.value)
|
|
516
|
+
}
|
|
508
517
|
}, [props.current])
|
|
509
518
|
|
|
510
519
|
useEffect(() => {
|
|
@@ -566,18 +575,25 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
566
575
|
targetOffset: -moveToTargetPos
|
|
567
576
|
}
|
|
568
577
|
}
|
|
569
|
-
function
|
|
578
|
+
function checkUnCircular (eventData: EventDataType) {
|
|
570
579
|
'worklet'
|
|
571
580
|
const { translation } = eventData
|
|
572
581
|
const currentOffset = Math.abs(offset.value)
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
582
|
+
// 向右滑动swiper
|
|
583
|
+
if (translation < 0) {
|
|
584
|
+
const boundaryOffset = step.value * (childrenLength.value - 1)
|
|
585
|
+
const gestureMovePos = Math.abs(translation) + currentOffset
|
|
586
|
+
return {
|
|
587
|
+
// 防止快速连续向右滑动时,手势移动的距离 加 当前的offset超出边界
|
|
588
|
+
targetOffset: gestureMovePos > boundaryOffset ? -boundaryOffset : offset.value + translation,
|
|
589
|
+
canMove: currentOffset < boundaryOffset
|
|
578
590
|
}
|
|
579
591
|
} else {
|
|
580
|
-
|
|
592
|
+
const gestureMovePos = currentOffset - translation
|
|
593
|
+
return {
|
|
594
|
+
targetOffset: gestureMovePos < 0 ? 0 : offset.value + translation,
|
|
595
|
+
canMove: currentOffset > 0
|
|
596
|
+
}
|
|
581
597
|
}
|
|
582
598
|
}
|
|
583
599
|
function handleEnd (eventData: EventDataType) {
|
|
@@ -636,7 +652,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
636
652
|
}
|
|
637
653
|
})
|
|
638
654
|
}
|
|
639
|
-
function
|
|
655
|
+
function computeHalf () {
|
|
640
656
|
'worklet'
|
|
641
657
|
const currentOffset = Math.abs(offset.value)
|
|
642
658
|
let preOffset = (currentIndex.value + patchElmNumShared.value) * step.value
|
|
@@ -646,6 +662,14 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
646
662
|
// 正常事件中拿到的transition值(正向滑动<0,倒着滑>0)
|
|
647
663
|
const diffOffset = preOffset - currentOffset
|
|
648
664
|
const half = Math.abs(diffOffset) > step.value / 2
|
|
665
|
+
return {
|
|
666
|
+
diffOffset,
|
|
667
|
+
half
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
function handleLongPress () {
|
|
671
|
+
'worklet'
|
|
672
|
+
const { diffOffset, half } = computeHalf()
|
|
649
673
|
if (+diffOffset === 0) {
|
|
650
674
|
runOnJS(resumeLoop)()
|
|
651
675
|
} else if (half) {
|
|
@@ -701,18 +725,29 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
701
725
|
runOnJS(pauseLoop)()
|
|
702
726
|
preAbsolutePos.value = e[strAbso]
|
|
703
727
|
moveTranstion.value = e[strAbso]
|
|
728
|
+
anotherDirectionMove.value = e[anotherAbso]
|
|
704
729
|
moveTime.value = new Date().getTime()
|
|
705
730
|
})
|
|
706
|
-
.
|
|
731
|
+
.onUpdate((e) => {
|
|
707
732
|
'worklet'
|
|
708
733
|
if (touchfinish.value) return
|
|
709
|
-
const
|
|
710
|
-
const moveDistance = touchEventData[strAbso] - preAbsolutePos.value
|
|
734
|
+
const moveDistance = e[strAbso] - preAbsolutePos.value
|
|
711
735
|
const eventData = {
|
|
712
736
|
translation: moveDistance
|
|
713
737
|
}
|
|
714
|
-
//
|
|
715
|
-
|
|
738
|
+
// 1. 在Move过程中,如果手指一直没抬起来,超过一半的话也会更新索引
|
|
739
|
+
const { half } = computeHalf()
|
|
740
|
+
if (half) {
|
|
741
|
+
const { selectedIndex } = getTargetPosition(eventData)
|
|
742
|
+
currentIndex.value = selectedIndex
|
|
743
|
+
}
|
|
744
|
+
// 2. 处理用户一直拖拽到临界点的场景, 不会执行onEnd
|
|
745
|
+
const { canMove, targetOffset } = checkUnCircular(eventData)
|
|
746
|
+
if (!circularShared.value) {
|
|
747
|
+
if (canMove) {
|
|
748
|
+
offset.value = targetOffset
|
|
749
|
+
preAbsolutePos.value = e[strAbso]
|
|
750
|
+
}
|
|
716
751
|
return
|
|
717
752
|
}
|
|
718
753
|
const { isBoundary, resetOffset } = reachBoundary(eventData)
|
|
@@ -721,28 +756,21 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
|
|
|
721
756
|
} else {
|
|
722
757
|
offset.value = moveDistance + offset.value
|
|
723
758
|
}
|
|
724
|
-
preAbsolutePos.value =
|
|
759
|
+
preAbsolutePos.value = e[strAbso]
|
|
725
760
|
})
|
|
726
|
-
.
|
|
761
|
+
.onFinalize((e) => {
|
|
727
762
|
'worklet'
|
|
728
763
|
if (touchfinish.value) return
|
|
729
|
-
const
|
|
730
|
-
const moveDistance = touchEventData[strAbso] - moveTranstion.value
|
|
764
|
+
const moveDistance = e[strAbso] - moveTranstion.value
|
|
731
765
|
touchfinish.value = true
|
|
732
766
|
const eventData = {
|
|
733
767
|
translation: moveDistance
|
|
734
768
|
}
|
|
735
|
-
if (childrenLength.value === 1) {
|
|
736
|
-
return handleBackInit()
|
|
737
|
-
}
|
|
738
|
-
// 用户手指按下起来, 需要计算正确的位置, 比如在滑动过程中突然按下然后起来,需要计算到正确的位置
|
|
739
|
-
if (!circularShared.value && !canMove(eventData)) {
|
|
740
|
-
return
|
|
741
|
-
}
|
|
742
769
|
const strVelocity = moveDistance / (new Date().getTime() - moveTime.value) * 1000
|
|
743
770
|
if (Math.abs(strVelocity) < longPressRatio) {
|
|
744
771
|
handleLongPress()
|
|
745
772
|
} else {
|
|
773
|
+
// 如果触发了onTouchesCancelled,不会触发onUpdate不会更新offset值, 索引不会变更
|
|
746
774
|
handleEnd(eventData)
|
|
747
775
|
}
|
|
748
776
|
})
|
|
@@ -143,7 +143,7 @@ const isPercent = (val: string | number | undefined): val is string => typeof va
|
|
|
143
143
|
const isBackgroundSizeKeyword = (val: string | number): boolean => typeof val === 'string' && /^cover|contain$/.test(val)
|
|
144
144
|
|
|
145
145
|
const isNeedLayout = (preImageInfo: PreImageInfo): boolean => {
|
|
146
|
-
const { sizeList, backgroundPosition, linearInfo } = preImageInfo
|
|
146
|
+
const { sizeList, backgroundPosition, linearInfo, type } = preImageInfo
|
|
147
147
|
const [width, height] = sizeList
|
|
148
148
|
const bp = backgroundPosition
|
|
149
149
|
|
|
@@ -153,7 +153,8 @@ const isNeedLayout = (preImageInfo: PreImageInfo): boolean => {
|
|
|
153
153
|
(isPercent(width) && height === 'auto') ||
|
|
154
154
|
isPercent(bp[1]) ||
|
|
155
155
|
isPercent(bp[3]) ||
|
|
156
|
-
isDiagonalAngle(linearInfo)
|
|
156
|
+
isDiagonalAngle(linearInfo) ||
|
|
157
|
+
(type === 'linear' && (isPercent(height) || isPercent(width)))
|
|
157
158
|
}
|
|
158
159
|
|
|
159
160
|
const checkNeedLayout = (preImageInfo: PreImageInfo) => {
|
|
@@ -246,7 +247,7 @@ function backgroundPosition (imageProps: ImageProps, preImageInfo: PreImageInfo,
|
|
|
246
247
|
|
|
247
248
|
// background-size 转换
|
|
248
249
|
function backgroundSize (imageProps: ImageProps, preImageInfo: PreImageInfo, imageSize: Size, layoutInfo: Size) {
|
|
249
|
-
const sizeList = preImageInfo
|
|
250
|
+
const { sizeList, type } = preImageInfo
|
|
250
251
|
if (!sizeList) return
|
|
251
252
|
const { width: layoutWidth, height: layoutHeight } = layoutInfo || {}
|
|
252
253
|
const { width: imageSizeWidth, height: imageSizeHeight } = imageSize || {}
|
|
@@ -286,10 +287,22 @@ function backgroundSize (imageProps: ImageProps, preImageInfo: PreImageInfo, ima
|
|
|
286
287
|
} else { // 数值类型 ImageStyle
|
|
287
288
|
// 数值类型设置为 stretch
|
|
288
289
|
imageProps.resizeMode = 'stretch'
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
290
|
+
if (type === 'linear') {
|
|
291
|
+
const dimensionWidth = calcPercent(width as NumberVal, layoutWidth) || 0
|
|
292
|
+
const dimensionHeight = calcPercent(height as NumberVal, layoutHeight) || 0
|
|
293
|
+
// ios 上 linear 组件只要重新触发渲染,在渲染过程中 width 或者 height 被设置为 0,即使后面再更新为正常宽高,也会渲染不出来
|
|
294
|
+
if (dimensionWidth && dimensionHeight) {
|
|
295
|
+
dimensions = {
|
|
296
|
+
width: dimensionWidth,
|
|
297
|
+
height: dimensionHeight
|
|
298
|
+
} as { width: NumberVal, height: NumberVal }
|
|
299
|
+
}
|
|
300
|
+
} else {
|
|
301
|
+
dimensions = {
|
|
302
|
+
width: isPercent(width) ? width : +width,
|
|
303
|
+
height: isPercent(height) ? height : +height
|
|
304
|
+
} as { width: NumberVal, height: NumberVal }
|
|
305
|
+
}
|
|
293
306
|
}
|
|
294
307
|
}
|
|
295
308
|
|
|
@@ -122,17 +122,17 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
|
|
|
122
122
|
|
|
123
123
|
const navigation = useNavigation()
|
|
124
124
|
|
|
125
|
-
useEffect(() => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}, [])
|
|
125
|
+
// useEffect(() => {
|
|
126
|
+
// let beforeRemoveSubscription:any
|
|
127
|
+
// if (__mpx_mode__ !== 'ios') {
|
|
128
|
+
// beforeRemoveSubscription = navigation?.addListener?.('beforeRemove', beforeRemoveHandle)
|
|
129
|
+
// }
|
|
130
|
+
// return () => {
|
|
131
|
+
// if (isFunction(beforeRemoveSubscription)) {
|
|
132
|
+
// beforeRemoveSubscription()
|
|
133
|
+
// }
|
|
134
|
+
// }
|
|
135
|
+
// }, [])
|
|
136
136
|
|
|
137
137
|
useNodesRef<WebView, WebViewProps>(props, ref, webViewRef, {
|
|
138
138
|
style: defaultWebViewStyle
|
|
@@ -212,7 +212,7 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
|
|
|
212
212
|
{ // case下不允许直接声明,包个块解决该问题
|
|
213
213
|
const title = postData._documentTitle?.trim()
|
|
214
214
|
if (title !== undefined) {
|
|
215
|
-
navigation && navigation.
|
|
215
|
+
navigation && navigation.setPageConfig({ navigationBarTitleText: title })
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
218
|
break
|
|
@@ -285,6 +285,93 @@ function transformPosition (styleObj: Record<string, any>, meta: PositionMeta) {
|
|
|
285
285
|
meta.hasPositionFixed = true
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
|
+
// 多value解析
|
|
289
|
+
function parseValues (str: string, char = ' ') {
|
|
290
|
+
let stack = 0
|
|
291
|
+
let temp = ''
|
|
292
|
+
const result = []
|
|
293
|
+
for (let i = 0; i < str.length; i++) {
|
|
294
|
+
if (str[i] === '(') {
|
|
295
|
+
stack++
|
|
296
|
+
} else if (str[i] === ')') {
|
|
297
|
+
stack--
|
|
298
|
+
}
|
|
299
|
+
// 非括号内 或者 非分隔字符且非空
|
|
300
|
+
if (stack !== 0 || (str[i] !== char && str[i] !== ' ')) {
|
|
301
|
+
temp += str[i]
|
|
302
|
+
}
|
|
303
|
+
if ((stack === 0 && str[i] === char) || i === str.length - 1) {
|
|
304
|
+
result.push(temp)
|
|
305
|
+
temp = ''
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return result
|
|
309
|
+
}
|
|
310
|
+
// parse string transform, eg: transform: 'rotateX(45deg) rotateZ(0.785398rad)'
|
|
311
|
+
function parseTransform (transformStr: string) {
|
|
312
|
+
const values = parseValues(transformStr)
|
|
313
|
+
const transform: {[propName: string]: string|number|number[]}[] = []
|
|
314
|
+
values.forEach(item => {
|
|
315
|
+
const match = item.match(/([/\w]+)\((.+)\)/)
|
|
316
|
+
if (match && match.length >= 3) {
|
|
317
|
+
let key = match[1]
|
|
318
|
+
const val = match[2]
|
|
319
|
+
switch (key) {
|
|
320
|
+
case 'translateX':
|
|
321
|
+
case 'translateY':
|
|
322
|
+
case 'scaleX':
|
|
323
|
+
case 'scaleY':
|
|
324
|
+
case 'rotateX':
|
|
325
|
+
case 'rotateY':
|
|
326
|
+
case 'rotateZ':
|
|
327
|
+
case 'rotate':
|
|
328
|
+
case 'skewX':
|
|
329
|
+
case 'skewY':
|
|
330
|
+
case 'perspective':
|
|
331
|
+
// rotate 处理成 rotateZ
|
|
332
|
+
key = key === 'rotate' ? 'rotateZ' : key
|
|
333
|
+
// 单个值处理
|
|
334
|
+
transform.push({ [key]: global.__formatValue(val) })
|
|
335
|
+
break
|
|
336
|
+
case 'matrix':
|
|
337
|
+
transform.push({ [key]: parseValues(val, ',').map(val => +val) })
|
|
338
|
+
break
|
|
339
|
+
case 'translate':
|
|
340
|
+
case 'scale':
|
|
341
|
+
case 'skew':
|
|
342
|
+
case 'translate3d': // x y 支持 z不支持
|
|
343
|
+
case 'scale3d': // x y 支持 z不支持
|
|
344
|
+
{
|
|
345
|
+
// 2 个以上的值处理
|
|
346
|
+
key = key.replace('3d', '')
|
|
347
|
+
const vals = parseValues(val, ',').splice(0, 3)
|
|
348
|
+
// scale(.5) === scaleX(.5) scaleY(.5)
|
|
349
|
+
if (vals.length === 1 && key === 'scale') {
|
|
350
|
+
vals.push(vals[0])
|
|
351
|
+
}
|
|
352
|
+
const xyz = ['X', 'Y', 'Z']
|
|
353
|
+
transform.push(...vals.map((v, index) => {
|
|
354
|
+
return { [`${key}${xyz[index] || ''}`]: global.__formatValue(v.trim()) }
|
|
355
|
+
}))
|
|
356
|
+
break
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
})
|
|
361
|
+
return transform
|
|
362
|
+
}
|
|
363
|
+
// format style transform
|
|
364
|
+
function transformTransform (style: Record<string, any>) {
|
|
365
|
+
if (!style.transform || Array.isArray(style.transform)) return
|
|
366
|
+
style.transform = parseTransform(style.transform)
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function transformBoxShadow (styleObj: Record<string, any>) {
|
|
370
|
+
if (!styleObj.boxShadow) return
|
|
371
|
+
styleObj.boxShadow = parseValues(styleObj.boxShadow).reduce((res, i, idx) => {
|
|
372
|
+
return `${res}${idx === 0 ? '' : ' '}${global.__formatValue(i)}`
|
|
373
|
+
}, '')
|
|
374
|
+
}
|
|
288
375
|
|
|
289
376
|
interface TransformStyleConfig {
|
|
290
377
|
enableVar?: boolean
|
|
@@ -427,6 +514,11 @@ export function useTransformStyle (styleObj: Record<string, any> = {}, { enableV
|
|
|
427
514
|
transformPosition(normalStyle, positionMeta)
|
|
428
515
|
// transform number enum stringify
|
|
429
516
|
transformStringify(normalStyle)
|
|
517
|
+
// transform rpx to px
|
|
518
|
+
transformBoxShadow(normalStyle)
|
|
519
|
+
|
|
520
|
+
// transform 字符串格式转化数组格式
|
|
521
|
+
transformTransform(normalStyle)
|
|
430
522
|
|
|
431
523
|
return {
|
|
432
524
|
hasVarDec,
|
|
@@ -525,7 +617,7 @@ export const useLayout = ({ props, hasSelfPercent, setWidth, setHeight, onLayout
|
|
|
525
617
|
}
|
|
526
618
|
if (enableOffset) {
|
|
527
619
|
nodeRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => {
|
|
528
|
-
const {
|
|
620
|
+
const { top: navigationY = 0 } = navigation?.layout || {}
|
|
529
621
|
layoutRef.current = { x, y: y - navigationY, width, height, offsetLeft, offsetTop: offsetTop - navigationY }
|
|
530
622
|
})
|
|
531
623
|
}
|
|
@@ -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>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { warn } from '@mpxjs/utils'
|
|
3
|
+
import { getCustomEvent } from './getInnerListeners'
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
name: 'mpx-sticky-header',
|
|
7
|
+
inject: ['scrollOffset', 'refreshVersion'],
|
|
8
|
+
props: {
|
|
9
|
+
offsetTop: {
|
|
10
|
+
type: Number,
|
|
11
|
+
default: 0
|
|
12
|
+
},
|
|
13
|
+
padding: Array
|
|
14
|
+
},
|
|
15
|
+
data() {
|
|
16
|
+
return {
|
|
17
|
+
headerTop: 0,
|
|
18
|
+
isStickOnTop: false
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
watch: {
|
|
22
|
+
scrollOffset: {
|
|
23
|
+
handler(newScrollOffset) {
|
|
24
|
+
const newIsStickOnTop = newScrollOffset > this.headerTop
|
|
25
|
+
if (newIsStickOnTop !== this.isStickOnTop) {
|
|
26
|
+
this.isStickOnTop = newIsStickOnTop
|
|
27
|
+
this.$emit('stickontopchange', getCustomEvent('stickontopchange', {
|
|
28
|
+
isStickOnTop: newIsStickOnTop
|
|
29
|
+
}, this))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
this.setTransformStyle()
|
|
33
|
+
},
|
|
34
|
+
immediate: true
|
|
35
|
+
},
|
|
36
|
+
refreshVersion: {
|
|
37
|
+
handler() {
|
|
38
|
+
this.setHeaderTop()
|
|
39
|
+
this.setTransformStyle()
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
mounted() {
|
|
44
|
+
this.setPaddingStyle()
|
|
45
|
+
this.setHeaderTop()
|
|
46
|
+
},
|
|
47
|
+
methods: {
|
|
48
|
+
setHeaderTop () {
|
|
49
|
+
const parentElement = this.$el.parentElement
|
|
50
|
+
if (!parentElement) return
|
|
51
|
+
|
|
52
|
+
const parentClass = parentElement.className || ''
|
|
53
|
+
const isStickySection = /mpx-sticky-section/.test(parentClass)
|
|
54
|
+
const isScrollViewWrapper = /mpx-inner-wrapper/.test(parentClass)
|
|
55
|
+
|
|
56
|
+
if (!isStickySection && !isScrollViewWrapper) {
|
|
57
|
+
warn('sticky-header only supports being a direct child of a scroll-view or sticky-section component.')
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
this.headerTop = isStickySection
|
|
61
|
+
? this.$el.offsetTop + parentElement.offsetTop
|
|
62
|
+
: this.$el.offsetTop
|
|
63
|
+
},
|
|
64
|
+
setPaddingStyle() {
|
|
65
|
+
const stickyHeader = this.$refs.stickyHeader
|
|
66
|
+
if (!stickyHeader) return
|
|
67
|
+
|
|
68
|
+
if (this.padding && Array.isArray(this.padding)) {
|
|
69
|
+
const [top = 0, right = 0, bottom = 0, left = 0] = this.padding
|
|
70
|
+
stickyHeader.style.padding = `${top}px ${right}px ${bottom}px ${left}px`
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
setTransformStyle () {
|
|
74
|
+
const stickyHeader = this.$refs.stickyHeader
|
|
75
|
+
if (!stickyHeader) return
|
|
76
|
+
|
|
77
|
+
// 设置 transform
|
|
78
|
+
if (this.scrollOffset > this.headerTop) {
|
|
79
|
+
stickyHeader.style.transform = `translateY(${this.scrollOffset - this.headerTop + this.offsetTop}px)`
|
|
80
|
+
} else {
|
|
81
|
+
stickyHeader.style.transform = 'none'
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
render(h) {
|
|
86
|
+
const style = {
|
|
87
|
+
width: '100%',
|
|
88
|
+
boxSizing: 'border-box',
|
|
89
|
+
position: 'relative',
|
|
90
|
+
zIndex: 10
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return h('div', {
|
|
94
|
+
style,
|
|
95
|
+
ref: 'stickyHeader'
|
|
96
|
+
}, this.$slots.default)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
</script>
|
|
@@ -181,7 +181,6 @@ function createApp ({ componentsMap, Vue, pagesMap, firstPage, VueRouter, App, t
|
|
|
181
181
|
global.__mpxRouter.lastStack = null
|
|
182
182
|
global.__mpxRouter.needCache = null
|
|
183
183
|
global.__mpxRouter.needRemove = []
|
|
184
|
-
global.__mpxRouter.eventChannelMap = {}
|
|
185
184
|
global.__mpxRouter.currentActionType = null
|
|
186
185
|
// 处理reLaunch中传递的url并非首页时的replace逻辑
|
|
187
186
|
global.__mpxRouter.beforeEach(function (to, from, next) {
|
|
@@ -241,7 +240,6 @@ function createApp ({ componentsMap, Vue, pagesMap, firstPage, VueRouter, App, t
|
|
|
241
240
|
case 'to':
|
|
242
241
|
stack.push(insertItem)
|
|
243
242
|
global.__mpxRouter.needCache = insertItem
|
|
244
|
-
if (action.eventChannel) global.__mpxRouter.eventChannelMap[to.path.slice(1)] = action.eventChannel
|
|
245
243
|
break
|
|
246
244
|
case 'back':
|
|
247
245
|
global.__mpxRouter.needRemove = stack.splice(stack.length - action.delta, action.delta)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const babylon = require('@babel/parser')
|
|
2
2
|
const MagicString = require('magic-string')
|
|
3
|
+
const { SourceMapConsumer, SourceMapGenerator } = require('source-map')
|
|
3
4
|
const traverse = require('@babel/traverse').default
|
|
4
5
|
const t = require('@babel/types')
|
|
5
6
|
const formatCodeFrame = require('@babel/code-frame')
|
|
@@ -625,7 +626,12 @@ function compileScriptSetup (
|
|
|
625
626
|
_s.appendRight(endOffset, '})')
|
|
626
627
|
|
|
627
628
|
return {
|
|
628
|
-
content: _s.toString()
|
|
629
|
+
content: _s.toString(),
|
|
630
|
+
map: _s.generateMap({
|
|
631
|
+
source: filePath,
|
|
632
|
+
hires: true,
|
|
633
|
+
includeContent: true
|
|
634
|
+
})
|
|
629
635
|
}
|
|
630
636
|
}
|
|
631
637
|
|
|
@@ -1165,14 +1171,30 @@ function getCtor (ctorType) {
|
|
|
1165
1171
|
return ctor
|
|
1166
1172
|
}
|
|
1167
1173
|
|
|
1168
|
-
module.exports = function (content) {
|
|
1174
|
+
module.exports = async function (content, sourceMap) {
|
|
1169
1175
|
const { queryObj } = parseRequest(this.resource)
|
|
1170
1176
|
const { ctorType, lang } = queryObj
|
|
1171
1177
|
const filePath = this.resourcePath
|
|
1172
|
-
const
|
|
1178
|
+
const callback = this.async()
|
|
1179
|
+
let finalSourceMap = null
|
|
1180
|
+
const {
|
|
1181
|
+
content: callbackContent,
|
|
1182
|
+
map
|
|
1183
|
+
} = compileScriptSetup({
|
|
1173
1184
|
content,
|
|
1174
1185
|
lang
|
|
1175
1186
|
}, ctorType, filePath)
|
|
1176
|
-
|
|
1177
|
-
|
|
1187
|
+
finalSourceMap = map
|
|
1188
|
+
if (sourceMap) {
|
|
1189
|
+
const compiledMapConsumer = await new SourceMapConsumer(map)
|
|
1190
|
+
const compiledMapGenerator = SourceMapGenerator.fromSourceMap(compiledMapConsumer)
|
|
1191
|
+
|
|
1192
|
+
const originalConsumer = await new SourceMapConsumer(sourceMap)
|
|
1193
|
+
compiledMapGenerator.applySourceMap(
|
|
1194
|
+
originalConsumer,
|
|
1195
|
+
filePath // 需要确保与原始映射的source路径一致
|
|
1196
|
+
)
|
|
1197
|
+
finalSourceMap = compiledMapGenerator.toJSON()
|
|
1198
|
+
}
|
|
1199
|
+
callback(null, callbackContent, finalSourceMap)
|
|
1178
1200
|
}
|
|
@@ -2,6 +2,7 @@ const babylon = require('@babel/parser')
|
|
|
2
2
|
const traverse = require('@babel/traverse').default
|
|
3
3
|
const t = require('@babel/types')
|
|
4
4
|
const generate = require('@babel/generator').default
|
|
5
|
+
const isValidIdentifierStr = require('../utils/is-valid-identifier-str')
|
|
5
6
|
|
|
6
7
|
const names = 'Infinity,undefined,NaN,isFinite,isNaN,' +
|
|
7
8
|
'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' +
|
|
@@ -41,7 +42,7 @@ function getCollectPath (path) {
|
|
|
41
42
|
if (current.node.computed) {
|
|
42
43
|
if (t.isLiteral(current.node.property)) {
|
|
43
44
|
if (t.isStringLiteral(current.node.property)) {
|
|
44
|
-
if (dangerousKeyMap[current.node.property.value]) {
|
|
45
|
+
if (dangerousKeyMap[current.node.property.value] || !isValidIdentifierStr(current.node.property.value)) {
|
|
45
46
|
break
|
|
46
47
|
}
|
|
47
48
|
keyPath += `.${current.node.property.value}`
|
|
@@ -581,7 +581,8 @@ function parseComponent (content, options) {
|
|
|
581
581
|
let text = content.slice(currentBlock.start, currentBlock.end)
|
|
582
582
|
// pad content so that linters and pre-processors can output correct
|
|
583
583
|
// line numbers in errors and warnings
|
|
584
|
-
|
|
584
|
+
// stylus编译遇到大量空行时会出现栈溢出,故针对stylus不走pad
|
|
585
|
+
if (options.pad && !(currentBlock.tag === 'style' && currentBlock.lang === 'stylus')) {
|
|
585
586
|
text = padContent(currentBlock, options.pad) + text
|
|
586
587
|
}
|
|
587
588
|
currentBlock.content = text
|
|
@@ -1849,7 +1850,7 @@ function processRefReact (el, meta) {
|
|
|
1849
1850
|
}])
|
|
1850
1851
|
}
|
|
1851
1852
|
|
|
1852
|
-
if (el.tag === 'mpx-scroll-view'
|
|
1853
|
+
if (el.tag === 'mpx-scroll-view') {
|
|
1853
1854
|
addAttrs(el, [
|
|
1854
1855
|
{
|
|
1855
1856
|
name: '__selectRef',
|
|
@@ -2725,8 +2726,8 @@ function processElement (el, root, options, meta) {
|
|
|
2725
2726
|
processIf(el)
|
|
2726
2727
|
processFor(el)
|
|
2727
2728
|
processRefReact(el, meta)
|
|
2728
|
-
processStyleReact(el, options)
|
|
2729
2729
|
if (!pass) {
|
|
2730
|
+
processStyleReact(el, options)
|
|
2730
2731
|
processEventReact(el, options)
|
|
2731
2732
|
processComponentGenerics(el, meta)
|
|
2732
2733
|
processComponentIs(el, options)
|