Dialog升级,支持可拖动,支持v-model控制显隐
This commit is contained in:
		| @@ -1,112 +1,103 @@ | ||||
| <template> | ||||
|   <section class="ai-dialog__wrapper"> | ||||
|     <el-dialog | ||||
|         custom-class="ai-dialog" | ||||
|         v-on="$listeners" | ||||
|         v-if="isEmpty" | ||||
|         :close-on-click-modal="closeOnClickModal" | ||||
|         v-bind="$attrs" | ||||
|         :destroy-on-close="destroyOnClose" | ||||
|         :visible.sync="dialogVisible"> | ||||
|       <div class="ai-dialog__header" slot="title"> | ||||
|         <h2>{{ title }}</h2> | ||||
|       </div> | ||||
|       <div class="ai-dialog__content" :style="{'max-height': isScrool ? '500px' : 'auto'}"> | ||||
|         <div class="ai-dialog__content--wrapper" :style="{'padding-right': isScrool ? '8px' : '0'}"> | ||||
|           <slot></slot> | ||||
|     <el-dialog custom-class="ai-dialog" v-on="$listeners" v-bind="$attrs" :visible.sync="dialog"> | ||||
|       <div class="ai-dialog__header fill" slot="title" v-text="title"/> | ||||
|       <div class="ai-dialog__content"> | ||||
|         <div class="ai-dialog__content--wrapper pad-r8"> | ||||
|           <slot/> | ||||
|         </div> | ||||
|       </div> | ||||
|       <template v-if="customFooter" slot="footer"> | ||||
|         <slot name="footer"></slot> | ||||
|         <slot name="footer"/> | ||||
|       </template> | ||||
|       <div v-else class="dialog-footer" slot="footer"> | ||||
|         <el-button @click="onCancel">取消</el-button> | ||||
|         <el-button @click="onConfirm" type="primary" style="width: 92px;">确认</el-button> | ||||
|         <el-button @click="onConfirm" type="primary">确认</el-button> | ||||
|       </div> | ||||
|     </el-dialog> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|  | ||||
| export default { | ||||
|   name: 'AiDialog', | ||||
|   props: { | ||||
|     visible: { | ||||
|       type: Boolean, | ||||
|       default: false | ||||
|     }, | ||||
|     title: { | ||||
|       type: String, | ||||
|       default: '' | ||||
|     }, | ||||
|     customFooter: { | ||||
|       type: Boolean, | ||||
|       default: false | ||||
|     }, | ||||
|     'close-on-click-modal': { | ||||
|       type: Boolean, | ||||
|       default: false | ||||
|     }, | ||||
|     destroyOnClose: { | ||||
|       type: Boolean, | ||||
|       default: true | ||||
|     } | ||||
|   model: { | ||||
|     prop: "visible", | ||||
|     event: "input" | ||||
|   }, | ||||
|   props: { | ||||
|     visible: Boolean, | ||||
|     title: {type: String, default: ''}, | ||||
|     customFooter: Boolean, | ||||
|     isDrag: {type: Boolean, default: true} | ||||
|   }, | ||||
|  | ||||
|   data() { | ||||
|     return { | ||||
|       dialogVisible: false, | ||||
|       isScrool: true, | ||||
|       isEmpty: true | ||||
|       dialog: false, | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   watch: { | ||||
|     visible: { | ||||
|       handler(val) { | ||||
|         this.dialogVisible = val | ||||
|  | ||||
|         // if (val) { | ||||
|         // 	this.$nextTick(() => { | ||||
|         // 		setTimeout(() => { | ||||
|         // 			this.isScrool = document.querySelector('.ai-dialog__content') && document.querySelector('.ai-dialog__content').clientHeight >= 500 | ||||
|         // 		}, 100) | ||||
|         // 	}) | ||||
|         // } | ||||
|  | ||||
|         if (this.destroyOnClose && !val) { | ||||
|           setTimeout(() => { | ||||
|             this.isEmpty = false | ||||
|  | ||||
|             setTimeout(() => { | ||||
|               this.isEmpty = true | ||||
|             }, 50) | ||||
|           }, 500) | ||||
|         } | ||||
|       } | ||||
|     dialog(v) { | ||||
|       this.visible != v && this.$emit("input", v) | ||||
|     }, | ||||
|     visible(v) { | ||||
|       this.dialog = v | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   mounted() { | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     onCancel() { | ||||
|       this.$emit('update:visible', false) | ||||
|       this.$emit('onCancel') | ||||
|       this.dialog = false | ||||
|       this.$emit('cancel') | ||||
|     }, | ||||
|  | ||||
|     onConfirm() { | ||||
|       this.$emit('onConfirm') | ||||
|       this.$emit('confirm') | ||||
|     } | ||||
|     }, | ||||
|     initDraggable() { | ||||
|       const dialogHeaderEl = this.$el.querySelector('.el-dialog__header') | ||||
|       const dragDom = this.$el.querySelector('.el-dialog') | ||||
|       const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null) | ||||
|  | ||||
|       dialogHeaderEl.onmousedown = e => { | ||||
|         console.log(e) | ||||
|         // 鼠标按下,获得鼠标在盒子内的坐标(鼠标在页面的坐标 减去 对话框的坐标),计算当前元素距离可视区的距离 | ||||
|         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/g, '') | ||||
|           styT = +sty.top.replace(/px/g, '') | ||||
|         } | ||||
|         document.onmousemove = function (e) { | ||||
|           // 鼠标移动,用鼠标在页面的坐标 减去 鼠标在盒子里的坐标,获得模态框的left和top值 | ||||
|           // 通过事件委托,计算移动的距离 | ||||
|           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 () { | ||||
|           //  鼠标弹起,移除鼠标移动事件 | ||||
|           document.onmousemove = null | ||||
|           document.onmouseup = null | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.isDrag && this.initDraggable() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| <style lang="scss"> | ||||
| .ai-dialog { | ||||
|   margin: 0 !important; | ||||
|   margin: unset !important; | ||||
|   top: 50%; | ||||
|   left: 50%; | ||||
|   transform: translate(-50%, -50%); | ||||
| @@ -118,11 +109,12 @@ export default { | ||||
|   .ai-dialog__content { | ||||
|     overflow-y: auto; | ||||
|     padding-bottom: 4px; | ||||
|     max-height: 500px; | ||||
|  | ||||
|     .ai-dialog__content--wrapper { | ||||
|       height: 100%; | ||||
|       overflow-x: hidden; | ||||
|       overflow-y: overlay; | ||||
|       overflow-y: auto; | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @@ -130,12 +122,9 @@ export default { | ||||
|     height: 48px; | ||||
|     line-height: 48px; | ||||
|     padding: 0 16px; | ||||
|     border-bottom: 1px solid #eee; | ||||
|  | ||||
|     h2 { | ||||
|       font-size: 16px; | ||||
|       font-weight: 700; | ||||
|     } | ||||
|     cursor: move; | ||||
|     font-size: 16px; | ||||
|     font-weight: 700; | ||||
|   } | ||||
|  | ||||
|   .el-dialog__footer { | ||||
| @@ -155,11 +144,17 @@ export default { | ||||
|  | ||||
|   .el-dialog__header { | ||||
|     padding: 0; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     border-bottom: 1px solid #eee; | ||||
|   } | ||||
|  | ||||
|   .el-dialog__headerbtn { | ||||
|     top: 24px; | ||||
|     transform: translateY(-50%); | ||||
|     position: relative; | ||||
|     flex-shrink: 0; | ||||
|     top: unset; | ||||
|     right: unset; | ||||
|     margin: 0 16px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user