Taro篇,小程序和Taro的Image组件添加mode属性中的那些坑

笔记

前言

最近在开发IM通讯系统的时候有发送并渲染图片的问题。因为发送的图片宽高不一,所以给了图片一个计算过的width和mode="widthFix" 属性。

但是,Taro的Image的标签的widthFix 属性存在一个问题(当然其他非裁剪的属性存在同样的问题,比如heightFix,)。就是在数据从头上开始重新渲染的时候,整个Image标签的告诉都会被重新计算。不管有没有加上key。

这个问题导致原因是,mode属性并不是在优先计算图片的宽高然后再渲染视图,而是先进行渲染然后再进行自适应宽高的计算。

PS:这个问题只有在往数组的前方添加内容的时候才会出现。

问题模拟

注意到了吗,图片会瞬间拉长然后恢复到自适应高度。实际上每次添加节点都会有这个情况,gif中点击没有出现的只是录制的时候帧数没有捕捉到。

实际上网上有很多资料会告诉你,这种闪烁是因为Image有一个固定240px的高度,给Image设定一个height:"auto"就好了。

实际上效果并没有想的那么顺利。

确实,图片突然拉长然后回到一个正常的高度的闪烁确实是因为图片在一开始width:xxx,height:320的情况下因为mode:widthFix的问题height的高度在渲染完成以后突然变成另一个高度导致的。但是把height调整为"auto"也并不能改变这个bug。无非就是让图片从height:320到自适应高度的闪烁变成了从height:0到自适应高度的闪烁。

效果如下图

这个问题就有意思了。以上两个区别就是从320-自适应高度和从0-自适应高度的区别。当然,在视觉效果上,后者显然会比前者更好一些。

所以,如何解决这个问题?

方案

当我发现不论我缓存组件(memo)还是添加key都不能避免这张图片的高度被重新计算的时候。我就放弃了避免他被重新渲染的方案。其实在这个问题最麻烦是高度的变化,而不是图片本身渲染的问题。

既然无法避免他被重新渲染。而问题的原因又是高度的变动导致的。所以我改变了策略,我让他记住这个图片的高度。会不会更好些?

解决方法一

使用mode中除去自适应宽高以外的属性,比如aspectFitaspectFill等裁剪属性,这些属性都是需要提前设定宽高的。所以不会出现高度闪烁或者宽度闪烁的情况。

这种方法适用的场景比较局限: 当我们的项目在渲染列表图片的时候允许同一固定宽高的情况下。不需要每一张图片都有自己特定的宽高的时候。

解决方法二

封装一个自定义的Image组件。

js 复制代码
import { Image } from "@tarojs/components";
import { FC, useEffect, useState } from "react";
import Taro, { pxTransform } from "@tarojs/taro";
import { memo } from "react";

interface Props {
  item: {
    url: string;
    key: string;
  };
}
export const ImageCom: FC<Props> = memo(({ item }) => {
  const [imageHW, setImageHW] = useState({
    width: 0,
    height: 0,
  });

  /**
   * 计算图片相对于屏幕的比例
   * @param res
   * @returns
   */
  const computeImageScale = (res: any) => {
    const { width, height } = res;
    const screenWidth = Taro.getSystemInfoSync().windowWidth * 2 * 0.7;
    if (screenWidth < width) {
      const scale = screenWidth / width;
      return {
        width: screenWidth,
        height: height * scale,
      };
    } else {
      return {
        width,
        height,
      };
    }
  };

  /**
   * 获取并计算图片的宽高
   */
  const handelGetImageInfo = () => {
    Taro.getImageInfo({
      src: item.url,
      success: (res) => {
        const elInfo = computeImageScale(res);
        setImageHW({
          height: elInfo.height,
          width: elInfo.width,
        });
      },
    });
  };

  useEffect(() => {
   handelGetImageInfo();
  });
  
  return (
    <>
      <Image
        src={item?.url}
        //一开始就给他一个固定的经过计算的宽高,不给他自适应的机会
        style={{ width: pxTransform(imageHW.width),height:pxTransform(imageHW.height) }}
        key={item.key}
      />
    </>
  );
});

第二种方法就是放弃mode属性,自己去计算图片在窗口中该有的宽和高。只要让图片在重新渲染的时候就保持他该有的高度,就不会出现闪烁的情况。

结尾

给大家参考两个API

第一个: Taro.getSystemInfoSync() 获取设备信息

第二个: Taro.getImageInfo({...}) 获取图片信息

相关推荐
匹马夕阳2 分钟前
Vue 3中导航守卫(Navigation Guard)结合Axios实现token认证机制
前端·javascript·vue.js
你熬夜了吗?4 分钟前
日历热力图,月度数据可视化图表(日活跃图、格子图)vue组件
前端·vue.js·信息可视化
桂月二二6 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
hunter2062067 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb8 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角8 小时前
CSS 颜色
前端·css
九酒8 小时前
从UI稿到代码优化,看Trae AI 编辑器如何帮助开发者提效
前端·trae
浪浪山小白兔9 小时前
HTML5 新表单属性详解
前端·html·html5
lee5769 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm
2401_897579659 小时前
AI赋能Flutter开发:ScriptEcho助你高效构建跨端应用
前端·人工智能·flutter