uniapp开发微信小程序[色彩大师]:相似色

119 views, 2022/08/29 updated   Go to Comments

经过前面几章的开发,选取展示颜色、Hex/RGB色码转换的核心功能基本实现了。

但是笔者在设计App时,经常自己也不知道颜色的具体色码,只知道大概应该用哪个色系,希望能够得到同色系其他颜色的推荐。

因此,本章让我们做一个相似色推荐的功能。

子组件

相似色通常是一组,比如十个或者二十个同时出现。因此很自然的会想到定义组件进行复用。

首先,创建一个叫 ColorPanel 的组件,用于展示每个单独的颜色画布:

编辑 ColorPanel.vue 文件,首先是模板:

<!-- components/ColorPanel/ColorPanel.vue -->

<template>
  <view>
    <view class="panel container" :style="panelColor">
      <view :style="canvasHexStyle" @click="onClickCanvas">
        <view class="">
          #{{hex}}
        </view>
        <view class="rgb-text">
          {{rgb.r}},{{rgb.g}},{{rgb.b}}
        </view>
      </view>
    </view>
  </view>
</template>

...

很简单,定义了一个带背景色的方块,里面的文字展示了背景色的色码。

然后是脚本部分:

// components/ColorPanel/ColorPanel.vue

...

<script>
  export default {
    name: "ColorPanel",
    props: {
      hsb: {
        type: Object,
      },
    },
    methods: {
      /**
       * hsb 转 rgb
       * @param {Object} 颜色模式  H(hues)表示色相,S(saturation)表示饱和度,B(brightness)表示亮度
       */
      HSBToRGB(hsb) {
        let rgb = {};
        let h = Math.round(hsb.h);
        let s = Math.round((hsb.s * 255) / 100);
        let v = Math.round((hsb.b * 255) / 100);
        if (s == 0) {
          rgb.r = rgb.g = rgb.b = v;
        } else {
          let t1 = v;
          let t2 = ((255 - s) * v) / 255;
          let t3 = ((t1 - t2) * (h % 60)) / 60;
          if (h == 360) h = 0;
          if (h < 60) {
            rgb.r = t1;
            rgb.b = t2;
            rgb.g = t2 + t3;
          } else if (h < 120) {
            rgb.g = t1;
            rgb.b = t2;
            rgb.r = t1 - t3;
          } else if (h < 180) {
            rgb.g = t1;
            rgb.r = t2;
            rgb.b = t2 + t3;
          } else if (h < 240) {
            rgb.b = t1;
            rgb.r = t2;
            rgb.g = t1 - t3;
          } else if (h < 300) {
            rgb.b = t1;
            rgb.g = t2;
            rgb.r = t2 + t3;
          } else if (h < 360) {
            rgb.r = t1;
            rgb.g = t2;
            rgb.b = t1 - t3;
          } else {
            rgb.r = 0;
            rgb.g = 0;
            rgb.b = 0;
          }
        }
        return {
          r: Math.round(rgb.r),
          g: Math.round(rgb.g),
          b: Math.round(rgb.b)
        };
      },
      // 将 rgb 转换为 hex
      rgbToHex(rgb) {
        let hex = [rgb.r.toString(16), rgb.g.toString(16), rgb.b.toString(16)];
        hex.map(function(str, i) {
          if (str.length == 1) {
            hex[i] = '0' + str;
          }
        });
        return hex.join('');
      },
      // 将 hex 复制到设备剪贴板
      onClickCanvas() {
        uni.setClipboardData({
          data: "#" + this.hex,
        });
      }
    },
    computed: {
      rgb() {
        return this.HSBToRGB(this.hsb)
      },
      hex() {
        return this.rgbToHex(this.rgb)
      },
      panelColor() {
        return `background: #${this.hex}`
      },
      // 设置 canvas 的文本颜色
      canvasHexStyle() {
        for (let key in this.rgb) {
          if (this.rgb[key] >= 130) {
            return "color: black"
          }
        }
        return "color: white"
      },
    },
  }
</script>

...

脚本部分内容和前面章节定义的画布非常相似(又是提取组件的好机会),最主要的区别是多了个 HSBToRGB() 方法。这里新出现的色彩编码:HSB 色码, 三个字母分别代表色相饱和度明度。之所以会用到它,是因为 HSB 来推导同一色相的相似色比较方便,只需要保持 H 值不变,改变 S 和 B 即可。

此函数来源于 t-color-picker 插件。RGB/HSB 转换的推导过程这里就不展开讲了。

最后是样式的代码:

/* components/ColorPanel/ColorPanel.vue */

...

