liveCommentInput.vue 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. <template>
  2. <view
  3. v-if="visible || focused"
  4. class="live-comment-input"
  5. :class="[
  6. 'live-comment-input--' + variant,
  7. 'live-comment-input--' + theme,
  8. { 'live-comment-input--focused': focused }
  9. ]">
  10. <!-- 未聚焦:点击唤起键盘 -->
  11. <view v-if="!focused" class="live-comment-input__bar">
  12. <view class="live-comment-input__trigger" @click="openInput">
  13. <text class="live-comment-input__trigger-text">{{ displayText }}</text>
  14. </view>
  15. <view v-if="showActions" class="live-comment-input__actions">
  16. <slot name="actions" />
  17. </view>
  18. </view>
  19. <!-- 聚焦:键盘上方输入框 + 发送 -->
  20. <view
  21. v-if="focused"
  22. class="live-comment-input__keyboard-panel"
  23. :style="keyboardPanelStyle">
  24. <view class="live-comment-input__editor">
  25. <input
  26. ref="commentInput"
  27. class="live-comment-input__field"
  28. type="text"
  29. :value="value"
  30. :placeholder="placeholder"
  31. :placeholder-style="placeholderStyle"
  32. placeholder-class="live-comment-input__placeholder-class"
  33. :focus="focused"
  34. :disabled="disabled"
  35. :adjust-position="false"
  36. cursor-spacing="100"
  37. :confirm-type="value ? 'send' : 'done'"
  38. @input="onInput"
  39. @focus="onFocus"
  40. @blur="onBlur"
  41. @confirm="handleSend" />
  42. <view
  43. class="live-comment-input__send"
  44. :class="{ 'live-comment-input__send--horizontal': showType === 1 }"
  45. @click.stop="handleSend">
  46. 发送
  47. </view>
  48. </view>
  49. </view>
  50. </view>
  51. </template>
  52. <script>
  53. export default {
  54. name: 'LiveCommentInput',
  55. props: {
  56. value: {
  57. type: String,
  58. default: ''
  59. },
  60. placeholder: {
  61. type: String,
  62. default: '说点什么...'
  63. },
  64. showType: {
  65. type: Number,
  66. default: 2
  67. },
  68. variant: {
  69. type: String,
  70. default: 'inline'
  71. },
  72. disabled: {
  73. type: Boolean,
  74. default: false
  75. },
  76. focused: {
  77. type: Boolean,
  78. default: false
  79. },
  80. keyboardHeight: {
  81. type: Number,
  82. default: 0
  83. },
  84. visible: {
  85. type: Boolean,
  86. default: true
  87. },
  88. showActions: {
  89. type: Boolean,
  90. default: true
  91. }
  92. },
  93. computed: {
  94. theme() {
  95. return this.showType === 1 ? 'light' : 'dark';
  96. },
  97. displayText() {
  98. return this.value || this.placeholder;
  99. },
  100. placeholderStyle() {
  101. return this.theme === 'light' ? 'color:#999999;' : 'color:#e7e7e7;';
  102. },
  103. keyboardPanelStyle() {
  104. const offset = this.keyboardHeight > 0 ? this.keyboardHeight : 0;
  105. return {
  106. transform: offset ? `translateY(-${offset}rpx)` : 'none'
  107. };
  108. }
  109. },
  110. watch: {
  111. focused(val) {
  112. if (val) {
  113. this.$nextTick(() => this.focusInput());
  114. }
  115. }
  116. },
  117. methods: {
  118. openInput() {
  119. if (this.disabled) return;
  120. this.$emit('focus');
  121. this.$nextTick(() => this.focusInput());
  122. },
  123. focusInput() {
  124. const input = this.$refs.commentInput;
  125. if (input && typeof input.focus === 'function') {
  126. input.focus();
  127. }
  128. },
  129. onInput(e) {
  130. this.$emit('input', e.detail.value);
  131. },
  132. onFocus() {
  133. this.$emit('focus');
  134. },
  135. onBlur() {
  136. this.$emit('blur');
  137. },
  138. handleSend() {
  139. if (this.disabled) return;
  140. this.$emit('send');
  141. },
  142. clearInput() {
  143. this.$emit('input', '');
  144. }
  145. }
  146. };
  147. </script>
  148. <style scoped lang="scss">
  149. .live-comment-input {
  150. width: 100%;
  151. box-sizing: border-box;
  152. }
  153. .live-comment-input--overlay {
  154. position: absolute;
  155. left: 0;
  156. right: 0;
  157. bottom: 0;
  158. padding: 24rpx;
  159. z-index: 99999;
  160. }
  161. .live-comment-input__bar {
  162. display: flex;
  163. flex-direction: row;
  164. align-items: center;
  165. justify-content: space-between;
  166. width: 100%;
  167. min-width: 0;
  168. }
  169. .live-comment-input__trigger {
  170. flex: 1;
  171. min-width: 0;
  172. border-radius: 36rpx;
  173. padding: 18rpx 20rpx;
  174. box-sizing: border-box;
  175. }
  176. .live-comment-input--dark .live-comment-input__trigger {
  177. background-color: rgba(0, 0, 0, 0.3);
  178. }
  179. .live-comment-input--light .live-comment-input__trigger {
  180. background: var(--input-bg, #f5f7fa);
  181. }
  182. .live-comment-input__trigger-text {
  183. font-size: 28rpx;
  184. line-height: 1.4;
  185. overflow: hidden;
  186. white-space: nowrap;
  187. text-overflow: ellipsis;
  188. }
  189. .live-comment-input--dark .live-comment-input__trigger-text {
  190. color: #e7e7e7;
  191. }
  192. .live-comment-input--light .live-comment-input__trigger-text {
  193. color: #999999;
  194. }
  195. .live-comment-input__actions {
  196. flex-shrink: 0;
  197. margin-left: 16rpx;
  198. display: flex;
  199. align-items: center;
  200. }
  201. .live-comment-input__keyboard-panel {
  202. position: fixed;
  203. left: 0;
  204. right: 0;
  205. bottom: 0;
  206. z-index: 10001;
  207. padding: 24rpx;
  208. box-sizing: border-box;
  209. background-color: var(--bottom-color, #ffffff);
  210. transform: translateZ(0);
  211. }
  212. .live-comment-input--dark .live-comment-input__keyboard-panel {
  213. background-color: transparent;
  214. }
  215. .live-comment-input__editor {
  216. display: flex;
  217. flex-direction: row;
  218. align-items: center;
  219. border-radius: 36rpx;
  220. padding: 10rpx 10rpx 10rpx 20rpx;
  221. box-sizing: border-box;
  222. width: 100%;
  223. }
  224. .live-comment-input--dark .live-comment-input__editor {
  225. background-color: rgba(0, 0, 0, 0.3);
  226. }
  227. .live-comment-input--light .live-comment-input__editor {
  228. background: var(--input-bg, #f5f7fa);
  229. }
  230. .live-comment-input__field {
  231. flex: 1;
  232. min-width: 0;
  233. border: none;
  234. background: transparent;
  235. font-size: 32rpx;
  236. color: var(--text-color, #333333);
  237. }
  238. .live-comment-input--dark .live-comment-input__field {
  239. color: #ffffff;
  240. }
  241. .live-comment-input__send {
  242. flex-shrink: 0;
  243. background-color: #ffffff;
  244. border-radius: 28rpx;
  245. padding: 14rpx 16rpx;
  246. color: #181818;
  247. font-weight: 500;
  248. font-size: 28rpx;
  249. min-width: 80rpx;
  250. text-align: center;
  251. margin-left: 16rpx;
  252. }
  253. .live-comment-input__send--horizontal {
  254. background-color: #FF233C;
  255. color: #ffffff;
  256. }
  257. .live-comment-input--dark .live-comment-input__send {
  258. background-color: transparent;
  259. color: #02b176;
  260. padding: 14rpx 8rpx;
  261. }
  262. </style>