前言

由于项目原因,直接用image 繁琐而麻烦,所以将其二次封装
实现 image渲染市默认图片,加载失败的底图,识别图片得主色调等功能


一、image?

image Api官网地址,不是熟悉的可以自己先看下文档

二、使用步骤

1.image的二次封装

代码如下(示例):

<template>
  <view class="y-image">
    <view class="y-image" :class="{ nodispaly: imgLoaded }">
      <image class="y-image" :src="src" @error="onErrorImg" @load="onSuccessImg" />
    </view>
    <div class="default" :class="{ nodispaly: !imgLoaded }">
      <image
        class="y-image-default"
        :style="defaultSryle"
        :src="require('@/assets/bank_no_networ-icon.png')"
      />
    </div>
  	//识别主色调的时候要用
    <template v-if="isBgColor">
      <view class="canvasstyle" v-if="isCanvas">
        <canvas :canvas-id="pid" id="pid"></canvas>
      </view>
    </template>
  </view>
</template>

<script>
// 引用的解析图片的主色调的方法在下边
import { getImageThemeColor } from '@/utils/getImageThemeColorCanvas'
export default {
  name: 'imageModel',
  props: {
    // 是否开启获取主色调
    isBgColor: {
      type: Boolean,
      default: false,
    },
    // 默认随生成Pid canvas
    pid: {
      type: String,
      default: () => {
        return Math.random().toString(36).slice(3, 10)
      },
    },
    // 默认iocn 大小
    defaultSize: {
      type: String,
      default: '100%',
    },
    //图片裁剪、缩放的模式
    mode: {
      type: String,
      default: 'center',
    },
    //图片资源地址
    src: String,
  },
  data() {
    return {
      imgLoaded: true,
      isCanvas: true,
    }
  },
  computed: {
    defaultSryle() {
      return `width:${this.defaultSize};height:${this.defaultSize}`
    },
  },
  created() {
    if (!this.src) {
      this.$emit('onSuccessImg', '')
      this.isCanvas = false
    }
  },
  methods: {
    // 图片加载成功
    async onSuccessImg(event) {
      let color = ''
      if (this.isBgColor) {
        try {
          color = await getImageThemeColor(this.src, this.pid)
        } catch (error) {
        	console.err('解析图片报错':error)
        }
      }
      this.$emit('onSuccessImg', color)
      this.isCanvas = false
      this.imgLoaded = false
    },
    // 图片加载失败
    onErrorImg(event) {
      this.$emit('onSuccessImg', '')
      this.imgLoaded = true
      this.isCanvas = false
    },
  },
}
</script>
<style lang="scss" scoped>
.nodispaly {
  display: none !important;
}
.y-image {
  width: 100%;
  height: 100%;
  overflow: hidden;
}
.default {
  background: #f2f2f2;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  .y-image-default {
    width: 100%;
    height: 100%;
  }
}
.canvasstyle {
  position: absolute;
  top: -9999999rpx;
}
</style>

注意 因为使用canvas 画出当前图片 所以 注意因为图片跨域而失败
因为性能原因 页面默认是不渲染canvas标签,只有需要的时候主动开启,解析出颜色值后销毁canvas

2.解析图片主色调

代码如下(示例):
文件名字 getImageThemeColorCanvas.js

/**
 * 获取图片主题色
 * @param {String} path
 * 图片的路径,可以是相对路径,临时文件路径,存储文件路径,网络图片路径
 * @param  {String}  canvasId
 * 画布表示
 * return  返回色值的promise
 */
export async function getImageThemeColor(path, canvasId) {
  return await new Promise((resolve, reject) => {
    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)
              //最终返回的主色调
           	 resolve(`${r},${g},${b}`)
            fail: (fail) => {
              console.log(fail)
              reject(fail)
            },
          })
        })
      },
      fail: (fail) => {
        console.log(fail)
        reject(fail)
      },
    })
  })
}
/**
 * 同步请求所有 Promise
 * @param {Array} asyncFunctions
 * Promise 数组
 * @returns 返回Promise值
 */
export async function executeAsyncFunctions(asyncFunctions) {
  const results = []
  for (const asyncFunction of asyncFunctions) {
    const result = await asyncFunction()
    results.push(result)
  }
  return results
}

注意 引用的页面内一定要有canvas标签存在。
解析主色调方法可以单独引用, 一个页面如果多张图片进行解析主色调,一定要等上一个解下完成,再进行下一个!!! 坑自己去踩 你可以试试 自己封装了一个同步请求的方法 可以参考下


总结

生活不易,处处是坑,既然还活着,那就风雨兼程

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