diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx index 6bb0fd386d..dd154461c3 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-picker-view-column.tsx @@ -2,8 +2,7 @@ import { View, Animated, SafeAreaView, NativeScrollEvent, NativeSyntheticEvent, LayoutChangeEvent, ScrollView } from 'react-native' import React, { forwardRef, useRef, useState, useEffect, ReactElement, ReactNode } from 'react' import { VarContext } from './context' -import { useTransformStyle } from './utils' -// import { Reanimated } from 'react-native-reanimated'; +import { useTransformStyle, splitStyle } from './utils' import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数 interface ColumnProps { children: React.ReactNode, @@ -29,20 +28,21 @@ const defaultItemHeight = 36 const _PickerViewColumn = forwardRef, ColumnProps>((props: ColumnProps, ref) => { const { children, selectedIndex, onColumnLayoutChange, onSelectChange, getInnerLayout, style, wrapperStyle, 'enable-var': enableVar, 'external-var-context': externalVarContext } = props // PickerViewColumn - const { normalStyle, hasVarDec, varContextRef } = useTransformStyle(style, { enableVar, externalVarContext }) + const { + normalStyle, + hasVarDec, + hasPercent, + varContextRef, + setContainerWidth, + setContainerHeight + } = useTransformStyle(style, { enableVar, externalVarContext }) + const { innerStyle } = splitStyle(normalStyle) // scrollView的ref const { nodeRef: scrollViewRef } = useNodesRef(props, ref, {}) // scrollView的布局存储 const layoutRef = useRef({}) // 每个元素的高度 let [itemH, setItemH] = useState(0) - // scrollView内容的初始offset - /* - let [offset, setOffset] = useState({ - x: 0, - y: 0 - }) - */ useEffect(() => { if (selectedIndex && itemH) { @@ -51,7 +51,12 @@ const _PickerViewColumn = forwardRef, } }, [selectedIndex, itemH]) - const onScrollViewLayout = () => { + const onScrollViewLayout = (res: LayoutChangeEvent) => { + if (hasPercent) { + const { width, height } = res?.nativeEvent?.layout || {} + setContainerWidth(width || 0) + setContainerHeight(height || 0) + } scrollViewRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => { layoutRef.current = { x, y, width, height, offsetLeft, offsetTop } getInnerLayout && getInnerLayout(layoutRef) @@ -97,17 +102,15 @@ const _PickerViewColumn = forwardRef, const InnerProps = index === 0 ? { onLayout: onItemLayout } : {} const strKey = 'picker' + props.prefix + '-column' + index const arrHeight = (wrapperStyle.itemHeight + '').match(/\d+/g) || [] - const iHeight = arrHeight[0] || defaultItemHeight - + const iHeight = (arrHeight[0] || defaultItemHeight) as number if (hasVarDec && varContextRef.current) { const wrapChild = ( - {item} + {item} ) return wrapChild } else { - return {item} + return {item} } - // return {item} }) const totalHeight = itemH * 5 if (wrapperStyle.height && totalHeight !== wrapperStyle.height) { @@ -126,10 +129,6 @@ const _PickerViewColumn = forwardRef, } const renderScollView = () => { - const contentContainerStyle = { - textAlign: 'center' - } - return ( + 'external-var-context'?: Record, + 'enable-offset': boolean } interface PickerLayout { @@ -66,9 +67,16 @@ const _PickerView = forwardRef, PickerViewProp // 微信设置到pick-view上上设置的normalStyle如border等需要转换成RN的style然后进行透传 const indicatorStyle = parseInlineStyle(props['indicator-style']) const { height: indicatorH, width: indicatorW } = indicatorStyle - // const { normalStyle: lineStyle} = useTransformStyle(indicatorStyle, { enableVar, externalVarContext}) // picker-view 设置的color等textStyle,在小程序上的表现是可以继承到最内层的text样式, 但是RN内部column是slot无法设置, 需要业务自己在column内的元素上设置 - const { normalStyle, hasVarDec, varContextRef } = useTransformStyle(style, { enableVar, externalVarContext }) + const { + normalStyle, + hasVarDec, + varContextRef, + hasPercent, + setContainerWidth, + setContainerHeight + } = useTransformStyle(style, { enableVar, externalVarContext }) + const isSetW = indicatorW !== undefined ? 1 : 0 const innerLayout = useRef({}) const cloneRef = useRef(null) @@ -81,11 +89,8 @@ const _PickerView = forwardRef, PickerViewProp } else { maskPos.height = itemH * 2 } - const { nodeRef } = useNodesRef(props, ref, {}) - // value 如何关联picker-view-column这几个slot的内容呢 - const onColumnLayoutChange = (layoutConfig: PickerLayout) => { pickH = layoutConfig.height setPickH(layoutConfig.height) @@ -97,18 +102,23 @@ const _PickerView = forwardRef, PickerViewProp const eventData = getCustomEvent('change', {}, { detail: { value: changeValue, source: 'change' }, layoutRef: innerLayout }) bindchange && bindchange(eventData) } - /* - const onWrapperLayout = () => { - wrapRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => { - const a = { x, y, width, height, offsetLeft, offsetTop } - }) - } - */ + const getInnerLayout = (layout: MutableRefObject<{}>) => { innerLayout.current = layout.current } - const innerProps = useInnerProps(props, { ref: nodeRef }, [], { layoutRef: innerLayout }) + const onWrapperLayout = (res: LayoutChangeEvent) => { + if (hasPercent) { + const { width, height } = res?.nativeEvent?.layout || {} + setContainerWidth(width || 0) + setContainerHeight(height || 0) + } + } + + const innerProps = useInnerProps(props, { ref: nodeRef }, [ + 'style', + 'enable-offset' + ], { layoutRef: innerLayout }) const cloneChild = (child: React.ReactNode, index: number) => { const extraProps = index === 0 ? { getInnerLayout: getInnerLayout, innerProps } : {} @@ -133,7 +143,6 @@ const _PickerView = forwardRef, PickerViewProp } else { return realElement } - // return React.cloneElement(child as ReactElement, childProps) } const renderTopMask = () => { @@ -190,7 +199,7 @@ const _PickerView = forwardRef, PickerViewProp } } - return ( + return ( {renderTopMask()} {renderSubChild()} diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-swiper-item.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-swiper-item.tsx index d6b36b8b6f..dbd33505a4 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-swiper-item.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-swiper-item.tsx @@ -1,24 +1,53 @@ -import { View } from 'react-native' +import { View, LayoutChangeEvent } from 'react-native' import { ReactNode, forwardRef, useRef } from 'react' import useInnerProps from './getInnerListeners' import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数 +import { wrapChildren } from './common' +import { useTransformStyle, splitStyle, splitProps } from './utils' interface SwiperItemProps { 'item-id'?: string; 'enable-offset'?: boolean; + 'enable-var': boolean; + 'external-var-context'?: Record; children?: ReactNode; style?: Object; } const _SwiperItem = forwardRef, SwiperItemProps>((props: SwiperItemProps, ref) => { - const { children, 'enable-offset': enableOffset, style } = props + const { + 'enable-offset': enableOffset, + 'enable-var': enableVar, + 'external-var-context': externalVarContext, + style, + children + } = props + + const { textProps } = splitProps(props) const layoutRef = useRef({}) const { nodeRef } = useNodesRef(props, ref, {}) - const onLayout = () => { - nodeRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => { - layoutRef.current = { x, y, width, height, offsetLeft, offsetTop } - }) + const { + normalStyle, + hasVarDec, + varContextRef, + hasPercent, + setContainerWidth, + setContainerHeight + } = useTransformStyle(style, { enableVar, externalVarContext }) + const { textStyle } = splitStyle(normalStyle) + + const onLayout = (e: LayoutChangeEvent) => { + if (hasPercent) { + const { width, height } = e?.nativeEvent?.layout || {} + setContainerWidth(width || 0) + setContainerHeight(height || 0) + } + if (enableOffset) { + nodeRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => { + layoutRef.current = { x, y, width, height, offsetLeft, offsetTop } + }) + } } const innerProps = useInnerProps(props, { @@ -34,7 +63,19 @@ const _SwiperItem = forwardRef, SwiperItemProp data-itemId={props['item-id']} style={[style]} {...innerProps}> - {children} + { + wrapChildren( + props, + { + hasVarDec, + varContext: varContextRef.current + }, + { + textStyle, + textProps + } + ) + } ) }) diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-swiper/carouse.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-swiper/carouse.tsx index 0111a94c11..df1b2437d4 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-swiper/carouse.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-swiper/carouse.tsx @@ -6,6 +6,8 @@ import { JSX, forwardRef, useState, useRef, useEffect, ReactNode } from 'react' import { CarouseProps, CarouseState } from './type' import { getCustomEvent } from '../getInnerListeners' import useNodesRef, { HandlerRef } from '../useNodesRef' // 引入辅助函数 +import { VarContext } from '../context' +import { useTransformStyle } from '../utils' /** * 默认的Style类型 @@ -46,11 +48,9 @@ const styles: { [key: string]: Object } = { const _Carouse = forwardRef, CarouseProps>((props, ref): JSX.Element => { // 默认取水平方向的width const { width } = Dimensions.get('window') - const { styleObj } = props + const { styleObj, previousMargin = 0, nextMargin = 0, enableVar, externalVarContext } = props const newChild = Array.isArray(props.children) ? props.children.filter(child => child) : props.children const totalElements = Array.isArray(newChild) ? newChild.length : (newChild ? 1 : 0) - // const defaultHeight = (styleObj?.height || 150) - previousMargin - nextMargin - // const defaultWidth = (styleObj?.width || width || 375) - previousMargin - nextMargin const defaultHeight = (styleObj?.height || 150) const defaultWidth = (styleObj?.width || width || 375) const dir = props.horizontal === false ? 'y' : 'x' @@ -60,10 +60,17 @@ const _Carouse = forwardRef, Carouse const initIndex = props.current || 0 // 这里要排除超过元素个数的设置 const initOffsetIndex = initIndex + (props.circular && totalElements > 1 ? 1 : 0) - // const defaultX = (defaultWidth * initOffsetIndex + previousMargin) || 0 - // const defaultY = (defaultHeight * initOffsetIndex + previousMargin) || 0 const defaultX = (defaultWidth * initOffsetIndex) || 0 const defaultY = (defaultHeight * initOffsetIndex) || 0 + // 计算transfrom之类的 + const { + normalStyle, + hasVarDec, + varContextRef, + hasPercent, + setContainerWidth, + setContainerHeight + } = useTransformStyle(styleObj, { enableVar, externalVarContext }) // 内部存储上一次的offset值 const autoplayTimerRef = useRef | null>(null) const { nodeRef: scrollViewRef } = useNodesRef(props, ref, { @@ -81,8 +88,8 @@ const _Carouse = forwardRef, Carouse const isDragRef = useRef(false) const [state, setState] = useState({ children: newChild, - width: defaultWidth || 375, - height: defaultHeight, + width: dir === 'x' && typeof defaultWidth === 'number' ? defaultWidth - previousMargin - nextMargin : defaultWidth, + height: dir === 'y' && typeof defaultHeight === 'number' ? defaultHeight - previousMargin - nextMargin : defaultHeight, // 真正的游标索引, 从0开始 index: initIndex, total: totalElements, @@ -92,7 +99,6 @@ const _Carouse = forwardRef, Carouse }, dir } as CarouseState) - /** * @desc: 开启下一次自动轮播 */ @@ -110,6 +116,27 @@ const _Carouse = forwardRef, Carouse } }, [props.autoplay, props.current, state.index, state.width, state.height]) + useEffect(() => { + // 确认这个是变化的props变化的时候才执行,还是初始化的时候就执行 + if (!props.autoplay && props.current !== state.index) { + const initIndex = props.current || 0 + // 这里要排除超过元素个数的设置 + const initOffsetIndex = initIndex + (props.circular && totalElements > 1 ? 1 : 0) + const defaultX = (defaultWidth * initOffsetIndex) || 0 + const offset = { + x: dir === 'x' ? defaultX : 0, + y: dir === 'y' ? defaultY : 0 + } + state.offset = offset + internalsRef.current.offset = offset + setState((preState) => { + return { + ...preState, + offset + } + }) + } + }, [props.current]) /** * @desc: 更新状态: index和offset, 并响应索引变化的事件 * scrollViewOffset: 移动到的目标位置 @@ -278,16 +305,6 @@ const _Carouse = forwardRef, Carouse const internalOffset = internalsRef.current.offset const previousOffset = props.horizontal ? internalOffset.x : internalOffset.y const moveOffset = props.horizontal ? contentOffset.x : contentOffset.y - // const diff = moveOffset - previousOffset - /* - if (diff > 0 && state.index + 1 >= total) { - const { nextOffset } = getNextConfig(contentOffset) - // scrollViewRef.current?.scrollTo({ x: nextOffset['x'], y: nextOffset['y'], animated: false }) - } else if ( diff < 0 && state.index -1 < 0) { - const { nextOffset } = getNextConfig(contentOffset) - // scrollViewRef.current?.scrollTo({ x: nextOffset['x'], y: nextOffset['y'], animated: false }) - } - */ if (previousOffset === moveOffset && (index === 0 || index === total - 1)) { internalsRef.current.isScrolling = false } @@ -303,16 +320,22 @@ const _Carouse = forwardRef, Carouse const isWDiff = state.width !== width const isHDiff = state.height !== height if (isWDiff || isHDiff) { + if (hasPercent) { + setContainerWidth(width || 0) + setContainerHeight(height || 0) + } const changeState = { width: isWDiff ? width : state.width, height: isHDiff ? height : state.height } + const attr = state.dir === 'x' ? 'width' : 'height' + changeState[attr] = changeState[attr] - previousMargin - nextMargin const correctOffset = Object.assign({}, state.offset, { [state.dir]: initOffsetIndex * (state.dir === 'x' ? changeState.width : changeState.height) }) state.offset = correctOffset - state.width = width - state.height = height + state.width = changeState.width + state.height = changeState.height setState((preState) => { return { ...preState, @@ -332,7 +355,9 @@ const _Carouse = forwardRef, Carouse const scrollElementProps = { ref: scrollViewRef, horizontal: props.horizontal, - pagingEnabled: true, + pagingEnabled: false, + // snapToOffsets: true, + decelerationRate: 0.99, // 'fast' showsHorizontalScrollIndicator: false, showsVerticalScrollIndicator: false, bounces: false, @@ -400,6 +425,10 @@ const _Carouse = forwardRef, Carouse const { width, height, total, children } = state const { circular } = props const pageStyle = { width: width, height: height } + // 设置了previousMargin或者nextMargin, + // 1. 元素的宽度是减去这两个数目之和 + // 2. previousMargin设置marginLeft正值, nextmargin设置marginRight负值 + // 3. 第一个元素设置previousMargin 和 nextMargin, 最后一个元素 if (total > 1 && Array.isArray(children)) { let arrElements: (Array) = [] // pages = ["2", "0", "1", "2", "0"] @@ -410,19 +439,39 @@ const _Carouse = forwardRef, Carouse pages.push('0') } arrElements = pages.map((page, i) => { - return ( - + const extraStyle = {} as { + [key: string]: any + } + if (i === 0 && dir === 'x' && typeof width === 'number') { + previousMargin && (extraStyle.marginLeft = previousMargin) + } else if (i === pages.length && typeof width === 'number') { + nextMargin && (extraStyle.marginRight = nextMargin) + } + const realElement = ( + {children[+page]} ) + if (hasVarDec && varContextRef.current) { + const wrapChild = {realElement} + return wrapChild + } else { + return realElement + } }) return arrElements } else { - return ( + const realElement = ( {children} ) + if (hasVarDec && varContextRef.current) { + const wrapChild = {realElement} + return wrapChild + } else { + return realElement + } } } @@ -430,7 +479,6 @@ const _Carouse = forwardRef, Carouse const strStyle: string = 'container_' + state.dir const eventProps = props.innerProps || {} const layoutStyle = dir === 'x' ? { width: defaultWidth, height: defaultHeight } : { width: defaultWidth } - return ( , SwiperPro previousMargin: props['previous-margin'] ? parseInt(props['previous-margin']) : 0, nextMargin: props['next-margin'] ? parseInt(props['next-margin']) : 0, enableOffset: props['enable-offset'] || true, + enableVar: props['enable-var'] || false, + externalVarContext: props['external-var-context'], bindchange: props.bindchange, easingFunction: props['easing-function'] || 'default' } diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-swiper/type.ts b/packages/webpack-plugin/lib/runtime/components/react/mpx-swiper/type.ts index 7d457533ca..0aa68e84bd 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-swiper/type.ts +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-swiper/type.ts @@ -19,6 +19,8 @@ export interface SwiperProps { 'previous-margin'?: string; 'next-margin'?: string; 'enable-offset'?: boolean; + 'enable-var': boolean; + 'external-var-context'?: Record; bindchange?: (event: NativeSyntheticEvent | unknown) => void; } @@ -38,12 +40,14 @@ export interface CarouseProps { nextMargin?: number; enableOffset?: boolean; bindchange?: (event: NativeSyntheticEvent | unknown) => void; - getInnerLayout: Function, + getInnerLayout: Function; innerProps: Object; styleObj: { height?: number; width?: number }; + enableVar: boolean; + externalVarContext?: Record; } export interface CarouseState {