与牧同行-小程序用户端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

406 lines
10 KiB

  1. Page({
  2. data: {
  3. post: null,
  4. replyContent: '',
  5. replyTarget: {
  6. type: '',
  7. username: '',
  8. replyId: '',
  9. replyIndex: null,
  10. commentId: '',
  11. commentIndex: null
  12. },
  13. replyPlaceholder: '输入您的回复...',
  14. isInputFocused: false,
  15. inputTransformY: '0',
  16. isSubmitting: false,
  17. showPreview: false,
  18. previewImages: [],
  19. previewIndex: 0,
  20. loading: false,
  21. scrollToId: '',
  22. currentUser: '当前用户',
  23. keyboardHeight: 0
  24. },
  25. onLoad: function(options) {
  26. const postId = options.id || '1';
  27. this.loadPostDetail(postId);
  28. // 监听键盘高度变化
  29. wx.onKeyboardHeightChange(res => {
  30. if (res.height > 0) {
  31. this.setData({ keyboardHeight: res.height });
  32. }
  33. });
  34. },
  35. // 加载帖子详情
  36. loadPostDetail: function(postId) {
  37. this.setData({ loading: true });
  38. // 模拟API请求
  39. setTimeout(() => {
  40. const mockPost = {
  41. id: 1,
  42. username: '技术爱好者',
  43. avatar: 'https://img.yzcdn.cn/vant/cat.jpeg',
  44. time: '2小时前',
  45. title: '微信小程序如何实现图片上传和预览功能?',
  46. content: '我正在开发一个微信小程序,需要实现图片上传功能,并且能够在上传前预览图片。请问有什么好的实现方案吗?上传的图片大小限制和格式有什么建议?',
  47. images: [
  48. 'https://img.yzcdn.cn/vant/cat.jpeg',
  49. 'https://img.yzcdn.cn/vant/cat.jpeg'
  50. ],
  51. tags: ['微信小程序', '图片上传', '前端开发'],
  52. likeCount: 12,
  53. replyCount: 5,
  54. viewCount: 156,
  55. liked: false,
  56. solved: false,
  57. replies: [
  58. {
  59. replyId: 'r1_1',
  60. username: '前端开发工程师',
  61. avatar: 'https://img.yzcdn.cn/vant/cat.jpeg',
  62. time: '1小时前',
  63. content: '可以使用wx.chooseImage选择图片,然后使用wx.uploadFile上传到服务器。预览功能可以使用wx.previewImage实现。',
  64. likeCount: 3,
  65. liked: false,
  66. comments: [
  67. {
  68. commentId: 'c1_1',
  69. username: '学习者',
  70. avatar: 'https://img.yzcdn.cn/vant/cat.jpeg',
  71. toUsername: '前端开发工程师',
  72. time: '30分钟前',
  73. content: '感谢分享,请问有具体的代码示例吗?'
  74. }
  75. ]
  76. },
  77. {
  78. replyId: 'r1_2',
  79. username: '小程序开发者',
  80. avatar: 'https://img.yzcdn.cn/vant/cat.jpeg',
  81. time: '45分钟前',
  82. content: '建议将图片大小限制在2MB以内,支持JPG、PNG格式。可以使用云开发存储功能简化上传流程。',
  83. likeCount: 2,
  84. liked: true,
  85. comments: []
  86. }
  87. ]
  88. };
  89. this.setData({
  90. post: mockPost,
  91. loading: false
  92. });
  93. }, 500);
  94. },
  95. // 滚动监听
  96. onScroll: function(e) {
  97. // 可以在这里实现滚动相关逻辑
  98. },
  99. // 输入框获取焦点
  100. onInputFocus: function(e) {
  101. this.setData({
  102. isInputFocused: true,
  103. inputTransformY: `-${e.detail.height}px`
  104. });
  105. },
  106. // 输入框失去焦点
  107. onInputBlur: function() {
  108. this.setData({
  109. isInputFocused: false,
  110. inputTransformY: '0'
  111. });
  112. },
  113. // 回复输入
  114. onReplyInput: function(e) {
  115. this.setData({
  116. replyContent: e.detail.value
  117. });
  118. },
  119. // 聚焦到输入框
  120. focusReplyInput: function() {
  121. this.setData({
  122. replyTarget: {
  123. type: 'post',
  124. username: this.data.post.username
  125. },
  126. replyPlaceholder: `回复 ${this.data.post.username}...`,
  127. replyContent: '',
  128. isInputFocused: true
  129. });
  130. },
  131. // 回复用户
  132. replyToUser: function(e) {
  133. const { type, index, replyIndex, commentIndex, username } = e.currentTarget.dataset;
  134. const replyTarget = {
  135. type: type,
  136. username: username
  137. };
  138. if (type === 'reply') {
  139. replyTarget.replyIndex = parseInt(index);
  140. replyTarget.replyId = this.data.post.replies[index].replyId;
  141. } else if (type === 'comment') {
  142. replyTarget.replyIndex = parseInt(replyIndex);
  143. replyTarget.commentIndex = parseInt(commentIndex);
  144. replyTarget.commentId = this.data.post.replies[replyIndex].comments[commentIndex].commentId;
  145. replyTarget.replyId = this.data.post.replies[replyIndex].replyId;
  146. }
  147. this.setData({
  148. replyTarget: replyTarget,
  149. replyPlaceholder: `回复 @${username}...`,
  150. replyContent: '',
  151. isInputFocused: true
  152. });
  153. // 滚动到输入框位置
  154. setTimeout(() => {
  155. this.setData({
  156. scrollToId: type === 'reply' ? `reply-${replyTarget.replyId}` : ''
  157. });
  158. }, 100);
  159. },
  160. // 清除回复目标
  161. clearReplyTarget: function() {
  162. this.setData({
  163. replyTarget: {
  164. type: '',
  165. username: '',
  166. replyId: '',
  167. replyIndex: null,
  168. commentId: '',
  169. commentIndex: null
  170. },
  171. replyPlaceholder: '输入您的回复...',
  172. replyContent: ''
  173. });
  174. },
  175. // 提交回复
  176. submitReply: function() {
  177. const { replyContent, replyTarget, post } = this.data;
  178. const content = replyContent.trim();
  179. if (!content) {
  180. wx.showToast({ title: '请输入内容', icon: 'none' });
  181. return;
  182. }
  183. if (content.length > 500) {
  184. wx.showToast({ title: '回复内容不能超过500字', icon: 'none' });
  185. return;
  186. }
  187. this.setData({ isSubmitting: true });
  188. // 模拟网络请求
  189. setTimeout(() => {
  190. if (replyTarget.type === 'post') {
  191. // 回复帖子
  192. this.replyToPost(content);
  193. } else if (replyTarget.type === 'reply') {
  194. // 回复评论
  195. this.replyToComment(content, replyTarget);
  196. } else if (replyTarget.type === 'comment') {
  197. // 回复评论的回复
  198. this.replyToCommentReply(content, replyTarget);
  199. } else {
  200. // 普通回复(直接回复帖子)
  201. this.replyToPost(content);
  202. }
  203. this.setData({ isSubmitting: false });
  204. }, 500);
  205. },
  206. // 回复帖子
  207. replyToPost: function(content) {
  208. const post = this.data.post;
  209. const replyId = `r${post.id}_${Date.now()}`;
  210. const newReply = {
  211. replyId: replyId,
  212. username: this.data.currentUser,
  213. avatar: 'https://img.yzcdn.cn/vant/cat.jpeg',
  214. time: '刚刚',
  215. content: content,
  216. likeCount: 0,
  217. liked: false,
  218. comments: []
  219. };
  220. post.replies.push(newReply);
  221. post.replyCount += 1;
  222. this.setData({
  223. post: post,
  224. replyContent: '',
  225. replyTarget: {
  226. type: '',
  227. username: '',
  228. replyId: '',
  229. replyIndex: null,
  230. commentId: '',
  231. commentIndex: null
  232. },
  233. replyPlaceholder: '输入您的回复...',
  234. isInputFocused: false
  235. });
  236. wx.showToast({
  237. title: '回复成功',
  238. icon: 'success',
  239. duration: 1500
  240. });
  241. // 滚动到最新回复
  242. setTimeout(() => {
  243. this.setData({
  244. scrollToId: `reply-${replyId}`
  245. });
  246. }, 800);
  247. },
  248. // 回复评论
  249. replyToComment: function(content, target) {
  250. const post = this.data.post;
  251. const replyIndex = target.replyIndex;
  252. const reply = post.replies[replyIndex];
  253. const commentId = `c${reply.replyId}_${Date.now()}`;
  254. const newComment = {
  255. commentId: commentId,
  256. username: this.data.currentUser,
  257. avatar: 'https://img.yzcdn.cn/vant/cat.jpeg',
  258. toUsername: target.username,
  259. time: '刚刚',
  260. content: content
  261. };
  262. if (!reply.comments) {
  263. reply.comments = [];
  264. }
  265. reply.comments.push(newComment);
  266. this.setData({
  267. post: post,
  268. replyContent: '',
  269. replyTarget: {
  270. type: '',
  271. username: '',
  272. replyId: '',
  273. replyIndex: null,
  274. commentId: '',
  275. commentIndex: null
  276. },
  277. replyPlaceholder: '输入您的回复...',
  278. isInputFocused: false
  279. });
  280. wx.showToast({
  281. title: '回复成功',
  282. icon: 'success',
  283. duration: 1500
  284. });
  285. },
  286. // 回复评论的回复
  287. replyToCommentReply: function(content, target) {
  288. const post = this.data.post;
  289. const reply = post.replies[target.replyIndex];
  290. const originalComment = reply.comments[target.commentIndex];
  291. const commentId = `cc${originalComment.commentId}_${Date.now()}`;
  292. const newComment = {
  293. commentId: commentId,
  294. username: this.data.currentUser,
  295. avatar: 'https://img.yzcdn.cn/vant/cat.jpeg',
  296. toUsername: target.username,
  297. time: '刚刚',
  298. content: content
  299. };
  300. reply.comments.push(newComment);
  301. this.setData({
  302. post: post,
  303. replyContent: '',
  304. replyTarget: {
  305. type: '',
  306. username: '',
  307. replyId: '',
  308. replyIndex: null,
  309. commentId: '',
  310. commentIndex: null
  311. },
  312. replyPlaceholder: '输入您的回复...',
  313. isInputFocused: false
  314. });
  315. wx.showToast({
  316. title: '回复成功',
  317. icon: 'success',
  318. duration: 1500
  319. });
  320. },
  321. // 图片预览
  322. previewImage: function(e) {
  323. const imgIndex = e.currentTarget.dataset.imgIndex;
  324. const images = this.data.post.images;
  325. this.setData({
  326. showPreview: true,
  327. previewImages: images,
  328. previewIndex: imgIndex
  329. });
  330. },
  331. // 图片预览滑动
  332. onSwiperChange: function(e) {
  333. this.setData({
  334. previewIndex: e.detail.current
  335. });
  336. },
  337. // 隐藏预览
  338. hidePreview: function() {
  339. this.setData({ showPreview: false });
  340. },
  341. // 下拉刷新
  342. onPullDownRefresh: function() {
  343. if (this.data.post) {
  344. this.loadPostDetail(this.data.post.id);
  345. }
  346. wx.stopPullDownRefresh();
  347. },
  348. // 页面上拉触底
  349. onReachBottom: function() {
  350. // 这里可以实现加载更多回复的逻辑
  351. console.log('加载更多回复');
  352. },
  353. // 页面卸载
  354. onUnload: function() {
  355. // 移除键盘高度监听
  356. wx.offKeyboardHeightChange();
  357. }
  358. });