From c31a8def0ac90d86b8e8e345441bd28002a9ef2f Mon Sep 17 00:00:00 2001
From: cloudroam <cloudroam>
Date: 星期一, 16 六月 2025 20:14:52 +0800
Subject: [PATCH] add: 分享

---
 sub-pages/film-list/film-detail.vue |  157 ++++++++++++++++++++++++++
 components/share-popup.vue          |  152 +++++++++++++++++++++++++
 2 files changed, 308 insertions(+), 1 deletions(-)

diff --git a/components/share-popup.vue b/components/share-popup.vue
new file mode 100644
index 0000000..9cd2ef9
--- /dev/null
+++ b/components/share-popup.vue
@@ -0,0 +1,152 @@
+<template>
+  <view class="share-popup" v-if="show">
+    <view class="share-mask" @click="closePopup"></view>
+    <view class="share-content">
+      <view class="share-title">分享到</view>
+      <view class="share-options">
+        <button class="share-item" open-type="share" @click="handleShare('wechat')">
+          <image src="/static/common/wechat.png" class="share-icon" />
+          <text>微信好友</text>
+        </button>
+        <button class="share-item" open-type="share" @click="handleShare('moments')">
+          <image src="/static/common/wechat-moments.png" class="share-icon" />
+          <text>朋友圈</text>
+        </button>
+        <view class="share-item" @click="handleCopyLink">
+          <image src="/static/common/link.png" class="share-icon" />
+          <text>复制链接</text>
+        </view>
+      </view>
+      <view class="share-cancel" @click="closePopup">取消</view>
+    </view>
+  </view>
+</template>
+
+<script setup lang="ts">
+import { ref, defineProps, defineEmits } from 'vue'
+
+const props = defineProps({
+  show: {
+    type: Boolean,
+    default: false
+  },
+  shareData: {
+    type: Object,
+    default: () => ({
+      title: '',
+      desc: '',
+      image: '',
+      url: ''
+    })
+  }
+})
+
+const emit = defineEmits(['update:show'])
+
+// 关闭弹窗
+const closePopup = () => {
+  emit('update:show', false)
+}
+
+// 处理分享
+const handleShare = (type: 'wechat' | 'moments') => {
+  // 小程序分享通过页面配置和按钮的 open-type="share" 实现
+  // 分享内容在页面的 onShareAppMessage 中配置
+  closePopup()
+}
+
+// 复制链接
+const handleCopyLink = () => {
+  uni.setClipboardData({
+    data: props.shareData.url,
+    success: () => {
+      uni.showToast({
+        title: '链接已复制',
+        icon: 'success'
+      })
+      closePopup()
+    }
+  })
+}
+</script>
+
+<style lang="scss" scoped>
+.share-popup {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  z-index: 9999;
+
+  .share-mask {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: rgba(0, 0, 0, 0.5);
+  }
+
+  .share-content {
+    position: absolute;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: #fff;
+    border-radius: 20rpx 20rpx 0 0;
+    padding: 30rpx;
+    transform: translateY(0);
+    transition: transform 0.3s ease-out;
+
+    .share-title {
+      text-align: center;
+      font-size: 32rpx;
+      color: #333;
+      margin-bottom: 30rpx;
+    }
+
+    .share-options {
+      display: flex;
+      justify-content: space-around;
+      padding: 20rpx 0;
+
+      .share-item {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        width: 120rpx;
+        background: none;
+        border: none;
+        padding: 0;
+        margin: 0;
+        line-height: normal;
+
+        &::after {
+          border: none;
+        }
+
+        .share-icon {
+          width: 80rpx;
+          height: 80rpx;
+          margin-bottom: 10rpx;
+        }
+
+        text {
+          font-size: 24rpx;
+          color: #666;
+        }
+      }
+    }
+
+    .share-cancel {
+      text-align: center;
+      color: #888;
+      font-size: 28rpx;
+      padding: 20rpx 0;
+      border-top: 1px solid #eee;
+      margin-top: 20rpx;
+    }
+  }
+}
+</style>
\ No newline at end of file
diff --git a/sub-pages/film-list/film-detail.vue b/sub-pages/film-list/film-detail.vue
index afeab9e..3d89490 100644
--- a/sub-pages/film-list/film-detail.vue
+++ b/sub-pages/film-list/film-detail.vue
@@ -1,6 +1,7 @@
 <template>
     <view>
         <view class="page">
+
             <up-sticky bgColor="#fff">
                 <view class="card-footer">
                     <view class="user-info">
@@ -11,7 +12,7 @@
                     </view>
                     <view class="opera-info">
                         <button class="custom-btn">关注</button>
