fix(custom): fix wgts-film aspect-ratio

This commit is contained in:
jerry
2026-02-06 11:28:29 +08:00
parent 01246988bb
commit dd5c5e1ea3
7 changed files with 125 additions and 103 deletions

View File

@@ -57,7 +57,10 @@ const config = {
sourceRoot: 'src',
outputRoot: DIST_PATH,
sass: {
resource: path.resolve(__dirname, '..', 'src/style/imports.scss'),
resource:
process.env.TARO_ENV === 'weapp'
? ['src/style/imports.scss', 'src/style/weapp-mixins.scss']
: ['src/style/imports.scss', 'src/style/h5-mixins.scss'],
projectDirectory: path.resolve(__dirname, '..')
},

View File

@@ -2,91 +2,39 @@
* Copyright © ShopeX http://www.shopex.cn. All rights reserved.
* See LICENSE file for license details.
*/
import React, { useState, useEffect, useMemo } from 'react'
import Taro, { getCurrentInstance } from '@tarojs/taro'
import React, { useMemo } from 'react'
import { View, Video, Text } from '@tarojs/components'
import { classNames, styleNames, linkPage } from '@/utils'
import { getGlobalBaseStyle } from '../helper'
import './index.scss'
const $instance = getCurrentInstance()
// proportion 与比例 class 的映射0=16:9, 1=9:16, 2=4:3, 3=3:4, 4=1:1
const RATIO_CLASS_MAP = ['16-9', '9-16', '4-3', '3-4', '1-1']
function WgtFilm(props) {
const { info } = props
const [screenWidth, setScreenWidth] = useState(null)
// 从 params 中获取配置和数据,兼容两种数据结构
// 1. 新结构info.params.config, info.params.data, info.params.base
// 2. 旧结构info.config, info.data, info.base
const params = info?.params || info || {}
const base = params.base || {}
const config = params.config || {}
const data = params.data || []
useEffect(() => {
const res = Taro.getSystemInfoSync()
setScreenWidth(res.screenWidth)
}, [])
// 获取外层样式(包含 outerMargin 和背景配置)
const outerStyle = useMemo(() => {
return getGlobalBaseStyle(base.outerMargin)
}, [base])
// 计算视频尺寸
const videoSize = useMemo(() => {
if (!screenWidth) {
return { width: '100%', height: 'auto', objectFit: 'contain' }
}
// 根据 base.proportion / config.ratio 得到比例 class用 aspect-ratio mixin 渲染
const videoWrapClass = useMemo(() => {
if (config.ratio === 'square') return 'wgt-film__video-wrap--1-1'
if (config.ratio === 'rectangle') return 'wgt-film__video-wrap--16-9'
const proportion = base.proportion ?? 0
const key = RATIO_CLASS_MAP[proportion] || RATIO_CLASS_MAP[0]
return `wgt-film__video-wrap--${key}`
}, [base.proportion, config.ratio])
// 计算实际可用宽度(减去边距)
const padding = config.padded || base.padded ? 32 : 0 // 16px * 2
const availableWidth = screenWidth - padding
const aspectRatios = [16 / 9, 9 / 16, 4 / 3, 3 / 4, 1 / 1]
const { proportion = 0 } = base
let ratio = aspectRatios[proportion]
let w = '100%',
h
let objectFit = 'contain'
const defaultHeight = Math.round(availableWidth / ratio)
if (config.width && config.height) {
ratio = config.width / config.height
if (ratio <= 10 / 16) {
h = defaultHeight
} else {
objectFit = 'cover'
h = Math.round(availableWidth / ratio)
}
} else {
h = defaultHeight
}
if (config.ratio === 'square') {
// 1:1
objectFit = 'cover'
h = availableWidth
} else if (config.ratio === 'rectangle') {
// 16:9
h = defaultHeight
}
return {
width: w,
height: `${h}px`,
objectFit
}
}, [
screenWidth,
base.proportion,
base.padded,
config.width,
config.height,
config.ratio,
config.padded
])
const objectFit = config.ratio === 'square' ? 'cover' : 'contain'
const handleClickItem = linkPage
@@ -109,20 +57,16 @@ function WgtFilm(props) {
</View>
</View>
)}
<View
className={classNames('slider-wrap')}
style={styleNames({
width: videoSize.width,
height: videoSize.height
})}
>
<Video
className='flim-video'
direction={90}
src={data[0].url}
controls
objectFit={videoSize.objectFit}
/>
<View className={classNames('wgt-film__video-wrap', videoWrapClass)}>
<View className='wgt-film__video-inner'>
<Video
className='flim-video'
direction={90}
src={data[0].url}
controls
objectFit={objectFit}
/>
</View>
</View>
</View>
)

