React IconTint(画布)动态改变颜色

Posted

技术标签:

【中文标题】React IconTint(画布)动态改变颜色【英文标题】:React IconTint (canvas) change color dynamically 【发布时间】:2021-12-17 00:09:49 【问题描述】:

有没有办法从react-icon-tint 库中动态更改<IconTint /> 元素的颜色? 我需要在 isActive 状态更改时更改颜色,但它看起来不像我预期的那样工作,因为它在引擎盖下使用了 canvas 元素。

我还尝试重新渲染isActive 上的整个元素,像这样改变


  isActive ? (
    <IconTint src=getCustomIcon() color=icon />
  ) : (
    <IconTint src=getCustomIcon() color=iconOnBackground />
  );

但它也没有工作。

【问题讨论】:

【参考方案1】:

我查看了源代码,因为它是一个记忆化组件,它不会在父级重新渲染时重新渲染,并且因为在组件内部使用的 useEffect 内部,不包括颜色和图像 src 等依赖项,它确实不重新渲染道具更改,显然这是一个错误或不受欢迎的行为。我不知道为什么你的做法不起作用,因为这两个 IconTint 组件是两个不同的组件!但你可以这样做:

 isActive && <IconTint src=getCustomIcon() color='#0000ff' />
 !isActive && <IconTint src=getCustomIcon() color='#b43285' />

我不认为这是高性能的,源代码是如此简单,所以你可以在你的项目中实现 IconTint 并在 useEffect 依赖数组中添加依赖。这里我提供了修改后的版本。

import React,  memo, useEffect, useRef, useState  from "react";
import PropTypes from "prop-types";

const IconTint = ( fallback = <span />, src, color, maxWidth, maxHeight ) => 
  const canvasRef = useRef(null);
  const [size, setSize] = useState();

  const _scaleImage = (srcWidth, srcHeight, maxWidth, maxHeight) => 
    if (maxWidth && maxHeight) 
      const ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);
      return  width: srcWidth * ratio, height: srcHeight * ratio ;
    
    if ((maxWidth && !maxHeight) || (!maxWidth && maxHeight)) 
      throw new Error(
        "If you are going to provide width, make sure to provide height as well"
      );
    
    return  width: srcWidth, height: srcHeight ;
  ;

  useEffect(() => 
    const canvas = canvasRef.current;
    // eslint-disable-next-line no-undef
    const pic = new Image();
    pic.src = src;
    const tintCanvas = document.createElement("canvas");
    const tintCtx = tintCanvas.getContext("2d");
    const ctx = canvas.getContext("2d");
    pic.onload = () => 
      const result = _scaleImage(pic.width, pic.height, maxWidth, maxHeight);
      setSize(result);
      tintCanvas.width = result.width;
      tintCanvas.height = result.height;
      tintCtx.fillStyle = color;
      tintCtx.fillRect(0, 0, result.width, result.height);
      tintCtx.globalCompositeOperation = "destination-atop";
      tintCtx.drawImage(pic, 0, 0, result.width, result.height);
      ctx.globalAlpha = 1;
      ctx.drawImage(tintCanvas, 0, 0, result.width, result.height);
    ;
  , [src,color,maxHeight,maxWidth]);

  if (
    typeof window !== "undefined" &&
    window.document &&
    window.document.createElement
  ) 
    return <canvas width=size.width height=size.height ref=canvasRef />;
  
  return fallback;
;

IconTint.propTypes = 
  src: PropTypes.string.isRequired,
  color: PropTypes.string.isRequired,
  fallback: PropTypes.node,
  maxWidth: PropTypes.number,
  maxHeight: PropTypes.number
;

export default memo(IconTint);

现在您可以像这样使用这个修改后的版本:

<IconTint src=getCustomIcon() color=isActive ? '#0000ff' : "#b43285"/>

【讨论】:

以上是关于React IconTint(画布)动态改变颜色的主要内容,如果未能解决你的问题,请参考以下文章

动态改变描边颜色

利用canvas画一个动态时钟

winform 动态改变listview字体颜色

fabricjs画布内的svg颜色没有改变

easyUI的datagrid,怎么动态改变某一行的背景颜色

photoshop如何改变矩形线条颜色