ShareModal.vue 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. <template>
  2. <view class="share-modal" v-if="visible">
  3. <view class="modal-overlay" @tap="handleClose"></view>
  4. <view class="modal-content">
  5. <view class="share-options">
  6. <view
  7. v-for="option in shareOptions"
  8. :key="option.id"
  9. class="share-item"
  10. @tap="handleShare(option.id)"
  11. >
  12. <view class="share-icon">
  13. <image :src="option.icon" mode="aspectFit"></image>
  14. </view>
  15. <text class="option-title">{{ option.title }}</text>
  16. </view>
  17. </view>
  18. <view class="cancel-button" @tap="handleClose">
  19. <text>更多</text>
  20. </view>
  21. </view>
  22. </view>
  23. </template>
  24. <script>
  25. export default {
  26. name: 'ShareModal',
  27. props: {
  28. visible: {
  29. type: Boolean,
  30. default: false
  31. },
  32. shareUrl: {
  33. type: String,
  34. required: true
  35. },
  36. shareTitle: {
  37. type: String,
  38. default: ''
  39. },
  40. shareDesc: {
  41. type: String,
  42. default: ''
  43. },
  44. shareImg: {
  45. type: String,
  46. default: ''
  47. }
  48. },
  49. data() {
  50. return {
  51. shareOptions: [
  52. { id: 'wechat', title: '微信好友', icon: '/static/images/share/wechat.png' },
  53. { id: 'moments', title: '朋友圈', icon: '/static/images/share/moments.png' },
  54. { id: 'qq', title: 'QQ好友', icon: '/static/images/share/qq.png' },
  55. { id: 'copy', title: '复制链接', icon: '/static/images/share/link.png' },
  56. { id: 'report', title: '举报', icon: '/static/images/share/report.png' }
  57. ]
  58. }
  59. },
  60. methods: {
  61. handleClose() {
  62. this.$emit('close')
  63. },
  64. handleShare(type) {
  65. switch (type) {
  66. case 'copy':
  67. this.copyToClipboard(this.shareUrl)
  68. uni.showToast({
  69. title: '链接已复制',
  70. icon: 'success'
  71. })
  72. break
  73. case 'wechat':
  74. this.shareToWechat()
  75. break
  76. case 'moments':
  77. this.shareToMoments()
  78. break
  79. case 'qq':
  80. // 实现QQ分享
  81. break
  82. case 'report':
  83. // 实现举报功能
  84. break
  85. }
  86. },
  87. copyToClipboard(text) {
  88. // #ifdef H5
  89. const input = document.createElement('input')
  90. input.value = text
  91. document.body.appendChild(input)
  92. input.select()
  93. document.execCommand('copy')
  94. document.body.removeChild(input)
  95. // #endif
  96. // #ifdef APP-PLUS || MP
  97. uni.setClipboardData({
  98. data: text,
  99. success: () => {
  100. console.log('复制成功')
  101. }
  102. })
  103. // #endif
  104. },
  105. // 分享到微信好友
  106. shareToWechat() {
  107. // #ifdef APP-PLUS
  108. uni.share({
  109. provider: 'weixin',
  110. scene: 'WXSceneSession',
  111. type: 0,
  112. title: this.shareTitle,
  113. summary: this.shareDesc,
  114. imageUrl: this.shareImg,
  115. href: this.shareUrl,
  116. success: function (res) {
  117. uni.showToast({
  118. title: '分享成功',
  119. icon: 'success'
  120. })
  121. },
  122. fail: function (err) {
  123. uni.showToast({
  124. title: '分享失败',
  125. icon: 'none'
  126. })
  127. console.error('分享失败:', err)
  128. }
  129. })
  130. // #endif
  131. // #ifdef H5
  132. // H5环境下使用微信JS-SDK
  133. if (typeof wx !== 'undefined') {
  134. wx.ready(() => {
  135. wx.updateAppMessageShareData({
  136. title: this.shareTitle,
  137. desc: this.shareDesc,
  138. link: this.shareUrl,
  139. imgUrl: this.shareImg,
  140. success: () => {
  141. uni.showToast({
  142. title: '分享成功',
  143. icon: 'success'
  144. })
  145. },
  146. fail: (err) => {
  147. uni.showToast({
  148. title: '分享失败',
  149. icon: 'none'
  150. })
  151. console.error('分享失败:', err)
  152. }
  153. })
  154. })
  155. }
  156. // #endif
  157. // #ifdef MP-WEIXIN
  158. uni.showShareMenu({
  159. withShareTicket: true,
  160. menus: ['shareAppMessage']
  161. })
  162. // #endif
  163. },
  164. // 分享到朋友圈
  165. shareToMoments() {
  166. // #ifdef APP-PLUS
  167. uni.share({
  168. provider: 'weixin',
  169. scene: 'WXSenceTimeline',
  170. type: 0,
  171. title: this.shareTitle,
  172. summary: this.shareDesc,
  173. imageUrl: this.shareImg,
  174. href: this.shareUrl,
  175. success: function (res) {
  176. uni.showToast({
  177. title: '分享成功',
  178. icon: 'success'
  179. })
  180. },
  181. fail: function (err) {
  182. uni.showToast({
  183. title: '分享失败',
  184. icon: 'none'
  185. })
  186. console.error('分享失败:', err)
  187. }
  188. })
  189. // #endif
  190. // #ifdef H5
  191. // H5环境下使用微信JS-SDK
  192. if (typeof wx !== 'undefined') {
  193. wx.ready(() => {
  194. wx.updateTimelineShareData({
  195. title: this.shareTitle,
  196. link: this.shareUrl,
  197. imgUrl: this.shareImg,
  198. success: () => {
  199. uni.showToast({
  200. title: '分享成功',
  201. icon: 'success'
  202. })
  203. },
  204. fail: (err) => {
  205. uni.showToast({
  206. title: '分享失败',
  207. icon: 'none'
  208. })
  209. console.error('分享失败:', err)
  210. }
  211. })
  212. })
  213. }
  214. // #endif
  215. // #ifdef MP-WEIXIN
  216. uni.showShareMenu({
  217. withShareTicket: true,
  218. menus: ['shareTimeline']
  219. })
  220. // #endif
  221. }
  222. }
  223. }
  224. </script>
  225. <style scoped>
  226. .share-modal {
  227. position: fixed;
  228. left: 0;
  229. right: 0;
  230. top: 0;
  231. bottom: 0;
  232. z-index: 1000;
  233. }
  234. .modal-overlay {
  235. position: absolute;
  236. left: 0;
  237. right: 0;
  238. top: 0;
  239. bottom: 0;
  240. background-color: rgba(0, 0, 0, 0.4);
  241. }
  242. .modal-content {
  243. position: absolute;
  244. left: 0;
  245. right: 0;
  246. bottom: 0;
  247. background-color: #FFFFFF;
  248. border-top-left-radius: 24rpx;
  249. border-top-right-radius: 24rpx;
  250. padding: 32rpx;
  251. }
  252. .share-options {
  253. display: flex;
  254. flex-wrap: wrap;
  255. justify-content: space-between;
  256. padding: 16rpx 32rpx;
  257. }
  258. .share-item {
  259. display: flex;
  260. flex-direction: column;
  261. align-items: center;
  262. width: 25%;
  263. margin-bottom: 32rpx;
  264. }
  265. .share-icon {
  266. width: 88rpx;
  267. height: 88rpx;
  268. display: flex;
  269. justify-content: center;
  270. align-items: center;
  271. margin-bottom: 16rpx;
  272. }
  273. .share-icon image {
  274. width: 100%;
  275. height: 100%;
  276. }
  277. .option-title {
  278. font-size: 26rpx;
  279. color: #333333;
  280. text-align: center;
  281. }
  282. .cancel-button {
  283. position: relative;
  284. margin-top: 16rpx;
  285. padding: 24rpx 0;
  286. text-align: center;
  287. color: #666666;
  288. font-size: 28rpx;
  289. }
  290. .cancel-button::before {
  291. content: '';
  292. position: absolute;
  293. left: 0;
  294. right: 0;
  295. top: 0;
  296. height: 2rpx;
  297. background-color: #EEEEEE;
  298. transform: scaleY(0.5);
  299. }
  300. </style>