<style scoped>
  .container {
    display: flex;
    flex-direction: column;
    justify-content: center;
    text-align: center;
  }

  .rgb-text {
    font-size: 10px;
  }

  .panel {
    height: 60px;
    width: 100px;
    border-radius: 10px;
    border-color: #484848;
    border-style: dashed;
  }
</style>

像前面说的,基本上就是定义了一个圆角小方块,方块的颜色由脚本里绑定的样式动态改变。

测试下运行是否正常。在首页里随便找个位置写下代码:

<ColorPanel :hsb="{h: 10,s: 50,b: 50}"></ColorPanel>

顺利的话就会出现一个带有颜色的圆角小方块了。

让我们继续。

父组件

现在我们可以和之前章节一样,直接在 index.vue 里写逻辑,推导相似色并遍历出几十个小方块。

但是推导相似色这堆功能,全放在 index.vue 太臃肿了。因此继续封装,再创建一个 SimilarColors 组件,它通过 props 从上一级获取色码,并根据此色码推导相似色。

首先是模板:

<!-- components/SimilarColors/SimilarColors.vue -->

<template>
  <view class="content">
    <uni-row>
      <uni-col :xs="8" :sm="6" :md="4" :lg="3" :xl="2" v-for="(item, index) in similarColors" :key="index">
        <ColorPanel :hsb="item"></ColorPanel>
        <view style="padding-bottom: 10px;"></view>
      </uni-col>
    </uni-row>
  </view>
</template>

...

它将遍历 similarColors 状态,并将<ColorPanel> 组件以宫格的形式展示。

<uni-col> 来自于 uni-ui 插件。插件的用法请参考官方文档。

接下来写脚本:

// components/SimilarColors/SimilarColors.vue

...

<script>
  export default {
    name: "SimilarColors",
    props: {
      rgb: {
        type: Object,
      },
    },
    computed: {
      // 根据props的rgb,获取hsb色码
      hsb() {
        const rgb = this.rgb
        let hsb = {
          h: 0,
          s: 0,
          b: 0
        };
        let min = Math.min(rgb.r, rgb.g, rgb.b);
        let max = Math.max(rgb.r, rgb.g, rgb.b);
        let delta = max - min;
        hsb.b = max;
        hsb.s = max != 0 ? 255 * delta / max : 0;
        if (hsb.s != 0) {
          if (rgb.r == max) hsb.h = (rgb.g - rgb.b) / delta;
          else if (rgb.g == max) hsb.h = 2 + (rgb.b - rgb.r) / delta;
          else hsb.h = 4 + (rgb.r - rgb.g) / delta;
        } else hsb.h = -1;
        hsb.h *= 60;
        if (hsb.h < 0) hsb.h = 0;
        hsb.s *= 100 / 255;
        hsb.b *= 100 / 255;
        return hsb;
      },
      // 推导相似色
      similarColors() {
        const {
          h,
          s,
          b
        } = this.hsb
        // 饱和度阶梯
        const Sstep = [100, 90, 80, 70, 60, 50, 40, 30, 20, 10]
        // 相似色数组
        let colors = []
        for (let item of Sstep) {
          colors.push({
            h: h,
            s: item,
            b: b
          })
        }
        // 明度阶梯
        const Bstep = [100, 90, 80, 70, 60, 50, 40, 30]
        for (let item of Bstep) {
          colors.push({
            h: h,
            s: s,
            b: item
          })
        }
        return colors
      },
    },
  }
</script>

...
  • 计算属性 hsb() 可将 RGB 转化为 HSB 色码,同样的,推导过程不展开了,有兴趣的读者自行搜索。
  • similarColors() 根据 HSB 色码推导相似色。其原理很简单,保持 H 通道不变,修改其余两个通道即可。

然后,加上一点样式:

/* components/SimilarColors/SimilarColors.vue */

...

<style scoped>
  .content {
    padding-left: 20px;
  }
</style>

最后,只需要在 index.vue 合适的位置调用组件:

<!-- pages/index/index.vue -->

<template>
  <view>
    ...

    <!-- 相似色 -->
    <view class="padding-10">
      <sectionTitle num="02" title="相似色彩"></sectionTitle>
    </view>
    <SimilarColors :rgb="canvasColor"></SimilarColors>

  </view>
</template>

...

ok 了,看看效果:

修改画布颜色,下面的同一色系的相似色推荐就跟着变化。

是不是挺酷炫?

结语

首页的功能这样基本就完整了,小而精。

下一章节,我们将开发中国色用户留言功能,给本教程收官。




本文作者: 杜赛
发布时间: 2022年08月29日 - 14:53
最后更新: 2022年08月29日 - 14:53
转载请保留原文链接及作者
本站使用 Github 评论后端。鉴于国内复杂的网络环境,如遇评论无法加载、发表等问题,请尝试刷新页面,或更换上网姿势。