comment reply framework

This commit is contained in:
landaiqing
2024-09-19 01:03:21 +08:00
parent c260ca642a
commit 1539a2d9bb
21 changed files with 1563 additions and 493 deletions

View File

@@ -65,159 +65,7 @@ onMounted(() => {
});
</script>
<style scoped lang="scss">
<style src="./index.scss" scoped lang="scss">
h1 {
color: #3e3e42;
font-size: 32px;
font-weight: 800;
letter-spacing: -1px;
margin-bottom: 30px;
transform: translateZ(35px);
}
h3 {
color: #eb285d;
font-size: 16px;
margin-bottom: 6px;
transform: translateZ(25px);
}
.cards {
background: #fff;
border-radius: 15px;
box-shadow: 0px 10px 20px 20px rgba(0, 0, 0, 0.17);
display: inline-block;
padding: 30px 35px;
perspective: 1800px;
text-align: left;
transform-origin: 50% 50%;
transform-style: preserve-3d;
transform: rotateX(11deg) rotateY(16.5deg);
min-width: 595px;
}
.card {
border-radius: 15px;
box-shadow: 5px 5px 20px -5px rgba(0, 0, 0, 0.6);
display: inline-block;
height: 250px;
overflow: hidden;
perspective: 1200px;
position: relative;
transform-style: preserve-3d;
transform: translatez(35px);
transition: transform 200ms ease-out;
width: 175px;
text-align: center;
}
.card:not(:last-child) {
margin-right: 30px;
}
.card__img {
position: relative;
height: 100%;
}
.card__bg {
bottom: -50px;
left: -50px;
position: absolute;
right: -50px;
top: -50px;
transform-origin: 50% 50%;
transform: translateZ(-50px);
z-index: 0;
}
.card__one .card__img {
top: 14px;
right: -10px;
height: 110%;
}
.card__one .card__bg {
background: url("@/assets/images/3dr_monobg.jpg") center/cover no-repeat;
}
.card__two .card__img {
top: 25px;
}
.card__two .card__bg {
background: url("@/assets/images/3dr_spirited.jpg") center/cover no-repeat;
}
.card__three .card__img {
top: 5px;
left: -4px;
height: 110%;
}
.card__three .card__bg {
background: url("@/assets/images/3dr_howlbg.jpg") center/cover no-repeat;
}
.card__text {
align-items: center;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.55) 100%);
bottom: 0;
display: flex;
flex-direction: column;
height: 70px;
justify-content: center;
position: absolute;
width: 100%;
z-index: 2;
}
.card__title {
color: #fff;
font-size: 18px;
font-weight: 700;
padding: 0 10px;
margin-bottom: 3px;
}
.notice {
background: gold;
border-top-left-radius: 6px;
bottom: 0;
font-family: monospace;
font-size: 14px;
padding: 8px 10px;
position: absolute;
right: -20px;
}
.twitter__link {
cursor: pointer;
position: absolute;
right: -10px;
top: 12px;
z-index: -1;
background: #00aced;
border-radius: 20px;
height: 30px;
text-decoration: none;
padding-right: 10px;
justify-content: space-between;
font-weight: 600;
display: flex;
align-items: center;
color: #fff;
font-size: 14px;
width: 74px;
opacity: 0.4;
}
.twitter__link:hover {
opacity: 1;
}
.twitter__icon {
height: 30px;
}
</style>

View File

