本周我分到的任务是两个组件,显示好友列表和聊天界面,我选择仿微信做一个界面,然后分别在其中镶嵌两个组件
这是做好的成品展示
具体的如下
总体界面
<template>
<div id="building">
<div id="app">
<div class="sidebar">
<mycard></mycard>
</div>
<div class="main">
<router-view></router-view>
</div>
</div>
</div>
</template>
<script>
import mycard from '@/components/mycard/mycard'
import { mapActions } from 'vuex'
export default {
components: {
mycard
},
created() {
this.$store.dispatch('fetchUserInfo');
this.$store.dispatch('initData')
}
}
</script>
<style scoped>
#app {
display: flex;
border-radius: 50px;
margin-bottom: 50px;
/* margin: 0px auto; */
/* width: 860px; */
/* height: 600px; */
width: 100%;
height: 600px;
background-color: rgb(255, 255, 255);
/* background-color: #fff; */
}
.sidebar {
width: 60px;
height: 600px;
/* background: #2b2c2f */
background: #f8d080;
}
.main {
flex: 1;
height: 600px;
background: rgb(243, 243, 243);
/* background: #f2f2f2; */
}
building {
background: url("../assets/chat1.png");
width: 100%;
height: 100%;
position: fixed;
background-size: 100% 100%;
}
</style>
选择框
<!-- 最左边的选择框 -->
<template>
<div class="mycard">
<header>
<img :src="user.img" class="avatar">
</header>
<div class="navbar" @click="clearSearch">
<router-link to="/friends" class="icon iconfont icon-msg" ></router-link>
<router-link to="/friend" class="icon iconfont icon-friend"></router-link>
<router-link to="/chatWithDoctor" class="icon iconfont icon-collection"></router-link>
<router-link v-show="health" to="/addFriends" class="icon iconfont icon-search"></router-link>
</div>
<footer>
<i class="icon iconfont icon-more"></i>
</footer>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
data: () => ({
modal:true,
dialogVisible: false,
friend:Array(6).fill({}),
wish:'',
loading:false,
health:false
}),
computed: {
...mapState([
'user',
])
},
methods: {
clearSearch() {
this.$store.dispatch('search', '')
},
},
created(){
this.request.get("/test/isHealth",{
params:{
uid:JSON.parse(localStorage.getItem("user")).id,
},
}).then((res) => {
if (res.data.code === "0" && res.data.data===true) {
this.health=true;
}
});
}
}
</script>
<style lang="stylus" scoped>
@import '../../assets/fonts/iconfont.css'
.mycard
position: relative
width: 100%
height: 100%
.avatar
width: 36px
height: 36px
margin: 20px 12px 0 12px
border-radius: 2px
.navbar
width: 100%
text-align: center
.icon
display: inline-block
font-size: 26px
margin-top: 28px
padding: 0 16px
box-sizing: border-box
color: rgb(173,174,175)
opacity: 0.8
cursor: pointer
&.active
color: rgb(0,220,65)
&:hover
opacity: 1;
.icon-msg,.icon-more
font-size: 22px
.icon-msg
padding: 0 19px
footer
position: absolute
bottom: 20px
width: 100%
text-align: center
</style>
朋友列表
朋友界面分为两个部分,一个是朋友信息列表,一个是选中后显示选中朋友信息
<template>
<div class="content">
<div class="msglist">
<search></search>
<chatlist></chatlist>
</div>
<div class="chatbox">
<message></message>
<vText></vText>
</div>
</div>
</template>
<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';
import search from '../components/search/search'
import chatlist from '../components/chatlist/chatlist'
import message from '../components/message/message'
import vText from '../components/text/text'
export default {
//import引入的组件需要注入到对象中才能使用
components: {
search,
chatlist,
message,
vText
}
}
</script>
<style lang="stylus" scoped>
.content
display: flex
width: 100%
.msglist
width: 250px
background: rgb(230,230,230)
.chatbox
flex: 1
width:100%
</style>
朋友信息列表
<!-- 好友列表 -->
<template>
<div class="friendlist">
<ul>
<li v-for="item in searchedFriendlist" class="frienditem" :class="{ noborder: !item.initial}">
<div class="list_title" v-if="item.initial">{{item.initial}}</div>
<div class="friend-info" :class="{ active: item.id === selectFriendId }" @click="selectFriend(item.id)">
<img class="avatar" width="36" height="36" :src="item.img">
<div class="remark">{{item.remark}}</div>
</div>
</li>
</ul>
</div>
</template>
<script>
import { mapState, mapActions ,mapGetters } from 'vuex'
export default {
data: () => ({
img: require('../../assets/chat/images/1.jpg')
}),
computed: {
...mapState([
'selectFriendId',
'searchText'
]),
...mapGetters([
'searchedFriendlist'
])
},
methods: {
...mapActions([
'selectFriend',
])
}
}
</script>
<style lang="stylus" scoped>
.friendlist
height: 540px
width: 250px
overflow-y: auto
.frienditem
border-top: 1px solid #dadada
&:first-child,&.noborder
border-top: none
.list_title
box-sizing: border-box
width: 100%
font-size: 12px
padding: 15px 0 3px 12px
color: #999
.friend-info
display: flex
padding: 12px
transition: background-color .1s
font-size: 0
&:hover
background-color: rgb(220,220,220)
&.active
background-color: #c4c4c4
.avatar
border-radius: 2px
margin-right: 12px
.remark
font-size: 14px
line-height: 36px
</style>
搜索框
<!-- 搜索框 -->
<template>
<div class="wrapper">
<div class="search-wrapper">
<input type="text" class="searchInput" v-model="search" @keyup="change" placeholder="搜索">
<i class="icon iconfont icon-search" v-show="noText"></i>
<div class="searchInput-delete" v-show="haveText" @click="del"></div>
</div>
</div>
</template>
<script>
export default {
methods: {
change () {
this.$store.dispatch('search', this.search)
},
del () {
this.search= ''
this.change()
}
},
data () {
return {
search: '',
active: false
}
},
computed: {
noText () {
if(this.search === '') return true
return false
},
haveText () {
if(this.search === '') return false
return true
}
}
}
</script>
<style lang="stylus" scoped>
.wrapper
padding: 22px 12px 12px 12px
.search-wrapper
position: relative
display: flex
box-sizing: border-box
height: 26px
width: 100%
background-color: #e5e3e2
border: 1px solid #d9d7d6
border-radius: 2px
.searchInput
flex: 1
font-size: 12px
padding: 6px
background-color: #e5e3e2
outline: none
&:focus
background-color: #f2efee
.icon-search
display: inline-block
width: 24px
height: 24px
font-size: 14px
line-height: 24px
text-align: center
.searchInput-delete
display: block
position: absolute
outline: none
top: 0;
right: 0;
width: 24px
height: 100%
background-image: url(delete.png)
background-size: 26px
background-position: center
background-repeat: no-repeat
cursor: pointer
</style>
朋友信息
<!-- 好友信息 -->
<template>
<div style="overflow-y: scroll;"class="Info-wrapper">
<div class="newfriend" v-show="selectedFriend.id === 0">
<div class="box p-5 px-6" style="width: 1500px;height: 500px;">
<h3 style="font-weight: bold;text-align: left;">好友申请</h3>
<div class="side-list">
<div v-for="(request, index) in friendRequests" :key="index" class="side-list-item">
<img :src="request.avatar" alt="Avatar" class="side-list-image rounded-full">
<div class="flex-1">
<h4 style="text-align: left;" class="side-list-title">{{ request.name }}</h4>
<div class="side-list-info">{{ request.traits.join(", ") }}</div>
<div class="side-list-info">{{ request.qualities.join(", ") }}</div>
</div>
<div style="margin-top: 50px;margin-left: 100px;">
<el-button type="info" >拒绝</el-button>
<el-button type="primary" >同意</el-button>
</div>
</div>
</div>
</div>
</div>
<div class="friendInfo" v-show="selectedFriend.id > 0">
<div class="esInfo" >
<div class="left">
<div class="people">
<div class="nickname">{{selectedFriend.nickname}}</div>
<div :class="[selectedFriend.sex===1?'gender-male':'gender-female']"></div>
</div>
<div class="signature">{{selectedFriend.signature}}</div>
</div>
<div class="right">
<img class="avatar" width="60" height="60" :src="selectedFriend.img">
</div>
</div>
<div class="detInfo">
<div class="remark"><span>备   注</span>{{selectedFriend.remark}}</div>
<div class="area"><span>地   区</span>{{selectedFriend.area}}</div>
<div class="wxid"><span>微信号</span>{{selectedFriend.wxid}}</div>
</div>
<div class="send" @click="send">
<span>发消息</span>
</div>
</div>
</div>
</template>
<script>
import router from '../../router'
import { mapGetters } from 'vuex'
export default {
data: () => ({
img: '../../assets/chat/images/1.jpg',
friendRequests: [
{
avatar: "../../public/images/avatars/avatar-2.jpg",
name: "John Michael",
traits: ["好奇", "探索", "谨慎尝试", "有选择性", "焦虑", "敏感", "紧张", "易尴尬", "内向", "沉默"],
qualities: ["害羞", "拘谨", "温和", "谦逊", "谨慎", "有同情心", "细致", "认真", "有序", "考虑周全"],
status:0
},
{
avatar: "../../public/images/avatars/avatar-2.jpg",
name: "John Michael",
traits: ["好奇", "探索", "谨慎尝试", "有选择性", "焦虑", "敏感", "紧张", "易尴尬", "内向", "沉默"],
qualities: ["害羞", "拘谨", "温和", "谦逊", "谨慎", "有同情心", "细致", "认真", "有序", "考虑周全"],
status:1
},
{
avatar:"../../public/images/avatars/avatar-2.jpg",
name: "John Michael",
traits: ["好奇", "探索", "谨慎尝试", "有选择性", "焦虑", "敏感", "紧张", "易尴尬", "内向", "沉默"],
qualities: ["害羞", "拘谨", "温和", "谦逊", "谨慎", "有同情心", "细致", "认真", "有序", "考虑周全"],
status:2
},
{
avatar: "../../public/images/avatars/avatar-2.jpg",
name: "John Michael",
traits: ["好奇", "探索", "谨慎尝试", "有选择性", "焦虑", "敏感", "紧张", "易尴尬", "内向", "沉默"],
qualities: ["害羞", "拘谨", "温和", "谦逊", "谨慎", "有同情心", "细致", "认真", "有序", "考虑周全"]
},
{
avatar:"../../public/images/avatars/avatar-2.jpg",
name: "John Michael",
traits: ["好奇", "探索", "谨慎尝试", "有选择性", "焦虑", "敏感", "紧张", "易尴尬", "内向", "沉默"],
qualities: ["害羞", "拘谨", "温和", "谦逊", "谨慎", "有同情心", "细致", "认真", "有序", "考虑周全"]
},
{
avatar: "../../public/images/avatars/avatar-2.jpg",
name: "John Michael",
traits: ["好奇", "探索", "谨慎尝试", "有选择性", "焦虑", "敏感", "紧张", "易尴尬", "内向", "沉默"],
qualities: ["害羞", "拘谨", "温和", "谦逊", "谨慎", "有同情心", "细致", "认真", "有序", "考虑周全"]
},
{
avatar:"../../public/images/avatars/avatar-2.jpg",
name: "John Michael",
traits: ["好奇", "探索", "谨慎尝试", "有选择性", "焦虑", "敏感", "紧张", "易尴尬", "内向", "沉默"],
qualities: ["害羞", "拘谨", "温和", "谦逊", "谨慎", "有同情心", "细致", "认真", "有序", "考虑周全"]
},
{
avatar: "../../public/images/avatars/avatar-2.jpg",
name: "John Michael",
traits: ["好奇", "探索", "谨慎尝试", "有选择性", "焦虑", "敏感", "紧张", "易尴尬", "内向", "沉默"],
qualities: ["害羞", "拘谨", "温和", "谦逊", "谨慎", "有同情心", "细致", "认真", "有序", "考虑周全"]
},
// 添加更多好友申请数据...
]
}),
computed: {
...mapGetters([
'selectedFriend'
])
},
methods: {
send () {
this.$store.dispatch('send')
this.$store.dispatch('search', '')
}
}
}
</script>
<style scoped>
.side-list {
display: flex;
flex-direction: column;
gap: 20px;
}
.side-list-item {
display: flex;
align-items: center;
gap: 20px;
}
.side-list-image {
width: 50px;
height: 50px;
border-radius: 50%;
}
.side-list-title {
font-weight: bold;
}
.side-list-info {
color: #666;
}
.button {
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
}
.bg-primary {
background-color: #007bff;
color: #fff;
}
.bg-secondery {
background-color: #6c757d;
color: #fff;
}
.button:hover {
opacity: 0.8;
}
</style>
<style lang="stylus" scoped>
.newfriend
height: 100%
padding: 28px 0 0 30px
box-sizing: border-box
border-bottom: 1px solid #e7e7e7
.nickname
font-size: 18px
.friendInfo
padding: 0 90px
.esInfo
display: flex
align-items: center
padding: 100px 0 45px 0
.left
flex: 1
.people
.nickname
display: inline-block
font-size: 20px
margin-bottom: 16px
.gender-male,.gender-female
display: inline-block
width: 18px
height: 18px
vertical-align: top
margin-top: 2px
.gender-male
background-image: url(man.png)
background-size: cover
.gender-female
background-image: url(woman.png)
background-size: cover
.signature
font-size: 14px
color: rgba(153,153,153,.8)
.right
.avatar
border-radius: 3px
.detInfo
padding: 40px 0
border-top: 1px solid #e7e7e7
border-bottom: 1px solid #e7e7e7
.remark,.area,.wxid
font-size: 14px
margin-top: 20px
span
font-size: 14px
color: rgba(153,153,153,.8)
margin-right: 40px
.remark
margin-top: 0
.send
position: relative
text-align: center
width: 140px
height: 36px
left: 115px
top: 50px
line-height: 36px
font-size: 14px
color: #fff
background-color: #1aad19
cursor: pointer
border-radius: 2px
&:hover
background: rgb(18,150,17)
</style>
聊天界面
分为四个部分,除了搜索框(代码已经贴过)外,还有聊天列表页面、显示信息界面、发送信息界面
聊天列表
<!-- 聊天列表 -->
<template>
<div class="msglist">
<ul>
<li v-for="item in searchedChatlist" class="sessionlist" :class="{ active: item.id === selectId }"
@click="selectSession(item.id)">
<div class="list-left">
<img class="avatar" width="42" height="42" :src="item.user.img" :alt="item.user.name" >
</div>
<div class="list-right">
<p class="name">{{ item.user.name }}</p>
<span class="time">{{ item.messages[item.messages.length - 1].date | time }}</span>
<!-- <p class="lastmsg">{{ item.messages[item.messages.length - 1].content }}</p>-->
</div>
</li>
</ul>
</div>
</template>
<script>
import { mapState, mapActions, mapGetters } from 'vuex'
import axios from 'axios'
export default {
created() {
this.fetchMessage();
},
computed: {
...mapState([
'selectId',
'searchText'
]),
...mapGetters([
'searchedChatlist'
])
},
methods: {
fetchMessage() {
const user = JSON.parse(localStorage.getItem('user'));
//var params = new URLSearchParams();
//params.append('username', '123456');
// 发送POST请求
axios.post('http://localhost:9966/message/getMessage', {
username: user.uname,
}, {
headers: {
'Content-Type':'application/json'
}
})
.then(response => {
// 假设后端返回的是一个List<GetMessageVO>的JSON数组
const messagesFromBackend = response.data; // 提取后端返回的数据
// 将后端返回的数据添加到chatlist中
// 你可能需要使用Vuex的mutation来确保状态更新的正确性
this.$store.commit('addMessagesToList', messagesFromBackend);
})
.catch(error => {
console.error('Error fetching messages:', error);
});
},
...mapActions([
'selectSession',
])
},
filters: {
// 将日期过滤为 hour:minutes
time(date) {
//month =data.getMonth() < 9 ? "0" + (data.getMonth() + 1) : data.getMonth() + 1;
if (typeof date === 'string') {
date = new Date(date);
}
if (date.getMinutes() < 10) {
return date.getHours() + ':0' + date.getMinutes();
} else {
return date.getHours() + ':' + date.getMinutes();
}
}
},
}
</script>
<style lang="stylus" scoped>
.msglist
height: 540px
overflow-y: auto
.sessionlist
display: flex
padding: 12px
transition: background-color .1s
font-size: 0
&:hover
background-color: rgb(220,220,220)
&.active
background-color: #c4c4c4
.avatar
border-radius: 2px
margin-right: 12px
.list-right
position: relative
flex: 1
margin-top: 4px
.name
display: inline-block
vertical-align: top
font-size: 14px
.time
float: right
color: #999
font-size: 10px
vertical-align: top
.lastmsg
position: absolute
font-size: 12px
width: 130px
height: 15px
line-height: 15px
color: #999
bottom: 4px
overflow: hidden
white-space:nowrap
text-overflow:ellipsis
</style>
信息显示
<!-- 消息框 -->
<template>
<div class="message">
<header class="header">
<div class="friendname">{{ selectedChat.user.name }}</div>
</header>
<div class="message-wrapper" ref="list">
<ul v-if="selectedChat">
<li v-for="(item, i) in selectedChat.messages" class="message-item" :key="i">
<div class="time"><span>{{ selectedChat.messages[i].date | time }}</span></div>
<div class="main" :class="{ self: item.self }">
<img class="avatar" width="36" height="36"
:src="item.self ? user.img : selectedChat.user.img" />
<div class="content">
<div class="text" v-html="replaceFace(item.content)"></div>
</div>
</div>
</li>
</ul>
</div>
</div>
</template>
<script>
import { mapGetters, mapState } from 'vuex'
export default {
/*data() {
return {
selectedChat: {
user: {
name: "John Doe",
img: "public/images/avatars/avatar-4.jpg"
},
messages: [
{
date: "2024-05-05T12:00:00",
self: false,
content: "Hey there! How are you?"
},
{
date: "2024-05-05T12:05:00",
self: true,
content: "Hi! I'm doing well, thanks. How about you?"
},
{
date: "2024-05-05T12:10:00",
self: false,
content: "I'm good too. Just busy with work."
}
]
},
user: {
name: "You",
img: "public/images/avatars/avatar-5.jpg"
}
};
},*/
computed: {
...mapGetters([
'selectedChat',
'messages'
]),
...mapState([
'user',
'emojis'
])
},
mounted() {
// 在页面加载时让信息滚动到最下面
setTimeout(() => this.$refs.list.scrollTop = this.$refs.list.scrollHeight, 0)
},
watch: {
// 发送信息后,让信息滚动到最下面
messages() {
setTimeout(() => this.$refs.list.scrollTop = this.$refs.list.scrollHeight, 0)
}
},
methods: {
// 在发送信息之后,将输入的内容中属于表情的部分替换成emoji图片标签
// 再经过v-html 渲染成真正的图片
replaceFace(con) {
if (con.includes('/:')) {
var emojis = this.emojis;
for (var i = 0; i < emojis.length; i++) {
con = con.replace(emojis[i].reg, '<img src="static/emoji/' + emojis[i].file + '" alt="" style="vertical-align: middle; width: 24px; height: 24px" />');
}
return con;
}
return con;
}
},
filters: {
// 将日期过滤为 hour:minutes
time(date) {
console.log('time的++', date);
if (typeof date === 'string') {
date = new Date(date);
}
if (date.getMinutes() < 10) {
return date.getHours() + ':0' + date.getMinutes();
} else {
return date.getHours() + ':' + date.getMinutes();
}
}
}
}
</script>
<style lang="stylus" scoped>
.message
width: 100%
height: 450px
.header
height: 60px
padding: 28px 0 0 30px
box-sizing: border-box
border-bottom: 1px solid #e7e7e7
.friendname
font-size: 18px
.message-wrapper
min-height: 390px
max-height: 390px
padding: 10px 15px
box-sizing: border-box
overflow-y: auto
border-bottom: 1px solid #e7e7e7
.message
margin-bottom: 15px
.time
width: 100%
font-size: 12px
margin: 7px auto
text-align: center
span
display: inline-block
padding: 4px 6px
color: #fff
border-radius: 3px
background-color: #dcdcdc
.main
display: flex
align-items: flex-start
&.self
justify-content: flex-end
.avatar
border-radius: 3px
width: 36px
height: 36px
margin-left: 10px
.content
margin-left: 10px
padding: 6px 10px
max-width: 330px
line-height: 24px
box-sizing: border-box
font-size: 14px
word-break: break-all
background-color: #fafafa
border-radius: 4px
text-align: left
&.self
margin-right: 10px
margin-left: 0
background-color: #b2e281
&:before
content: " "
position: absolute
top: 50%
transform: translateY(-50%)
border-width: 6px
border-style: solid
border-color: transparent
&.self
right: -12px
border-left-color: #b2e281
&:not(.self)
left: -12px
border-right-color: #fafafa
</style>
发送
这个vue页面主要是将发送信息的那个输入框和显示信息的message.vue分开了
<!-- 文本输入框 -->
<template>
<div class="text">
<div class="emoji">
<i class="icon iconfont icon-look" @click="showEmoji = !showEmoji"></i>
<transition name="showbox">
<div class="emojiBox" v-show="showEmoji">
<li v-for="(item, index) in icon" @click="content += item">
{{ item }}
</li>
</div>
</transition>
</div>
<textarea ref="text" v-model="content" @keyup="onKeyup" @click="showEmoji = false">
</textarea>
<div class="send" @click="send">
<span>发送(ent)</span>
</div>
<transition name="appear">
<div class="warn" v-show="warn">
<div class="description">不能发送空白信息</div>
</div>
</transition>
</div>
</template>
<script>
import { mapGetters, mapState } from 'vuex'
let socket;
export default {
data() {
return {
content: '',
reply: '未找到',
frequency: 0,
warn: false,
showEmoji: false,
};
},
computed: {
...mapState([
'selectId',
'emojis',
'icon'
]),
...mapGetters([
'selectedChat',
])
},
methods: {
getImageUrl(file) {
return require(`../../assets/chat/emoji/${file}`);
},
// 按回车发送信息
onKeyup(e) {
if (e.keyCode === 13) {
this.send()
}
},
// 点击发送按钮发送信息
send() {
if (this.content.length <= 1) {
this.warn = true
this.content = ''
setTimeout(() => {
this.warn = false;
}, 1000)
} else {
if (typeof (WebSocket) == "undefined") {
console.log("您的浏览器不支持WebSocket");
} else {
console.log("开始连接服务器");
//const user = JSON.parse(localStorage.getItem('user'))
//let message = {from: user.uname,to:}
}
var msg = {
content: this.content,
}
this.content = ''
this.$store.dispatch('sendMessage', msg)
}
}
},
// 在进入的时候 聚焦输入框
mounted() {
this.$refs.text.focus()
},
watch: {
// 在选择其它对话的时候 聚焦输入框
selectId() {
setTimeout(() => {
this.$refs.text.focus()
}, 0)
},
// 当输入框中的值为空时 弹出提示 并在一秒后消失
content() {
if (this.content === '') {
if (this.frequency === 0) {
this.warn = true;
this.frequency++
setTimeout(() => {
this.warn = false;
}, 1000)
}
}
}
}
}
</script>
<style lang="stylus" scoped>
.text
position: relative
height: 150px
background: rgb(243, 243, 243)
.emoji
position: relative
width: 100%
height: 40px
line-height: 40px
font-size: 12px
padding: 0 30px
box-sizing: border-box
color: #7c7c7c
.icon-look
cursor: pointer
&:hover
color: #1aad19
.emojiBox
position: absolute
display: flex
flex-wrap: wrap
top: -210px
left: -100px
width: 300px
overflow-y: auto
max-height: 200px
padding: 5px
background-color: #fff
border: 1px solid #d1d1d1
border-radius: 2px
box-shadow:0 1px 2px 1px #d1d1d1
&.showbox-enter-active, &.showbox-leave-active
transition: all .5s
&.showbox-enter,&.showbox-leave-active
opacity: 0
textarea
box-sizing: border-box
padding: 0 30px
height: 110px
width: 100%
border: none
outline: none
font-family: "Micrsofot Yahei"
resize: none
background-color: rgb(243, 243, 243)
.send
position: absolute
bottom: 10px
right: 30px
width: 75px
height: 28px
line-height: 28px
box-sizing: border-box
text-align: center
border: 1px solid #e5e5e5
border-radius: 3px
background: #f5f5f5
font-size: 14px
color: #7c7c7c
&:hover
background: rgb(18,150,17)
color: #fff
.warn
position: absolute
bottom: 50px
right: 10px
width: 110px
height: 30px
line-height: 30px
font-size: 12px
text-align: center
border: 1px solid #bdbdbd
border-radius: 4px
box-shadow:0 1px 5px 1px #bdbdbd
&.appear-enter-active, &.appear-leave-active
transition: all 1s
&.appear-enter,&.appear-leave-active
opacity: 0
&:before
content: " "
position: absolute
top: 100%
right: 20px
border: 7px solid transparent
border-top-color: #fff
filter:drop-shadow(1px 3px 2px #bdbdbd)
</style>
总结
本周没有什么特别的难点,但是好久没有用到vue,好多知识已经遗忘,而且组件还这么多,因此写的时候很痛苦,当时遇到了好多问题。不过因为当时没有写博客,所以这里直接将代码帖了上来,实际上,这些是改动后的代码,还有js部分也是我后来才写的,这里也直接贴了上去,懒得分了,然后就是医生端和用户端大同小异,因此博客中就没有写。