@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.
Files changed (51) hide show
  1. package/lib/dependencies/RecordPageConfigsMapDependency.js +1 -1
  2. package/lib/index.js +71 -51
  3. package/lib/parser.js +1 -1
  4. package/lib/platform/json/wx/index.js +0 -1
  5. package/lib/platform/style/wx/index.js +7 -0
  6. package/lib/platform/template/wx/component-config/button.js +1 -1
  7. package/lib/platform/template/wx/component-config/index.js +5 -1
  8. package/lib/platform/template/wx/component-config/input.js +1 -1
  9. package/lib/platform/template/wx/component-config/movable-view.js +1 -10
  10. package/lib/platform/template/wx/component-config/sticky-header.js +23 -0
  11. package/lib/platform/template/wx/component-config/sticky-section.js +23 -0
  12. package/lib/react/processJSON.js +2 -1
  13. package/lib/runtime/components/react/AsyncContainer.tsx +189 -0
  14. package/lib/runtime/components/react/context.ts +23 -4
  15. package/lib/runtime/components/react/dist/AsyncContainer.jsx +141 -0
  16. package/lib/runtime/components/react/dist/context.js +5 -2
  17. package/lib/runtime/components/react/dist/mpx-button.jsx +2 -2
  18. package/lib/runtime/components/react/dist/mpx-input.jsx +1 -1
  19. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +64 -10
  20. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +358 -98
  21. package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +3 -0
  22. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +31 -15
  23. package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +117 -0
  24. package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +45 -0
  25. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +2 -2
  26. package/lib/runtime/components/react/dist/mpx-swiper.jsx +53 -27
  27. package/lib/runtime/components/react/dist/mpx-view.jsx +21 -7
  28. package/lib/runtime/components/react/dist/mpx-web-view.jsx +13 -13
  29. package/lib/runtime/components/react/dist/utils.jsx +94 -1
  30. package/lib/runtime/components/react/mpx-button.tsx +3 -2
  31. package/lib/runtime/components/react/mpx-input.tsx +1 -1
  32. package/lib/runtime/components/react/mpx-movable-area.tsx +99 -12
  33. package/lib/runtime/components/react/mpx-movable-view.tsx +413 -100
  34. package/lib/runtime/components/react/mpx-rich-text/index.tsx +3 -0
  35. package/lib/runtime/components/react/mpx-scroll-view.tsx +84 -59
  36. package/lib/runtime/components/react/mpx-sticky-header.tsx +181 -0
  37. package/lib/runtime/components/react/mpx-sticky-section.tsx +96 -0
  38. package/lib/runtime/components/react/mpx-swiper-item.tsx +2 -2
  39. package/lib/runtime/components/react/mpx-swiper.tsx +53 -25
  40. package/lib/runtime/components/react/mpx-view.tsx +20 -7
  41. package/lib/runtime/components/react/mpx-web-view.tsx +12 -12
  42. package/lib/runtime/components/react/utils.tsx +93 -1
  43. package/lib/runtime/components/web/mpx-scroll-view.vue +18 -4
  44. package/lib/runtime/components/web/mpx-sticky-header.vue +99 -0
  45. package/lib/runtime/components/web/mpx-sticky-section.vue +15 -0
  46. package/lib/runtime/optionProcessor.js +0 -2
  47. package/lib/script-setup-compiler/index.js +27 -5
  48. package/lib/template-compiler/bind-this.js +2 -1
  49. package/lib/template-compiler/compiler.js +4 -3
  50. package/package.json +4 -4
  51. 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
- updateCurrent(props.current || 0, step.value)
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 canMove (eventData: EventDataType) {
578
+ function checkUnCircular (eventData: EventDataType) {
570
579
  'worklet'
571
580
  const { translation } = eventData
572
581
  const currentOffset = Math.abs(offset.value)
573
- if (!circularShared.value) {
574
- if (translation < 0) {
575
- return currentOffset < step.value * (childrenLength.value - 1)
576
- } else {
577
- return currentOffset > 0
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
- return true
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 handleLongPress () {
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
- .onTouchesMove((e) => {
731
+ .onUpdate((e) => {
707
732
  'worklet'
708
733
  if (touchfinish.value) return
709
- const touchEventData = e.changedTouches[0]
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
- // 处理用户一直拖拽到临界点的场景, 不会执行onEnd
715
- if (!circularShared.value && !canMove(eventData)) {
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 = touchEventData[strAbso]
759
+ preAbsolutePos.value = e[strAbso]
725
760
  })
726
- .onTouchesUp((e) => {
761
+ .onFinalize((e) => {
727
762
  'worklet'
728
763
  if (touchfinish.value) return
729
- const touchEventData = e.changedTouches[0]
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.sizeList
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
- dimensions = {
290
- width: isPercent(width) ? width : +width,
291
- height: isPercent(height) ? height : +height
292
- } as { width: NumberVal, height: NumberVal }
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
- 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
- }, [])
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.setOptions({ title })
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 { y: navigationY = 0 } = navigation?.layout || {}
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>
@@ -0,0 +1,15 @@
1
+ <script>
2
+ export default {
3
+ name: 'mpx-sticky-section',
4
+ render(h) {
5
+ const style = {
6
+ position: 'relative'
7
+ }
8
+
9
+ return h('div', {
10
+ style,
11
+ class: 'mpx-sticky-section'
12
+ }, this.$slots.default)
13
+ }
14
+ }
15
+ </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 { content: callbackContent } = compileScriptSetup({
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
- this.callback(null, callbackContent)
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
- if (options.pad) {
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' && el.attrsMap['scroll-into-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)