写一个pc端的可拖动的弹窗组件(类似elementUI的el-dialog组件)

先上效果图
在这里插入图片描述

新建一个dialog.vue文件,把下面的代码复制进去

// dialog.vue
<template>
    <div class="dialogBox" v-show="dialoShow">
        <div class="conte " :style="{width:`${width}%`,left: `${(100 - width)/2}%`}" @mousedown="talkBtnBoxMousedown" id="dialogBoxDrag">
            <div class="title">
                <!-- <span class="line"></span> -->
                <span class="text">{{title}}</span>
            </div>
            <div class="contentBox" id="dialogContentBox" ref="dialogContentBox"  v-closeSelectDropdown>
                <div class="mar" >
                    <slot></slot>
                </div>
            </div>
            <div class="foot" v-if="btnShow">
                <div class="btnGround">
                  <span class="footDesc">
                    <slot name="footDesc"></slot>
                  </span>
                   <el-button class=" crmColorBtn" v-if="cancelBtnShow" @click.stop="cancelClick" size="mini" >{{cancelText}}</el-button>
                   <el-button class="crmColorBgBtn" :disabled="saveBtnDisabled"  @click.stop="updateSave" type="primary" size="mini" :loading="dis" >{{saveText}}</el-button>

                </div>
            </div>
            <div class="foot" v-else-if="!btnShow">
                <div class="btnGround">
                   <el-button class=" cancal crmColorBtn" size="mini"  @click.stop="closeDialo">{{closeText}}</el-button>
                </div>
            </div>
        <i class="el-icon-close closeIcon"  @click.stop="closeDialo"></i>

        </div>

    </div>
</template>

<script>
export default {
  //  props:['title', 'dialoShow', 'width'],
    props: {
        title: {
           type: String,
           required: true,
         },
        dialoShow: {
           type: Boolean,
           required: true,
        },
        width: {
          type: Number,
          default: 30
        },
        btnShow: {
            type: Boolean,
            default: true
        },
        height: {
          type: Number | String,
          default: 0
        },
        saveText: {
          type: String,
          default: '保存'
        },
        cancelText:{
          type:String,
          default: "取消"
        },
        closeText:{
          type:String,
          default:"关闭"
        },
        saveBtnDisabled:{
          type: Boolean,
          required: false,
          default: false
        },
        cancelBtnShow:{
          type: Boolean,
          required: false,
          default: true
        }
   },
   methods: {
       updateSave(ev) {
        ev.stopPropagation();
        this.$emit('updateSave');
       },
       closeDialo(ev) {
        ev.stopPropagation();
        this.$emit('closeDialo', 'iconCloseClick');
       },
       cancelClick(ev) {
        ev.stopPropagation();
        this.$emit('cancelClick');
        this.$emit('closeDialo');
       },
       resetDomScrollHeight(){
        const refDom = this.$refs.dialogContentBox;
        this.$nextTick(()=>{
          if(refDom)refDom.scrollTop = 0;
        })
       },
      setHeight() {
            window.setTimeout(() => {
                let winHeight = window.innerHeight;
                let conHeight = null;
                let dialogBox = document.querySelectorAll(".dialogBox");
                if(dialogBox.length > 0) {
                    for(const val of dialogBox) {
                    if(val.style.display !== 'none'){
                        conHeight = val.childNodes[0].childNodes[2].childNodes[0].clientHeight;
                        let percentage = parseInt(((conHeight + 160)/winHeight )*100) ; // 计算出弹窗实际内容高度占浏览器高度比
                        if (percentage + 8 < 80 && !this.height) {
                            let num = `${percentage + 10}%`
                            val.childNodes[0].style.height = num;
                        } else {
                          if(typeof this.height === 'number'){
                            val.childNodes[0].style.height = this.height ? `${this.height}%` : '82%';
                          } else if(typeof this.height === 'string'){
                            console.log(this.height);
                            val.childNodes[0].style.height = this.height ? `${this.height}` : '82%';

                          }
                        }
                    }
                }
                }
            }, 100)

       },
         // 拖动
    talkBtnBoxMousedown(event) {

      if(event.target.nodeName.toLowerCase() !== 'div'){
        return false;
      }
      // event.stopPropagation();


      let talkBtnBox = this.findParentNodeId(event.target);

        let talkBtnBoxX = talkBtnBox.offsetLeft;
        let talkBtnBoxY = talkBtnBox.offsetTop;
        let mouseX = event.clientX;
        let mouseY = event.clientY;
        let distanceX = mouseX - talkBtnBoxX;
        let distanceY = mouseY - talkBtnBoxY;
      document.onmousemove = (ev) => {
        console.log('move');
        ev.stopPropagation();
        talkBtnBox.style.left = ev.clientX - distanceX + 'px';
        talkBtnBox.style.top = ev.clientY - distanceY + 'px';
      }
      document.onmouseup = (evt) => {
        evt.stopPropagation();
        document.onmousemove = null;
        document.onmouseup = null;
      }
    },
    findParentNodeId(target) {

      var parentNodeList = [];
      parentNodeList.push(target);
      while(target.parentNode) {
          parentNodeList.unshift(target.parentNode);
          target = target.parentNode;
      }
      if(parentNodeList.length > 0) {
        for(let i = 0; i < parentNodeList.length; i++) {
          if(parentNodeList[i].id === 'dialogBoxDrag') {
            return parentNodeList[i];
          }
        }
      }
      return null;

    },
   },
    watch: {
      dialoShow(nv,ov) {
        if(nv) {
            this.setHeight();
        }
        if(!ov && nv){
          this.resetDomScrollHeight();
        }
      },
   },
   computed: {
     dis() {
       return this.$store.state.disabledBtn;
     }
   }

}
</script>

