vue+js实现预览图片--拖拽、放大、缩小查看

效果

点击预览弹窗:
默认100%

可调整进度条放大缩小,超过100%鼠标可以拖拽图片移动位置

代码:

<template>
  <el-dialog
    :visible.sync="dialogVisible"
    width="30%"
    :close-on-press-escape="false"
    :close-on-click-modal="false"
    :show-close="false"
  >
    <div class="screen-wrap">
      <div
        id="playScreen"
        class="screen"
      >
        <!-- 图片类型   getImgUrl是获取图片URL链接 -->
        <img
          :src="dialogData | getImgUrl"
          class="img"
          :style="style"
        >
      </div>
      <div class="tool">
        <!-- 缩放图片 -->
        <div class="enlarge">
          <div id="Enlarge">
            <!-- 百分比进度条 -->
            <div class="scroll">
              <div
                class="speed"
                :style="{width:speed+'%'}"
              >
                <span class="drag-dom" />
              </div>
            </div>
            <div class="math">
              <el-input
                v-model="num"
                size="mini"
                @change="change"
              />
              <span class="percentage">%</span>
            </div>
          </div>
          <!-- 关闭按钮 -->
          <div class="btn">
            <el-button
              type="primary"
              @click="handleClose"
            >
              关闭
            </el-button>
          </div>
        </div>
      </div>
    </div>
    <div />
  </el-dialog>
</template>


<script>
import {getImgUrl} from '@/utils'
export default {
    name: "DialogFilePreview",
    filters: {
        getImgUrl(val){
            return getImgUrl(val)
        }
    },
    props:{
        dialogData:{
            type:String,
            default:()=>""
        }
    },
    data(){
        return{
            dialogVisible:true,
            style:{},  // 图片位置动态改变
            num:100,   // 初始化百分比
            node:'',   // 父级
            imgDom:'', // 元素
            width:'',
            height:'',
        }
    },
    computed:{
        speed(){ // 进度条位置
            return this.change();
        }
    },
    watch:{
        num(){ // 监听百分比放大缩小
            this.scale();
        }
    },
    mounted() {
        this.$nextTick(()=>{
            this.node = document.getElementById('playScreen');
            let img = document.querySelector('#playScreen .img');
            this.imgDom = img;
            this.width = img.offsetWidth;    // 图片宽度
            this.height = img.offsetHeight;  // 图片高度
            this.drag();
            //初始化拖拽移动
            this.dragBox(img);
        })
    },
    methods:{
        // 关闭弹窗反参父组件
        handleClose(){
            this.$emit('dialogEmit',false)
        },
        // 拖拽进度条
        drag() {
            let speed = document.querySelector('.speed');
            let dom = document.querySelector('.drag-dom');
            let scroll = document.querySelector('.scroll');


            let initX,  //初始鼠标x坐标
                speedWidth,  //当前进度条宽度
                scrollWidth,  //整个进度条最大宽度
                cm, //多少px代表1%
                flag = false,   //开关
                _this = this;


            dom.addEventListener("mousedown", (e) => {
                flag = true;
                initX = e.clientX;  //初始鼠标x坐标
                speedWidth = speed.clientWidth;    // 当前dom宽度
                scrollWidth = scroll.clientWidth;  // 整个进度条最大宽度
                cm = scroll.clientWidth / 300; // 多少px代表1%
            }, false);


            document.addEventListener("mousemove", function (e) {
                if (flag) {
                    let nowX = e.clientX,
                        disX = nowX - initX,
                        disWidth = disX + speedWidth;
                    disWidth < 10 ? speed.style.width = "10px" : disWidth > scrollWidth ? speed.style.width = scrollWidth + "px" : speed.style.width = disWidth + "px";
                    let w = Math.round(disWidth / cm);
                    _this.num = w > 300 ? 300 : w < 10 ? 10 : w;
                    _this.imgDom.style.maxWidth = _this.num + '%'; // 更新最大值
                    _this.imgDom.style.maxHeight = _this.num + '%';
                }
            });
            document.addEventListener("mouseup", async () => {
                if (flag) {
                    flag = false;
                    document.onmousemove = null;
                    document.mouseup = null;
                    this.scale();
                }
            }, false);
        },
        // 缩放
        scale() {
            let _this = this;
            _this.$nextTick(() => {
                let proportion = Number(_this.num) / 100; // 得到放大多少倍
                let w = _this.node.offsetWidth; // 得到父级宽度
                let h = _this.node.offsetHeight;
                let left = (w - (_this.width * proportion)) / 2; // 使没有超出时居中
                let top = (h - (_this.height * proportion)) / 2;
                // left/top:如果超出父级就默认0,否则计算居中;w/h是计算倍数后的大小
                _this.style = {
                    left:left + 'px',
                    top: top + 'px',
                    width: _this.width * proportion + 'px',
                    height: _this.height * proportion + 'px'
                };
            });
        },
        // 进度条修改
        change() {
            let _this = this;
            if(_this.imgDom) {
                //判断是否输入的是正确数字格式
                isNaN(_this.num) ? _this.num = 100 : _this.num = Math.round(_this.num);

                if (_this.num > 300) {
                    _this.num = 300;
                }
                return _this.num / 3
            }
        },


        // 拖拽移动
        dragBox(drag) {
            if (!drag) return;
            let initX,  //初始鼠标x坐标
                initY,  //初始鼠标Y坐标
                dragAble = false,   //开关
                wrapLeft,    //当前dom left坐标
                wrapTop,  //当前dom top坐标
                _this = this;
            drag.onmousedown = function(ev) {// 鼠标按下事件
                let e = ev || window.event;
                e.preventDefault();
                //判断是否有操作权限并且当前缩放比例必须大于100%才能拖拽
                if (_this.num > 100) {
                    dragAble = true;
                    wrapLeft = _this.getCss(drag, "left");   //当前dom left坐标
                    wrapTop = _this.getCss(drag, "top");  //当前dom top坐标
                    initX = e.clientX;  //初始鼠标x坐标
                    initY = e.clientY;  //初始鼠标y坐标
                }
                _this.node.onmousemove = function(ev1) {
                    let e1 = ev1 || window.event;
                    if (dragAble) {
                        e1.preventDefault();
                        let nowX = e1.clientX,
                            nowY = e1.clientY,
                            disX = nowX - initX,
                            disY = nowY - initY,
                            left = wrapLeft + disX, //当前x坐标
                            top = wrapTop + disY;   //当前y坐标


                        drag.style.left = left + "px";
                        drag.style.top = top + "px";
                    }
                }
            }
            document.onmouseup = function() {
                if (dragAble) {
                    dragAble = false;
                    // 鼠标抬起
                    _this.node.onmousemove = null;
                }
            }
        },
        // 获取css
        getCss(ele, prop) {
            return parseInt(window.getComputedStyle(ele)[prop]);
        }
    }
}
</script>


