5 changed files with 548 additions and 67 deletions
@ -0,0 +1,165 @@ |
|||||||
|
<template> |
||||||
|
<transition name="from-bottom"> |
||||||
|
<div ref="dialog" class="FromBottomDialog" v-if="modelValue" :class="mode" :style="{height}" |
||||||
|
@touchstart="start" |
||||||
|
@touchmove="move" |
||||||
|
@touchend="end" |
||||||
|
> |
||||||
|
<div class="heng-gang" :class="mode"> |
||||||
|
<div class="content"></div> |
||||||
|
</div> |
||||||
|
<slot></slot> |
||||||
|
</div> |
||||||
|
</transition> |
||||||
|
|
||||||
|
</template> |
||||||
|
<script> |
||||||
|
export default { |
||||||
|
name: "FromBottomDialog", |
||||||
|
props: { |
||||||
|
modelValue: { |
||||||
|
type: Boolean, |
||||||
|
default: false |
||||||
|
}, |
||||||
|
mode: { |
||||||
|
type: String, |
||||||
|
default: 'dark' |
||||||
|
}, |
||||||
|
height: { |
||||||
|
type: String, |
||||||
|
default: '70vh' |
||||||
|
} |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
modelValue(newVal) { |
||||||
|
if (newVal) { |
||||||
|
this.scroll = document.documentElement.scrollTop |
||||||
|
document.body.style.position = 'fixed' |
||||||
|
document.body.style.top = -this.scroll + 'px' |
||||||
|
} else { |
||||||
|
document.body.style.position = 'static' |
||||||
|
document.documentElement.scrollTop = this.scroll |
||||||
|
} |
||||||
|
this.$store.commit('setMaskDialog', newVal) |
||||||
|
}, |
||||||
|
maskDialog(newVal) { |
||||||
|
this.hide(newVal) |
||||||
|
} |
||||||
|
}, |
||||||
|
data() { |
||||||
|
return { |
||||||
|
scroll: 0, |
||||||
|
startLocationY: 0, |
||||||
|
moveYDistance: 0, |
||||||
|
startTime: 0 |
||||||
|
} |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
maskDialog() { |
||||||
|
return this.$store.state.maskDialog |
||||||
|
}, |
||||||
|
}, |
||||||
|
created() { |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
hide(val = false) { |
||||||
|
this.$emit('update:modelValue', val) |
||||||
|
}, |
||||||
|
start(e) { |
||||||
|
if (this.$refs.dialog.scrollTop !== 0) return |
||||||
|
this.$setCss(this.$refs.dialog, 'transition-duration', `0ms`) |
||||||
|
this.startLocationY = e.touches[0].pageY |
||||||
|
this.startTime = Date.now() |
||||||
|
}, |
||||||
|
move(e) { |
||||||
|
if (this.$refs.dialog.scrollTop !== 0) return |
||||||
|
this.moveYDistance = e.touches[0].pageY - this.startLocationY |
||||||
|
if (this.moveYDistance > 0) { |
||||||
|
this.$setCss(this.$refs.dialog, 'transform', `translate3d(0,${this.moveYDistance}px,0)`) |
||||||
|
} |
||||||
|
}, |
||||||
|
end(e) { |
||||||
|
if (this.$refs.dialog.scrollTop !== 0) return |
||||||
|
let clientHeight = this.$refs.dialog.clientHeight |
||||||
|
if (Math.abs(this.moveYDistance) > clientHeight / 2) { |
||||||
|
this.$setCss(this.$refs.dialog, 'transition-duration', `300ms`) |
||||||
|
this.$setCss(this.$refs.dialog, 'transform', `translate3d(0,${clientHeight}px,0)`) |
||||||
|
setTimeout(this.hide, 300) |
||||||
|
} else { |
||||||
|
this.$setCss(this.$refs.dialog, 'transition-duration', `300ms`) |
||||||
|
this.$setCss(this.$refs.dialog, 'transform', `translate3d(0,0,0)`) |
||||||
|
setTimeout(()=>{ |
||||||
|
this.$setCss(this.$refs.dialog, 'transform', 'none') |
||||||
|
this.$setCss(this.$refs.dialog, 'transition-duration', `0ms`) |
||||||
|
}, 300) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
@import "../assets/scss/index"; |
||||||
|
|
||||||
|
.from-bottom-enter-active, |
||||||
|
.from-bottom-leave-active { |
||||||
|
transition: transform 0.2s ease; |
||||||
|
} |
||||||
|
|
||||||
|
.from-bottom-enter-from, |
||||||
|
.from-bottom-leave-to { |
||||||
|
transform: translate3d(0, 100vh, 0); |
||||||
|
} |
||||||
|
|
||||||
|
.FromBottomDialog { |
||||||
|
z-index: 9; |
||||||
|
position: fixed; |
||||||
|
width: 100%; |
||||||
|
overflow: auto; |
||||||
|
bottom: 0; |
||||||
|
box-sizing: border-box; |
||||||
|
border-radius: .5rem .5rem 0 0; |
||||||
|
|
||||||
|
&.dark { |
||||||
|
background: $main-bg; |
||||||
|
} |
||||||
|
|
||||||
|
&.light { |
||||||
|
background: white; |
||||||
|
} |
||||||
|
|
||||||
|
.heng-gang { |
||||||
|
border-radius: .5rem .5rem 0 0; |
||||||
|
z-index: 3; |
||||||
|
width: 100%; |
||||||
|
position: fixed; |
||||||
|
padding-top: 1rem; |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
|
||||||
|
&.dark { |
||||||
|
background: $main-bg; |
||||||
|
|
||||||
|
.content { |
||||||
|
background: $second-btn-color; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.light { |
||||||
|
background: white; |
||||||
|
|
||||||
|
.content { |
||||||
|
background: darkgray; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.content { |
||||||
|
border-radius: 2px; |
||||||
|
height: .4rem; |
||||||
|
width: 3rem; |
||||||
|
margin-bottom: 1rem; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
Loading…
Reference in new issue