View File

@@ -2,12 +2,41 @@
* Copyright © ShopeX http://www.shopex.cn. All rights reserved.
* See LICENSE file for license details.
*/
.wgt-film {
.flim-video {
height: 100%;
display: block;
width: 100%;
// background-color: #000;
.wgt-film {
.wgt-film__video-wrap {
width: 100%;
overflow: hidden;
&--16-9 {
@include aspect-ratio(16, 9);
}
&--9-16 {
@include aspect-ratio(9, 16);
}
&--4-3 {
@include aspect-ratio(4, 3);
}
&--3-4 {
@include aspect-ratio(3, 4);
}
&--1-1 {
@include aspect-ratio(1, 1);
}
}
.wgt-film__video-inner {
// 作为 aspect-ratio 容器的直接子元素,由 mixin 设为 absolute 填满
video,
.flim-video {
width: 100%;
height: 100%;
display: block;
}
}
.flim-video {
height: 100%;
display: block;
width: 100%;
}
}

View File

@@ -36,14 +36,14 @@ function WgtImgHotZone(props) {
}
// 高度优先级config.imgHeight > animation模式下的imgHeight > auto
if (config.imgHeight) {
style.height = Taro.pxTransform(config.imgHeight)
} else if (isVertical) {
style.height = Taro.pxTransform(imgHeight)
} else {
style.height = 'auto'
}
// if (config.imgHeight) {
// style.height = Taro.pxTransform(config.imgHeight)
// } else if (isVertical) {
// style.height = Taro.pxTransform(imgHeight)
// } else {
// style.height = 'auto'
// }
style.height = 'auto'
return style
}, [outerStyle, config.imgWidth, config.imgHeight, isVertical, imgHeight])

View File

@@ -49,15 +49,15 @@ function WgtImgHotZone(props) {
}
// 纵向布局时,优先使用 base.imgHeight
if (isVertical && base.imgHeight) {
style.height = Taro.pxTransform(base.imgHeight)
} else if (config.imgHeight) {
// 横向布局时,使用 config.imgHeight
style.height = Taro.pxTransform(config.imgHeight)
} else {
style.height = 'auto'
}
// if (isVertical && base.imgHeight) {
// style.height = Taro.pxTransform(base.imgHeight)
// } else if (config.imgHeight) {
// // 横向布局时,使用 config.imgHeight
// style.height = Taro.pxTransform(config.imgHeight)
// } else {
// style.height = 'auto'
// }
style.height = 'auto'
return style
}, [config.imgWidth, config.imgHeight, isVertical, base.imgHeight])

27
src/style/h5-mixins.scss Normal file
View File

@@ -0,0 +1,27 @@
@mixin aspect-ratio($width: 1, $height: 1, $useFallback: true) {
// 计算 padding-top 降级比例
$ratio: $width / $height;
$padding: percentage($height / $width);
// 降级方案:使用 padding-top 模拟宽高比
@if $useFallback {
@supports not (aspect-ratio: #{$width}/#{$height}) {
position: relative;
padding-top: $padding;
width: 100%;
flex-grow: 0;
// 使用 > 选择器确保仅匹配直接子元素
> * {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
}
}
@supports (aspect-ratio: #{$width}/#{$height}) {
// 现代浏览器标准语法
aspect-ratio: #{$width}/#{$height};
}
}

View File

@@ -0,0 +1,19 @@
@mixin aspect-ratio($width: 1, $height: 1, $useFallback: true) {
// 计算 padding-top 降级比例
$ratio: $width / $height;
$padding: percentage($height / $width);
// 降级方案:使用 padding-top 模拟宽高比
position: relative;
padding-top: $padding;
width: 100%;
flex-grow: 0;
// 使用 > 选择器确保仅匹配直接子元素
> view {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
}