记录一次关于小程序rpx的坑
相关知识点:小程序,background-position,rpx,百分比,taro + react + hooks
背景:
公司的抽奖活动改成了老虎机的那种形式。类似下面这样。
于是参考社区的这篇文章。
当时写的时候就是想封装成一个公共的组件,因为这是公司第一次的老虎机抽奖,后续有类似活动,可以直接使用我的组件,代码后面贴出来。
大致思路
所以大致思路:利用background-position 能够改变背景图片的相对位置 + transition 实现动态效果。
为什么不使用, transfrom: translateY ? 因为需要动态去计算元素的搞,增加额外的dom 消耗。
简单说下,计算滚动的距离:
**计算规则:**每一个icon 的高度 x 圈数 x 最后定位到第几个的高度。其中圈数的高度: 圈数 x icon 的个数
(position - 1 + turnC * count) * height
具体问题
在使用background-position 的时候,第一默认想法是 使用rpx 去计算 需要滚动的高度。
做到这里一切都在预料之中,没什么问题,但是当提测以后,ui发现iphone 12上面怎么都无法剧中对齐,总是偏差一点距离,这是为什么呢?
苦思冥想了好久,测试了好久发现:当我把圈数调的越大,这个差距就会越明显?但是除了12以外其机型都是完美剧中,并且得出结论:计算公式没有错误,但是iphone12 上面会有计算偏差,而且偏差会根据偏移值越大而越大。
于是使用了百分比去进行位移操作以后就不会出现偏差了。代码如下:
公共组件:
/**
* @Owners ph
* @Title 老虎机-滚动效果
*/
import { Image, View } from '@tarojs/components';
import Taro from '@tarojs/taro';
import { cIcon } from 'mj-mall-taro-consts';
import { Ref, forwardRef, useImperativeHandle, useState } from 'react';
import './wheel.scss';
type Config = {
// 每个icon的宽高
width?: number,
height?: number,
// 初始位置是第几个 -- 默认第一个
initPos?: number,
// 总个数
count?: number,
// 转几圈 -- 默认一圈
turnCount?: number,
bg?: string,
};
export type Transition = {
// 转的速度: 完成的时间
duration?: number,
// 转的方式
timingFunction?: string | 'ease-in-out' | 'ease-in' | 'ease-out' | 'ease' | 'linear',
// 延迟的时间
delay?: number,
};
const ratio: number = Taro.getStorageSync('ratio') || 2;
type Props = {
config?: Config,
initTransition?: Transition,
};
const Wheel = (props: Props, ref: Ref<unknown> | undefined) => {
const { config, initTransition } = props;
const {
count = 4,
width = 142,
height = 172,
initPos = 1,
turnCount = 1,
bg = cIcon.LUCKY_SLOT_MACHINE_WHEELS,
} = config || {};
const {
duration = 2.5,
timingFunction = 'ease-in-out',
delay = 0,
} = initTransition || {};
// 转动到第几个 转动的时间 延时
const [transition, updateTransition] = useState<Transition>({
duration,
timingFunction,
delay,
});
// 转以后定位到第几个 -- 默认第一个
const [position, updatePosition] = useState<number>(initPos);
// 转几圈
const [turnC, updateTurnC] = useState<number>(turnCount);
// 是否开始了
const [isStart, updateIsStart] = useState<boolean>(false);
const doAnimation = (p: number, _turnCount?: Transition | number, pos?: Transition) => {
updateIsStart(true);
updatePosition(p);
if (typeof _turnCount === 'object') {
updateTransition({
...transition,
..._turnCount,
});
} else {
_turnCount && updateTurnC(_turnCount);
updateTransition({
...transition,
...pos,
});
}
// 重制
// rest()
};
useImperativeHandle(ref, () => ({
doAnimation,
// 重制,待实现
// reset: () => {},
}));
return <View className='wheel-container' style={{
width: (width / ratio) + 'px',
}}>
<Image className='wheel-shadow' src={cIcon.LUCKY_SLOT_MACHINE_SHADOW} />
<View className='wheel-box-image' style={{
backgroundImage: `url(${bg})`,
width: (width / ratio) + 'px',
height: (height / ratio) + 'px',
// backgroundPosition: `0px ${isStart ? `-${(position - 1 + turnC * count) * height / ratio}px` : `-${(position - 1) * height / ratio}px`}`,
backgroundPosition: `0px ${isStart ? `-${(position - 1 + turnC * count) * 100}%` : `-${(position - 1) * height / ratio}px`}`,
transition: `all ${transition.duration}s ${transition.timingFunction} ${transition.delay}s`,
}} />
</View>;
};
export default forwardRef(Wheel);
使用:
// ref
const getWheel_one = useRef<{
doAnimation(posi: number, turnCount?: number, transi?: Transition): void,
}>();
// 配置初始化
<Wheel
ref={getWheel_one}
config={{
initPos: 1,
}} />
// 调用
const position = 2;
const DURATION1 = 2;
// 转多少圈
const turnCount1 = 2;
getWheel_one.current?.doAnimation(position, turnCount1, {
duration: DURATION1,
timingFunction: 'cubic-bezier(0.52, 0.06, 0.3, 1)',
});
所以大家知道为什么 iphone 12 会计算出现偏差吗?