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来实现一些特定的需求,挺好

相关推荐
Martin -Tang7 分钟前
vite和webpack的区别
前端·webpack·node.js·vite
迷途小码农零零发8 分钟前
解锁微前端的优秀库
前端
王解1 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
老码沉思录1 小时前
写给初学者的React Native 全栈开发实战班
javascript·react native·react.js
我不当帕鲁谁当帕鲁1 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂1 小时前
工程化实战内功修炼测试题
前端·javascript
放逐者-保持本心,方可放逐2 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架
毋若成4 小时前
前端三大组件之CSS,三大选择器,游戏网页仿写
前端·css
红中马喽4 小时前
JS学习日记(webAPI—DOM)
开发语言·前端·javascript·笔记·vscode·学习
Black蜡笔小新5 小时前
网页直播/点播播放器EasyPlayer.js播放器OffscreenCanvas这个特性是否需要特殊的环境和硬件支持
前端·javascript·html