likes
comments
collection
share

Vue2+Vuecli+component

作者站长头像
站长
· 阅读数 279

工作中遇到了一个问题,需要对接口返回的数据进行处理。

接口返回的:
<img src="http://www.test.com/1.png" ... />你好<img src="http://www.test.com/2.png" ... />你好,你好

实际需要的:
<ImgMsg url="http://www.test.com/1.png" />你好<ImgMsg url="http://www.test.com/2.png" />你好,你好

思考后,想到了一种方式,借助component,将img替换为自己封装的ImgMsg组件(包含了占位图、算出最佳合适显示比例、预览功能等功能)。

具体实现需要进行如下步骤:

1. 配置项

// vue.config.js
module.exports = {
  ...
  /* 是否使用包含运行时编译器的 Vue 构建版本。设置为 true 后你就可以在 Vue 组件中使用 template 选项了,但是这会让你的应用额外增加 10kb 左右。(默认false) */
  runtimeCompiler: true,
}

2. 全局注册


// components/Common/index.js
import Vue from 'vue'
imoort ImgMsg from '@/components/ImgMsg'

const components = [ImgMsg];

components.forEach(component => {
  Vue.component(component.name, component);
});

3. 组件中使用

<!-- MassMsg.vue -->
<template>
  <div>
    <component :is="massMsg"></component>
  </div>
</template>

<script>
export default {
  name: 'massMsg',
  data() {
    return {
      regImg: /<img((?!class="biaoqing").)*?>/gi,
      regDataSrc: /data-src="(.*?)"/,
    };
  },
  props: {
    item: {
      type: Object,
      default: () => {}
    }
  },
  computed: {
    massMsg() {
      const msg = this.item.content.replace(this.regImg, result => {
        let groups = this.regDataSrc.exec(result);
        if (groups) {
          return '<ImgMsg url="' + groups[1] + '"></ImgMsg>';
        }
        return result;
      });
      return {
        template: `<div>${msg}</div>`
      };
    }
  }
};
</script>

附:ImgMsg组件代码

<!-- ImgMsg.vue -->
<template>
  <img class="el-common-img" :src="imgSrc" @click="setPicPreviewVisible(url)" @load="loadImg($event, url)" @error="loadError" />
</template>

<script>
import M from '@store/mutations';
import imgLoading from '@assets/images/loading.gif';
import loadError from '@assets/images/loadError.png';
export default {
  name: 'imgMsg',
  data() {
    return {
      ImgMaxWidth: 170,
      ImgMaxHeight: 170,
      imgSrc: imgLoading
    };
  },
  props: {
    url: {
      type: String,
      default: ''
    }
  },
  watch: {
    url(newVal) {
      if (newVal) this.imgSrc = newVal;
    }
  },
  methods: {
    /**
     * 处理图片消息显示大小
     */
    loadImg(e, url) {
      let imgTarget = e.target,
        img = document.createElement('img');

      img.onload = e => {
        let target = e.target;
        let { w, h } = this.getImgSize(this.ImgMaxWidth, this.ImgMaxHeight, target.width, target.height);
        imgTarget.width = w;
        imgTarget.height = h;
        this.imgSrc = url;
      };
      img.src = url || '';
    },
    getImgSize(mw, mh, w, h) {
      if (w > mw && h <= mh) {
        // 图片宽度大于最大值
        h *= mw / w;
        w = mw;
      } else if (w <= mw && h > mh) {
        // 图片宽度小于等于最大值
        w *= mh / h;
        h = mh;
      } else if (w > mw && h > mh) {
        // 图片宽度和高度均大于最大值
        if (w / h >= mw / mh) {
          // 宽高比大于默认比例
          h *= mw / w;
          w = mw;
        } else {
          // 宽高比小于等于默认比例
          w *= mh / h;
          h = mh;
        }
      }
      return { w, h };
    },
    /**
     * 预览图片
     */
    setPicPreviewVisible(url) {
      this.$store.commit(M.Chat.setPicPreviewVisible, true);
      this.$store.commit(M.Chat.setPicPreviewSrc, url);
    },
    /**
     * 加载错误占位图片
     */
    loadError() {
      this.imgSrc = loadError;
    }
  }
};
</script>