mirror of
https://github.com/kuaifan/dootask.git
synced 2026-02-27 20:30:32 +00:00
perf: DrawerOverlay 使用 Model
This commit is contained in:
parent
6610a948c5
commit
6e8ee60df0
@ -62,7 +62,7 @@ export default {
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['userId', 'userToken', 'cacheDrawerOverlay']),
|
||||
...mapState(['userId', 'userToken']),
|
||||
},
|
||||
|
||||
watch: {
|
||||
@ -221,10 +221,6 @@ export default {
|
||||
if (this.$Modal.removeLast()) {
|
||||
return true;
|
||||
}
|
||||
if (this.cacheDrawerOverlay.length > 0) {
|
||||
this.cacheDrawerOverlay[this.cacheDrawerOverlay.length - 1].close();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
this.$Electron.registerMsgListener('dispatch', args => {
|
||||
if (!$A.isJson(args)) {
|
||||
|
||||
@ -1,177 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
v-transfer-dom
|
||||
:data-transfer="transfer"
|
||||
:class="['drawer-overlay', placement, value ? 'overlay-visible' : 'overlay-hide']"
|
||||
:style="overlayStyle">
|
||||
<div class="overlay-mask" @click="mask"></div>
|
||||
<div class="overlay-body" :style="bodyStyle">
|
||||
<div class="overlay-close">
|
||||
<a href="javascript:void(0)" @click.stop="close">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26" fill="none" role="img" class="icon fill-current">
|
||||
<path d="M8.28596 6.51819C7.7978 6.03003 7.00634 6.03003 6.51819 6.51819C6.03003 7.00634 6.03003 7.7978 6.51819 8.28596L11.2322 13L6.51819 17.714C6.03003 18.2022 6.03003 18.9937 6.51819 19.4818C7.00634 19.97 7.7978 19.97 8.28596 19.4818L13 14.7678L17.714 19.4818C18.2022 19.97 18.9937 19.97 19.4818 19.4818C19.97 18.9937 19.97 18.2022 19.4818 17.714L14.7678 13L19.4818 8.28596C19.97 7.7978 19.97 7.00634 19.4818 6.51819C18.9937 6.03003 18.2022 6.03003 17.714 6.51819L13 11.2322L8.28596 6.51819Z" fill="currentColor"></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<ResizeLine v-if="resize" class="overlay-resize" :placement="placement" v-model="dynamicSize" :min="minSize" :max="0" reverse/>
|
||||
<div class="overlay-content"><slot/></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ResizeLine from "./ResizeLine";
|
||||
import TransferDom from '../directives/transfer-dom';
|
||||
import {mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
name: 'DrawerOverlay',
|
||||
components: {ResizeLine},
|
||||
directives: { TransferDom },
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
maskClosable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
escClosable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
placement: {
|
||||
validator (value) {
|
||||
return ['right', 'bottom'].includes(value)
|
||||
},
|
||||
default: 'bottom'
|
||||
},
|
||||
size: {
|
||||
type: [Number, String],
|
||||
default: "100%"
|
||||
},
|
||||
minSize: {
|
||||
type: Number,
|
||||
default: 300
|
||||
},
|
||||
resize: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
transfer: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
beforeClose: Function
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
dynamicSize: 0,
|
||||
zIndex: 0,
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
document.addEventListener('keydown', this.escClose);
|
||||
},
|
||||
|
||||
beforeDestroy () {
|
||||
document.removeEventListener('keydown', this.escClose);
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['cacheDrawerIndex']),
|
||||
|
||||
overlayStyle() {
|
||||
return {
|
||||
zIndex: 1000 + this.zIndex
|
||||
}
|
||||
},
|
||||
|
||||
bodyStyle() {
|
||||
let size = this.dynamicSize;
|
||||
size = size <= 100 ? `${size}%` : `${size}px`
|
||||
if (this.placement == 'right') {
|
||||
return {
|
||||
width: size,
|
||||
height: "100%"
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
width: "100%",
|
||||
height: size,
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
value(val) {
|
||||
if (this._uid) {
|
||||
const index = this.$store.state.cacheDrawerOverlay.findIndex(({_uid}) => _uid === this._uid);
|
||||
if (val && index === -1) {
|
||||
this.$store.state.cacheDrawerOverlay.push({
|
||||
_uid: this._uid,
|
||||
close: this.close
|
||||
});
|
||||
}
|
||||
if (!val && index > -1) {
|
||||
this.$store.state.cacheDrawerOverlay.splice(index, 1);
|
||||
}
|
||||
}
|
||||
//
|
||||
if (val) {
|
||||
this.zIndex = this.$store.state.cacheDrawerIndex++;
|
||||
} else if (this.$store.state.cacheDrawerOverlay.length === 0) {
|
||||
this.$store.state.cacheDrawerIndex = 0;
|
||||
}
|
||||
},
|
||||
size: {
|
||||
handler(val) {
|
||||
this.dynamicSize = parseInt(val);
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
mask() {
|
||||
if (this.maskClosable) {
|
||||
this.close()
|
||||
}
|
||||
},
|
||||
close() {
|
||||
if (!this.beforeClose) {
|
||||
return this.handleClose();
|
||||
}
|
||||
|
||||
const before = this.beforeClose();
|
||||
|
||||
if (before && before.then) {
|
||||
before.then(this.handleClose);
|
||||
} else {
|
||||
this.handleClose();
|
||||
}
|
||||
},
|
||||
handleClose () {
|
||||
this.$emit("input", false)
|
||||
},
|
||||
escClose(e) {
|
||||
if (this.value && this.escClosable) {
|
||||
if (e.keyCode === 27) {
|
||||
if (this.$Modal.visibles().length > 0) {
|
||||
return;
|
||||
}
|
||||
const list = this.$store.state.cacheDrawerOverlay;
|
||||
if (list.length > 0) {
|
||||
const $Drawer = list[list.length - 1]
|
||||
$Drawer.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
81
resources/assets/js/components/DrawerOverlay/index.vue
Normal file
81
resources/assets/js/components/DrawerOverlay/index.vue
Normal file
@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<Modal
|
||||
ref="modal"
|
||||
v-model="show"
|
||||
:closable="escClosable"
|
||||
:mask-closable="maskClosable"
|
||||
:footer-hide="true"
|
||||
:transition-names="[`drawer-fade-${placement}`, '']"
|
||||
:beforeClose="beforeClose"
|
||||
fullscreen
|
||||
:class-name="`common-drawer-overlay ${placement}`">
|
||||
<DrawerOverlayView
|
||||
:placement="placement"
|
||||
:size="size"
|
||||
:minSize="minSize"
|
||||
:resize="resize"
|
||||
@on-close="onClose">
|
||||
<slot/>
|
||||
</DrawerOverlayView>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DrawerOverlayView from "./view";
|
||||
|
||||
export default {
|
||||
name: 'DrawerOverlay',
|
||||
components: {DrawerOverlayView},
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
maskClosable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
escClosable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
placement: {
|
||||
validator (value) {
|
||||
return ['right', 'bottom'].includes(value)
|
||||
},
|
||||
default: 'bottom'
|
||||
},
|
||||
size: {
|
||||
type: [Number, String],
|
||||
default: "100%"
|
||||
},
|
||||
minSize: {
|
||||
type: Number,
|
||||
default: 300
|
||||
},
|
||||
resize: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
beforeClose: Function
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: this.value,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(v) {
|
||||
this.show = v;
|
||||
},
|
||||
show(v) {
|
||||
this.value !== v && this.$emit("input", v)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onClose() {
|
||||
this.$refs.modal.close();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
113
resources/assets/js/components/DrawerOverlay/view.vue
Normal file
113
resources/assets/js/components/DrawerOverlay/view.vue
Normal file
@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<div ref="body" class="overlay-body" :style="bodyStyle">
|
||||
<div class="overlay-close">
|
||||
<a href="javascript:void(0)" @click.stop="onClose">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26" fill="none" role="img" class="icon fill-current">
|
||||
<path d="M8.28596 6.51819C7.7978 6.03003 7.00634 6.03003 6.51819 6.51819C6.03003 7.00634 6.03003 7.7978 6.51819 8.28596L11.2322 13L6.51819 17.714C6.03003 18.2022 6.03003 18.9937 6.51819 19.4818C7.00634 19.97 7.7978 19.97 8.28596 19.4818L13 14.7678L17.714 19.4818C18.2022 19.97 18.9937 19.97 19.4818 19.4818C19.97 18.9937 19.97 18.2022 19.4818 17.714L14.7678 13L19.4818 8.28596C19.97 7.7978 19.97 7.00634 19.4818 6.51819C18.9937 6.03003 18.2022 6.03003 17.714 6.51819L13 11.2322L8.28596 6.51819Z" fill="currentColor"></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<ResizeLine
|
||||
v-if="resize"
|
||||
class="overlay-resize"
|
||||
v-model="dynamicSize"
|
||||
:placement="placement"
|
||||
:min="minSize"
|
||||
:max="0"
|
||||
:reverse="true"
|
||||
:beforeResize="beforeResize"
|
||||
@on-change="onChangeResize"/>
|
||||
<div class="overlay-content"><slot/></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ResizeLine from "../ResizeLine";
|
||||
|
||||
export default {
|
||||
name: 'DrawerOverlayView',
|
||||
components: {ResizeLine},
|
||||
props: {
|
||||
placement: {
|
||||
validator (value) {
|
||||
return ['right', 'bottom'].includes(value)
|
||||
},
|
||||
default: 'bottom'
|
||||
},
|
||||
size: {
|
||||
type: [Number, String],
|
||||
default: "100%"
|
||||
},
|
||||
minSize: {
|
||||
type: Number,
|
||||
default: 300
|
||||
},
|
||||
resize: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
dynamicSize: 0,
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
bodyStyle() {
|
||||
let size = this.dynamicSize;
|
||||
size = size <= 100 ? `${size}%` : `${size}px`
|
||||
if (this.placement == 'right') {
|
||||
return {
|
||||
width: size,
|
||||
height: "100%"
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
width: "100%",
|
||||
height: size,
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
size: {
|
||||
handler(val) {
|
||||
this.dynamicSize = parseInt(val);
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onClose() {
|
||||
this.$emit("on-close")
|
||||
},
|
||||
|
||||
beforeResize() {
|
||||
return new Promise(resolve => {
|
||||
if (this.dynamicSize <= 100) {
|
||||
this.updateSize();
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
|
||||
onChangeResize({event}) {
|
||||
if (event === 'up') {
|
||||
this.updateSize();
|
||||
}
|
||||
},
|
||||
|
||||
updateSize() {
|
||||
if (this.placement === 'bottom') {
|
||||
this.dynamicSize = this.$refs.body.clientHeight;
|
||||
} else {
|
||||
this.dynamicSize = this.$refs.body.clientWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -39,8 +39,6 @@ export default {
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['cacheDrawerOverlay']),
|
||||
|
||||
style() {
|
||||
return {
|
||||
top: this.y + 'px',
|
||||
@ -79,20 +77,13 @@ export default {
|
||||
if (!this.showTabbar) {
|
||||
return true;
|
||||
}
|
||||
if (this.$Modal.visibles().length > 0) {
|
||||
return true;
|
||||
}
|
||||
return this.cacheDrawerOverlay.length > 0;
|
||||
return this.$Modal.visibles().length > 0;
|
||||
},
|
||||
|
||||
onBack() {
|
||||
if (this.$Modal.removeLast()) {
|
||||
return;
|
||||
}
|
||||
if (this.cacheDrawerOverlay.length > 0) {
|
||||
this.cacheDrawerOverlay[this.cacheDrawerOverlay.length - 1].close();
|
||||
return;
|
||||
}
|
||||
this.goBack();
|
||||
},
|
||||
|
||||
|
||||
4
resources/assets/js/store/state.js
vendored
4
resources/assets/js/store/state.js
vendored
@ -12,10 +12,6 @@ const stateData = {
|
||||
// 数据缓存
|
||||
cacheLoading: {},
|
||||
|
||||
// DrawerOverlay
|
||||
cacheDrawerIndex: 0,
|
||||
cacheDrawerOverlay: [],
|
||||
|
||||
// User
|
||||
cacheUserActive: {},
|
||||
cacheUserWait: [],
|
||||
|
||||
134
resources/assets/sass/components/drawer-overlay.scss
vendored
134
resources/assets/sass/components/drawer-overlay.scss
vendored
@ -1,26 +1,23 @@
|
||||
.drawer-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
z-index: 1000;
|
||||
box-sizing: border-box;
|
||||
pointer-events: none;
|
||||
background: rgba(10, 10, 10, 0.76);
|
||||
outline: none;
|
||||
opacity: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
.common-drawer-overlay {
|
||||
.ivu-modal {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
.overlay-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
.ivu-modal-content {
|
||||
background: transparent;
|
||||
|
||||
.ivu-modal-close {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ivu-modal-body {
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
align-content: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.overlay-body {
|
||||
@ -37,22 +34,27 @@
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-end;
|
||||
|
||||
> a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
color: #dbdbde;
|
||||
color: #fff;
|
||||
|
||||
.icon {
|
||||
width: 24px;
|
||||
height: 24px
|
||||
}
|
||||
|
||||
> svg {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
|
||||
> svg {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
@ -72,71 +74,65 @@
|
||||
position: relative;
|
||||
background: #fff;
|
||||
border-radius: 18px 18px 0 0;
|
||||
transform: translate(0, 15%) scale(0.98);
|
||||
transform: translate(0, 0) scale(1);
|
||||
cursor: default;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.overlay-visible {
|
||||
pointer-events: auto;
|
||||
opacity: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: opacity 0.2s ease;
|
||||
.overlay-body {
|
||||
.overlay-content {
|
||||
opacity: 1;
|
||||
transform: translate(0, 0) scale(1);
|
||||
transition: opacity 0.2s ease, transform 0.3s ease;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.overlay-hide {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: opacity 0.2s ease;
|
||||
.overlay-body {
|
||||
.overlay-content {
|
||||
transform: translate(0, 15%) scale(0.98);
|
||||
transition: opacity 0.2s ease, transform 0.2s ease
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.right {
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
.ivu-modal {
|
||||
.ivu-modal-content {
|
||||
.ivu-modal-body {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.overlay-body {
|
||||
flex-direction: row;
|
||||
|
||||
.overlay-close {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.overlay-resize {
|
||||
width: 5px;
|
||||
height: 100%;
|
||||
margin-right: -5px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.overlay-content {
|
||||
transform: translate(15%, 0) scale(0.98);
|
||||
border-radius: 18px 0 0 18px;
|
||||
}
|
||||
}
|
||||
&.overlay-visible {
|
||||
.overlay-body {
|
||||
.overlay-content {
|
||||
transform: translate(0, 0) scale(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
&.overlay-hide {
|
||||
.overlay-body {
|
||||
.overlay-content {
|
||||
transform: translate(15%, 0) scale(0.98);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-fade-bottom-enter-active {
|
||||
transition: all .2s ease;
|
||||
}
|
||||
|
||||
.drawer-fade-bottom-leave-active {
|
||||
transition: all .2s ease;
|
||||
}
|
||||
|
||||
.drawer-fade-bottom-enter,
|
||||
.drawer-fade-bottom-leave-to {
|
||||
transform: translate(0, 15%) scale(0.98);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.drawer-fade-right-enter-active {
|
||||
transition: all .2s ease;
|
||||
}
|
||||
|
||||
.drawer-fade-right-leave-active {
|
||||
transition: all .2s ease;
|
||||
}
|
||||
|
||||
.drawer-fade-right-enter,
|
||||
.drawer-fade-right-leave-to {
|
||||
transform: translate(15%, 0) scale(0.98);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user