el-popper点击事件(ElmentUI的el-dialog拖拽最大化)
el-popper点击事件(ElmentUI的el-dialog拖拽最大化)<template> <div class="components-container"> <el-button type="primary" @click="dialogTableVisible = true"> open a Drag Dialog </el-button> <el-button type="primary" @click="openDialog()"> 拖拽弹窗1 </el-button> <el-button type="primary" @click="openDialog1()"> 拖拽弹窗
最近要做一个新项目,使用的是花裤衩大佬的vue-elment-admin框架,但是有需求是要求弹窗可以拖拽,并且要做成非模态形式,打不过产品经理,开始搞!!!
先看看写好的效果图吧,后面再优化:
这是最小化效果
弹出效果
话不多说 直接上代码吧,先是封装好的dialog: index.vue
<template>
<el-dialog
v-el-drag-dialog
ref="dragDialog"
class="dragDialog"
:title="config.title"
:fullscreen="isFullScreen"
:visible.sync="config.dialogVisible"
:append-to-body="true"
:close-on-click-modal="false"
:show-close="false"
:width="config.width"
:modal="config.modal"
@close="closeDialogDom()"
:class="isMiniSize? 'isMiniSize': ''"
>
<div v-show="!isMiniSize" slot="title" class="medium">
<div class="centers"><span>{{config.title}}</span></div>
<div class="icons">
<i class="el-icon-minus" style="font-size: 24px" @click="minimize"></i>
<i :class="isFullScreen? 'el-icon-remove-outline' : 'el-icon-circle-plus-outline' " style="font-size: 24px" @click="IsFullscreen"></i>
<i class="el-icon-close" style="font-size: 24px" @click="closeDialog"></i>
</div>
</div>
<div v-show="isMiniSize" slot="title" class="horn">
<div class="lefts"><span>{{config.title}}</span></div>
<div class="centers"><i class="el-icon-circle-plus-outline" style="font-size: 24px" @click="backSize"></i></div>
<div class="rights"><i class="el-icon-close" style="font-size: 24px" @click="closeDialog"></i></div>
</div>
<div v-show="!isMiniSize" class="dialogBody">
<slot></slot>
</div>
<div v-show="!isMiniSize" v-if="config.isFooter" class="dialogFooter">
<slot name="footer" solt="footer">
<el-button size="small" @click="config.dialogVisible = false">取 消</el-button>
<el-button size="small" type="primary" @click="config.dialogVisible = false">确 定</el-button>
</slot>
</div>
</el-dialog>
</template>
<script>
import elDragDialog from './drag'
export default {
directives: { elDragDialog }
props: {
config: {
type: Object
default: () => ({})
}
}
data() {
return {
isFullScreen: false // 全屏
isMiniSize: false // 最小化
dialogVisible: false // 隐藏弹窗
}
}
watch: {
config: {
handler(newVal oldVal) {
console.log(newVal)
this.initDialog()
}
immediate: true
}
}
methods: {
// 初始化dialog
initDialog() {
// console.log(this.config)
}
// 最小化
minimize() {
this.isMiniSize = !this.isMiniSize
if (this.isFullScreen) this.isFullScreen = !this.isFullScreen
this.$nextTick(() => {
var miniSizeDom = document.getElementsByClassName('isMiniSize')
miniSizeDom.forEach((item index) => {
item.style.left = 240 * index 'px'
})
})
}
// 关闭回调
closeDialogDom() {
this.$nextTick(() => { // dragDialog
var miniSizeDom = document.getElementsByClassName('isMiniSize')
console.log(miniSizeDom)
miniSizeDom.forEach((item index) => {
item.style.left = 240 * index 'px'
})
})
}
// 复原
backSize() {
this.isMiniSize = !this.isMiniSize
if (this.isFullScreen) this.isFullScreen = !this.isFullScreen
this.$nextTick(() => {
var dragDialogDom = document.getElementsByClassName('dragDialog')
dragDialogDom.forEach((item index) => {
item.style.left = 0 'px'
})
var miniSizeDom = document.getElementsByClassName('isMiniSize')
miniSizeDom.forEach((item index) => {
item.style.left = 240 * index 'px'
})
})
}
// 关闭弹窗
closeDialog() {
this.config.dialogVisible = false
}
// 打开弹窗
openDialog() {
this.dialogVisible = true
}
// 全屏
IsFullscreen() {
this.isFullScreen = !this.isFullScreen
if (this.isFullScreen) this.$emit('isFullScreen')
}
}
}
</script>
<style lang="scss">
// 覆盖层元素增加可穿透点击事件
.el-dialog__wrapper{
pointer-events: none !important;
}
// 弹窗元素不可穿透点击事件(不影响弹窗层的元素点击事件)
.el-dialog{
pointer-events: auto !important;
}
.el-dialog{
margin-top: 10vh!important;
}
.no_select{
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.isMiniSize{
left: 20px;
bottom: 20px;
top: auto;
right: auto;
overflow:hidden;
border-radius: 20px;
margin: 0px 5px;
.el-dialog {
margin: 0 !important;
width: 240px !important;
height: 32px;
top: 0 !important;
left: 0 !important;
}
.el-dialog__header{
cursor: auto!important;
background: #cccccc;
.el-dialog__headerbtn {
display: none;
}
}
.dialogFooter{
position: absolute;
bottom: 0;
background: #cccccc;
}
}
.dragDialog {
.is-fullscreen {
width: 100% !important;
left: 0 !important;
top: 0 !important;
margin-top: 0 !important;
overflow:hidden;
position: relative;
.el-dialog__header{
cursor: auto!important;
}
.el-dialog__body{
height: 100%;
.dialogBody{
height:100%!important;
max-height:none!important;
padding-bottom:120px!important;
}
}
.dialogFooter{
position: absolute;
bottom: 0;
width: 100%;
background: #ccc;
}
}
.el-dialog{
.el-dialog__header{
width: 100%;
padding: 5px 20px 5px !important;
display: flex;
background: #ccc;
border-bottom: 1px solid #ccc;
@extend .no_select;
cursor: auto;
.medium{
width: 100%;
height: 30px;
line-height: 30px;
display: flex;
div{
flex:1;
}
.centers{
span{
text-align: center;
font-size:16px;
color:#606266;
}
}
.icons{
display: flex;
justify-content: flex-end;
i{
color:#5f6368;
font-size: 18px!important;
display: block;
padding:0 7px;
}
i:hover{
background: #dcdfe6;
cursor: pointer;
}
.el-icon-close:hover{
background: #f00;
color:#fff;
}
}
}
.horn{
width: 100%;
height: 100%;
display: flex;
justify-content: space-between;
div{
i{
color:#5f6368;
font-size:20px!important;
}
}
.lefts{
flex:4;
margin-top: 3px;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
span{
font-size: 16px;
color:#606266;
}
}
.centers{
flex:1;
}
.rights{
flex:1;
}
i:hover{
cursor: pointer;
color:#000;
}
}
.el-dialog__headerbtn {
top: 0;
font-size: 24px;
}
}
.el-dialog__body{
padding: 1px !important;
.dialogBody{
max-height: calc(80vh - 50px);
overflow: auto;
padding: 20px 25px 20px;
&::-webkit-scrollbar {
width: 4px;
height: 8px;
}
&::-webkit-scrollbar-thumb {
background: transparent;
border-radius: 4px;
}
&:hover::-webkit-scrollbar-thumb {
background: hsla(0 0% 53% .4)
}
&:hover::-webkit-scrollbar-track {
background: hsla(0 0% 53% .1)
}
}
.dialogFooter{
padding: 10px 15px;
border-top: 1px solid #ccc;
text-align: right;
.el-button{
padding:7px 15px;
}
}
}
}
.dragDialog{
.el-select{
width: 100%;
}
.el-date-editor{
width: 100%;
}
}
}
</style>
drag.js文件
export default {
bind(el binding vnode oldVnode) {
const dialogHeaderEl = el.querySelector('.el-dialog__header')
const dragDom = el.querySelector('.el-dialog')
dialogHeaderEl.style.cursor = 'move'
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素 null);
const sty = dragDom.currentStyle || window.getComputedStyle(dragDom null)
dialogHeaderEl.onmousedown = (e) => {
// 判断当前是否为全屏状态
const path = event.path || (event.composedPath && event.composedPath())
const isFull = path.find(s => {
if (s.className === undefined) {
return false
} else {
return s.className.indexOf('is-fullscreen') > -1
}
})
if (isFull !== undefined) {
return
}
const isMinix = path.find(s => {
if (s.className === undefined) {
return false
} else {
return s.className.indexOf('isminimize') > -1
}
})
if (isMinix !== undefined) {
return
}
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - dialogHeaderEl.offsetLeft
const disY = e.clientY - dialogHeaderEl.offsetTop
// 获取到的值带px 正则匹配替换
let styL styT
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
if (sty.left.includes('%')) {
styL = document.body.clientWidth * ( sty.left.replace(/\%/g '') / 100)
styT = document.body.clientHeight * ( sty.top.replace(/\%/g '') / 100)
} else {
styL = sty.left.replace('px' '')
styT = sty.top.replace('px' '')
}
document.onmousemove = function(e) {
// 通过事件委托,计算移动的距离
const l = e.clientX - disX
const t = e.clientY - disY
// 移动当前元素
dragDom.style.left = `${l styL}px`
dragDom.style.top = `${t styT}px`
}
document.onmouseup = function(e) {
const dragDom = el.querySelector('.el-dialog')
const offsetLeft = dragDom.offsetLeft
const offsetTop = dragDom.offsetTop
const left = Number(dragDom.style.left.replace('px' ''))
const top = Number(dragDom.style.top.replace('px' ''))
const windowWidth = window.innerWidth
const windowHeight = window.innerHeight - 50
const offsetRight = offsetLeft dragDom.offsetWidth - windowWidth
const offsetBottom = offsetTop dragDom.offsetHeight - windowHeight
if (offsetLeft < 0) {
dragDom.style.left = (left - offsetLeft) 'px'
}
if (offsetTop < 0) {
dragDom.style.top = (top - offsetTop) 'px'
}
if (offsetRight > 0) {
dragDom.style.left = (left - offsetRight) 'px'
}
if (offsetBottom > 0) {
dragDom.style.top = (top - offsetBottom) 'px'
}
document.onmousemove = null
document.onmouseup = null
}
}
}
}
下面这个是我们的父组件:drag-dialog.vue
<template>
<div class="components-container">
<el-button type="primary" @click="dialogTableVisible = true">
open a Drag Dialog
</el-button>
<el-button type="primary" @click="openDialog()">
拖拽弹窗1
</el-button>
<el-button type="primary" @click="openDialog1()">
拖拽弹窗2
</el-button>
<el-button type="primary" @click="openDialog2()">
拖拽弹窗3
</el-button>
<el-dialog v-el-drag-dialog :visible.sync="dialogTableVisible" title="Shipping address" @dragDialog="handleDrag">
<el-select ref="select" v-model="value" placeholder="请选择">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<el-table :data="gridData">
<el-table-column property="date" label="Date" width="150" />
<el-table-column property="name" label="Name" width="200" />
<el-table-column property="address" label="Address" />
</el-table>
</el-dialog>
<drag-dialog v-if="dialogData.dialogVisible" :config="dialogData">1</drag-dialog>
<drag-dialog v-if="dialogData1.dialogVisible" :config="dialogData1">2</drag-dialog>
<drag-dialog v-if="dialogData2.dialogVisible" :config="dialogData2">3</drag-dialog>
</div>
</template>
<script>
import elDragDialog from '@/directive/el-drag-dialog' // base on element-ui
import dragDialog from '@/components/DragDialog'
export default {
name: 'DragDialogDemo'
components: { dragDialog }
directives: { elDragDialog }
data() {
return {
dialogData: {
width: '50%'
dialogVisible: false
title: '拖拽1'
modal: false
isFooter: true
}
dialogData1: {
width: '80%'
dialogVisible: false
title: '拖拽2'
modal: false
isFooter: true
}
dialogData2: {
width: '80%'
dialogVisible: false
title: '拖拽3'
modal: false
isFooter: true
}
dialogTableVisible: false
options: [
{ value: '选项1' label: '黄金糕' }
{ value: '选项2' label: '双皮奶' }
{ value: '选项3' label: '蚵仔煎' }
{ value: '选项4' label: '龙须面' }
]
value: ''
gridData: [{
date: '2016-05-02'
name: 'John Smith'
address: 'No.1518 Jinshajiang Road Putuo District'
} {
date: '2016-05-04'
name: 'John Smith'
address: 'No.1518 Jinshajiang Road Putuo District'
} {
date: '2016-05-01'
name: 'John Smith'
address: 'No.1518 Jinshajiang Road Putuo District'
} {
date: '2016-05-03'
name: 'John Smith'
address: 'No.1518 Jinshajiang Road Putuo District'
}]
}
}
methods: {
// v-el-drag-dialog onDrag callback function
handleDrag() {
this.$refs.select.blur()
}
openDialog() {
this.dialogData.dialogVisible = true
}
openDialog1() {
this.dialogData1.dialogVisible = true
}
openDialog2() {
this.dialogData2.dialogVisible = true
}
}
}
</script>
话不多说,大佬们,各位兄弟们,有不明白的地方直接留言,看到都会及时回复。