@@ -0,0 +1,153 @@
h1 {
color: #3e3e42;
font-size: 32px;
font-weight: 800;
letter-spacing: -1px;
margin-bottom: 30px;
transform: translateZ(35px);
}
h3 {
color: #eb285d;
font-size: 16px;
margin-bottom: 6px;
transform: translateZ(25px);
}
.cards {
background: #fff;
border-radius: 15px;
box-shadow: 0px 10px 20px 20px rgba(0, 0, 0, 0.17);
display: inline-block;
padding: 30px 35px;
perspective: 1800px;
text-align: left;
transform-origin: 50% 50%;
transform-style: preserve-3d;
transform: rotateX(11deg) rotateY(16.5deg);
min-width: 595px;
}
.card {
border-radius: 15px;
box-shadow: 5px 5px 20px -5px rgba(0, 0, 0, 0.6);
display: inline-block;
height: 250px;
overflow: hidden;
perspective: 1200px;
position: relative;
transform-style: preserve-3d;
transform: translatez(35px);
transition: transform 200ms ease-out;
width: 175px;
text-align: center;
}
.card:not(:last-child) {
margin-right: 30px;
}
.card__img {
position: relative;
height: 100%;
}
.card__bg {
bottom: -50px;
left: -50px;
position: absolute;
right: -50px;
top: -50px;
transform-origin: 50% 50%;
transform: translateZ(-50px);
z-index: 0;
}
.card__one .card__img {
top: 14px;
right: -10px;
height: 110%;
}
.card__one .card__bg {
background: url("@/assets/images/3dr_monobg.jpg") center/cover no-repeat;
}
.card__two .card__img {
top: 25px;
}
.card__two .card__bg {
background: url("@/assets/images/3dr_spirited.jpg") center/cover no-repeat;
}
.card__three .card__img {
top: 5px;
left: -4px;
height: 110%;
}
.card__three .card__bg {
background: url("@/assets/images/3dr_howlbg.jpg") center/cover no-repeat;
}
.card__text {
align-items: center;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.55) 100%);
bottom: 0;
display: flex;
flex-direction: column;
height: 70px;
justify-content: center;
position: absolute;
width: 100%;
z-index: 2;
}
.card__title {
color: #fff;
font-size: 18px;
font-weight: 700;
padding: 0 10px;
margin-bottom: 3px;
}
.notice {
background: gold;
border-top-left-radius: 6px;
bottom: 0;
font-family: monospace;
font-size: 14px;
padding: 8px 10px;
position: absolute;
right: -20px;
}
.twitter__link {
cursor: pointer;
position: absolute;
right: -10px;
top: 12px;
z-index: -1;
background: #00aced;
border-radius: 20px;
height: 30px;
text-decoration: none;
padding-right: 10px;
justify-content: space-between;
font-weight: 600;
display: flex;
align-items: center;
color: #fff;
font-size: 14px;
width: 74px;
opacity: 0.4;
}
.twitter__link:hover {
opacity: 1;
}
.twitter__icon {
height: 30px;
}

View File

