uni-app 实现轮播图组件父容器背景色随图片主题色改变

uni-app 实现轮播图组件父容器背景色随图片主题色改变

实现思路

1、获取轮播图主题色,通过 canvas 获取图片主题色。
2、随着轮播图组件图片的轮播,动态设置父容器背景色为图片的主题色。

实现代码

<template>
  <view class="container">
    <canvas
      canvas-id="getThemeColorCanvas"
      id="getThemeColorCanvas"
      style="position: absolute;left: -600rpx;top: -300rpx;"
    >
    </canvas>

    <view
      class="home-head"
      :style="{ background: swiperList[swiperCurrent].themeColor || '#F35B30' }"
    >
      <view
        class=""
        style="width: 100%;height: 216rpx;display: flex;justify-content: center;"
      >
        <view class="" style="width: 100%;height: 216rpx;margin-top: 20rpx;">
          <u-swiper
            :list="swiperList"
            keyName="url"
            @change="handleUSwiperChange"
            @click="handleUSwiperClick"
          >
          </u-swiper>
        </view>
      </view>
    </view>
  </view>
</template>

<script>
  import { getImageThemeColor } from "@/utils/index.js";

  export default {
    data() {
      return {
        swiperList: [
          {
            url: "https://cdn.uviewui.com/uview/swiper/swiper2.png",
          },
          {
            url: "https://cdn.uviewui.com/uview/swiper/swiper1.png",
          },
          {
            url: "https://cdn.uviewui.com/uview/swiper/swiper3.png",
          },
        ],
        swiperCurrent: 0,
      };
    },
    onLoad() {
      this.getSwiperThemeColor();
    },
    methods: {
      // 定义一个递归函数来依次执行任务
      runTasks(index, tasks) {
        const self = this;
        if (index >= tasks.length) {
          // 如果所有任务都已经执行完毕,返回一个 resolved 的 Promise
          return Promise.resolve();
        }

        // 执行当前任务,然后递归执行下一个任务
        return tasks[index]().then(function () {
          return self.runTasks(index + 1, tasks);
        });
      },
      getSwiperThemeColor() {
        const self = this;

        const tasks = [];
        this.swiperList.forEach((item) => {
          tasks.push(function () {
            return new Promise((resolve) => {
              getImageThemeColor(item.url, "getThemeColorCanvas", (ret) => {
                item.themeColor = `rgb(${ret})`;
                resolve(ret);
              });
            });
          });
        });

        // 调用递归函数来执行任务
        this.runTasks(0, tasks)
          .then(function () {
            // 在所有获取图片主题色任务完成后,强制 Vue 实例重新渲染,
            // 解决轮播图组件在初始加载时父容器背景色非首图主题色的问题
            self.$forceUpdate();
            // console.log('All tasks are done!');
          })
          .catch(function (error) {
            console.error(error);
          });
      },
      handleUSwiperChange(e) {
        this.swiperCurrent = e.current;
      },
      handleUSwiperClick(e) {},
    },
  };
</script>

<style scoped>
  .container {
    min-height: 100vh;
    background: #f1f2f5;
  }

  .home-head {
    width: 100%;
    height: 532rpx;
    background: #f35b30;
    border-radius: 0px 0px 52px 52px;

    padding: 0px 30rpx;
  }
</style>

轮播图组件用的 uView 2.x 的 u-swiper 组件。

// @/utils/index.js

/**
 * 获取图片主题色
 * @param path
 * 图片的路径,可以是相对路径,临时文件路径,存储文件路径,网络图片路径
 * @param canvasId
 * 画布表示
 * @param callback
 * 回调函数,返回图片主题色的 RGB 颜色值
 */
export function getImageThemeColor(path, canvasId, callback) {
  // 小程序下获取网络图片信息需先配置 download 域名白名单才能生效。
  uni.getImageInfo({
    src: path,
    success: function (img) {
      // 创建一个 Canvas 对象
      const ctx = uni.createCanvasContext(canvasId);
      // 将图片绘制到 Canvas 上
      const imgWidth = 300;
      const imgHeight = 150;
      ctx.drawImage(img.path, 0, 0, imgWidth, imgHeight);
      ctx.save();
      ctx.draw(true, () => {
        uni.canvasGetImageData({
          canvasId: canvasId,
          x: 0,
          y: 0,
          width: imgWidth,
          height: imgHeight,
          success(res) {
            let data = res.data;
            let arr = [];
            let r = 1,
              g = 1,
              b = 1;
            // 取所有像素的平均值
            for (let row = 0; row < imgHeight; row++) {
              for (let col = 0; col < imgWidth; col++) {
                if (row == 0) {
                  r += data[imgWidth * row + col];
                  g += data[imgWidth * row + col + 1];
                  b += data[imgWidth * row + col + 2];
                  arr.push([r, g, b]);
                } else {
                  r += data[(imgWidth * row + col) * 4];
                  g += data[(imgWidth * row + col) * 4 + 1];
                  b += data[(imgWidth * row + col) * 4 + 2];
                  arr.push([r, g, b]);
                }
              }
            }
            // 求取平均值
            r /= imgWidth * imgHeight;
            g /= imgWidth * imgHeight;
            b /= imgWidth * imgHeight;
            // 将最终的值取整
            r = Math.round(r);
            g = Math.round(g);
            b = Math.round(b);

            if (!!callback) {
              // 返回图片主题色的 RGB 颜色值
              callback(`${r},${g},${b}`);
            }
          },
        });
      });
    },
  });
}

解决 H5 在获取跨域网络图片主题色时报错

实现效果

img

posted @ 2023-03-17 11:28  飞仔FeiZai  阅读(423)  评论(0编辑  收藏  举报