diff --git a/packages/core/package.json b/packages/core/package.json index f96625c2f..f7b12ea88 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -34,6 +34,7 @@ "react-native-gesture-handler": "^2.19.0", "react-native-linear-gradient": "^2.8.3", "react-native-safe-area-context": "^4.10.1", + "@d11/react-native-fast-image": "^8.8.0", "react-native-webview": "^13.10.5", "vue": "^2.7.10", "vue-demi": "^0.14.6", @@ -79,6 +80,9 @@ }, "react-native-linear-gradient": { "optional": true + }, + "@d11/react-native-fast-image": { + "optional": true } }, "publishConfig": { diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx index 1089d50b9..3dfc99ca7 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-image.tsx @@ -25,7 +25,7 @@ import { import { SvgCssUri } from 'react-native-svg/css' import useInnerProps, { getCustomEvent } from './getInnerListeners' import useNodesRef, { HandlerRef } from './useNodesRef' -import { SVG_REGEXP, useLayout, useTransformStyle } from './utils' +import { SVG_REGEXP, useLayout, useTransformStyle, renderImage } from './utils' export type Mode = | 'scaleToFill' @@ -51,6 +51,7 @@ export interface ImageProps { 'enable-offset'?: boolean; 'enable-var'?: boolean 'external-var-context'?: Record + 'enable-fast-image'?: boolean 'parent-font-size'?: number 'parent-width'?: number 'parent-height'?: number @@ -100,6 +101,7 @@ const Image = forwardRef, ImageProps>((props, re style = {}, 'enable-var': enableVar, 'external-var-context': externalVarContext, + 'enable-fast-image': enableFastImage, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, @@ -363,18 +365,18 @@ const Image = forwardRef, ImageProps>((props, re ...modeStyle }} /> - : + } + }, enableFastImage) } ) diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-view.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-view.tsx index 44578c85e..30aafc951 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-view.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-view.tsx @@ -4,12 +4,12 @@ * ✔ hover-start-time * ✔ hover-stay-time */ -import { View, TextStyle, NativeSyntheticEvent, ViewProps, ImageStyle, ImageResizeMode, StyleSheet, Image, LayoutChangeEvent, Text } from 'react-native' -import { useRef, useState, useEffect, forwardRef, ReactNode, JSX, Children, cloneElement } from 'react' +import { View, TextStyle, NativeSyntheticEvent, ViewProps, ImageStyle, StyleSheet, Image, LayoutChangeEvent } from 'react-native' +import { useRef, useState, useEffect, forwardRef, ReactNode, JSX } from 'react' import useInnerProps from './getInnerListeners' import { ExtendedViewStyle } from './types/common' import useNodesRef, { HandlerRef } from './useNodesRef' -import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout } from './utils' +import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout, renderImage } from './utils' import LinearGradient from 'react-native-linear-gradient' export interface _ViewProps extends ViewProps { @@ -20,6 +20,7 @@ export interface _ViewProps extends ViewProps { 'hover-stay-time'?: number 'enable-background'?: boolean 'enable-var'?: boolean + 'enable-fast-image'?: boolean 'external-var-context'?: Record 'parent-font-size'?: number 'parent-width'?: number @@ -71,9 +72,11 @@ type PreImageInfo = { type ImageProps = { style: ImageStyle, src?: string, + source?: {uri: string }, colors: Array, locations?: Array angle?: number + resizeMode?: 'cover' | 'stretch' } const linearMap = new Map([ @@ -114,17 +117,6 @@ const applyHandlers = (handlers: Handler[], args: any[]) => { } } -const normalizeStyle = (style: ExtendedViewStyle = {}) => { - ['backgroundSize', 'backgroundPosition'].forEach(name => { - if (style[name] && typeof style[name] === 'string') { - if (style[name].trim()) { - style[name] = style[name].split(' ') - } - } - }) - return style -} - const isPercent = (val: string | number | undefined): val is string => typeof val === 'string' && PERCENT_REGEX.test(val) const isBackgroundSizeKeyword = (val: string | number): boolean => typeof val === 'string' && /^cover|contain$/.test(val) @@ -275,7 +267,7 @@ function backgroundSize (imageProps: ImageProps, preImageInfo: PreImageInfo, ima if (!dimensions) return } else { // 数值类型 ImageStyle // 数值类型设置为 stretch - (imageProps.style as ImageStyle).resizeMode = 'stretch' + imageProps.resizeMode = 'stretch' dimensions = { width: isPercent(width) ? width : +width, height: isPercent(height) ? height : +height @@ -291,8 +283,9 @@ function backgroundSize (imageProps: ImageProps, preImageInfo: PreImageInfo, ima // background-image转换为source function backgroundImage (imageProps: ImageProps, preImageInfo: PreImageInfo) { - if (preImageInfo.src) { - imageProps.src = preImageInfo.src + const src = preImageInfo.src + if (src) { + imageProps.source = { uri: src } } } @@ -321,8 +314,8 @@ function linearGradient (imageProps: ImageProps, preImageInfo: PreImageInfo, ima const imageStyleToProps = (preImageInfo: PreImageInfo, imageSize: Size, layoutInfo: Size) => { // 初始化 const imageProps: ImageProps = { + resizeMode: 'cover', style: { - resizeMode: 'cover' as ImageResizeMode, position: 'absolute' // ...StyleSheet.absoluteFillObject }, @@ -512,7 +505,7 @@ function normalizeBackgroundSize (backgroundSize: Exclude = {}) { + return ['borderRadius', 'borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius'].reduce>((acc, key) => { + if (key in innerStyle) acc[key] = innerStyle[key] || 0 + return acc + }, {}) +} + +function wrapImage (imageStyle?: ExtendedViewStyle, innerStyle?: Record, enableFastImage?: boolean) { // 预处理数据 const preImageInfo: PreImageInfo = preParseImage(imageStyle) // 预解析 @@ -611,9 +611,9 @@ function wrapImage (imageStyle?: ExtendedViewStyle) { } } - return + return {show && type === 'linear' && } - {show && type === 'image' && } + {show && type === 'image' && (renderImage(imageStyleToProps(preImageInfo, sizeInfo.current as Size, layoutInfo.current as Size), enableFastImage) )} } @@ -624,9 +624,11 @@ interface WrapChildrenConfig { backgroundStyle?: ExtendedViewStyle varContext?: Record textProps?: Record + innerStyle?: Record + enableFastImage?: boolean } -function wrapWithChildren (props: _ViewProps, { hasVarDec, enableBackground, textStyle, backgroundStyle, varContext, textProps }: WrapChildrenConfig) { +function wrapWithChildren (props: _ViewProps, { hasVarDec, enableBackground, textStyle, backgroundStyle, varContext, textProps, innerStyle, enableFastImage }: WrapChildrenConfig) { const children = wrapChildren(props, { hasVarDec, varContext, @@ -635,7 +637,7 @@ function wrapWithChildren (props: _ViewProps, { hasVarDec, enableBackground, tex }) return [ - enableBackground ? wrapImage(backgroundStyle) : null, + enableBackground ? wrapImage(backgroundStyle, innerStyle, enableFastImage) : null, children ] } @@ -650,6 +652,7 @@ const _View = forwardRef, _ViewProps>((viewProps, r 'enable-var': enableVar, 'external-var-context': externalVarContext, 'enable-background': enableBackground, + 'enable-fast-image': enableFastImage, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight @@ -777,7 +780,9 @@ const _View = forwardRef, _ViewProps>((viewProps, r textStyle, backgroundStyle, varContext: varContextRef.current, - textProps + textProps, + innerStyle, + enableFastImage } ) } diff --git a/packages/webpack-plugin/lib/runtime/components/react/utils.tsx b/packages/webpack-plugin/lib/runtime/components/react/utils.tsx index 665685d3a..dc0740a31 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/utils.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/utils.tsx @@ -4,6 +4,7 @@ import { isObject, hasOwn, diffAndCloneA, error, warn, getFocusedNavigation } fr import { VarContext } from './context' import { ExpressionParser, parseFunc, ReplaceSource } from './parser' import { initialWindowMetrics } from 'react-native-safe-area-context' +import FastImage from '@d11/react-native-fast-image' export const TEXT_STYLE_REGEX = /color|font.*|text.*|letterSpacing|lineHeight|includeFontPadding|writingDirection/ export const PERCENT_REGEX = /^\s*-?\d+(\.\d+)?%\s*$/ @@ -523,3 +524,9 @@ export function wrapChildren (props: Record = {}, { hasVarDec, varC } return children } + +export function renderImage (imageProps: Record, enableFastImage = false) { + const Component = enableFastImage ? FastImage : Image + return +} + diff --git a/packages/webpack-plugin/package.json b/packages/webpack-plugin/package.json index 4396dfb75..21ec538bf 100644 --- a/packages/webpack-plugin/package.json +++ b/packages/webpack-plugin/package.json @@ -82,6 +82,7 @@ }, "devDependencies": { "@ant-design/react-native": "^5.2.2", + "@d11/react-native-fast-image": "^8.8.0", "@mpxjs/api-proxy": "^2.9.65", "@types/babel-traverse": "^6.25.4", "@types/babel-types": "^7.0.4",