fs-comment.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. <template>
  2. <view>
  3. <fs-cell-group full border :radius="false">
  4. <fs-cell align="top" v-for="(item,index) in list" :key="item.id">
  5. <template #title>
  6. <fs-avatar :src="item[keyMap.avatar]"></fs-avatar>
  7. </template>
  8. <template #value>
  9. <view class="fs-comment-hd">
  10. <view class="fs-comment-hd-item fs-comment-hd-title">{{item[keyMap.name]}}</view>
  11. <view class="fs-comment-hd-item">{{item[keyMap.time]}}</view>
  12. </view>
  13. <view class="fs-comment-content">
  14. {{item[keyMap.content]}}
  15. </view>
  16. <view class="fs-comment-reply">
  17. <view class="fs-comment-reply-item" @click="handleLike(item)" v-if="showLike">
  18. <fs-icon type="icon-like" :color="item[keyMap.isLike] ? 'red' : ''"></fs-icon>
  19. <view v-if="!item[keyMap.isLike]">点赞</view>
  20. </view>
  21. <view class="fs-comment-reply-item" @click="initInput(item)">
  22. <fs-icon type="icon-comment"></fs-icon> 回复
  23. </view>
  24. </view>
  25. <view class="fs-comment-reply-box">
  26. <fs-cell-group border bgColor="transparent" full>
  27. <fs-cell align="top" v-for="reply in item[keyMap.replyList]" :key="reply.id">
  28. <template #title>
  29. <fs-avatar :src="reply[keyMap.avatar]"></fs-avatar>
  30. </template>
  31. <template #value>
  32. <view class="fs-comment-hd fs-comment-hd-title">
  33. <view class="fs-comment-hd-item">{{reply[keyMap.name]}}</view>
  34. <view class="fs-comment-hd-item">{{reply[keyMap.time]}}</view>
  35. </view>
  36. <view class="fs-comment-content">
  37. {{reply[keyMap.content]}}
  38. </view>
  39. <view class="fs-comment-reply">
  40. <view class="fs-comment-reply-item" @click="handleLike(reply)" v-if="showLike">
  41. <fs-icon type="icon-like" :color="reply[keyMap.isLike] ? 'red' : ''"></fs-icon>
  42. <view v-if="!reply[keyMap.isLike]">点赞</view>
  43. </view>
  44. <view class="fs-comment-reply-item" @click="initInput(reply)">
  45. <fs-icon type="icon-comment"></fs-icon> 回复
  46. </view>
  47. </view>
  48. </template>
  49. </fs-cell>
  50. </fs-cell-group>
  51. </view>
  52. </template>
  53. </fs-cell>
  54. </fs-cell-group>
  55. <view class="fs-comment-input-box" v-if="showInput">
  56. <input
  57. type="text"
  58. class="fs-comment-input"
  59. placeholder="回复..."
  60. v-model="replyValue"
  61. :focus="focus"
  62. @confirm="handleConfirm"/>
  63. <view
  64. class="fs-comment-button"
  65. @click="handleConfirm">
  66. 发送
  67. </view>
  68. <!-- :style="{backgroundColor: replyValue ? '#08bf65' : '#f7f7f7',color: replyValue ? '#fff' : '#cecece'}" -->
  69. </view>
  70. </view>
  71. </template>
  72. <script>
  73. export default {
  74. name: 'fs-comment'
  75. }
  76. </script>
  77. <script setup>
  78. import { ref, nextTick } from 'vue'
  79. const props = defineProps({
  80. list: {
  81. type: Array,
  82. default() {
  83. return []
  84. }
  85. },
  86. showLike: Boolean,
  87. keyMap: {
  88. type: Object,
  89. default() {
  90. return {
  91. avatar: 'avatar',
  92. name: 'name',
  93. time: 'time',
  94. content: 'content',
  95. replyList: 'children',
  96. isLike: 'isLike'
  97. }
  98. }
  99. }
  100. })
  101. const emits = defineEmits(['like', 'reply'])
  102. let focus = ref(false)
  103. let showInput = ref(false)
  104. let reply = ref(null)
  105. let replyValue = ref('')
  106. const initInput = (item) => {
  107. showInput.value = true
  108. focus.value = true
  109. reply.value = item
  110. replyValue.value = ''
  111. }
  112. const handleBlur = () => {
  113. nextTick(() => {
  114. showInput.value = false
  115. focus.value = false
  116. })
  117. }
  118. const handleConfirm = () => {
  119. if (replyValue.value) {
  120. emits('reply', reply.value)
  121. }
  122. showInput.value = false
  123. focus.value = false
  124. }
  125. const handleLike = (item) => {
  126. item[props.keyMap.isLike] = !item[props.keyMap.isLike]
  127. emits('like', item)
  128. }
  129. </script>
  130. <style lang="scss">
  131. .fs-comment{
  132. font-size: 14px;
  133. &-hd{
  134. display: flex;
  135. &-title{
  136. color: #222;
  137. }
  138. &-item{
  139. padding-right: 30rpx;
  140. position: relative;
  141. margin-bottom: 10rpx;
  142. & + &{
  143. padding-left: 30rpx;
  144. &::before{
  145. position: absolute;
  146. left: 0;
  147. top: 50%;
  148. transform: translateY(-50%);
  149. width: 2rpx;
  150. height: 24rpx;
  151. background-color: #D9D9D9;
  152. content: '';
  153. }
  154. }
  155. }
  156. }
  157. &-content{
  158. font-size: 14px;
  159. }
  160. &-reply-box{
  161. background-color: #f7f8fa;
  162. margin-top: 10rpx;
  163. border-radius: var(--radius);
  164. overflow: hidden;
  165. }
  166. &-reply{
  167. display: flex;
  168. font-size: 14px;
  169. margin-top: 10rpx;
  170. align-items: center;
  171. &-item{
  172. display: flex;
  173. align-items: center;
  174. margin-right: 30rpx;
  175. }
  176. }
  177. &-input-box{
  178. height: 110rpx;
  179. position: fixed;
  180. display: flex;
  181. left: 0;
  182. right: 0;
  183. bottom: 0;
  184. padding: 20rpx;
  185. border-top: 1rpx solid #eaeaea;
  186. background-color: #fff;
  187. align-items: center;
  188. z-index: 10;
  189. }
  190. &-input{
  191. height: 100%;
  192. margin-right: 20rpx;
  193. flex: 1;
  194. background-color: #fff;
  195. border-radius: 8rpx;
  196. padding-left: 20rpx;
  197. }
  198. &-button {
  199. height: 100%;
  200. padding: 10rpx 20rpx;
  201. border-radius: 8rpx;
  202. box-sizing: border-box;
  203. display: flex;
  204. align-items: center;
  205. background-color: #08bf65;
  206. color: #fff;
  207. }
  208. }
  209. </style>