Browse Source

优化弹窗

pull/19/head
zyronon 4 years ago
parent
commit
00cd6876e7
  1. 15
      src/App.vue
  2. 165
      src/components/FromBottomDialog.vue
  3. 3
      src/components/Search.vue
  4. 426
      src/pages/home/Message.vue
  5. 6
      src/store/index.js

15
src/App.vue

@ -1,5 +1,8 @@ @@ -1,5 +1,8 @@
<template>
<router-view v-slot="{ Component }">
<transition name="fade">
<Mask v-if="maskDialog" @click="hideMaskDialog"></Mask>
</transition>
<transition :name="transitionName">
<component :is="Component"/>
</transition>
@ -11,7 +14,17 @@ export default { @@ -11,7 +14,17 @@ export default {
name: 'App',
data() {
return {
transitionName: 'go'
transitionName: 'go',
}
},
computed: {
maskDialog() {
return this.$store.state.maskDialog
}
},
methods: {
hideMaskDialog() {
this.$store.commit('setMaskDialog', false)
}
},
// watch $route 使

165
src/components/FromBottomDialog.vue

@ -0,0 +1,165 @@ @@ -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>

3
src/components/Search.vue

@ -69,6 +69,7 @@ export default { @@ -69,6 +69,7 @@ export default {
}
.search {
padding: 0;
flex: 1;
position: relative;
height: 3.6rem;
@ -84,12 +85,14 @@ export default { @@ -84,12 +85,14 @@ export default {
}
input {
//margin-top: .4rem;
font-size: 1.6rem;
color: white;
height: 50%;
width: 100%;
outline: none;
border: none;
padding: 0;
background: transparent;
&::-webkit-input-placeholder {

426
src/pages/home/Message.vue

@ -1,9 +1,9 @@ @@ -1,9 +1,9 @@
<template>
<div id="Message">
<div id="Message" ref="app" :class="createChatDialog?'disable-scroll':''">
<div class="header ">
<div class="title">
<p class="tac c-white ">消息</p>
<span @click="nav('/myCard')">创建群聊</span>
<span @click="createChatDialog = true">创建群聊</span>
</div>
</div>
<Search class="m2r"></Search>
@ -99,31 +99,177 @@ @@ -99,31 +99,177 @@
</div>
</div>
<Footer v-bind:init-tab="4"/>
<from-bottom-dialog v-model="createChatDialog">
<div class="create-chat-wrapper" v-show="!showJoinedChat">
<Search class="ml2r mr2r" placeholder="搜索用户" v-model="createChatSearchKey"></Search>
<template v-if="createChatSearchKey">
<div class="search-result" v-if="searchFriends.length">
<div class="search-result-item" v-for="item in searchFriends"
@click="item.select = !item.select;createChatSearchKey = ''">
<img class="left" src="../../assets/img/icon/head-image.jpeg" alt="">
<div class="right">
<div class="info">
<span class="name">{{ item.name }}</span>
<span class="account">{{ item.account ? '抖音号:' + item.account : '' }}</span>
</div>
<img v-if="item.select" src="../../assets/img/icon/back.png" alt="">
<img v-if="!item.select" src="../../assets/img/icon/close.svg" alt=""></div>
</div>
</div>
<div class="no-result" v-else>
<div class="notice-h1">
搜索结果为空
</div>
<div class="notice-h2">
没有搜索到相关的联系人
</div>
</div>
</template>
<template v-else>
<div class="joined-chat" @click="showJoinedChat = true">
<img class="left" src="../../assets/img/icon/close-white.png" alt="">
<div class="right">
<span>已加入的群聊</span>
<img src="../../assets/img/icon/back.png" alt="">
</div>
</div>
<div class="friend-list">
<div class="index">Z</div>
<div class="friend-item" v-for="item in friends" @click="item.select = !item.select">
<img class="left" src="../../assets/img/icon/head-image.jpeg" alt="">
<div class="right">
<span>{{ item.name }}</span>
<img v-if="item.select" src="../../assets/img/icon/back.png" alt="">
<img v-if="!item.select" src="../../assets/img/icon/close.svg" alt="">
</div>
</div>
</div>
</template>
<div class="btn-wrapper">
<div class="btn" :class="selectFriends ? 'primary' : ''">
发起聊天
</div>
</div>
</div>
<div class="joined-chat-wrapper" v-show="showJoinedChat">
<div class="nav">
<img src="../../assets/img/icon/back.png" alt="" @click="showJoinedChat = false">
<span>已加入的群聊</span>
<span>&nbsp;</span>
</div>
<div class="create-chat">
<div class="heng-gang"></div>
<Search class="m2r"></Search>
</div>
<div class="chat-list">
<div class="chat-item" v-for="item in 15">
<img class="left" src="../../assets/img/icon/head-image.jpeg" alt="">
<div class="right">
<div class="title">
<div class="name">{{ text.length > 20 ? text.substr(0, 20) + '...' : text }}</div>
<div class="num">(3)</div>
</div>
<img class="arrow" src="../../assets/img/icon/back.png" alt="">
</div>
</div>
</div>
<NoMore></NoMore>
</div>
</from-bottom-dialog>
</div>
</template>
<script>
import Footer from '../../components/Footer.vue'
import Search from "../../components/Search";
import FromBottomDialog from '../../components/FromBottomDialog'
export default {
name: "Message",
components: {
Footer,
Search
Search,
FromBottomDialog
},
data() {
return {}
return {
createChatSearchKey: '',
showJoinedChat: false,
// createChatDialog: false,
createChatDialog: false,
text: 'AAAAAAAAA、BBBBBBBBBBBBB、CCCCCCCC',
friends: [
{
avatar: '',
name: '11',
account: '173123141231qoqo',
select: false
},
{
avatar: '',
name: 'Boooo',
account: '234242ooo',
select: false
},
{
avatar: '',
name: '三分钟情、',
account: '3029342',
select: false
},
{
avatar: '',
name: 'zzzzz',
account: '6034592',
select: false
},
{
avatar: '',
name: 'zzzzz',
account: '6034592',
select: false
},
{
avatar: '',
name: 'zzzzz',
account: '6034592',
select: false
},
{
avatar: '',
name: 'zzzzz',
account: '6034592',
select: false
},
{
avatar: '',
name: 'zzzzz',
account: '6034592',
select: false
},
],
searchFriends: []
}
},
created() {
computed: {
selectFriends() {
let res = this.friends.filter(v => v.select)
return res.length
}
},
watch: {
createChatSearchKey(newVal) {
if (newVal) {
//TODO 
this.searchFriends = this.friends.filter(v => {
if (v.name.includes(newVal)) return true
return v.account.includes(newVal);
})
} else {
this.searchFriends = []
}
}
},
mounted() {
},
methods: {
}
}
</script>
@ -133,90 +279,240 @@ export default { @@ -133,90 +279,240 @@ export default {
#Message {
background: $main-bg;
padding-bottom: 60px;
padding-bottom: 6rem;
color: white;
.create-chat {
padding: 10px 10px 0 10px;
z-index: 9;
position: fixed;
width: 100%;
max-height: 50vh;
overflow: auto;
bottom: 0;
background: $main-bg;
box-sizing: border-box;
border-radius: 5px 5px 0 0;
&.disable-scroll {
//height: calc(100vh - 6rem);
//overflow: hidden;
}
.create-chat-wrapper {
margin-top: 2.4rem;
padding-bottom: 6rem;
.joined-chat {
border-bottom: 1px solid $line-color;
height: 5rem;
padding: 0 2rem;
display: flex;
align-items: center;
.left {
width: 1.8rem;
height: 1.8rem;
margin-left: 1rem;
margin-right: 2rem;
}
.right {
font-size: 1.4rem;
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
img {
height: 1.5rem;
}
}
}
.friend-list {
padding: 0 2rem;
.index {
height: 6rem;
line-height: 6rem;
font-size: 1.4rem;
}
.friend-item {
margin-bottom: 2rem;
display: flex;
align-items: center;
&:nth-child(1) {
margin-top: 1rem;
}
.left {
width: 4.8rem;
height: 4.8rem;
border-radius: 50%;
margin-right: 1rem;
}
.right {
font-size: 1.4rem;
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
img {
height: 1.5rem;
}
}
}
}
.heng-gang {
.btn-wrapper {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: $main-bg;
//background: red;
display: flex;
align-items: center;
justify-content: center;
.content {
border-radius: 2px;
height: 4px;
width: 30px;
background: $second-btn-color;
margin-bottom: 5px;
.btn {
margin-bottom: 2rem;
width: calc(100% - 4rem);
height: 4rem;
display: flex;
align-items: center;
font-size: 1.4rem;
justify-content: center;
background: #3f445c;
border-radius: .2rem;
&.primary {
background: $primary-btn-color;
}
}
}
.collection {
margin: 10px 0;
background: white;
width: 100%;
border-radius: 6px;
.search-result {
padding: 0 2rem;
.search-result-item {
margin-bottom: 2rem;
display: flex;
align-items: center;
&:nth-child(1) {
margin-top: 1rem;
}
.left {
width: 4.8rem;
height: 4.8rem;
border-radius: 50%;
margin-right: 1rem;
}
.right {
font-size: 1.4rem;
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
.info {
display: flex;
flex-direction: column;
.name {
font-size: 1.4rem;
}
.account {
font-size: 1.3rem;
color: $second-text-color;
}
}
img {
height: 1.5rem;
}
}
}
}
.no-result {
height: 50vh;
display: flex;
align-items: center;
font-size: 1.6rem;
font-weight: bold;
padding: 10px;
box-sizing: border-box;
justify-content: center;
flex-direction: column;
img {
background: white;
width: 35px;
height: 35px;
margin-right: 10px;
.notice-h1 {
font-size: 1.6rem;
}
.notice-h2 {
margin-top: 1rem;
font-size: 1.4rem;
color: $second-text-color;
}
}
}
.joined-chat-wrapper {
margin-top: 2.4rem;
.nav {
padding: 2rem;
display: flex;
justify-content: space-between;
.friends {
background: white;
border-radius: 6px 6px 0 0;
img {
height: 2rem;
}
}
width: 100%;
.chat-list {
padding: 0 2rem;
.friend {
box-sizing: border-box;
padding: 10px;
width: 100%;
.chat-item {
margin-bottom: 2rem;
display: flex;
align-items: center;
//border-bottom: 1px solid ghostwhite;
border-bottom: 1px solid gainsboro;
position: relative;
overflow: hidden;
img {
&:nth-last-child(1) {
margin-bottom: 0;
}
&:nth-child(1) {
margin-top: 1rem;
}
.left {
width: 4.8rem;
height: 4.8rem;
border-radius: 50%;
width: 40px;
height: 40px;
margin-right: 1rem;
}
.right {
margin: 0 5px 0 15px;
font-size: 1.6rem;
width: 100%;
font-size: 1.4rem;
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
.share-btn {
font-size: 1.4rem;
color: white;
padding: 5px 20px;
background: $primary-btn-color;
border-radius: 2px;
.title {
box-sizing: border-box;
display: flex;
align-items: center;
.name {
}
.num {
margin-left: .5rem;
color: $second-text-color;
}
}
img {
height: 1.5rem;
}
}
}

6
src/store/index.js

@ -5,13 +5,14 @@ const store = Vuex.createStore({ @@ -5,13 +5,14 @@ const store = Vuex.createStore({
state: {
bodyHeight: document.body.clientHeight,
bodyWidth: document.body.clientWidth,
maskDialog: false,
userinfo: {
name: '',
account: '',
desc: '123',
sex: '',
birthday: '',
location:'',
location: '',
school: {
name: 'asdasd',
department: null,
@ -24,6 +25,9 @@ const store = Vuex.createStore({ @@ -24,6 +25,9 @@ const store = Vuex.createStore({
mutations: {
setUserinfo(store, val) {
store.userinfo = val
},
setMaskDialog(store, val) {
store.maskDialog = val
}
}
})

Loading…
Cancel
Save