@@ -66,161 +66,6 @@ onMounted(() => {
});
</script>
<style scoped lang="scss">
* {
box-sizing: border-box;
}
<style src="./index.scss" scoped lang="scss">
button {
background: #55B4FB;
border-radius: 30px;
border: 2px solid #55B4FB;
height: 44px;
width: 165px;
color: white;
position: relative;
cursor: pointer;
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.15);
transition: box-shadow 0.25s;
}
button:hover {
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
background: #46adfb;
}
button i {
background: #75C2FB;
padding: 10px;
border-radius: 50px;
position: absolute;
border: 1px solid white;
right: 2px;
top: 50%;
transform: translate(0%, -50%);
}
button .button-text {
position: absolute;
top: 50%;
transform: translate(0%, -50%);
left: 25px;
}
body {
background: #F4F5F8;
padding: 0 30px;
overflow: hidden;
}
.card-content {
z-index: 10;
width: 80%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -65%);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.card-content h1 {
color: white;
font-size: 2.5rem;
text-align: center;
margin-bottom: 10px;
font-family: Lato, sans-serif;
font-weight: 500;
text-shadow: 0px 1px 0px rgba(0, 0, 0, 0.15);
}
.card-content p {
color: white;
line-height: 1.5;
text-align: center;
margin-bottom: 25px;
margin-top: 0px;
font-size: 1.2rem;
font-weight: lighter;
max-width: 650px;
font-family: "Source Sans Pro", sans-serif;
font-weight: 300;
text-shadow: 0px 1px 0px rgba(0, 0, 0, 0.15);
}
.flex-wrapper {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100vh;
}
.container {
max-width: 800px;
min-width: 320px;
width: 100%;
background: #7A90F6;
/* fallback for old browsers */
/* Chrome 10-25, Safari 5.1-6 */
background: linear-gradient(to right, #7A90F6, #7B6FF6);
/* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
position: relative;
height: 400px;
border-radius: 10px;
box-shadow: 0 25px 60px rgba(0, 0, 0, 0.15);
}
.background-container {
position: relative;
overflow: hidden;
width: 100%;
height: 100%;
border-radius: 10px;
}
.background-container:before {
position: absolute;
top: 0;
left: 50%;
z-index: 1;
width: 2000px;
height: 100%;
//background: url("https://www.digitalocean.com/assets/media/products/header-04dcc3be.svg");
//background-position: bottom;
//background-repeat: no-repeat;
content: "";
transform: translateX(-50%);
}
.clouds {
width: 225px;
position: absolute;
}
#cloudOne {
top: -100px;
left: -90px;
}
#cloudTwo {
right: -100px;
bottom: -90px;
z-index: 3;
}
#cloudThree {
left: 150px;
bottom: -150px;
z-index: -1;
}
#cloudFour {
right: 80px;
top: -100px;
z-index: -1;
width: 100px;
}
</style>

View File

@@ -0,0 +1,156 @@
* {
box-sizing: border-box;
}
button {
background: #55B4FB;
border-radius: 30px;
border: 2px solid #55B4FB;
height: 44px;
width: 165px;
color: white;
position: relative;
cursor: pointer;
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.15);
transition: box-shadow 0.25s;
}
button:hover {
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
background: #46adfb;
}
button i {
background: #75C2FB;
padding: 10px;
border-radius: 50px;
position: absolute;
border: 1px solid white;
right: 2px;
top: 50%;
transform: translate(0%, -50%);
}
button .button-text {
position: absolute;
top: 50%;
transform: translate(0%, -50%);
left: 25px;
}
body {
background: #F4F5F8;
padding: 0 30px;
overflow: hidden;
}
.card-content {
z-index: 10;
width: 80%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -65%);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.card-content h1 {
color: white;
font-size: 2.5rem;
text-align: center;
margin-bottom: 10px;
font-family: Lato, sans-serif;
font-weight: 500;
text-shadow: 0px 1px 0px rgba(0, 0, 0, 0.15);
}
.card-content p {
color: white;
line-height: 1.5;
text-align: center;
margin-bottom: 25px;
margin-top: 0px;
font-size: 1.2rem;
font-weight: lighter;
max-width: 650px;
font-family: "Source Sans Pro", sans-serif;
font-weight: 300;
text-shadow: 0px 1px 0px rgba(0, 0, 0, 0.15);
}
.flex-wrapper {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100vh;
}
.container {
max-width: 800px;
min-width: 320px;
width: 100%;
background: #7A90F6;
/* fallback for old browsers */
/* Chrome 10-25, Safari 5.1-6 */
background: linear-gradient(to right, #7A90F6, #7B6FF6);
/* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
position: relative;
height: 400px;
border-radius: 10px;
box-shadow: 0 25px 60px rgba(0, 0, 0, 0.15);
}
.background-container {
position: relative;
overflow: hidden;
width: 100%;
height: 100%;
border-radius: 10px;
}
.background-container:before {
position: absolute;
top: 0;
left: 50%;
z-index: 1;
width: 2000px;
height: 100%;
//background: url("https://www.digitalocean.com/assets/media/products/header-04dcc3be.svg");
//background-position: bottom;
//background-repeat: no-repeat;
content: "";
transform: translateX(-50%);
}
.clouds {
width: 225px;
position: absolute;
}
#cloudOne {
top: -100px;
left: -90px;
}
#cloudTwo {
right: -100px;
bottom: -90px;
z-index: 3;
}
#cloudThree {
left: 150px;
bottom: -150px;
z-index: -1;
}
#cloudFour {
right: 80px;
top: -100px;
z-index: -1;
width: 100px;
}

View File

@@ -0,0 +1,450 @@
<template>
<div class="comment-main">
<AFlex :vertical="false" justify="flex-start" class="comment-header">
<span class="comment-header-title">{{ t('comment.comment') }}</span>
</AFlex>
<!-- 评论输入框 -->
<div class="comment">
<AFlex :vertical="false">
<AFlex :vertical="true">
<AAvatar :size="50" shape="circle" src="https://api.multiavatar.com/Starcrasher.svg"/>
</AFlex>
<AFlex :vertical="true" class="comment-content">
<ATextarea :rows="4" class="comment-text" @focus="onFocusHandler"
v-model:value="commentContent"
:placeholder="commentTextAreaPlaceholder" allow-clear :showCount="false"/>
<AFlex :vertical="false" align="center" justify="space-between" class="comment-actions"
v-if="showCommentActions">
<AFlex :vertical="false" align="center">
<AFlex :vertical="false" align="center" class="comment-action-item">
<APopover trigger="click" placement="bottom">
<template #content>
<div style="width: 170px;height: 200px;overflow: auto;">
<template v-for="(item) in EMOJI" :key="item">
<AButton @click="insertEmoji(item)" type="text" size="large">{{ item }}</AButton>
</template>
</div>
</template>
<AButton type="text" size="small" :icon="h(SmileOutlined)" class="comment-action-icon">
{{ t('comment.emoji') }}
</AButton>
</APopover>
</AFlex>
<AFlex :vertical="false" align="center" class="comment-action-item">
<AUpload
:accept="'image/jpg, image/png, image/jpeg, image/gif, image/svg+xml, image/webp'"
name="images"
:max-count="5"
:multiple="true"
method="post"
:directory="false"
:show-upload-list="false"
:custom-request="customUploadRequest"
:before-upload="beforeUpload"
:disabled="imageList.length >= 5"
>
<ABadge :count="imageList.length">
<AButton type="text" size="small" :icon="h(PictureOutlined)"
class="comment-action-icon">
{{ t('comment.picture') }}
</AButton>
</ABadge>
</AUpload>
<template v-if="imageList.length > 0">
<ABadge style="margin-left: 10px;" v-for="(item, index) in imageList" :key="index">
<template #count>
<CloseCircleOutlined @click="removeBase64Image(index)" style="color: #f5222d"/>
</template>
<AAvatar shape="square" size="small">
<template #icon>
<AImage v-if="item" :src="item"/>
</template>
</AAvatar>
</ABadge>
</template>
</AFlex>
</AFlex>
<AFlex :vertical="false" align="center">
<AButton
@click="console.log(commentContent.replace(/\r\n/g, '<br/>').replace(/\n/g, '<br/>').replace(/\s/g, ' '))"
type="primary" size="middle" class="comment-action-btn">{{ t('comment.sendComment') }}
</AButton>
</AFlex>
</AFlex>
</AFlex>
</AFlex>
</div>
<ADivider/>
<!-- 回复列表 -->
<div class="reply">
<div class="reply-header">
<!-- 评论列表头部 -->
<AFlex :vertical="true">
<AFlex :vertical="false">
<span class="reply-header-title">{{ t('comment.allComments') }}</span>
<span class="reply-header-count">123</span>
</AFlex>
<ASegmented v-model:value="segmentedValue" :options="data" class="reply-header-sort"/>
</AFlex>
</div>
<div class="reply-list">
<div class="reply-item">
<AFlex :vertical="false">
<!-- 评论头像 -->
<AFlex :vertical="true" class="reply-avatar">
<AAvatar :size="50" shape="circle" src="https://api.multiavatar.com/landaiqing.svg"/>
</AFlex>
<!-- 评论内容 -->
<AFlex :vertical="true" class="reply-content">
<AFlex :vertical="true">
<AFlex :vertical="false" align="flex-start">
<span class="reply-name">张立国</span>
<a-tag color="cyan" class="reply-tag" size="small">Lv.5</a-tag>
<a-tag color="red" class="reply-tag" size="small">UP</a-tag>
</AFlex>
<AFlex :vertical="false" align="flex-end" justify="space-between">
<AFlex :vertical="false" align="center" justify="space-between">
<span class="reply-ip"> 成都市 </span>
<span class="reply-ip" style="margin-left: 10px;">IP: 192.168.1.100 </span>
</AFlex>
<span class="reply-time">{{ new Date().toLocaleString() }}</span>
</AFlex>
</AFlex>
<AFlex :vertical="false" align="center">
<ACard class="reply-card" :body-style="{padding: '10px'}">
<span class="reply-text">
床前明月光疑是地上霜<br>
举头望明月低头思故乡
</span>
<AFlex :vertical="false" justify="space-between" align="center">
<!--评论操作按钮 -->
<AFlex :vertical="false" align="center" justify="space-between" class="reply-action-item">
<AFlex :vertical="false" align="center">
<AButton type="text" size="small" :icon="h(LikeOutlined)" class="reply-action-btn">
10
</AButton>
</AFlex>
<AFlex :vertical="false" align="center">
<AButton type="text" size="small" :icon="h(DislikeOutlined)" class="reply-action-btn">
1
</AButton>
</AFlex>
<AButton type="text" size="small" :icon="h(MessageOutlined)" class="reply-action-btn">
11
</AButton>
<AButton
@click="replyInputVisible === true? (replyInputVisible = false) : (replyInputVisible = true) "
type="text" size="small" :icon="h(CommentOutlined)"
class="reply-action-btn">
{{ t('comment.reply') }}
</AButton>
</AFlex>
<!-- 评论操作系统信息-->
<AFlex :vertical="false" align="center" justify="flex-end" class="reply-action-item-right">
<AButton type="text" disabled size="small" :icon="h(WindowsOutlined)" class="reply-action-info">
windows 10
</AButton>
<AButton type="text" disabled size="small" :icon="h(ChromeOutlined)" class="reply-action-info">
chrome
</AButton>
<!-- 评论操作按钮 -->
<ADropdown trigger="click">
<AButton type="text" size="small" :icon="h(EllipsisOutlined)" class="reply-action-btn"
@click.prevent>
</AButton>
<template #overlay>
<AMenu>
<AMenuItem key="report">
<WarningOutlined/>
{{ t('comment.report') }}
</AMenuItem>
<AMenuItem key="copy">
<CopyOutlined/>
{{ t('comment.copy') }}
</AMenuItem>
<AMenuItem key="delete">
<DeleteOutlined/>
{{ t('comment.delete') }}
</AMenuItem>
</AMenu>
</template>
</ADropdown>
</AFlex>
</AFlex>
</ACard>
</AFlex>
<!-- 回复输入框 -->
<AFlex :vertical="true" class="reply-input-main" v-show="replyInputVisible">
<AFlex :vertical="false" align="center" class="reply-input-header">
<span class="reply-input-title">{{ t('comment.reply') + '' }}</span>
<span class="reply-input-author">张立国</span>
<AButton @click="replyInputVisible = false" type="dashed" size="small" :icon="h(CloseOutlined )"
class="reply-input-cancel">
{{ t('comment.cancelReply') }}
</AButton>
</AFlex>
<!-- 回复头像-->
<AFlex :vertical="false" class="reply-input-content">
<AFlex :vertical="true" class="reply-input-avatar">
<AAvatar :size="40" shape="circle" src="https://api.multiavatar.com/landaiqing.svg"/>
</AFlex>
<!-- 评论输入框 -->
<AFlex :vertical="true" class="reply-input-content-text">
<ATextarea :rows="3" class="comment-text-reply"
:placeholder="commentTextAreaPlaceholder" allow-clear :showCount="false"/>
<AFlex :vertical="false" align="center" justify="space-between" class="comment-actions-reply"
>
<AFlex :vertical="false" align="center">
<AFlex :vertical="false" align="center" class="comment-action-item-reply">
<AButton type="text" size="small" :icon="h(SmileOutlined)" class="comment-action-icon-reply">
{{ t('comment.emoji') }}
</AButton>
</AFlex>
<AFlex :vertical="false" align="center" class="comment-action-item-reply">
<AButton type="text" size="small" :icon="h(PictureOutlined)"
class="comment-action-icon-reply">
{{ t('comment.picture') }}
</AButton>
</AFlex>
</AFlex>
<AFlex :vertical="false" align="center">
<AButton type="primary" size="middle" class="comment-action-btn-reply">
{{ t('comment.sendComment') }}
</AButton>
</AFlex>
</AFlex>
</AFlex>
</AFlex>
</AFlex>
<!-- 子回复列表 -->
<AFlex :vertical="false" class="reply-item-child">
<AFlex :vertical="true" class="reply-item-child-avatar">
<AAvatar :size="40" shape="circle" src="https://api.multiavatar.com/landaiqing.svg"/>
</AFlex>
<AFlex :vertical="true" class="reply-item-child-content">
<AFlex :vertical="true">
<AFlex :vertical="false" align="center">
<span class="reply-name-child">沈建明</span> <span class="reply-at">@张立国</span>
<a-tag color="cyan" class="reply-tag-child" size="small">Lv.5</a-tag>
<!-- <a-tag color="red" class="reply-tag" size="small">UP</a-tag>-->
</AFlex>
<AFlex :vertical="false" align="flex-end" justify="space-between">
<AFlex :vertical="false" align="center" justify="space-between">
<span class="reply-ip-child"> 成都市 </span>
<span class="reply-ip-child" style="margin-left: 10px;">IP: 192.168.1.100 </span>
</AFlex>
<span class="reply-time-child">{{ new Date().toLocaleString() }}</span>
</AFlex>
</AFlex>
<AFlex :vertical="true" align="center">
<ACard class="reply-card-child" :body-style="{padding: '10px'}">
<span class="reply-text-child">
床前明月光疑是地上霜<br>
举头望明月低头思故乡
</span>
<AFlex :vertical="false" justify="space-between" align="center">
<!--评论操作按钮 -->
<AFlex :vertical="false" align="center" justify="space-between" class="reply-action-item-child">
<AFlex :vertical="false" align="center">
<AButton type="text" size="small" :icon="h(LikeOutlined)" class="reply-action-btn-child">
10
</AButton>
</AFlex>
<AFlex :vertical="false" align="center">
<AButton type="text" size="small" :icon="h(DislikeOutlined)" class="reply-action-btn-child">
1
</AButton>
</AFlex>
<AButton type="text" size="small" :icon="h(MessageOutlined)" class="reply-action-btn-child">
11
</AButton>
<AButton
@click="replyInputVisible === true? (replyInputVisible = false) : (replyInputVisible = true) "
type="text" size="small" :icon="h(CommentOutlined)"
class="reply-action-btn-child">
{{ t('comment.reply') }}
</AButton>
</AFlex>
<!-- 评论操作系统信息-->
<AFlex :vertical="false" align="center" justify="flex-end"
class="reply-action-item-right-child">
<AButton type="text" disabled size="small" :icon="h(WindowsOutlined)"
class="reply-action-info-child">
windows 10
</AButton>
<AButton type="text" disabled size="small" :icon="h(ChromeOutlined)"
class="reply-action-info-child">
chrome
</AButton>
<!-- 评论操作按钮 -->
<ADropdown trigger="click">
<AButton type="text" size="small" :icon="h(EllipsisOutlined)" class="reply-action-btn-child"
@click.prevent>
</AButton>
<template #overlay>
<AMenu>
<AMenuItem key="report">
{{ t('comment.report') }}
</AMenuItem>
<AMenuItem key="copy">
{{ t('comment.copy') }}
</AMenuItem>
<AMenuItem key="delete">
{{ t('comment.delete') }}
</AMenuItem>
</AMenu>
</template>
</ADropdown>
</AFlex>
</AFlex>
</ACard>
<!-- 子评论回复输入框 -->
<AFlex :vertical="true" class="reply-input-main-child" v-show="replyInputVisible">
<AFlex :vertical="false" align="center" class="reply-input-header-child">
<span class="reply-input-title-child">{{ t('comment.reply') + '' }}</span>
<span class="reply-input-author-child">沈建明</span>
<AButton @click="replyInputVisible = false" type="dashed" size="small" :icon="h(CloseOutlined )"
class="reply-input-cancel-child">
{{ t('comment.cancelReply') }}
</AButton>
</AFlex>
<!-- 回复头像-->
<AFlex :vertical="false" class="reply-input-content-child">
<AFlex :vertical="true" class="reply-input-avatar-child">
<AAvatar :size="40" shape="circle" src="https://api.multiavatar.com/landaiqing.svg"/>
</AFlex>
<!-- 评论输入框 -->
<AFlex :vertical="true" class="reply-input-content-text-child">
<ATextarea :rows="3" class="comment-text-reply-child"
:placeholder="commentTextAreaPlaceholder" allow-clear :showCount="false"/>
<AFlex :vertical="false" align="center" justify="space-between"
class="comment-actions-reply-child"
>
<AFlex :vertical="false" align="center">
<AFlex :vertical="false" align="center" class="comment-action-item-reply-child">
<AButton type="text" size="small" :icon="h(SmileOutlined)"
class="comment-action-icon-reply-child">
{{ t('comment.emoji') }}
</AButton>
</AFlex>
<AFlex :vertical="false" align="center" class="comment-action-item-reply-child">
<AButton type="text" size="small" :icon="h(PictureOutlined)"
class="comment-action-icon-reply-child">
{{ t('comment.picture') }}
</AButton>
</AFlex>
</AFlex>
<AFlex :vertical="false" align="center">
<AButton type="primary" size="middle" class="comment-action-btn-reply-child">
{{ t('comment.sendComment') }}
</AButton>
</AFlex>
</AFlex>
</AFlex>
</AFlex>
</AFlex>
</AFlex>
</AFlex>
</AFlex>
</AFlex>
</AFlex>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import {useI18n} from "vue-i18n";
import {h, reactive, ref} from "vue";
import {
ChromeOutlined,
CloseOutlined,
CommentOutlined,
DislikeOutlined,
EllipsisOutlined,
LikeOutlined,
MessageOutlined,
PictureOutlined,
SmileOutlined,
WindowsOutlined
} from "@ant-design/icons-vue";
import EMOJI from "@/constant/emoji.ts";
import imageCompression from "browser-image-compression";
import {message} from "ant-design-vue";
const {t} = useI18n();
const showCommentActions = ref<boolean>(false);
const commentTextAreaPlaceholder = ref<string>(t('comment.placeholder'));
const data = reactive([t('comment.latest'), t('comment.hot')]);
const segmentedValue = ref<string>(data[0]);
const replyInputVisible = ref<boolean>(false);
const commentContent = ref<string>("");
const fileList = ref<any[]>([]);
const imageList = ref<any[]>([]);
/**
* 聚焦事件
*/
async function onFocusHandler() {
showCommentActions.value = true;
}
/**
* 插入表情
* @param emoji
*/
async function insertEmoji(emoji: string) {
commentContent.value += emoji;
}
// 压缩图片配置
const options = {
maxSizeMB: 0.4,
maxWidthOrHeight: 750,
maxIteration: 2
};
/**
* 上传文件前置
* @param file
*/
async function beforeUpload(file: any) {
if (!window.FileReader) return false; // 判断是否支持FileReader
const compressedFile = await imageCompression(file, options);
const reader = new FileReader();
reader.readAsDataURL(compressedFile); // 文件转换
reader.onloadend = async function () {
if (fileList.value.length >= 5) {
message.error("最多只能上传5张图片");
return false;
}
fileList.value.push(reader.result);
};
return true;
}
/**
* 自定义上传图片请求
*/
async function customUploadRequest() {
imageList.value = fileList.value;
}
/**
* 移除图片
* @param index
*/
async function removeBase64Image(index: number) {
fileList.value.splice(index, 1);
imageList.value.splice(index, 1);
}
</script>
<style src="./index.scss" lang="scss" scoped>
</style>

View File

@@ -0,0 +1,373 @@
.comment-main {
display: flex;
flex-direction: column;
border: 1px solid #ccc;
margin-top: 20px;
width: 100%;
padding: 50px;
.comment-header-title {
font-size: 18px;
line-height: 30px;
font-weight: 600;
margin-bottom: 10px;
}
.comment-content {
margin-left: 20px;
.comment-text {
width: 600px;
}
.comment-actions {
margin-top: 10px;
.comment-action-item {
cursor: pointer;
color: #767779;
.comment-action-icon {
font-size: 14px;
color: #767779;
}
.comment-action-icon:hover {
color: #08a327;
}
}
}
}
.reply-header {
.reply-header-title {
font-size: 18px;
line-height: 30px;
font-weight: 600;
}
.reply-header-count {
font-size: 12px;
color: #767779;
margin-top: 10px;
}
.reply-header-sort {
margin-top: 10px;
width: 100px;
}
}
.reply-list {
margin-top: 30px;
.reply-content {
margin-left: 20px;
.reply-name {
font-size: 14px;
font-weight: 600;
cursor: pointer;
}
.reply-tag {
font-size: 10px;
font-weight: 800;
margin-left: 5px;
cursor: pointer;
}
.reply-ip {
font-size: 12px;
color: #767779;
}
.reply-time {
font-size: 12px;
color: #767779;
}
.reply-card {
width: 600px;
//margin-top: 5px;
.reply-action-item {
margin-top: 10px;
width: 200px;
.reply-action-btn {
font-size: 13px;
color: #767779;
cursor: pointer;
}
.reply-action-icon {
font-size: 14px;
color: #767779;
cursor: pointer;
}
.reply-action-icon:hover {
font-size: 14px;
color: #08a327;
cursor: pointer;
}
.reply-action-btn:hover {
font-size: 13px;
color: #08a327;
cursor: pointer;
}
.reply-action-icon-number {
font-size: 12px;
cursor: pointer;
color: #767779;
}
}
.reply-action-item-right {
margin-top: 10px;
.reply-action-btn {
font-size: 15px;
color: #767779;
cursor: pointer;
}
.reply-action-btn:hover {
font-size: 15px;
color: #08a327;
cursor: pointer;
}
.reply-action-info {
font-size: 12px;
color: #767779;
cursor: pointer;
}
}
}
.reply-input-main {
margin-top: 5px;
.reply-input-title {
font-size: 13px;
color: #767779;
}
.reply-input-author {
font-size: 13px;
color: #767779;
}
.reply-input-cancel {
margin-left: 10px;
font-size: 13px;
color: #767779;
cursor: pointer;
}
.reply-input-content {
margin-top: 10px;
.reply-input-content-text {
margin-left: 10px;
.comment-text-reply {
width: 550px;
}
.comment-actions-reply {
margin-top: 5px;
.comment-action-item-reply {
cursor: pointer;
color: #767779;
.comment-action-icon-reply {
font-size: 14px;
color: #767779;
}
.comment-action-icon-reply:hover {
color: #08a327;
}
}
}
}
}
}
.reply-item-child {
margin-top: 10px;
border-radius: 10px;
background-color: #f5f5f5;
padding: 10px;
.reply-item-child-content {
margin-left: 10px;
.reply-at {
font-size: 14px;
color: #767779;
cursor: pointer;
}
.reply-at:hover {
color: #25a9e3;
}
.reply-name-child {
font-size: 14px;
font-weight: 600;
cursor: pointer;
}
.reply-tag-child {
font-size: 10px;
font-weight: 800;
margin-left: 5px;
cursor: pointer;
}
.reply-ip-child {
font-size: 12px;
color: #767779;
}
.reply-time-child {
font-size: 12px;
color: #767779;
}
.reply-card-child {
width: 530px;
.reply-action-item-child {
margin-top: 10px;
width: 200px;
.reply-action-btn-child {
font-size: 13px;
color: #767779;
cursor: pointer;
}
.reply-action-icon-child {
font-size: 14px;
color: #767779;
cursor: pointer;
}
.reply-action-icon-child:hover {
font-size: 14px;
color: #08a327;
cursor: pointer;
}
.reply-action-btn-child:hover {
font-size: 13px;
color: #08a327;
cursor: pointer;
}
.reply-action-icon-number-child {
font-size: 12px;
cursor: pointer;
color: #767779;
}
}
.reply-action-item-right-child {
margin-top: 10px;
.reply-action-btn-child {
font-size: 15px;
color: #767779;
cursor: pointer;
}
.reply-action-btn-child:hover {
font-size: 15px;
color: #08a327;
cursor: pointer;
}
.reply-action-info-child {
font-size: 12px;
color: #767779;
cursor: pointer;
}
}
}
}
}
.reply-input-main-child {
margin-top: 5px;
.reply-input-title-child {
font-size: 13px;
color: #767779;
}
.reply-input-author-child {
font-size: 13px;
color: #767779;
}
.reply-input-cancel-child {
margin-left: 10px;
font-size: 13px;
color: #767779;
cursor: pointer;
}
.reply-input-content-child {
margin-top: 10px;
.reply-input-content-text-child {
margin-left: 10px;
.comment-text-reply-child {
width: 480px;
}
.comment-actions-reply-child {
margin-top: 5px;
.comment-action-item-reply-child {
cursor: pointer;
color: #767779;
.comment-action-icon-reply-child {
font-size: 14px;
color: #767779;
}
.comment-action-icon-reply-child:hover {
color: #08a327;
}
}
}
}
}
}
}
}
}