diff --git a/src/assets/user/1.jpg b/src/assets/user/1.jpg new file mode 100644 index 0000000..5fb8441 Binary files /dev/null and b/src/assets/user/1.jpg differ diff --git a/src/assets/user/2.jpg b/src/assets/user/2.jpg new file mode 100644 index 0000000..1dabf67 Binary files /dev/null and b/src/assets/user/2.jpg differ diff --git a/src/assets/user/3.jpeg b/src/assets/user/3.jpeg new file mode 100644 index 0000000..a16a772 Binary files /dev/null and b/src/assets/user/3.jpeg differ diff --git a/src/views/customer/AnonymousShareCircle.vue b/src/views/customer/AnonymousShareCircle.vue index ba232ba..b081699 100644 --- a/src/views/customer/AnonymousShareCircle.vue +++ b/src/views/customer/AnonymousShareCircle.vue @@ -1,13 +1,137 @@ @@ -15,33 +139,944 @@ export default { data () { return { + currentUser: { + name: 'Infinity', + avatar: require('@/assets/user/1.jpg') + }, + coverImage: require('@/assets/user/1.jpg'), + publishDialogVisible: false, newPost: '', - posts: [] + selectedImages: [], + refreshState: 'none', + refreshHeight: 0, + touchStartY: 0, + lastScrollTop: 0, + isRefreshing: false, + posts: [ + { + id: 1, + userName: '用户1', + avatar: require('@/assets/user/1.jpg'), + content: '春天来了,校园里的樱花开得真美!', + time: '44分钟前', + images: [ + require('@/assets/user/1.jpg') + ], + likes: 3, + isLiked: false, + likeUsers: ['张三', '李四', '王五'], + comments: [ + { + userName: '张三', + content: '确实很美,我也拍了好多照片!' + }, + { + userName: '李四', + content: '今年的樱花开得特别早呢' + }, + { + userName: '王五', + content: '周末一起去赏花吧?' + } + ], + showActions: false + }, + { + id: 2, + userName: '用户2', + avatar: require('@/assets/user/1.jpg'), + content: '今天天气真好,适合出去玩', + time: '1小时前', + images: [ + require('@/assets/user/1.jpg') + ], + likes: 2, + isLiked: false, + likeUsers: ['小明', '小红'], + comments: [ + { + userName: '小明', + content: '是啊,阳光正好' + }, + { + userName: '小红', + content: '我们去哪里玩呢?' + } + ], + showActions: false + }, + { + id: 3, + userName: '小王', + avatar: require('@/assets/user/1.jpg'), + content: '新买的相机终于到了,迫不及待想要出去拍照了!分享一下开箱照片', + time: '2小时前', + images: [ + require('@/assets/user/1.jpg'), + require('@/assets/user/1.jpg'), + require('@/assets/user/1.jpg') + ], + likes: 8, + isLiked: true, + likeUsers: ['小张', '小李', '小陈', '小林', '阿华', '小美', '大卫', '杰克'], + comments: [ + { + userName: '小张', + content: '这个机型不错,我也在用' + }, + { + userName: '小李', + content: '期待你的作品!' + }, + { + userName: '小陈', + content: '求拍照教程' + } + ], + showActions: false + }, + { + id: 4, + userName: '咖啡控', + avatar: require('@/assets/user/1.jpg'), + content: '发现了一家很棒的咖啡店,环境超赞,咖啡也很香!推荐大家来尝尝~', + time: '3小时前', + images: [ + require('@/assets/user/1.jpg'), + require('@/assets/user/1.jpg') + ], + likes: 5, + isLiked: false, + likeUsers: ['奶茶控', '美食家', '探店达人', '小饭', '老王'], + comments: [ + { + userName: '奶茶控', + content: '下次一起去!' + }, + { + userName: '美食家', + content: '这家店我也去过,他们家的提拉米苏也很好吃' + }, + { + userName: '探店达人', + content: '求具体位置' + }, + { + userName: '咖啡控', + content: '在市中心新开的购物中心三楼,店名叫"啡时光"' + } + ], + showActions: false + }, + { + id: 5, + userName: '运动达人', + avatar: require('@/assets/user/1.jpg'), + content: '今天完成了半程马拉松训练,为下个月的比赛做准备!', + time: '5小时前', + images: [ + require('@/assets/user/1.jpg') + ], + likes: 12, + isLiked: false, + likeUsers: ['跑步爱好者', '健身教练', '马拉松', '小跑', '老李', '小王'], + comments: [ + { + userName: '跑步爱好者', + content: '加油!看好你' + }, + { + userName: '健身教练', + content: '记得做好赛前准备和恢复' + } + ], + showActions: false + } + ] + } + }, + computed: { + refreshText () { + const texts = { + none: '', + pulling: '下拉刷新', + ready: '释放立即刷新', + loading: '刷新中...' + } + return texts[this.refreshState] } }, methods: { - submitPost () { - if (this.newPost) { - this.posts.push({ id: Date.now(), content: this.newPost }) - this.newPost = '' + showPublishDialog () { + this.publishDialogVisible = true + }, + handleImageChange (file) { + this.selectedImages.push(file.raw) + }, + handleCommand (command, post) { + // 兼容旧的下拉菜单方式 + }, + handleLike (post) { + // 处理点赞逻辑 + post.isLiked = !post.isLiked + + if (post.isLiked) { + // 增加点赞数 + post.likes++ + // 添加当前用户到点赞列表 + post.likeUsers.push(this.currentUser.name) + + // 显示点赞成功消息 + this.$message({ + message: '点赞成功', + type: 'success', + duration: 1000 + }) + } else { + // 减少点赞数 + post.likes-- + // 从点赞列表中移除当前用户 + const index = post.likeUsers.indexOf(this.currentUser.name) + if (index !== -1) { + post.likeUsers.splice(index, 1) + } } + + // 点赞后关闭操作菜单 + post.showActions = false + }, + handleComment (post) { + // 首先关闭操作菜单 + post.showActions = false + + // 弹出评论输入框 + this.$prompt('请输入评论内容', '发表评论', { + confirmButtonText: '发表', + cancelButtonText: '取消', + inputPlaceholder: '说点什么吧...' + }).then(({ value }) => { + if (value.trim()) { + // 添加新评论 + post.comments.push({ + userName: this.currentUser.name, + content: value.trim() + }) + + // 显示评论成功消息 + this.$message({ + message: '评论成功', + type: 'success', + duration: 1000 + }) + } + }).catch(() => { + // 用户取消评论,不做处理 + }) + }, + submitPost () { + if (this.newPost || this.selectedImages.length) { + const newPost = { + id: Date.now(), + userName: this.currentUser.name, + avatar: this.currentUser.avatar, + content: this.newPost, + time: '刚刚', + images: this.selectedImages.map(img => URL.createObjectURL(img)), + likes: 0, + isLiked: false, + likeUsers: [], + comments: [], + showActions: false + } + this.posts.unshift(newPost) + this.newPost = '' + this.selectedImages = [] + this.publishDialogVisible = false + } + }, + handleWheel (e) { + // 如果正在刷新中或已经触发刷新但尚未完成,阻止滚轮事件处理 + if (this.refreshState === 'loading' || this.isRefreshing) { + e.preventDefault() + return + } + + const scrollTop = window.pageYOffset || document.documentElement.scrollTop + + // 判断页面是否在顶部 + if (scrollTop <= 5) { + // 向上滚动鼠标滚轮(deltaY为负值) + if (e.deltaY < 0) { + e.preventDefault() // 阻止默认滚动行为 + + // 计算拉动距离,取绝对值并缩放以使操作更平滑 + const pullDistance = Math.abs(e.deltaY) * 2 // 增大倍数,使效果更明显 + + // 设置拉动阈值,超过此值直接触发刷新 + const threshold = 60 // 降低阈值,让刷新更容易触发 + + if (pullDistance >= threshold) { + // 显示刷新指示并直接刷新 + this.refreshState = 'ready' + this.refreshHeight = threshold + + // 更新内容区域位置 + const content = document.querySelector('.moments-content') + if (content) { + content.style.transform = `translateY(${this.refreshHeight}px)` + } + + // 标记当前已触发刷新,防止重复触发 + this.isRefreshing = true + + // 直接触发刷新 + setTimeout(() => { + this.refreshData() + }, 200) + } else { + // 轻微拉动时只显示拉动效果 + this.handlePull(pullDistance) + } + } + } + + this.lastScrollTop = scrollTop + }, + handleTouchMove (e) { + // 如果正在加载中或已经触发刷新但尚未完成,阻止触摸移动事件 + if (this.refreshState === 'loading' || this.isRefreshing) { + e.preventDefault() + return + } + + const scrollTop = window.pageYOffset || document.documentElement.scrollTop + const touch = e.touches[0] + + if (this.touchStartY === 0) { + this.touchStartY = touch.clientY + } + + if (scrollTop <= 5) { + const moveY = touch.clientY - this.touchStartY + if (moveY > 0) { + e.preventDefault() + this.handlePull(moveY / 1.2) + } + } + }, + handleTouchEnd (e) { + // 如果正在加载中或已经触发刷新但尚未完成,阻止触摸结束事件 + if (this.refreshState === 'loading' || this.isRefreshing) { + e.preventDefault() + return + } + + if (this.refreshState === 'ready') { + // 标记当前已触发刷新,防止重复触发 + this.isRefreshing = true + this.refreshData() + } else if (this.refreshState === 'pulling') { + this.resetRefresh() + } + + this.touchStartY = 0 + }, + handlePull (distance) { + // 如果已经在加载状态或已经触发刷新但尚未完成,不再处理拉动 + if (this.refreshState === 'loading' || this.isRefreshing) return + + // 设置最大拉动距离 + const maxDistance = 200 + const threshold = maxDistance * 0.6 // 触发刷新的阈值 + + // 限制拉动距离 + this.refreshHeight = Math.min(distance, maxDistance) + + // 更新界面显示 + const content = document.querySelector('.moments-content') + if (content) { + content.style.transform = `translateY(${this.refreshHeight}px)` + } + + // 根据拉动距离决定刷新状态 + if (this.refreshHeight >= threshold) { + this.refreshState = 'ready' + } else { + this.refreshState = 'pulling' + } + }, + resetRefresh () { + console.log('重置刷新状态和UI') + + // 重置所有状态变量 + this.refreshState = 'none' + this.refreshHeight = 0 + this.touchStartY = 0 + this.isRefreshing = false // 重置刷新标记 + + // 强制刷新DOM + const content = document.querySelector('.moments-content') + if (content) { + // 确保内容区域回到原位 + content.style.transform = 'translateY(0)' + // 强制浏览器重新计算样式 - 使用读取属性来触发重排 + // eslint-disable-next-line no-unused-expressions + content.offsetHeight + } + + // 确保指示器被完全移除 + // Vue的v-if会处理DOM的移除,所以这里不需要额外的DOM操作 + }, + refreshData () { + // 清楚标记当前正在刷新,阻止其他刷新操作 + console.log('开始刷新,refreshState设置为loading') + this.refreshState = 'loading' + this.isRefreshing = true // 确保刷新标记被设置 + + // 模拟数据库查询延迟 + setTimeout(() => { + try { + // 模拟数据获取 + console.log('正在从服务器获取数据...') + + // 模拟新数据 + const newPost = { + id: Date.now(), + userName: '新朋友', + avatar: require('@/assets/user/1.jpg'), + content: '刚刚发布的新内容,下拉刷新测试!', + time: '刚刚', + images: [require('@/assets/user/1.jpg')], + likes: 0, + isLiked: false, + likeUsers: [], + comments: [], + showActions: false + } + + // 添加新数据到列表顶部 + this.posts.unshift(newPost) + + // 显示成功消息 + this.$message({ + message: '刷新成功,新增1条朋友圈', + type: 'success' + }) + + console.log('刷新完成,数据已更新') + } catch (error) { + console.error('更新数据失败:', error) + this.$message({ + message: '刷新失败,请稍后再试', + type: 'error' + }) + } finally { + console.log('刷新状态重置') + // 先重置刷新状态 + this.refreshState = 'none' + + // 然后重置UI + setTimeout(() => { + this.resetRefresh() // 这将同时重置isRefreshing标记 + }, 100) + } + }, 1500) // 模拟1.5秒的加载时间 + }, + handleScroll () { + if (this.refreshState !== 'loading' && window.pageYOffset > 10) { + this.resetRefresh() + } + }, + handleVisibilityChange () { + if (document.visibilityState === 'visible') { + // 页面重新可见时,如果不是加载状态,则重置刷新 + if (this.refreshState !== 'loading') { + this.resetRefresh() + } + } + }, + handleDocumentClick (event) { + // 检查点击的元素是否在操作菜单内或是三点菜单按钮 + const isActionMenu = event.target.closest('.actions-menu') + const isMoreButton = event.target.closest('.more-actions') + + // 如果点击的既不是操作菜单也不是三点菜单按钮,则关闭所有操作菜单 + if (!isActionMenu && !isMoreButton) { + this.closeAllActionMenus() + } + }, + showActionsMenu (post, event) { + // 阻止事件传播到document,避免立即触发关闭 + event.stopPropagation() + + // 关闭其他所有帖子的操作菜单 + this.posts.forEach(item => { + if (item.id !== post.id) { + item.showActions = false + } + }) + // 切换当前帖子的操作菜单显示状态 + post.showActions = !post.showActions + }, + closeAllActionMenus () { + this.posts.forEach(post => { + post.showActions = false + }) } + }, + mounted () { + // 初始化刷新状态 + this.refreshState = 'none' + this.refreshHeight = 0 + this.touchStartY = 0 + + // 添加滚动事件监听器 + window.addEventListener('scroll', this.handleScroll) + + // 添加页面可见性变化事件监听器,确保页面重新可见时重置刷新状态 + document.addEventListener('visibilitychange', this.handleVisibilityChange) + + // 添加document点击事件监听器,用于点击页面其他区域时关闭操作菜单 + document.addEventListener('click', this.handleDocumentClick) + }, + beforeUnmount () { + // 移除所有事件监听器 + window.removeEventListener('scroll', this.handleScroll) + document.removeEventListener('visibilitychange', this.handleVisibilityChange) + document.removeEventListener('click', this.handleDocumentClick) } } diff --git a/vue.config.js b/vue.config.js index 12072e5..78b7d1c 100644 --- a/vue.config.js +++ b/vue.config.js @@ -1,11 +1,12 @@ const { defineConfig } = require('@vue/cli-service') -module.exports = defineConfig({ - transpileDependencies: true -}) + module.exports = { + transpileDependencies: true, + //publicPath: 'http://localhosst:3100', // 这里控制静态资源的前缀路径 devServer: { port: 3100, // 将默认端口 3100 host: 'localhost', // 可选:设置为 '0.0.0.0' 后台访问 open: true // 自动打开浏览器 } + }