index.vue 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. <template>
  2. <!-- 分享弹窗,沿用你原有样式结构 -->
  3. <uni-popup ref="popupRef" type="bottom" background-color="#fff" :mask-click="false">
  4. <view class="share-popup-box">
  5. <!-- 标题 -->
  6. <view class="share-title">分享到 </view>
  7. <view class="close-btn" @click="close"></view>
  8. <!-- 分享选项 -->
  9. <scroll-view scroll-x class="share-scroll" :show-scrollbar="false">
  10. <view class="share-list">
  11. <!-- 微信好友 -->
  12. <view class="share-item" @click="select('session')">
  13. <view class="share-icon wechat-icon"></view>
  14. <text class="share-text">微信好友</text>
  15. </view>
  16. <!-- 朋友圈 -->
  17. <view class="share-item" @click="select('timeline')">
  18. <view class="share-icon timeline-icon"></view>
  19. <text class="share-text">朋友圈</text>
  20. </view>
  21. </view>
  22. </scroll-view>
  23. </view>
  24. </uni-popup>
  25. </template>
  26. <!-- <SharePopup ref="sharePopup" :type="0" title="测试图文分享" desc="这是分享描述" link="https://xxx.com"
  27. image="https://xxx.com/xxx.jpg" currentPage="" :mini-program="{
  28. appId: 'wxXXXXXXX',
  29. path: '/pages/index/index'
  30. }" @success="handleShareSuccess" @error="handleShareError" /> -->
  31. <script setup>
  32. import {
  33. ref,
  34. computed
  35. } from 'vue'
  36. // 定义props,支持你指定的6种分享类型
  37. const props = defineProps({
  38. // 分享类型 0:图文 1:纯文字 2:纯图片 3:音乐 4:视频 5:小程序
  39. type: {
  40. type: [String, Number],
  41. default: 0,
  42. validator: (val) => [0, 1, 2, 3, 4, 5].includes(Number(val))
  43. },
  44. // 分享标题
  45. title: {
  46. type: String,
  47. default: '分享标题'
  48. },
  49. // 分享描述/纯文字内容
  50. desc: {
  51. type: String,
  52. default: '分享描述'
  53. },
  54. // 分享链接,图文/音乐/视频/小程序使用
  55. link: {
  56. type: String,
  57. default: ''
  58. },
  59. // 分享图片/封面,纯图片/音乐/视频/小程序/图文使用
  60. image: {
  61. type: String,
  62. default: ''
  63. },
  64. // 标识是否为海报分享,华为卓易通纯图片分享传 haibao
  65. currentPage: {
  66. type: String,
  67. default: ''
  68. },
  69. // 小程序专属配置,type=5时必传
  70. miniProgram: {
  71. type: Object,
  72. default: () => ({
  73. appId: '',
  74. path: '',
  75. hdImageUrl: '',
  76. withShareTicket: false,
  77. miniprogramType: 'release'
  78. })
  79. }
  80. })
  81. const emit = defineEmits(['close', 'select', 'success', 'error'])
  82. const popupRef = ref(null)
  83. // 计算标准化的分享类型
  84. const shareType = computed(() => Number(props.type))
  85. // 打开弹窗
  86. const open = () => {
  87. popupRef.value.open()
  88. }
  89. // 关闭弹窗
  90. const close = () => {
  91. popupRef.value.close()
  92. emit('close')
  93. }
  94. // 选择分享场景
  95. const select = (scene) => {
  96. emit('select', scene)
  97. try {
  98. // 朋友圈限制:不支持纯文字、音乐、小程序
  99. if (scene === 'timeline' && [1, 3, 5].includes(shareType.value)) {
  100. uni.showToast({
  101. title: '朋友圈不支持该分享类型',
  102. icon: 'none'
  103. })
  104. return
  105. }
  106. if (props.currentPage == 'tupian') {
  107. shareToWeChatHaibao(scene)
  108. } else {
  109. shareToWeChat(scene)
  110. }
  111. close()
  112. } catch (error) {
  113. emit('error', error)
  114. handleShareError(error)
  115. }
  116. }
  117. // 微信常规分享,支持6种类型
  118. const shareToWeChat = (scene) => {
  119. const type = shareType.value
  120. // 基础分享配置
  121. const shareConfig = {
  122. provider: 'weixin',
  123. scene: scene === 'timeline' ? 'WXSceneTimeline' : 'WXSceneSession',
  124. type: type,
  125. success: (res) => {
  126. emit('success', {
  127. scene
  128. })
  129. },
  130. fail: (err) => {
  131. emit('error', err)
  132. handleShareError(err)
  133. }
  134. }
  135. // 按类型填充参数
  136. switch (type) {
  137. // 图文分享
  138. case 0:
  139. shareConfig.title = props.title
  140. shareConfig.summary = props.desc
  141. shareConfig.imageUrl = props.image
  142. shareConfig.href = props.link
  143. break
  144. // 纯文字分享
  145. case 1:
  146. shareConfig.summary = props.desc || props.title
  147. break
  148. // 纯图片分享
  149. case 2:
  150. shareConfig.imageUrl = props.image
  151. break
  152. // 音乐分享
  153. case 3:
  154. shareConfig.title = props.title
  155. shareConfig.summary = props.desc
  156. shareConfig.imageUrl = props.image
  157. shareConfig.href = props.link
  158. break
  159. // 视频分享
  160. case 4:
  161. shareConfig.title = props.title
  162. shareConfig.summary = props.desc
  163. shareConfig.imageUrl = props.image
  164. shareConfig.href = props.link
  165. break
  166. // 小程序分享,仅微信好友支持
  167. case 5:
  168. shareConfig.title = props.title
  169. shareConfig.imageUrl = props.image
  170. shareConfig.href = props.link
  171. shareConfig.miniprogram = props.miniProgram
  172. break
  173. }
  174. console.log('常规微信分享配置', shareConfig)
  175. uni.share(shareConfig)
  176. }
  177. // 华为卓易通海报纯图片分享,保留你原有逻辑
  178. const shareToWeChatHaibao = (scene) => {
  179. console.log('海报分享模式')
  180. if (!props.image) {
  181. const err = new Error('海报图片地址不能为空')
  182. emit('error', err)
  183. handleShareError(err)
  184. return
  185. }
  186. uni.downloadFile({
  187. url: props.image,
  188. success: (downloadRes) => {
  189. const type = shareType.value
  190. const shareConfig = {
  191. provider: 'weixin',
  192. scene: scene === 'timeline' ? 'WXSceneTimeline' : 'WXSceneSession',
  193. type: type,
  194. success: (res) => {
  195. emit('success', {
  196. scene
  197. })
  198. },
  199. fail: (err) => {
  200. emit('error', err)
  201. handleShareError(err)
  202. }
  203. }
  204. // 仅纯图片类型使用本地临时路径
  205. if (type == 2) {
  206. shareConfig.imageUrl = downloadRes.tempFilePath
  207. } else {
  208. shareConfig.title = props.title
  209. shareConfig.summary = props.desc
  210. shareConfig.imageUrl = props.image
  211. shareConfig.href = props.link
  212. // 小程序配置透传
  213. if (type === 5) {
  214. shareConfig.miniprogram = props.miniProgram
  215. }
  216. }
  217. console.log('海报分享配置', shareConfig)
  218. uni.share(shareConfig)
  219. },
  220. fail: (err) => {
  221. emit('error', err)
  222. handleShareError(err)
  223. }
  224. })
  225. }
  226. // 统一错误处理,沿用你原有逻辑
  227. const handleShareError = (error) => {
  228. console.error('分享失败:', error)
  229. const errCode = error.errCode || error.code
  230. const errMsg = error.errMsg || error.message
  231. // 未安装微信
  232. if (errCode === 1004 || errCode === -4004) {
  233. uni.showModal({
  234. title: '提示',
  235. content: '请先安装微信',
  236. showCancel: false
  237. })
  238. return
  239. }
  240. // 用户取消,不提示
  241. if (errCode === 1001 || errCode === -4001) {
  242. return
  243. }
  244. // 其他错误提示
  245. uni.showToast({
  246. title: errMsg || '分享失败,请重试',
  247. icon: 'none',
  248. duration: 3000
  249. })
  250. }
  251. // 暴露方法给父组件
  252. defineExpose({
  253. open,
  254. close
  255. })
  256. </script>