louzhedong / blog

前端基础,深入以及算法数据结构
934 stars 84 forks source link

IMG图片尺寸自适配 #182

Open louzhedong opened 4 years ago

louzhedong commented 4 years ago

问题描述

平时在使用阿里云OSS图片时,总是会用一些不加后缀的图片,导致图片过大,影响使用,使用口头约定,在图片后面手动加上后缀,但还是经常会忘记。在移动端这个问题会更加迫切,不同的手机大小不一,分辨率不一,如果在小手机上使用大图片,会造成流量浪费,如果在大手机上使用小图片,会造成图片模糊

所以希望找出一个能在不同屏幕显示不同大小图片的方法

本文实例都用vue来描述

优化方案

方案一:

通过函数来计算每个img的宽度

<template>
    <img :src="test(teacher.image, 2.2)" alt /> // 宽度单位为rem,也可以用其他单位
</template>

<script>
test(url, width) {
      let dpr = window.devicePixelRatio;   // 获取dpr
      let fontSize = parseFloat(document.documentElement.style.fontSize);

      let _url = url.split("?")[0];
      let _width = Math.ceil(fontSize * width * dpr);
      _url += `?x-oss-process=image/resize,w_${_width}`;
      return _url;
    }
</script>

此种方式需要事先知道所有img的宽度

方案二:

将初始链接置于data-src里,在页面渲染完成后获取所有img标签,随后获取img的宽度,根据dpr计算得到最终的图片宽度,并将它置于src里

遇到的问题:

无法得知页面何时渲染完成,img标签也可能使用v-if来修饰,一开始是不存在的

如果在有属性变化时去遍历这个操作,当img的src为空时进行计算并赋值,可能会有性能问题(不确定)

具体方式如下:

<template>
    <img :data-src="item.image" alt />
</template>

<script>
updated() {
    this.$nextTick(() => {
      let $imgList = document.querySelectorAll("img");
      let length = $imgList.length;
      for (var i = 0; i < length; i++) {
        let current = $imgList[i];
        if (!$imgList.src) {
          let dataSrc = current.dataset.src.split("?")[0];
          let width = current.width;
          let dpr = window.devicePixelRatio;
          let _width = Math.ceil(width * dpr);
          current.src =
            dataSrc + `?x-oss-process=image/resize,w_${_width}`;
        }
      }
    });
  }
</script>

此种方式只需要我们为图片设置data-src,不需要知道img具体的大小,但可能会有性能隐患