基于vue的可拖拽组件

/**
    fixed(固定定位) 这里所固定的参照对像是--可视窗口-而并非是body或是父级元素。可通过z-index进行层次分级。
*/
/**
    fixed(固定定位) 这里所固定的参照对像是--可视窗口-而并非是body或是父级元素。可通过z-index进行层次分级。
*/
<template>
    <!-- 外层蒙版 -->
    <transition name="dialog" >
        <!-- @mouseup.stop="clickUpDialog" -->
        <div class="dialog-layer" :data-hash="timeStamp" v-if="show" @click="closeLayer" :style="{'z-index':computedZindex}" id="dialog-layer" >
            <!-- 中间容器 -->
            <div class="dialog-resize_wrapper" @click.stop="stopFn" :style="{'background-color':backgroundColor,'top':top,'left':left,transform:(left == '50%' && top == '50%') ? 'translate(-50%,-50%)' : (top !== '50%' ? 'translate(-50%,0)' : '')}">
                <div class="dialog-wrapper"    >
                    <!-- 容器的头部 -->
                    <div class="dialog-header" :style="{'font-size':computedHeaderFontSize,'color':headerColor}"  @mousedown="clickDownDialog('mousedown')"  @mousemove="moveDialog" @mouseup.stop="clickUpDialog('dialog-header-mouseup')" >
                        <!-- 标题的外层容器 -->
                        <div class="dialog-header_wrapper">
                            <div class="dialog-header_inner" >{{title}}</div>
                            <!-- 点击关闭的按钮外层容器 -->
                            <div class="dialog-close_wrapper" @click.stop="closeDialog" @mouseover="closeJudge(true)" @mouseout="closeJudge(false)">
                                <!-- 外层按钮 -->
                                <i class="dialog-header_close iconfont icon-shanchu" ></i>
                            </div>
                        </div>
                    </div>
                    <!-- 容器的内容,放置外部直接放置在容器里面的内容 为默认的插槽-->
                    <div class="dialog-content" ref="dialog-content" :style="{'width':computedWidth,'min-height':computedHeight,'min-width':minWidth,'max-width':maxWidth,'max-height':maxHeight,padding:contentPadding}" name="content" >
                        <!-- 写在组件里面的内容就插入到这里 -->
                        <slot ></slot>
                    </div>
                    <!-- 默认的按钮组,默认不显示,需要显示可以在引用组件的时候 :show-fotter="true"-->
                    <div class="dialog-footer"  v-if="showFooter">
                        <button class="button"  @click.stop="closeDialog">取消</button>
                        <button class="button primary" @click.stop="submit" :disabled="submitLoading">确定</button>
                    </div>
                </div>
            </div>
        </div>
    </transition>
