feat(评论模块): 优化评论列表样式并添加点赞功能
- 重构评论列表布局,增加评论数量显示和查看更多按钮 - 为评论添加点赞功能,支持切换点赞状态并更新点赞数 - 优化底部操作栏样式,调整输入框为多行文本区域
Showing
1 changed file
with
92 additions
and
15 deletions
| ... | @@ -51,24 +51,54 @@ | ... | @@ -51,24 +51,54 @@ |
| 51 | <div class="h-2 bg-gray-100"></div> | 51 | <div class="h-2 bg-gray-100"></div> |
| 52 | 52 | ||
| 53 | <div id="comment" class="py-4 px-4 space-y-4"> | 53 | <div id="comment" class="py-4 px-4 space-y-4"> |
| 54 | - <div v-for="comment in comments" :key="comment.id" class="bg-white rounded-lg p-4 shadow-sm"> | 54 | + <div class="flex justify-between items-center mb-4"> |
| 55 | - <div class="flex items-center mb-2"> | 55 | + <div class="text-gray-900 font-medium text-sm">评论 ({{ comments.length }})</div> |
| 56 | - <img :src="comment.avatar" class="w-8 h-8 rounded-full mr-2" /> | 56 | + <div class="text-gray-500 cursor-pointer text-sm">查看更多</div> |
| 57 | - <div> | 57 | + </div> |
| 58 | - <div class="font-medium">{{ comment.username }}</div> | 58 | + <div v-for="comment in comments" :key="comment.id" class="border-b border-gray-100 last:border-b-0 py-4"> |
| 59 | - <div class="text-gray-500 text-xs">{{ comment.time }}</div> | 59 | + <div class="flex"> |
| 60 | + <!-- 左侧头像 --> | ||
| 61 | + <img :src="comment.avatar" class="w-10 h-10 rounded-full flex-shrink-0" style="margin-right: 0.5rem;" /> | ||
| 62 | + | ||
| 63 | + <!-- 右侧内容 --> | ||
| 64 | + <div class="flex-1 ml-3"> | ||
| 65 | + <!-- 第一行:用户名和点赞 --> | ||
| 66 | + <div class="flex justify-between items-center mb-1"> | ||
| 67 | + <span class="font-medium text-gray-900">{{ comment.username }}</span> | ||
| 68 | + <div class="flex items-center space-x-1"> | ||
| 69 | + <span class="text-sm text-gray-500">{{ comment.likes }}</span> | ||
| 70 | + <van-icon | ||
| 71 | + :name="comment.isLiked ? 'like' : 'like-o'" | ||
| 72 | + :class="{'text-red-500': comment.isLiked, 'text-gray-400': !comment.isLiked}" | ||
| 73 | + @click="toggleLike(comment)" | ||
| 74 | + class="text-lg cursor-pointer" | ||
| 75 | + /> | ||
| 76 | + </div> | ||
| 77 | + </div> | ||
| 78 | + | ||
| 79 | + <!-- 第二行:评论内容 --> | ||
| 80 | + <p class="text-gray-700 text-sm mb-1">{{ comment.content }}</p> | ||
| 81 | + | ||
| 82 | + <!-- 第三行:时间 --> | ||
| 83 | + <div class="text-gray-400 text-xs">{{ comment.time }}</div> | ||
| 60 | </div> | 84 | </div> |
| 61 | </div> | 85 | </div> |
| 62 | - <div class="text-gray-700">{{ comment.content }}</div> | ||
| 63 | </div> | 86 | </div> |
| 64 | </div> | 87 | </div> |
| 65 | </div> | 88 | </div> |
| 66 | 89 | ||
| 67 | <!-- 底部操作栏 --> | 90 | <!-- 底部操作栏 --> |
| 68 | <div class="fixed bottom-0 left-0 right-0 bg-white border-t px-4 py-2 flex items-center space-x-4"> | 91 | <div class="fixed bottom-0 left-0 right-0 bg-white border-t px-4 py-2 flex items-center space-x-4"> |
| 69 | - <van-button icon="bars" class="flex-none" @click="showCatalog = true">课程目录</van-button> | 92 | + <div class="flex-none flex flex-col items-center gap-1 cursor-pointer active:opacity-80" @click="showCatalog = true"> |
| 70 | - <div class="flex-grow"> | 93 | + <van-icon name="bars" class="text-lg text-gray-600" /> |
| 71 | - <van-field v-model="newComment" placeholder="说点什么吧~" class="bg-gray-100 rounded-full" /> | 94 | + <span class="text-xs text-gray-600">课程目录</span> |
| 95 | + </div> | ||
| 96 | + <div class="flex-grow flex-1 min-w-0"> | ||
| 97 | + <van-field v-model="newComment" rows="1" autosize type="textarea" placeholder="请输入留言" class="bg-gray-100 rounded-lg !p-0"> | ||
| 98 | + <template #input> | ||
| 99 | + <textarea v-model="newComment" rows="1" placeholder="请输入留言" class="w-full h-full bg-transparent outline-none resize-none" /> | ||
| 100 | + </template> | ||
| 101 | + </van-field> | ||
| 72 | </div> | 102 | </div> |
| 73 | <van-button type="primary" size="small" @click="submitComment">发送</van-button> | 103 | <van-button type="primary" size="small" @click="submitComment">发送</van-button> |
| 74 | </div> | 104 | </div> |
| ... | @@ -115,21 +145,54 @@ const comments = ref([ | ... | @@ -115,21 +145,54 @@ const comments = ref([ |
| 115 | username: '欢乐马', | 145 | username: '欢乐马', |
| 116 | avatar: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', | 146 | avatar: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', |
| 117 | content: '教育的顶级传承,是你用什么样的心,传承智慧', | 147 | content: '教育的顶级传承,是你用什么样的心,传承智慧', |
| 118 | - time: '2024-12-04 18:51' | 148 | + time: '2024-12-04 18:51', |
| 149 | + likes: 12, | ||
| 150 | + isLiked: false | ||
| 151 | + }, | ||
| 152 | + { | ||
| 153 | + id: 2, | ||
| 154 | + username: '欢乐马', | ||
| 155 | + avatar: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', | ||
| 156 | + content: '不要用战术上的勤奋,掩盖战略上的懒惰', | ||
| 157 | + time: '2024-12-04 08:01', | ||
| 158 | + likes: 8, | ||
| 159 | + isLiked: true | ||
| 160 | + }, | ||
| 161 | + { | ||
| 162 | + id: 3, | ||
| 163 | + username: '欢乐马', | ||
| 164 | + avatar: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', | ||
| 165 | + content: '和老师积极互动,整个课堂像为你而讲', | ||
| 166 | + time: '2024-12-04 07:54', | ||
| 167 | + likes: 5, | ||
| 168 | + isLiked: false | ||
| 169 | + }, | ||
| 170 | + { | ||
| 171 | + id: 1, | ||
| 172 | + username: '欢乐马', | ||
| 173 | + avatar: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', | ||
| 174 | + content: '教育的顶级传承,是你用什么样的心,传承智慧', | ||
| 175 | + time: '2024-12-04 18:51', | ||
| 176 | + likes: 12, | ||
| 177 | + isLiked: false | ||
| 119 | }, | 178 | }, |
| 120 | { | 179 | { |
| 121 | id: 2, | 180 | id: 2, |
| 122 | username: '欢乐马', | 181 | username: '欢乐马', |
| 123 | avatar: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', | 182 | avatar: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', |
| 124 | content: '不要用战术上的勤奋,掩盖战略上的懒惰', | 183 | content: '不要用战术上的勤奋,掩盖战略上的懒惰', |
| 125 | - time: '2024-12-04 08:01' | 184 | + time: '2024-12-04 08:01', |
| 185 | + likes: 8, | ||
| 186 | + isLiked: true | ||
| 126 | }, | 187 | }, |
| 127 | { | 188 | { |
| 128 | id: 3, | 189 | id: 3, |
| 129 | username: '欢乐马', | 190 | username: '欢乐马', |
| 130 | avatar: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', | 191 | avatar: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', |
| 131 | content: '和老师积极互动,整个课堂像为你而讲', | 192 | content: '和老师积极互动,整个课堂像为你而讲', |
| 132 | - time: '2024-12-04 07:54' | 193 | + time: '2024-12-04 07:54', |
| 194 | + likes: 5, | ||
| 195 | + isLiked: false | ||
| 133 | } | 196 | } |
| 134 | ]); | 197 | ]); |
| 135 | 198 | ||
| ... | @@ -164,6 +227,12 @@ onMounted(() => { | ... | @@ -164,6 +227,12 @@ onMounted(() => { |
| 164 | }) | 227 | }) |
| 165 | 228 | ||
| 166 | // 提交评论 | 229 | // 提交评论 |
| 230 | +// 切换点赞状态 | ||
| 231 | +const toggleLike = (comment) => { | ||
| 232 | + comment.isLiked = !comment.isLiked; | ||
| 233 | + comment.likes += comment.isLiked ? 1 : -1; | ||
| 234 | +}; | ||
| 235 | + | ||
| 167 | const submitComment = () => { | 236 | const submitComment = () => { |
| 168 | if (!newComment.value.trim()) return; | 237 | if (!newComment.value.trim()) return; |
| 169 | 238 | ||
| ... | @@ -172,7 +241,9 @@ const submitComment = () => { | ... | @@ -172,7 +241,9 @@ const submitComment = () => { |
| 172 | username: '当前用户', | 241 | username: '当前用户', |
| 173 | avatar: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', | 242 | avatar: 'https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg', |
| 174 | content: newComment.value, | 243 | content: newComment.value, |
| 175 | - time: new Date().toLocaleString() | 244 | + time: new Date().toLocaleString(), |
| 245 | + likes: 0, | ||
| 246 | + isLiked: false | ||
| 176 | }); | 247 | }); |
| 177 | 248 | ||
| 178 | newComment.value = ''; | 249 | newComment.value = ''; |
| ... | @@ -182,7 +253,7 @@ const submitComment = () => { | ... | @@ -182,7 +253,7 @@ const submitComment = () => { |
| 182 | const handleTabChange = (name) => { | 253 | const handleTabChange = (name) => { |
| 183 | nextTick(() => { | 254 | nextTick(() => { |
| 184 | const element = document.getElementById(name === 'intro' ? 'intro' : 'comment'); | 255 | const element = document.getElementById(name === 'intro' ? 'intro' : 'comment'); |
| 185 | - if (element && container) { | 256 | + if (element) { |
| 186 | const topOffset = element.offsetTop - parseInt(topWrapperHeight.value); | 257 | const topOffset = element.offsetTop - parseInt(topWrapperHeight.value); |
| 187 | window.scrollTo({ | 258 | window.scrollTo({ |
| 188 | top: topOffset, | 259 | top: topOffset, |
| ... | @@ -194,3 +265,9 @@ const handleTabChange = (name) => { | ... | @@ -194,3 +265,9 @@ const handleTabChange = (name) => { |
| 194 | 265 | ||
| 195 | 266 | ||
| 196 | </script> | 267 | </script> |
| 268 | + | ||
| 269 | +<style lang="less" scoped> | ||
| 270 | +:deep(.van-cell.van-field) { | ||
| 271 | + background-color: rgb(244, 244, 244); | ||
| 272 | +} | ||
| 273 | +</style> | ... | ... |
-
Please register or login to post a comment