vue3插件开发-图片预览 记录实现过程

插件预览效果

在这里插入图片描述
安装插件

cnpm i l-vue3-preview-img

使用插件

//main.js
import previewImg from 'l-vue3-preview-img'
app.use(previewImg)
//vue页面中
import {previewImg} from 'l-vue3-preview-img'
//img 为图片路径 或者num(需传入imgList,才为图片下标。)
previewImg(img, imgList)

开发过程

  1. src下创建plugins->lib->index.vue, plugins-> index.js
    在这里插入图片描述
    index.vue文件用于创建显示图片的文本
<template>
  <div class='plugin_preview_box' v-if="isShow" @mouseup="mouseupImg">
    <div class="left_box" v-if="currentImgIndex>0" @click="handleChangeImg('left')">
    </div>
    <div class="right_box"  v-if="currentImgIndex<imgUrlList.length-1" @click="handleChangeImg('right')">
    </div>
    <img @mousedown="mousedownImg" :draggable="false" @mousemove="mousemoveImg" @mouseup="mouseupImg" @mouseleave="mouseupImg" :style="imgStyleComputed" class="preview_img"  :src="imgUrl" alt="图片无法加载">
    <div class="right_menu_box">
      <!-- 下面功能按钮部分 -->
      <div class="menu_container">
        <!-- 加 -->
        <svg @click="changImg('enlarge')" t="1667462990225" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1487" width="200" height="200"><path d="M426.666667 426.666667H85.546667A85.418667 85.418667 0 0 0 0 512c0 47.445333 38.314667 85.333333 85.546667 85.333333H426.666667v341.12c0 47.274667 38.186667 85.546667 85.333333 85.546667 47.445333 0 85.333333-38.314667 85.333333-85.546667V597.333333h341.12A85.418667 85.418667 0 0 0 1024 512c0-47.445333-38.314667-85.333333-85.546667-85.333333H597.333333V85.546667A85.418667 85.418667 0 0 0 512 0c-47.445333 0-85.333333 38.314667-85.333333 85.546667V426.666667z" p-id="1488" fill="#ffffff"></path></svg>
        <!-- 减 -->
        <svg @click="changImg('narrow')" t="1667462953117" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1043" width="200" height="200"><path d="M587.229378 437.990403 580.722174 437.990403 76.975139 437.990403 76.975139 581.918419 580.722174 581.918419 587.229378 581.918419 940.542216 581.918419 940.542216 437.990403Z" p-id="1044" fill="#ffffff"></path></svg>
        <!-- 旋转 -->
        <svg @click="changImg('rotate')" t="1667462977679" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1265" width="200" height="200"><path d="M941.728 137.152C941.728 122.304 932.576 109.152 919.456 103.424 905.728 97.728 889.728 100.576 879.456 111.424L805.152 185.152C724.576 109.152 615.456 64 502.88 64 261.152 64 64 261.152 64 502.88 64 744.576 261.152 941.728 502.88 941.728 633.728 941.728 757.152 884 840.576 783.424 846.304 776 846.304 765.152 839.456 758.88L761.152 680C757.152 676.576 752 674.88 746.88 674.88 741.728 675.424 736.576 677.728 733.728 681.728 677.728 754.304 593.728 795.424 502.88 795.424 341.728 795.424 210.304 664 210.304 502.88 210.304 341.728 341.728 210.304 502.88 210.304 577.728 210.304 648.576 238.88 702.304 288.576L623.456 367.424C612.576 377.728 609.728 393.728 615.456 406.88 621.152 420.576 634.304 429.728 649.152 429.728L905.152 429.728C925.152 429.728 941.728 413.152 941.728 393.152L941.728 137.152Z" p-id="1266" fill="#ffffff"></path></svg>
      </div>
      <!-- 右上角叉号 -->
      <svg  @click="hide" t="1667464237202" class="icon exit" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1073" width="200" height="200"><path d="M886.784 746.496q29.696 30.72 43.52 56.32t-4.608 58.368q-4.096 6.144-11.264 14.848t-14.848 16.896-15.36 14.848-12.8 9.728q-25.6 15.36-60.416 8.192t-62.464-34.816l-43.008-43.008-57.344-57.344-67.584-67.584-73.728-73.728-131.072 131.072q-60.416 60.416-98.304 99.328-38.912 38.912-77.312 48.128t-68.096-17.408l-7.168-7.168-11.264-11.264-11.264-11.264q-6.144-6.144-7.168-8.192-11.264-14.336-13.312-29.184t2.56-29.184 13.824-27.648 20.48-24.576q9.216-8.192 32.768-30.72l55.296-57.344q33.792-32.768 75.264-73.728t86.528-86.016q-49.152-49.152-93.696-93.184t-79.872-78.848-57.856-56.832-27.648-27.136q-26.624-26.624-27.136-52.736t17.92-52.736q8.192-10.24 23.552-24.064t21.504-17.92q30.72-20.48 55.296-17.92t49.152 28.16l31.744 31.744q23.552 23.552 58.368 57.344t78.336 76.288 90.624 88.576q38.912-38.912 76.288-75.776t69.632-69.12 58.368-57.856 43.52-43.008q24.576-23.552 53.248-31.232t55.296 12.8q1.024 1.024 6.656 5.12t11.264 9.216 10.752 9.728 7.168 5.632q27.648 26.624 27.136 57.856t-27.136 57.856q-18.432 18.432-45.568 46.08t-60.416 60.416-70.144 69.632l-77.824 77.824q37.888 36.864 74.24 72.192t67.584 66.048 56.32 56.32 41.472 41.984z" p-id="1074" fill="#ffffff"></path></svg>
    </div>
    <div class="left_top_box">
      {{currentImgIndex+1}} / {{imgUrlList.length}}
    </div>
  </div>
