parent
986f909628
commit
664413e5d7
@ -0,0 +1,242 @@
|
|||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
ref="modal"
|
||||||
|
:class="getClass(modalClass)"
|
||||||
|
:style="getStyle(modalStyle)"
|
||||||
|
:visible="visible"
|
||||||
|
v-bind="_attrs"
|
||||||
|
v-on="$listeners"
|
||||||
|
@ok="handleOk"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
destroyOnClose
|
||||||
|
>
|
||||||
|
|
||||||
|
<slot></slot>
|
||||||
|
<!--有设置标题-->
|
||||||
|
<template v-if="!isNoTitle" slot="title">
|
||||||
|
<a-row class="j-modal-title-row" type="flex">
|
||||||
|
<a-col class="left">
|
||||||
|
<slot name="title">{{ title }}</slot>
|
||||||
|
</a-col>
|
||||||
|
<a-col v-if="switchFullscreen" class="right" @click="toggleFullscreen">
|
||||||
|
<a-button class="ant-modal-close ant-modal-close-x" ghost type="link" :icon="fullscreenButtonIcon"/>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</template>
|
||||||
|
<!--没有设置标题-->
|
||||||
|
<template v-else slot="title">
|
||||||
|
<a-row class="j-modal-title-row" type="flex">
|
||||||
|
<a-col v-if="switchFullscreen" class="right" @click="toggleFullscreen">
|
||||||
|
<a-button class="ant-modal-close ant-modal-close-x" ghost type="link" :icon="fullscreenButtonIcon"/>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 处理 scopedSlots -->
|
||||||
|
<template v-for="slotName of scopedSlotsKeys" :slot="slotName">
|
||||||
|
<slot :name="slotName"></slot>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 处理 slots -->
|
||||||
|
<template v-for="slotName of slotsKeys" v-slot:[slotName]>
|
||||||
|
<slot :name="slotName"></slot>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import { getClass, getStyle } from '@/utils/props-util'
|
||||||
|
import { triggerWindowResizeEvent } from '@/utils/util'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JModal',
|
||||||
|
props: {
|
||||||
|
title: String,
|
||||||
|
// 可使用 .sync 修饰符
|
||||||
|
visible: Boolean,
|
||||||
|
// 是否全屏弹窗,当全屏时无论如何都会禁止 body 滚动。可使用 .sync 修饰符
|
||||||
|
fullscreen: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否允许切换全屏(允许后右上角会出现一个按钮)
|
||||||
|
switchFullscreen: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 点击确定按钮的时候是否关闭弹窗
|
||||||
|
okClose: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 内部使用的 slots ,不再处理
|
||||||
|
usedSlots: ['title'],
|
||||||
|
// 实际控制是否全屏的参数
|
||||||
|
innerFullscreen: this.fullscreen,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 一些未处理的参数或特殊处理的参数绑定到 a-modal 上
|
||||||
|
_attrs() {
|
||||||
|
let attrs = { ...this.$attrs }
|
||||||
|
// 如果全屏就将宽度设为 100%
|
||||||
|
if (this.innerFullscreen) {
|
||||||
|
attrs['width'] = '100%'
|
||||||
|
}
|
||||||
|
return attrs
|
||||||
|
},
|
||||||
|
modalClass() {
|
||||||
|
return {
|
||||||
|
'j-modal-box': true,
|
||||||
|
'fullscreen': this.innerFullscreen,
|
||||||
|
'no-title': this.isNoTitle,
|
||||||
|
'no-footer': this.isNoFooter,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modalStyle() {
|
||||||
|
let style = {}
|
||||||
|
// 如果全屏就将top设为 0
|
||||||
|
if (this.innerFullscreen) {
|
||||||
|
style['top'] = '0'
|
||||||
|
}
|
||||||
|
return style
|
||||||
|
},
|
||||||
|
isNoTitle() {
|
||||||
|
return !this.title && !this.allSlotsKeys.includes('title')
|
||||||
|
},
|
||||||
|
isNoFooter() {
|
||||||
|
return this._attrs['footer'] === null
|
||||||
|
},
|
||||||
|
slotsKeys() {
|
||||||
|
return Object.keys(this.$slots).filter(key => !this.usedSlots.includes(key))
|
||||||
|
},
|
||||||
|
scopedSlotsKeys() {
|
||||||
|
return Object.keys(this.$scopedSlots).filter(key => !this.usedSlots.includes(key))
|
||||||
|
},
|
||||||
|
allSlotsKeys() {
|
||||||
|
return Object.keys(this.$slots).concat(Object.keys(this.$scopedSlots))
|
||||||
|
},
|
||||||
|
// 切换全屏的按钮图标
|
||||||
|
fullscreenButtonIcon() {
|
||||||
|
return this.innerFullscreen ? 'fullscreen-exit' : 'fullscreen'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
visible() {
|
||||||
|
if (this.visible) {
|
||||||
|
this.innerFullscreen = this.fullscreen
|
||||||
|
}
|
||||||
|
},
|
||||||
|
innerFullscreen(val) {
|
||||||
|
this.$emit('update:fullscreen', val)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
getClass(clazz) {
|
||||||
|
return { ...getClass(this), ...clazz }
|
||||||
|
},
|
||||||
|
getStyle(style) {
|
||||||
|
return { ...getStyle(this), ...style }
|
||||||
|
},
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.$emit('update:visible', false)
|
||||||
|
},
|
||||||
|
|
||||||
|
handleOk() {
|
||||||
|
if (this.okClose) {
|
||||||
|
this.close()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleCancel() {
|
||||||
|
this.close()
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 切换全屏 */
|
||||||
|
toggleFullscreen() {
|
||||||
|
this.innerFullscreen = !this.innerFullscreen
|
||||||
|
triggerWindowResizeEvent()
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
|
||||||
|
.j-modal-box {
|
||||||
|
&.fullscreen {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
// 兼容1.6.2版本的antdv
|
||||||
|
& .ant-modal {
|
||||||
|
top: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .ant-modal-content {
|
||||||
|
height: 100vh;
|
||||||
|
border-radius: 0;
|
||||||
|
|
||||||
|
& .ant-modal-body {
|
||||||
|
/* title 和 footer 各占 55px */
|
||||||
|
height: calc(100% - 55px - 55px);
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.no-title, &.no-footer {
|
||||||
|
.ant-modal-body {
|
||||||
|
height: calc(100% - 55px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.no-title.no-footer {
|
||||||
|
.ant-modal-body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.j-modal-title-row {
|
||||||
|
.left {
|
||||||
|
width: calc(100% - 56px - 56px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
width: 56px;
|
||||||
|
position: inherit;
|
||||||
|
|
||||||
|
.ant-modal-close {
|
||||||
|
right: 56px;
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: rgba(0, 0, 0, 0.75);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.no-title{
|
||||||
|
.ant-modal-header {
|
||||||
|
padding: 0px 24px;
|
||||||
|
border-bottom: 0px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.j-modal-box.fullscreen {
|
||||||
|
margin: 0;
|
||||||
|
max-width: 100vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,124 @@
|
|||||||
|
<template>
|
||||||
|
<j-modal :visible="visible" :confirmLoading="loading" :after-close="afterClose" v-bind="modalProps" @ok="onOk" @cancel="onCancel">
|
||||||
|
<a-spin :spinning="loading">
|
||||||
|
<div v-html="content"></div>
|
||||||
|
<a-form-model ref="form" :model="model" :rules="rules">
|
||||||
|
<a-form-model-item prop="input">
|
||||||
|
<a-input ref="input" v-model="model.input" v-bind="inputProps" @pressEnter="onInputPressEnter"/>
|
||||||
|
</a-form-model-item>
|
||||||
|
</a-form-model>
|
||||||
|
</a-spin>
|
||||||
|
</j-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import pick from 'lodash.pick'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JPrompt',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
loading: false,
|
||||||
|
content: '',
|
||||||
|
// 弹窗参数
|
||||||
|
modalProps: {
|
||||||
|
title: '',
|
||||||
|
},
|
||||||
|
inputProps: {
|
||||||
|
placeholder: '',
|
||||||
|
},
|
||||||
|
// form model
|
||||||
|
model: {
|
||||||
|
input: '',
|
||||||
|
},
|
||||||
|
// 校验
|
||||||
|
rule: [],
|
||||||
|
// 回调函数
|
||||||
|
callback: {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
rules() {
|
||||||
|
return {
|
||||||
|
input: this.rule
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
show(options) {
|
||||||
|
this.content = options.content
|
||||||
|
if (Array.isArray(options.rule)) {
|
||||||
|
this.rule = options.rule
|
||||||
|
}
|
||||||
|
if (options.defaultValue != null) {
|
||||||
|
this.model.input = options.defaultValue
|
||||||
|
}
|
||||||
|
// 取出常用的弹窗参数
|
||||||
|
let pickModalProps = pick(options, 'title', 'centered', 'cancelText', 'closable', 'mask', 'maskClosable', 'okText', 'okType', 'okButtonProps', 'cancelButtonProps', 'width', 'wrapClassName', 'zIndex', 'dialogStyle', 'dialogClass')
|
||||||
|
this.modalProps = Object.assign({}, pickModalProps, options.modalProps)
|
||||||
|
// 取出常用的input参数
|
||||||
|
let pickInputProps = pick(options, 'placeholder', 'allowClear')
|
||||||
|
this.inputProps = Object.assign({}, pickInputProps, options.inputProps)
|
||||||
|
// 回调函数
|
||||||
|
this.callback = pick(options, 'onOk', 'onOkAsync', 'onCancel')
|
||||||
|
this.visible = true
|
||||||
|
this.$nextTick(() => this.$refs.input.focus())
|
||||||
|
},
|
||||||
|
|
||||||
|
onOk() {
|
||||||
|
this.$refs.form.validate((ok, err) => {
|
||||||
|
if (ok) {
|
||||||
|
let event = {value: this.model.input, target: this}
|
||||||
|
// 异步方法优先级高于同步方法
|
||||||
|
if (typeof this.callback.onOkAsync === 'function') {
|
||||||
|
this.callback.onOkAsync(event)
|
||||||
|
} else if (typeof this.callback.onOk === 'function') {
|
||||||
|
this.callback.onOk(event)
|
||||||
|
this.close()
|
||||||
|
} else {
|
||||||
|
this.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onCancel() {
|
||||||
|
if (typeof this.callback.onCancel === 'function') {
|
||||||
|
this.callback.onCancel(this.model.input)
|
||||||
|
}
|
||||||
|
this.close()
|
||||||
|
},
|
||||||
|
|
||||||
|
onInputPressEnter() {
|
||||||
|
this.onOk()
|
||||||
|
},
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.visible = this.loading ? this.visible : false
|
||||||
|
},
|
||||||
|
|
||||||
|
forceClose() {
|
||||||
|
this.visible = false
|
||||||
|
},
|
||||||
|
|
||||||
|
showLoading() {
|
||||||
|
this.loading = true
|
||||||
|
},
|
||||||
|
hideLoading() {
|
||||||
|
this.loading = false
|
||||||
|
},
|
||||||
|
|
||||||
|
afterClose(e) {
|
||||||
|
if (typeof this.modalProps.afterClose === 'function') {
|
||||||
|
this.modalProps.afterClose(e)
|
||||||
|
}
|
||||||
|
this.$emit('after-close', e)
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
import JModal from './JModal'
|
||||||
|
import JPrompt from './JPrompt'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
install(Vue) {
|
||||||
|
Vue.component(JModal.name, JModal)
|
||||||
|
|
||||||
|
const JPromptExtend = Vue.extend(JPrompt)
|
||||||
|
Vue.prototype.$JPrompt = function (options = {}) {
|
||||||
|
// 创建prompt实例
|
||||||
|
const vm = new JPromptExtend().$mount()
|
||||||
|
vm.show(options)
|
||||||
|
// 关闭后销毁
|
||||||
|
vm.$on('after-close', () => vm.$destroy())
|
||||||
|
return vm
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
Loading…
Reference in new issue