Componentize modal (#5386)

This commit is contained in:
Aya Morisawa 2019-10-29 09:51:19 +09:00 committed by syuilo
parent 34c82776fc
commit bf654c6f42
6 changed files with 188 additions and 223 deletions

View file

@ -1,6 +1,12 @@
<template>
<div class="felqjxyj" :class="{ splash }">
<div class="bg" ref="bg" @click="onBgClick"></div>
<ui-modal
ref="modal"
class="modal"
:class="{ splash }"
:close-anime-duration="300"
:close-on-bg-click="false"
@bg-click="onBgClick"
@before-close="onBeforeClose">
<div class="main" ref="main" :class="{ round: $store.state.device.roundedCorners }">
<template v-if="type == 'signin'">
<mk-signin/>
@ -38,7 +44,7 @@
</ui-horizon-group>
</template>
</div>
</div>
</ui-modal>
</template>
<script lang="ts">
@ -120,14 +126,6 @@ export default Vue.extend({
if (this.user) this.canOk = false;
this.$nextTick(() => {
(this.$refs.bg as any).style.pointerEvents = 'auto';
anime({
targets: this.$refs.bg,
opacity: 1,
duration: 100,
easing: 'linear'
});
anime({
targets: this.$refs.main,
opacity: 1,
@ -170,33 +168,27 @@ export default Vue.extend({
this.close();
},
onBgClick() {
if (this.cancelableByBgClick) this.cancel();
}
close() {
this.$refs.modal.close();
},
onBeforeClose() {
this.$el.style.pointerEvents = 'none';
(this.$refs.bg as any).style.pointerEvents = 'none';
(this.$refs.main as any).style.pointerEvents = 'none';
anime({
targets: this.$refs.bg,
opacity: 0,
duration: 300,
easing: 'linear'
});
anime({
targets: this.$refs.main,
opacity: 0,
scale: 0.8,
duration: 300,
easing: 'cubicBezier(0, 0.5, 0.5, 1)',
complete: () => this.destroyDom()
});
},
onBgClick() {
if (this.cancelableByBgClick) {
this.cancel();
}
},
onInputKeydown(e) {
if (e.which == 13) { // Enter
e.preventDefault();
@ -209,34 +201,17 @@ export default Vue.extend({
</script>
<style lang="stylus" scoped>
.felqjxyj
.modal
display flex
align-items center
justify-content center
position fixed
z-index 30000
top 0
left 0
width 100%
height 100%
&.splash
> .main
min-width 0
width initial
> .bg
display block
position fixed
top 0
left 0
width 100%
height 100%
background rgba(#000, 0.7)
opacity 0
pointer-events none
> .main
.main
display block
position fixed
margin auto

View file

@ -1,24 +1,14 @@
<template>
<div class="dkjvrdxtkvqrwmhfickhndpmnncsgacq" v-hotkey.global="keymap">
<div class="bg" @click="close"></div>
<img :src="image.url" :alt="image.name" :title="image.name" @click="close"/>
</div>
<ui-modal ref="modal" v-hotkey.global="keymap">
<img :src="image.url" :alt="image.name" :title="image.name" @click="close" />
</ui-modal>
</template>
<script lang="ts">
import Vue from 'vue';
import anime from 'animejs';
export default Vue.extend({
props: ['image'],
mounted() {
anime({
targets: this.$el,
opacity: 1,
duration: 100,
easing: 'linear'
});
},
computed: {
keymap(): any {
return {
@ -28,40 +18,14 @@ export default Vue.extend({
},
methods: {
close() {
anime({
targets: this.$el,
opacity: 0,
duration: 100,
easing: 'linear',
complete: () => this.destroyDom()
});
(this.$refs.modal as any).close();
}
}
});
</script>
<style lang="stylus" scoped>
.dkjvrdxtkvqrwmhfickhndpmnncsgacq
display block
position fixed
z-index 2048
top 0
left 0
width 100%
height 100%
opacity 0
> .bg
display block
position fixed
z-index 1
top 0
left 0
width 100%
height 100%
background rgba(#000, 0.7)
> img
img
position fixed
z-index 2
top 0

View file

@ -47,6 +47,7 @@ import uiInfo from './ui/info.vue';
import uiMargin from './ui/margin.vue';
import uiHr from './ui/hr.vue';
import uiPagination from './ui/pagination.vue';
import uiModal from './ui/modal.vue';
import formButton from './ui/form/button.vue';
import formRadio from './ui/form/radio.vue';
@ -97,5 +98,6 @@ Vue.component('ui-info', uiInfo);
Vue.component('ui-margin', uiMargin);
Vue.component('ui-hr', uiHr);
Vue.component('ui-pagination', uiPagination);
Vue.component('ui-modal', uiModal);
Vue.component('form-button', formButton);
Vue.component('form-radio', formRadio);

View file

@ -0,0 +1,80 @@
<template>
<div class="modal">
<div class="bg" ref="bg" @click="onBgClick" />
<slot class="main" />
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import anime from 'animejs';
export default Vue.extend({
props: {
closeOnBgClick: {
type: Boolean,
required: false,
default: true
},
openAnimeDuration: {
type: Number,
required: false,
default: 100
},
closeAnimeDuration: {
type: Number,
required: false,
default: 100
}
},
mounted() {
anime({
targets: this.$refs.bg,
opacity: 1,
duration: this.openAnimeDuration,
easing: 'linear'
});
},
methods: {
onBgClick() {
this.$emit('bg-click');
if (this.closeOnBgClick) this.close();
},
close() {
this.$emit('before-close');
anime({
targets: this.$refs.bg,
opacity: 0,
duration: this.closeAnimeDuration,
easing: 'linear',
complete: () => (this as any).destroyDom()
});
}
}
});
</script>
<style lang="stylus" scoped>
.modal
position fixed
z-index 2048
top 0
left 0
width 100%
height 100%
.bg
display block
position fixed
z-index 1
top 0
left 0
width 100%
height 100%
background rgba(#000, 0.7)
opacity 0
.main
z-index 1
</style>

View file

@ -1,23 +1,15 @@
<template>
<div class="mk-media-video-dialog" v-hotkey.global="keymap">
<div class="bg" @click="close"></div>
<video :src="video.url" :title="video.name" controls autoplay ref="video" @volumechange="volumechange"/>
</div>
<ui-modal v-hotkey.global="keymap">
<video :src="video.url" :title="video.name" controls autoplay ref="video" @volumechange="volumechange" />
</ui-modal>
</template>
<script lang="ts">
import Vue from 'vue';
import anime from 'animejs';
export default Vue.extend({
props: ['video', 'start'],
mounted() {
anime({
targets: this.$el,
opacity: 1,
duration: 100,
easing: 'linear'
});
const videoTag = this.$refs.video as HTMLVideoElement;
if (this.start) videoTag.currentTime = this.start
videoTag.volume = this.$store.state.device.mediaVolume;
@ -31,13 +23,6 @@ export default Vue.extend({
},
methods: {
close() {
anime({
targets: this.$el,
opacity: 0,
duration: 100,
easing: 'linear',
complete: () => this.destroyDom()
});
},
volumechange() {
const videoTag = this.$refs.video as HTMLVideoElement;
@ -48,27 +33,7 @@ export default Vue.extend({
</script>
<style lang="stylus" scoped>
.mk-media-video-dialog
display block
position fixed
z-index 2048
top 0
left 0
width 100%
height 100%
opacity 0
> .bg
display block
position fixed
z-index 1
top 0
left 0
width 100%
height 100%
background rgba(#000, 0.7)
> video
video
position fixed
z-index 2
top 0

View file

@ -1,6 +1,9 @@
<template>
<div class="ulveipglmagnxfgvitaxyszerjwiqmwl">
<div class="bg" ref="bg"></div>
<ui-modal
ref="modal"
:close-on-bg-click="false"
:close-anime-duration="300"
@before-close="onBeforeClose">
<div class="main" ref="main">
<x-post-form ref="form"
:reply="reply"
@ -12,7 +15,7 @@
@posted="onPosted"
@cancel="onCanceled"/>
</div>
</div>
</ui-modal>
</template>
<script lang="ts">
@ -55,14 +58,6 @@ export default Vue.extend({
mounted() {
this.$nextTick(() => {
(this.$refs.bg as any).style.pointerEvents = 'auto';
anime({
targets: this.$refs.bg,
opacity: 1,
duration: 100,
easing: 'linear'
});
anime({
targets: this.$refs.main,
opacity: 1,
@ -78,26 +73,22 @@ export default Vue.extend({
this.$refs.form.focus();
},
close() {
(this.$refs.bg as any).style.pointerEvents = 'none';
anime({
targets: this.$refs.bg,
opacity: 0,
duration: 300,
easing: 'linear'
});
onBeforeClose() {
(this.$refs.main as any).style.pointerEvents = 'none';
anime({
targets: this.$refs.main,
opacity: 0,
translateY: 16,
duration: 300,
easing: 'easeOutQuad',
complete: () => this.destroyDom()
easing: 'easeOutQuad'
});
},
close() {
(this.$refs.modal as any).close();
},
onPosted() {
this.$emit('posted');
this.close();
@ -112,20 +103,8 @@ export default Vue.extend({
</script>
<style lang="stylus" scoped>
.ulveipglmagnxfgvitaxyszerjwiqmwl
> .bg
display block
position fixed
z-index 10000
top 0
left 0
width 100%
height 100%
background rgba(#000, 0.7)
opacity 0
pointer-events none
> .main
.main
display block
position fixed
z-index 10000