</template>
<script setup>
import { computed, onMounted, reactive, ref, toRaw } from "vue"
const imgUrl = ref('')
const imgUrlList = ref([])
const currentImgIndex = ref(-1)
const isShow = ref(false)
//保留初始化状态使用
const initStyle = {
  scale: 1,
  rotate: 0,
  top:0,
  left: 0,
}
const imgStatus = reactive({
  isMoveImg: false,
  startX: 0,
  startY: 0,
  imgStartTop: 0,
  imgStartLeft: 0,
})
//设置成可修改的变量
const imgStyle = reactive({...initStyle})
//最后统一处理好塞到img 的 style上
const imgStyleComputed = computed(() =>{
  return {
    transform: `scale(${imgStyle.scale}) rotate(${imgStyle.rotate}deg)`,
    top: imgStyle.top+'px',
    left: imgStyle.left+'px',
  }
})
//img显示
const show = (img, imgList) => {
  //初始化数据
  imgStatus.isMoveImg = false
  Object.assign(imgStyle, initStyle)
  currentImgIndex.value = 0
  //处理数据
  if(Array.isArray(imgList)&&imgList.length>0) {
    imgUrlList.value = imgList
    if(typeof img == 'number') {
      currentImgIndex.value = img
    } else if(imgList.indexOf(img)>-1) {
      currentImgIndex.value = imgList.indexOf(img)
    }
  }else {
    imgUrlList.value = [img]
  }
  if(typeof img == 'number'){
    imgUrl.value = imgUrlList.value[currentImgIndex.value]
  } else  {
    imgUrl.value = img
    
  }
  isShow.value = true
  //监听鼠标滚轮事件
  document.addEventListener('mousewheel', mousewheelFun)
  document.addEventListener('DOMMouseScroll', mousewheelFun)
}
//img隐藏
const hide = () =>{
  isShow.value = false
  document.removeEventListener('mousewheel', mousewheelFun)
  document.removeEventListener('DOMMouseScroll', mousewheelFun)
}
//下部按钮部分的事件
const changImg = (type) => {
  if(type == 'enlarge') {
    imgStyle.scale +=0.1
  } else if(type == 'narrow') {
    imgStyle.scale>0.3&&(imgStyle.scale -=0.1)
  } else if(type == 'rotate') {
    imgStyle.rotate += 90
  }
}
/**往左或者往右切换 */
const handleChangeImg = (type) =>{
  if(type == 'left') {
    if(currentImgIndex.value>0) {
      currentImgIndex.value = currentImgIndex.value-1
      imgUrl.value = imgUrlList.value[currentImgIndex.value]
    }
  } else {
    if(currentImgIndex.value<imgUrlList.value.length-1) {
      currentImgIndex.value = currentImgIndex.value+1
      imgUrl.value = imgUrlList.value[currentImgIndex.value]
    }
  }
}
//滚轮滚动事件
const mousewheelFun = (e) =>{
  if(e.wheelDelta) {
    if(e.wheelDelta>0) {
      imgStyle.scale+=0.05
    } else {
      imgStyle.scale>0.3&&(imgStyle.scale-=0.05)
    }
  } else {
    if(e.detail > 0) {
      imgStyle.scale>0.3&&(imgStyle.scale-=0.05)
    } else {
      imgStyle.scale+=0.05
    }
  }
}
/**鼠标在图片上按下 */
const mousedownImg = (e) => {
  imgStatus.isMoveImg = true
  imgStatus.startX = e.clientX
  imgStatus.startY = e.clientY
  imgStatus.imgStartTop = imgStyle.top
  imgStatus.imgStartLeft = imgStyle.left
}
/**鼠标在图片上移动 */
const mousemoveImg = (e) =>{
  if(imgStatus.isMoveImg) {
    imgStyle.top = imgStatus.imgStartTop + e.clientY- imgStatus.startY 
    imgStyle.left = imgStatus.imgStartLeft + e.clientX- imgStatus.startX
  }
}
/**鼠标松开 */
const mouseupImg = (e) =>{
  imgStatus.isMoveImg = false
}
//把外部需要的方法暴露出去
defineExpose({
  show,
  hide
})
</script>
<style scoped>
.plugin_preview_box {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background-color:rgba(0,0,0,0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 999999999;
}
.right_menu_box {
  position: absolute;
  top: 50px;
  right: 50px;
  display: flex;
  line-height: normal;
}
.right_menu_box .icon {
  height: 20px;
  width: 20px;
  cursor: pointer;
  background-color:rgba(84, 81, 81, 0.7);
  padding: 10px;
  border-radius: 50%;
  box-sizing: content-box;
  margin: 0 8px;
}
.menu_container {
  display: flex;
  align-items: center;
}
.preview_img {
  max-height: 100%;
  max-width: 100%;
  user-select: none;
  transition: transform 0.5s;
  position: relative;
  cursor: all-scroll;
}
.left_box, .right_box {
  position: absolute;
  width: 50%;
  top: 0;
  height: 100%;
}
.left_box {
  cursor: url('./left.cur'), default;
  left: 0;
}
.right_box {
  right: 0;
  cursor: url('./right.cur'), default;
}
.left_top_box {
  position: fixed;
  top: 20px;
  left: 20px;
  color: #fff;
  font-size: 24px;
  font-weight: bold;
}
</style>

index.js用于配制插件

import { createVNode, render } from 'vue'
import PreveiwImg from './lib/index.vue'
// 组件创建为虚拟dom
const vnode = createVNode(PreveiwImg)
//抛出一个方法 方便直接组件中用import { previewImg } from 'l-vue3-preview-img'
// 需要在组件中用defineExpose({fun1, fun2})暴露出来 才可以获取到
export const previewImg = (img, imgList) => vnode.component?.exposed?.show(img, imgList)
export default {
  install(app) {
  	// 渲染到页面上
    render(vnode, document.body)
    const fun = {
      show: (img, imgList) =>  vnode.component?.exposed?.show(img, imgList),
      hide: () => vnode.component?.exposed?.hide()
    }
    //提供一个全局方法,官方推荐使用provide代替全局方法
    app.provide('$previewImg', fun)
  }
}

正常引用看是否可以使用,可以则插件开发完成

插件发布阶段

  1. 单独创建一个文件,并把开发阶段的plugins文件拷贝到下面,并创建package.json和README.md文件
    在这里插入图片描述
{
  "name": "l-vue3-preview-img",
  "version": "1.1.0",
  "description": "图片预览",
  "main": "pulgins/index.js",
  "directories": {
    "lib": "lib"
  },
  "keywords": [
    "vue3",
    "preview",
    "image"
  ],
  "author": "li",
  "license": "ISC",
  "dependencies": {}
}
  1. 测试插件是否可用
    任意找个项目,在node_modules文件下创建l-vue3-preview-img文件夹并把几个文件拷贝进去,按插件使用方法开是否可用,调节到可用就行
  2. 去npm官网注册账号
    npm官网
  3. 到单独这个文件夹下 输入npm login
    按要求填写 姓名、密码、邮箱
  4. 发布 npm publish
  5. 删除已经发布的npm unpublish 包名 --force

参考文档:预览图片插件开发视频发布到npm上教程

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值