-                        <up-icon name="/static/common/share2.png" size="40rpx" color="#999" />
+                        <up-icon name="/static/common/share2.png" size="40rpx" color="#999" @click="openSharePopup" />
                     </view>
                 </view>
             </up-sticky>
@@ -116,10 +117,19 @@
                     <!-- <up-icon name="chat" size="60rpx" color="#B9B9B9" label="33" /> -->
                 </view>
             </view>
+
+
         </view>
 
         <comment-popup v-model="commentShow" :film-id="filmInfo?.id" :parent-id="commentParendId"
             @success="handleCommentSuccess" />
+
+        <!-- 自定义分享弹窗 -->
+        <share-popup
+            v-model:show="showSharePopup"
+            :share-data="shareData"
+        />
+
     </view>
 </template>
 
@@ -151,6 +161,42 @@
 
 const liked = ref(false)      // 是否已点赞
 const collected = ref(false)  // 是否已收藏
+
+const sharePopupShow = ref(false)
+
+import SharePopup from '@/components/share-popup.vue'
+
+// 分享弹窗控制
+const showSharePopup = ref(false)
+
+const shareData = ref({
+  title: '',
+  desc: '',
+  image: '',
+  url: ''
+})
+
+// 打开分享弹窗
+const openSharePopup = () => {
+  // 设置分享内容
+  shareData.value = {
+    title: filmInfo.value?.coverTitle || '分享内容',
+    desc: filmInfo.value?.filmContent?.substring(0, 50) || '',
+    image: filmPictureList.value[0] || '',
+    url: `https://您的域名/sub-pages/film-list/film-detail?id=${filmInfo.value?.id}`
+  }
+  showSharePopup.value = true
+}
+
+
+// 复制链接
+const copyLink = () => {
+  sharePopupShow.value = false
+  uni.setClipboardData({
+    data: `https://你的域名/sub-pages/film-list/film-detail?id=${filmInfo.value?.id}`,
+    success: () => $message.showToast('链接已复制')
+  })
+}
 
 
 onLoad((options: any) => {
@@ -364,6 +410,27 @@
     $message.showToast('操作失败')
   }
 }
+
+// 小程序分享配置
+defineExpose({
+  onShareAppMessage() {
+    return {
+      title: filmInfo.value?.coverTitle || '分享内容',
+      path: `/sub-pages/film-list/film-detail?id=${filmInfo.value?.id}`,
+      imageUrl: filmPictureList.value[0] || '',
+      desc: filmInfo.value?.filmContent?.substring(0, 50) || ''
+    }
+  },
+  // 分享到朋友圈
+  onShareTimeline() {
+    return {
+      title: filmInfo.value?.coverTitle || '分享内容',
+      query: `id=${filmInfo.value?.id}`,
+      imageUrl: filmPictureList.value[0] || ''
+    }
+  }
+})
+
 </script>
 
 
@@ -593,4 +660,92 @@
     padding-bottom: 180rpx;
     /* 留出评论区高度,避免遮挡 */
 }
+
+.share-popup {
+  background: #fff;
+  padding: 30rpx;
+  border-top-left-radius: 20rpx;
+  border-top-right-radius: 20rpx;
+  min-height: 300rpx;
+}
+.share-title {
+  text-align: center;
+  font-size: 32rpx;
+  margin-bottom: 30rpx;
+  color: #333;
+}
+.share-options {
+  display: flex;
+  justify-content: space-around;
+  margin-bottom: 30rpx;
+  padding: 20rpx 0;
+}
+.share-btn {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  width: 120rpx;
+}
+.share-icon {
+  width: 80rpx;
+  height: 80rpx;
+  margin-bottom: 10rpx;
+}
+.share-btn text {
+  font-size: 24rpx;
+  color: #666;
+  margin-top: 10rpx;
+}
+.share-cancel {
+  text-align: center;
+  color: #888;
+  font-size: 28rpx;
+  padding: 20rpx 0;
+  border-top: 1px solid #eee;
+  margin-top: 20rpx;
+}
+</style>
+
+<style lang="scss" scoped>
+// 分享按钮样式
+.share-btn {
+  background: none;
+  border: none;
+  padding: 0;
+  margin: 0;
+  line-height: normal;
+  
+  &::after {
+    border: none;
+  }
+}
+
+// 分享弹窗样式
+.share-popup {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  z-index: 9999;
+  
+  .share-mask {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: rgba(0, 0, 0, 0.5);
+  }
+  
+  .share-content {
+    position: absolute;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: #fff;
+    border-radius: 20rpx 20rpx 0 0;
+    padding: 30rpx;
+  }
+}
 </style>
\ No newline at end of file

--
Gitblit v1.9.3