<style scoped>

.dialogBox{
    position: fixed;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    background: rgba(0,0,0,0.3);
    z-index: 1000;
}
.conte{
    background: #fff;
    position: fixed;
    top: 12%;
    left: 35%;
    border-radius:16px;
    height: 80%;
    overflow: hidden;
     min-height: 280px;
     min-width: 360px;
}
.title{
    width: 100%;
    /* padding: 14px 0; */
    line-height: 40px;
    border-bottom: 1px solid #EEEEEE;
}
.line{
    width: 4px;
    height:20px ;
    display: inline-block;
   background: #118ca1;
   background: #32cecb;
   vertical-align: middle;
   margin-left: 26px;
    margin-right: 10px;
}
.text{
  margin-left: 22px;

    font-family: PingFangSC-Semibold;
    font-size: 16px;
    color: #118ca1;
    color: rgba(0,0,0,0.85);
    vertical-align: middle;
    font-weight: 600;
}
.contentBox{
    margin: 16px 0;
    /* padding-bottom: 40px; */
    /* max-height: 555px; */
    overflow-x: hidden;
    overflow-y: auto;
    height: calc(100% - 110px);
}
/* .contentBox::-webkit-scrollbar{
   opacity: 0;
} */
.contentBox::-webkit-scrollbar{
          /* opacity: 0; */
          width: 6px;
          min-height: 20px;
          background: #e3e3e3;
      }
.contentBox::-webkit-scrollbar-thumb {
    /* //滚动条里面小方块/ */
border-radius: 10px;
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
background: #ccc;
}


.mar{
  margin: 0 28px;
  margin-left: 32px;
    font-size: 14px;
}
.foot{
    overflow: hidden;
    padding: 10px 0;
    position: absolute;
    bottom: 0px;;
    width:100%;
    border-top: 1px solid #EEEEEE;

}
.btnGround{
    float: right;
    margin-right: 50px;
}
.buttons{
    padding: 10px 16px;
    display: inline-block;
    cursor: pointer;
    background: #fff;
}
.cancal{
    border: 1px solid #C0C4CC;
border-radius: 4px;
margin-right: 10px;
}
.save{
background: #1D82FA;
border-radius: 4px;
color: #fff;
}
.closeIcon{
  position:absolute;
  top:10px;
  right:14px;
  color:#C0C4CC;
  cursor:pointer;
  font-size:18px;
}
.footDesc{
  margin-right: 16px;
}
</style>

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值