</template>
<script>
export default {
    // rebuild-dialog 这里这个名字不要更改,会影响组件的使用
    name:'rebuild-dialog',
    // 这里的 prop 只能增加不能减少
    props:{
        //弹窗的显示隐藏
        show:{
            default:false,
            type:Boolean
        },
        zIndex:{
            default:100,//默认层级
        },
        mofifyTop:{
            //传入的top 
            default:null,
        },
        //弹窗的标题
        title:{
            default:'标题',
        },
        //传入的弹窗的宽
        width:{
            default:500,
        },
        //传入的弹窗的高
        height:{
            default:100,
            type:Number
        },
        minWidth:{
            default:500,
        },
        maxWidth:{
            default:'95vw',
        },
        maxHeight:{
            default:'85vh',
        },
        //  标题部分的背景色
        headerBg:{
            default:'white'
        },
        //标题部分的字体大小
        headerFontSize:{
            default:18,
        },
        //标题部分的字体颜色
        headerColor:{
            default:'rgb(60,60,60)'
        },
        // 容器内容的背景色
        backgroundColor:{
            default:'white'
        },
        contentPadding:{
            default:'10px 18px 10px 10px'
        },
        //通过点击蒙版来关闭弹窗
        clickModalCloseLayer:{
            default:false,
        },
        //是否显示地步的按钮组
        showFooter:{
            default:false,
        },
        //点击确认之后的loading
        submitLoading:{
            default:false
        },
        //弹窗覆盖处理 --增加层级
        appendToBody:{
            default:false,
        }
        
    },
    data () {
        return {
            showTest:false,//测试用
            isDrag:false,//是否为拖拽,即长按并滑动鼠标
            //定位 上
            top:'50%',
            left:'50%',
            topTest:'20px',
            leftTest:'20px',
            //鼠标按下的时候鼠标所在的坐标
            oldMouseX:'',
            oldMouseY:'',
            toClose:false,//是否有关闭意图
            timeStamp:'',
        }
    },
    computed:{
        //计算后的容器宽度
        computedWidth(){
            console.log(this.width)
            //传入可以是带px的字符串也可以是数值
            if(typeof this.width == 'number'){
                return this.width+'px'
            }else{
                return this.width
            }
        },
        // 计算后的容器高度
        computedHeight(){
            if(typeof this.height == 'number'){
                return this.height+'px'
            }else{
                return this.height
            }
        },
        computedHeaderFontSize(){
            if(typeof this.headerFontSize == 'number'){
                return this.headerFontSize+'px'
            }else{
                return this.headerFontSize
            }
        },
        //层级
        computedZindex(){
            let index = this.zIndex;
            if(this.appendToBody){
                //加深层级
                index += 2;
            }
            return index
        },
    },
    watch:{
        // 当检测到这个值变化的时候,重置拖拽框的位置
        show: {
            immediate: true, // 将立即以表达式的当前值触发回调
            handler (val) { // 固定写法
                //初始值是0,操作后才是false
                if(val === false){
                    //是关闭状态的时候才执行
                    this.reset();
                }else if(val === true){
                    //执行一次append
                    this.reset(2);
                    this.$nextTick(()=>{
                        //有自定义的top传过来的时候
                        if(this.mofifyTop !== null){
                            this.top = this.mofifyTop;
                        }
                    })
                }
            },
            // deep:true
        }
    },
    mounted(){
        //鼠标抬起事件应该做成监听
        window.addEventListener('mouseup',this.clickUpDialog)
    },
    updated(){
        if(this.$refs['dialog-content']){
            this.$refs['dialog-content']
        }
    },
    beforeDestroy(){
        //销毁组件
        window.removeEventListener('mouseup',this.clickUpDialog);
    },
    activated(){
        console.log("哈哈哈哈");
    },
    methods:{
        //阻止冒泡的函数,在允许点击蒙版关闭的时候需要用到,请勿删除
        stopFn(){
            
        },
        //关闭弹窗
        closeLayer(){
            console.log("哈哈哈哈")
            if(this.clickModalCloseLayer){
                this.$emit('close')
            }
        },
        submit(){
            //点击确定
            this.$emit('submit');
        },
        closeJudge(val){
            //鼠标划过close的处理
            this.toClose = val
        },
        //根据鼠标位置获取当前框的定位信息
        getTarget(ev){
            //有关闭意图的时候直接return
            if(this.toClose){
                return
            }
            // //可视区的高
            let windowHeight = window.innerHeight;
            // // 可视区的宽
            let windowWidth = window.innerWidth;
            ev = ev || window.event;
            //计算具体的位置
            if(this.isDrag){//拖拽的状态
                if(ev.pageX + this.width/2 > windowWidth && ev.pageX > 0){
                    //超出宽度
                    this.left = windowWidth - this.width/2 + 20 ;
                }else if(ev.pageX <= this.width/2){
                    this.left = this.width/2
                }else{
                    this.left = (ev.pageX + 15)+'px';
                }

                if(ev.pageY + this.height+25 > windowHeight && ev.pageY > 0){
                    //超出高度
                    this.top = windowHeight - this.height - 25;
                }else if(ev.pageY <= 0){
                    this.top = 0;
                }else{
                    //加上运行的距离与按下时的坐标的比较
                    this.top = (ev.pageY )+'px';
                }
            }
        },
        clickDialog(ev){
            //点击鼠标左键
            if(ev.button == 0){
                
            }
        },
        clickDownDialog(ev){
            ev = ev || window.event;
            //记录鼠标按下时候的坐标
            this.oldMouseX = ev.pageX;
            this.oldMouseY = ev.pageY;

            //鼠标按下的事件
            this.isDrag  = true;
            //开始获取坐标
            // window.addEventListener('mousemove',this.getTarget);
        },
        clickUpDialog(val){
            //鼠标松开事件
            this.isDrag  = false
            //取消获取坐标
            window.removeEventListener('mousemove',this.getTarget);
        },
        moveDialog(ev){
            //按下左键之后才允许拖拽
            if(this.isDrag){
                window.addEventListener('mousemove',this.getTarget);//再添加监听
            }
        },
        closeDialog(){
            //需要关闭拖拽的动作,不然会干扰关闭弹窗
            this.isDrag = false;
            window.removeEventListener('mousemove',this.getTarget);
            window.removeEventListener('mouseup',this.clickUpDialog);
            this.reset();
            this.$emit('close');
            window.removeEventListener('mousemove',this.getTarget);
        },
        reset(times){
            if(times){
                this.oldMouseX = null;
                this.oldMouseY = null;
                console.log('other')
            }
            console.log("重置")
            //重置弹框的位置
            this.top = '50%';
            this.left = '50%';
        },
    },
}
</script>
<style scoped lang="scss">
    //一个简单的过渡 组件过渡
    .dialog-enter-active,.list-leave-active{
	  transition:all 0.3s;
	}
	.dialog-enter,.list-leave-to{
	  height:0;
	  opacity: 0;
	}
    // 外层蒙版
    .dialog-layer{
        position:fixed;
        top:0;
        right:0;
        bottom:0;
        left:0;
        background:rgba(0,0,0,0.5);
        .dialog-resize_wrapper{
            position:fixed;
            background:white;
            border-radius:4px;
        }
        .dialog-wrapper{
            .dialog-header{
                //禁止选中标题文字
                user-select:none;
                cursor:move;
                color:#e8e8e8;
                padding:5px 10px;
                .dialog-header_wrapper{
                    width:100%;
                    display:flex;
                    justify-content: space-between;
                    align-items: center;
                    padding:4px 2px;
                    border-bottom:1px solid rgba(220,220,220,0.9);
                    .dialog-close_wrapper{
                        // border:1px solid red;
                        padding:0 3px;
                        .dialog-header_close{
                            //删除按钮
                            cursor: pointer;
                            font-size:24px;
                            color:rgba(130,130,130,0.9);
                        }
                        .dialog-header_close:hover{
                            color:#409eff;
                        }
                    }
                }
            }
            .dialog-content{
                // border:1px solid red;
                overflow-y: auto;
                box-sizing: border-box;
                //设置最小的宽高
                min-width:300px;
                min-height:150px;
                //传入胡内容太少,内容太靠上的处理
                // display:flex;
                // // justify-content: center;
                // align-items: center;
                // flex-wrap: wrap;
            }
            .dialog-footer{
                border-top:1px solid #e8e8e8;
                padding:6px 15px 6px 3px;
                text-align:right;
            }
        }
    }
    //按钮样式
    .button{
        width:57px;
        height:32px;
        font-size:13px;
        color:#333333;
        outline: none;
        border-radius:5px;
        background:none;
        margin-left:10px;
        border:1px solid #e8e8e8;
    }
    .default{
        background:white;
        color:333333;
    }
    .default:hover{
        background:rgba(255,255,255,0.8);
    }
    .primary{
       background:rgb(39, 166, 240); 
    //    box-shadow:0 0  2px 2px rgb(39, 162, 233);
       color:white;
    }
    .primary:hover{
       background:rgba(39, 166, 240,0.8); 
    }
    .warning{
        background:rgb(231, 112, 26);
        // box-shadow:0 0 2px 2px rgb(231, 112, 26);
        color:white;
    }
    .warning:hover{
        background:rgb(231, 112, 26);
    }
    .danger{
        background:rgb(179, 64, 69);
        // box-shadow:0 0 2px 2px rgb(211, 99, 19);
        color:white;
    }
    .danger:hover{
        background:rgb(184, 73, 78);
    }
</style>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值