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({...}) 获取图片信息

相关推荐
spider_xcxc6 分钟前
Redis 深度实践:安全管控、性能压测与持久化分析(二)
运维·前端·redis·云计算·bootstrap·运维开发
乘风gg6 分钟前
代码都已经让 AI 写了,为什么有些人却更慌了?
前端·ai编程·claude
我不是外星人16 分钟前
一键还原任意网站,这套 Playwright + 多 Agent 工程流太猛了
前端·后端·ai编程
用户0595401744621 分钟前
AI 客服突然“失忆”,排查 6 小时发现 LangChain 记忆存储的 3 个致命坑
前端·css
IT_陈寒42 分钟前
Vue的v-if和v-show,我竟然用错了这么久
前端·人工智能·后端
云絮.1 小时前
计算机相关工作原理
服务器·前端·数据库
随风一样自由1 小时前
【前端+React+缓存竞态】导航切换缓存刷新机制
前端·react.js·缓存
恋猫de小郭1 小时前
Flutter 开发怎么做 Agent ?从工程实战详细给你解读下
android·前端·flutter
IT_陈寒1 小时前
React状态更新延迟搞晕我,原来是闭包在捣鬼
前端·人工智能·后端
晓得迷路了1 小时前
栗子前端技术周刊第 136 期 - pnpr、Flow 重构移植 Rust、Astryx...
前端·javascript·css