手把手带你实现RGBA颜色和Hex颜色转换器

1 .开始

做前端的避免不了和颜色值打交道,某天ui给我们了一个颜色#87cefaff,交代全部风格给我用这个颜色,但是出于代码的统一我们需要用rgba的形式进行代码的书写,于是我们send消息给ui表示我需要这个色号的rgba值,ui做完图就是划水时间了,哪有闲工夫再管你的破事,消息最终是已读未回。。。。最终我们还是要亲自面向百度来查找相关的网站进行解析。闲话说完,今天我们就来实现下在开发中,我们需要打交道最多的两个颜色表示形式(RGBA、HEX)的转换,PS:实现很简单,主要来复习下这两种色号的理解。我们先来粘上最终的实现效果:

在这里插入图片描述

在开始前,我们先来介绍下RGBA和HEX:

  • RGBA是代表Red(红色)Green(绿色Blue(蓝色)和Alpha的色彩空间。虽然它有的时候被描述为一个颜色空间,但是它其实仅仅是RGB模型的附加了额外的信息。采用的颜色是RGB,可以属于任何一种RGB颜色空间,但是Catmull和Smith在1971至1972年间提出了这个不可或缺的alpha数值,使得alpha渲染和alpha合成变得可能。提出者以alpha来命名是源于经典的线性插值方程αA + (1-α)B所用的就是这个希腊字母

  • Hex代码为“三字节”的十六进制数字,其中每一字节或每两个字符分别代表红、绿、蓝颜色的强度。 #XXXXXX Hex代码字节值的范围从颜色强度最低的00到最高强度FF。 举例来说,白色由最高强度的三基色混合而成,其Hex颜色代码即为#FFFFFF。

这里我们来举例说明下我们需要重点关注的知识点。先说rgba,我们拿红色字号RGBA(255,0,0,1)来说,255就是R也就是red的缩写,后面的两个0分别是G(green的缩写)和B(blue的缩写),他们的取值范围是0-255,可以简单理解为R、G、B的值越大,他的颜色就越纯,最后的那个1就是A(alpha的缩写),表示透明度,取值范围是0-1,可以理解为值越大不透明度也就越高,最终他们混的的结果就是我们所看到的颜色了。

可能开发中我们使用更多的是rgb,不关注最后的a,这里来举个例子分享下a值的用法之一:实现一个卡片,并且背景是天蓝色半透明。一眼看去,这是简单么,我直接background:skyblue;opacity:0.5,打完收工,我们来看下效果:

在这里插入图片描述

欸,这不对吧,我的文字怎么也变透明了,所以这里使用opacity是不正确的,它会使整个box区域透明,所以RGBA中的A就发挥作用了,只需要将上面的代码改为background:rgba(135, 206, 250, 0.5),就完事了,这里我们看下效果

在这里插入图片描述

说完RGBA我们再来浅聊下HEX,我们直接反推,还拿红色RGBA(255,0,0,1)来说,它对应的hex值是#ff0000ff,这里我们可以更清晰的观察到,R 255对应的16进制是ff、G 0对应的16进制是00、B 0对应的16进制是00、A 1*255 对应的16进制是ff,所以我们可以把hex值两两分割 ff 00 00 ff,也就是rgba对应的16进制(A需要乘255)。这里可能会有人说,不对啊这个hex值我写成#f00也是红色啊,这也是hex的另外一个特点,缩写,根据上面的规律,我们写#000000和写#000】、#ffffff和写#fff都是一样的,我们常见的hex长度也是3位、6位和8位。

2. 实现

通过上面的分析,实现也就很明了了,其实就是16进制和10进制的转换,看到这里其实你就可以自己先去实现下了。下面我们主要来实现两个方法rgbaToHexhexToRgba,在此之前我们要知道在js中如何进行10进制和16进制的转换,我们需要用到两个方法:

  • parseInt(string, radix) parseInt - JavaScript | MDN (mozilla.org),16进制转10进制,例如:parseInt('ff', 16) -> 255

    • string : 要被解析的值。如果参数不是一个字符串,则将其转换为字符串 (使用 ToString抽象操作)。字符串开头的空白符将会被忽略。
    • radix: 从 236 的整数,表示进制的基数。例如指定 16 表示被解析值是十六进制数。如果超出这个范围,将返回 NaN。假如指定 0 或未指定,基数将会根据字符串的值进行推算。注意,推算的结果不会永远是默认值 10!文章后面的描述解释了当参数 radix 不传时该函数的具体行为。
  • Number.toString(radix)Number.prototype.toString() - JavaScript | MDN (mozilla.org),10进制转16进制,例如:(255).toString(16) -> 'ff'

    • radix: 一个整数,范围在 236 之间,用于指定表示数字值的基数。默认为 10。

下面贴上实现代码:

  • hexToRgba,将hex颜色代码转成rgba颜色代码
  // hex转rgba,本质是将16进制转成10进制
  const hexToRgba = (hexStr: string): string => {
    // 去除#号
    let excludePrefix = hexStr.replace("#", "");
    // hex值的长度
    let hexStrLength = excludePrefix.length;
    // hex的格式 #bfa #bbffaa #bbffaaff(最后的ff表示透明度),这里判断是正确的格式
    if (hexStr.startsWith("#") && (hexStrLength == 3 || hexStrLength == 6 || hexStrLength == 8)) {
      let hexArr = [];
      // 最终的rgba字符串
      let rgbaStr = "";
      // 针对不同格式分别处理
      switch (hexStrLength) {
        // 如果是3位
        case 3:
          rgbaStr = `rgba(${excludePrefix
            .split("")
            .map(hex => parseInt(hex.repeat(2), 16))
            .join(", ")}, 1)`;
          break;
        // 如果是6位
        case 6:
          for (let i = 0; i < 3; i++) {
            hexArr.push(excludePrefix.slice(i * 2, i * 2 + 2));
          }
          rgbaStr = `rgba(${hexArr.map(hex => parseInt(hex, 16)).join(", ")}, 1)`;
          break;
        // 如果是8位
        case 8:
          for (let i = 0; i < 4; i++) {
            hexArr.push(excludePrefix.slice(i * 2, i * 2 + 2));
          }
          rgbaStr = `rgba(${hexArr
            .map((hex, index) => index < 3 && parseInt(hex, 16))
            .filter(item => item)
            .join(", ")}, ${(parseInt(hexArr[3], 16) / 255).toFixed(2)})`;
          break;
      }
      return rgbaStr;
    } else {
      message.error("请输入正确的hex值");
      return "";
    }
  };
  • rgbaToHex,将rgba颜色代码转成hex颜色代码
 // rgba转hex,本质是将10进制转成16进制
  const rgbaToHex = (rgbaStr: string): string => {
    // 匹配逗号分割的数字,join(".")是为了处理小数
    let rgbaArr = rgbaStr.split(",").map(item => item.match(/\d+/g)!.join("."));
    // 最终的hex字符串
    let hexStr = "#";
    // 这里判断是正确的格式
    if (rgbaArr.length == 3 || rgbaArr.length == 4) {
      hexStr += rgbaArr
        .map((item, index) => {
          // 如果r,g,b任何一个是0,转成16进制后把0重复两遍
          let str =
            index < 3
              ? Math.floor(Number(item)).toString(16)
              : Math.floor(Number(item) * 255).toString(16);
          return str.length == 1 ? str.repeat(2) : str;
        })
        .join("");
      return hexStr;
    } else {
      message.error("请输入正确的rgba值");
      return "";
    }
  };

两个主要方法实现完之后,再写出自己喜欢的样式,我们的功能就完成啦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值