<style scoped lang="scss">
  ::v-deep .el-dialog {
    width: 700px !important;
    height: 580px !important;
    .el-dialog__body{
      padding: 0;
      height: 100%;
    }
  }
    .screen-wrap {
      flex: 1;
      display: flex;
      flex-direction: column;
      height: 100%;
      width: 100%;


      .screen {
        flex: 1;
        overflow: hidden;
        background: #474747;
        position: relative;
        user-select: none;
        justify-content: center;
        align-items: center;
        display: flex;
        overflow: hidden;


        .share-media-play {
          width: 100%;
          height: 100%;


          div {
            width: 100%;
            height: 100%;
          }
        }
        .img {
          cursor: grabbing;
          position: absolute;
          max-width: 100%;
          max-height: 100%;
        }
      }
      .tool {
        height: 90px;


            .enlarge {
              flex: 1;
              padding-left: 20px;
              height: 100%;
              width: 100%;
              display: flex;
              position: relative;
              #Enlarge {
                display: flex;
                height: 100%;
                width: 60%;
                align-items: center;


                .scroll {
                  flex: 1;
                  height: 5px;
                  background: #848992;
                  border-radius: 2px;
                  position: relative;


                  .speed {
                    height: 5px;
                    background: #33ccff;
                    position: relative;


                    span {
                      width: 12px;
                      height: 12px;
                      display: block;
                      background: #33CCFF;
                      border-radius: 6px;
                      position: absolute;
                      right: -6px;
                      top: -3.5px;
                      cursor: pointer;
                    }
                  }
                }


                .math {
                  margin-left: 20px;
                  width: 80px;


                  /deep/ .el-input {
                    width: 50px;


                    .el-input__inner {
                      padding: 0;
                      text-align: center;
                    }
                  }


                  .percentage {
                    display: inline-block;
                    color: #594C4C;
                    height: 28px;
                    line-height: 28px;
                    margin-left: 10px;
                  }
                }
              }
              .btn{
                position: absolute;
                right: 10px;
                top: 0;
                bottom: 0;
                display: flex;
                align-items: center;
              }
            }
          }
        }


</style>

最近整理21年笔记发现那时候我还是喜欢用原生js来实现一些特定的需求,挺好

相关推荐
长风清留扬13 分钟前
小程序毕业设计-音乐播放器+源码(可播放)下载即用
javascript·小程序·毕业设计·课程设计·毕设·音乐播放器
web1478621072327 分钟前
C# .Net Web 路由相关配置
前端·c#·.net
m0_7482478027 分钟前
Flutter Intl包使用指南:实现国际化和本地化
前端·javascript·flutter
飞的肖31 分钟前
前端使用 Element Plus架构vue3.0实现图片拖拉拽,后等比压缩,上传到Spring Boot后端
前端·spring boot·架构
青灯文案138 分钟前
前端 HTTP 请求由 Nginx 反向代理和 API 网关到后端服务的流程
前端·nginx·http
m0_7482548843 分钟前
DataX3.0+DataX-Web部署分布式可视化ETL系统
前端·分布式·etl
ZJ_.1 小时前
WPSJS:让 WPS 办公与 JavaScript 完美联动
开发语言·前端·javascript·vscode·ecmascript·wps
GIS开发特训营1 小时前
Vue零基础教程|从前端框架到GIS开发系列课程(七)响应式系统介绍
前端·vue.js·前端框架·gis开发·webgis·三维gis
Cachel wood1 小时前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
学代码的小前端1 小时前
0基础学前端-----CSS DAY9
前端·css