为了过年更好的扫福字,我写了个图片放大插件

736 阅读3分钟

“ PK创意闹新春,我正在参加「春节创意投稿大赛」,详情请看:春节创意投稿大赛

前段时间摸鱼隐约看到有人吐槽沸点专栏图片的放大功能(不过现在好像是改版了哈),年前了也有点时间就想着如果我来实现这个功能的话会怎么做,做出来也方便了我们过年的时候一起扫敬业福不是嘛哈哈。

1.实现方案

正好最近在看vue3.0相关的东西,所以这个插件决定采用vue3.0+typescript来实现。

2.实现思路

本插件主要的功能是:实现点击一个小图片可以全屏展示当前图片的放大版。并且可以拖动,鼠标滚轴也可以控制图片的放大和缩小。

整体UI布局决定基于element-plusel-dialog来实现,显示遮罩层,背景设置为透明色。

3.实现代码

// html部分
<div class="picview">
    <el-dialog
      v-model="picture"
      :close-on-click-modal="false"
      :fullscreen="true"
      custom-class="picture"
    >
      <div v-loading.fullscreen.lock="loading" ref="myPic" class="main" @click="close($event)">
        <img
          v-show="isPicShow"
          :src="src"
          :width="picW"
          :height="picH"
          :style="{ transform: picTransform, top: picTop ,left:picLeft }"
          @load="scalePic"
          @error="setImgError"
          @mousedown.prevent="mousedown($event)"
          @mousemove.prevent="mousemove($event)"
          @mouseup.prevent="mouseup($event)"
        >
      </div>
    </el-dialog>
  </div>
// js部分
import { defineEmit, ref, watch, toRefs } from 'vue'
const props = defineProps({
  src: {
    type: String,
    default: ''
  },
  width: {
    type: String,
    default: ''
  },
  height: {
    type: String,
    default: ''
  },
  showPicture: {
    type: Boolean,
    default: false
  }
})
const emit = defineEmit(['update:showPicture'])

const { showPicture } = toRefs(props)

const loading = ref(false)
const picture = ref(false)
const picW = ref(0)
const picH = ref(0)
const isPicShow = ref(false)
const picTransform = ref('')
const picTop = ref('')
const picLeft = ref('')
let scale = 1,
  roted = 0,
  isMoving = false,
  disX = 0,
  disY = 0

const myPic: Ref = ref(null)

watch(showPicture, (newVal, oldVal) => {
  picture.value = newVal;
})


const scalePic = function() {
  loading.value = false;
  scale = 1;
  roted = 0;
  picTransform.value = 'scale(1)';
  countImg();
  window.onresize = function() {
    countImg();
  };
  document.body.onmousewheel = function(event: any) {
    event = event || window.event;
    if (picture.value === true) {
      if (event.deltaY > 0) {
        scale = scale > 0.2 ? scale - 0.1 : scale;
      } else {
        scale += 0.1;
      }
      picTransform.value = `scale(${scale}) rotate(${roted}deg)`
    }
  };
}
const rotePic = function() {
  roted = Number(roted) + 90;
  picTransform.value = `scale(${scale}) rotate(${roted}deg)`
}
const close = function(e: any) {
  if (e.target === myPic.value.childNodes[0]) {
    return;
  }
  //
  emit('update:showPicture', false);
  // showPicture.value = false
  e.stopPropagation();
}
const mousedown = function(e: any) {
  let oDiv = myPic.value.childNodes[0];
  isMoving = true;
  disX = e.clientX - oDiv.offsetLeft;
  disY = e.clientY - oDiv.offsetTop;
}
const mousemove = function(e) {
  if (
    isMoving &&
    e.clientY > 0 &&
    e.clientY < myPic.value.clientHeight &&
    e.clientX > 0 &&
    e.clientX < myPic.value.clientWidth
  ) {
    picTop.value = e.clientY - disY + 'px';
    picLeft.value = e.clientX - disX + 'px';
  }
}
const mouseup = function() {
  isMoving = false;
  return false;
}
const countImg = function() {
  const cpicW = myPic.value.childNodes[0].naturalWidth;
  const cpicH = myPic.value.childNodes[0].naturalHeight;
  let Width = myPic.value.offsetWidth;
  let Height = myPic.value.offsetHeight;
  if (Width / Height <= cpicW / cpicH) {
    if (Width > cpicW) {
      Width = cpicW;
    }
    picW.value = Width;
    picH.value = (Number(cpicH) * Width) / Number(cpicW);
    picTop.value = `${(Height - picH.value) / 2}px`;
    picLeft.value = `${(myPic.value.offsetWidth - picW.value) / 2}px`;
    isPicShow.value = true;
  } else {
    if (Height > cpicH) {
      Height = cpicW;
    }
    picH.value = Height;
    picW.value = (Number(cpicW) * Height) / Number(cpicH);
    picLeft.value = `${(Width - picW.value) / 2}px`;
    picTop.value = `${(myPic.value.offsetHeight - picH.value) / 2}px`;
    isPicShow.value = true;
  }
}
const setImgError = function() {
  loading.value = false;
}

组件实现之后,我们就可以来把当前组件改造成我们可以供vue3.0项目使用的插件了。

4.封装插件

// imageView.vue写我们的组件
import imageView from './lib/imageView.vue'

// 定义我们的插件
const myPlugin = {    
    // 该插件有一个install方法
    // 方法的第一个参数是传入的Vue,第二个参数可以插件的自定义参数
    install (Vue: any) {
        // 将其注册为vue的组件,'imageView'是组件名,imageView是我们开发的组件
        Vue.component('imageView', imageView)    
    }
}

// 最后将插件导出,并在main.js中通过Vue.use()即可使用插件
export default myPlugin

插件开发具体过程,这里就不多赘述了,感兴趣的童鞋可以翻之前的文章。

5.使用插件

// main.ts
import imageView from 'lmuy-image-view'

createApp(App).use(imageView).mount('#app')

// 页面中
<lmuy-image-view
  :src="src"
  :show-picture="item.dialogVisible"
  @update:show-picture="closeImage"/>

效果图如下所示,实现了图片的放大功能。并且使用方便,操作简单。沸点的放大完全可以这么来嘛,而且过年的时候我们传上去的那些隐藏在角落里的小敬业福,在我们这个插件的展示下,还不是乖乖被我们扫出来嘛~

草稿1图片.gif 当前插件已经被上传到npm上,感兴趣的童鞋可以搜索lmuy-image-view进行查看。