小程序模板網(wǎng)

【微信小程序】分享朋友圈組件開(kāi)發(fā)實(shí)踐

發(fā)布時(shí)間:2020-05-15 10:36 所屬欄目:小程序開(kāi)發(fā)教程

背景
在一個(gè)完整帶用戶交互的小程序項(xiàng)目開(kāi)發(fā)中,總會(huì)遇到分享這個(gè)功能,轉(zhuǎn)發(fā)給好友用通用的api方法,分享朋友圈總是有各種各樣的招式,一般的交互方案是生成一個(gè)帶二維碼的圖,二維碼有時(shí)候也分帶參數(shù)和默認(rèn)的。分享一個(gè)前段時(shí)間開(kāi)發(fā)的生成分享圖的功能,我當(dāng)時(shí)的業(yè)務(wù)二維碼是帶參數(shù)的,為了識(shí)別能定位到固定產(chǎn)品頁(yè)(生成帶參數(shù)二維碼是用微信云調(diào)用提供的方法處理,點(diǎn)此看帖

分享圖用canvas畫布開(kāi)發(fā),所以對(duì)wx封裝的canvas相關(guān)api要有一定了解

開(kāi)發(fā)步驟
新建一個(gè)share組件文件包,并開(kāi)發(fā)業(yè)務(wù)邏輯和樣式編寫含小程序規(guī)范的幾個(gè)文件js/wxml/wxss/json
開(kāi)發(fā)代碼,在需要引用頁(yè)面的對(duì)應(yīng)配置文件中加入組件配置
在引用的wxml中加入組件代碼和傳參,js文件寫參數(shù)的交互


效果圖

代碼概覽
1.share / share.wxml 【參考效果圖 步驟2/3

備注:
1.第一模塊 步驟2的分享引導(dǎo)層,點(diǎn)擊分享票圈,出來(lái)第二模塊彈框
2.第二模塊 步驟3效果圖,share-load.gif是一個(gè)加載中動(dòng)畫的gif;close.png是關(guān)閉圖標(biāo)

 

  1. <!--分享彈窗-->
  2. <view class="share-wrap" bindtap="toClose">
  3. <!-- 分享的引導(dǎo)層 分 轉(zhuǎn)發(fā)票圈或好友 -->
  4. <view class="share-mod" catchtap="doNothing">
  5. <view class="share-hd">
  6. <text class="fl">分享</text>
  7. <image class="share-close" catchtap="toClose" src="../../images/icons/close.png"></image>
  8. </view>
  9. <view class="share-guide">
  10. <view class="share-wx">
  11. <button class="share-btn" open-type="share"></button>
  12. <image src="../../images/icons/wx_friend.png"></image>
  13. <text>分享給好友</text>
  14. </view>
  15. <view class="share-line"></view>
  16. <view class="share-wx" catchtap="toShowShareImg">
  17. <image src="../../images/icons/wx_quan.png"></image>
  18. <text>生成分享海報(bào)</text>
  19. </view>
  20. </view>
  21. </view>
  22. <!-- 點(diǎn)擊引導(dǎo)層的 轉(zhuǎn)發(fā)票圈 觸發(fā)的生成畫布圖彈層 -->
  23. <view class="share-mod" hidden="{{!showShareImg}}" catchtap="doNothing">
  24. <view class="share-hd">
  25. <text class="fl">保存到相冊(cè)</text>
  26. <image class="share-close" catchtap="toCloseShareImg" src="../../images/icons/close.png"></image>
  27. </view>
  28. <view class="share-quan">
  29. <image wx:if="{{imgSrc!=''}}" class="share-img" src="{{imgSrc}}"></image>
  30. <view wx:else>
  31. <image class="share-img-load" src="../../images/icons/share-load.gif"></image>
  32. <text class="share-load-text">{{loadText}}</text>
  33. </view>
  34. <view class="save-btn" catchtap="saveImg">保存圖片</view>
  35. <view class="save-tip">保存圖片到手機(jī)相冊(cè)后,就可以分享至您的圈子啦</view>
  36. </view>
  37. </view>
  38. </view>

2.share/ share.json

 

  1. {
  2. "component": true
  3. }

3.share/ share.js

 

  1. /* 使用說(shuō)明↓↓↓
  2. 1.需要引用的頁(yè)面json配置文件新增如下配置項(xiàng)
  3. "usingComponents": {
  4. "share-win": "/component/share/share"
  5. }
  6.  
  7. 2.頁(yè)面wxml文件使用如下 shareInfo格式說(shuō)明見(jiàn)下文 該組件是否渲染根據(jù)該對(duì)象是否有具體數(shù)據(jù)
  8. <canvas canvas-id="shareCanvas" style="position:fixed;top:0;left:999rpx;width:1000px;height:750px;"></canvas>
  9. <share-win share-info="{{shareInfo}}" bindcloseshare="closeShareWin"></share-win>
  10.  
  11. 3.頁(yè)面對(duì)應(yīng)js需要定義一個(gè)closeshare事件[由組件里的toClose觸發(fā)] 內(nèi)部主要是將shareInfo參數(shù)置空
  12.  
  13. 4.shareInfo格式
  14.  
  15. */
  16.  
  17. Component({
  18. properties: {
  19. shareInfo: {
  20. type: Object,
  21. value: {},
  22. }
  23. },
  24. data: {
  25. imgSrc:'',
  26. showShareImg:false,
  27. hasDownload:false,
  28. loadText:'分享圖繪制準(zhǔn)備中...'
  29. },
  30. ready:function(){
  31.  
  32. },
  33. methods: {
  34. //點(diǎn)擊浮層區(qū)域關(guān)閉彈窗
  35. toClose:function(){
  36. this.toCloseShareImg();
  37. this.triggerEvent("closeshare")
  38. },
  39. toCloseShareImg:function(){
  40. this.setData({
  41. showShareImg:false
  42. })
  43. if(this.data.hasDownload){
  44. this.triggerEvent("closeshare")
  45. }
  46. },
  47. toShowShareImg:function(){
  48. this.setData({
  49. showShareImg:true
  50. })
  51. this.renderShareImg();
  52. },
  53. doNothing:function(){
  54. return false;
  55. },
  56. setLoadText:function(txt){
  57. this.setData({
  58. loadText:txt
  59. })
  60. },
  61. //渲染分享圖
  62. renderShareImg:function(){
  63. //1000x750
  64. const _this = this;
  65. const _obj = _this.data.shareInfo;
  66.  
  67. //默認(rèn)題圖
  68. let promise1 = new Promise(function (resolve, reject) {
  69. if(_obj.cover==undefined || _obj.cover==''){
  70. _obj.cover = '../../images/share_default.jpg'
  71. resolve({path:_obj.cover});
  72. }else{
  73. _obj.cover = "https://"+_obj.cover.split('//')[1]
  74. wx.getImageInfo({
  75. src: _obj.cover,
  76. success: function (res) {
  77. resolve(res);
  78. }, fail: function (error) {
  79. console.log(error);
  80.  
  81. _obj.cover = '../../images/share_default.jpg'
  82. resolve({path:_obj.cover});
  83. }
  84. })
  85. }
  86. });
  87.  
  88. //小程序碼
  89. let promise2 = new Promise(function (resolve, reject) {
  90. wx.cloud.callFunction({
  91. name: 'openapi',
  92. data: {
  93. action:'getWXACodeUnlimit',
  94. page: 'pages/detail/detail',
  95. width: 220,
  96. scene: _obj.id+"_"+_obj.goodsId,
  97. },
  98. success: res => {
  99. wx.getImageInfo({
  100. src: res.result[0].tempFileURL,
  101. success: function (suc) {
  102. resolve(suc);
  103. }, fail: function (error) {
  104. resolve({path:"../../images/qrcode.jpg"})
  105. console.log(error)
  106. }
  107. })
  108. },
  109. fail: error => {
  110. console.log(JSON.stringify(error))
  111. resolve({path:"../../images/qrcode.jpg"})
  112. }
  113. });
  114. });
  115.  
  116.  
  117. //加載所有完圖片后繪制畫布
  118. Promise.all(
  119. [promise1,promise2]
  120. ).then(res => {
  121. //繪制頭圖的圓角效果
  122. const ctx = wx.createCanvasContext('shareCanvas')
  123. ctx.setFillStyle('#ffffff');
  124. ctx.fillRect(0, 0, 750, 1125);
  125.  
  126. //繪制題圖
  127. _this.setLoadText("繪制商品圖...")
  128. ctx.drawImage(res[0].path, 25, 25, 700, 700)
  129.  
  130. // ...刪除了部分 繪制邏輯代碼...
  131.  
  132. //繪制小程序碼
  133. _this.setLoadText("繪制小程序碼...")
  134. ctx.drawImage(res[1].path, 35, 874, 228, 228);
  135.  
  136.  
  137. //畫布繪制完成轉(zhuǎn)圖片,將地址賦值給圖片
  138. _this.setLoadText("分享圖生成中...")
  139. ctx.draw();
  140.  
  141. setTimeout(function () {
  142. wx.canvasToTempFilePath({
  143. width: 750,
  144. height: 1125,
  145. destWidth: 750,
  146. destHeight: 1125,
  147. quality: 1,
  148. canvasId: 'shareCanvas',
  149. success: function (res) {
  150. // console.log("canvasToTempFilePath success:"+res.tempFilePath);
  151. wx.hideLoading({})
  152. _this.setData({
  153. imgSrc: res.tempFilePath,
  154. shareShow: true
  155. })
  156. },
  157. fail: function (res) {
  158. }
  159. })
  160. }, 200)
  161. })
  162. },
  163. //保存圖片
  164. saveImg:function(){
  165. //下載文件
  166. const _this = this;
  167. if(_this.data.imgSrc==''){
  168. wx.showToast({
  169. title:"分享圖還在生成中...",
  170. icon: 'none',
  171. duration:3000
  172. })
  173. return false;
  174. }
  175. wx.saveImageToPhotosAlbum({
  176. filePath: _this.data.imgSrc,
  177. success(res) {
  178. wx.showToast({
  179. title:"已保存至相冊(cè),可以分享啦",
  180. icon: 'none',
  181. duration:3000
  182. })
  183. _this.setData({
  184. hasDownload:true
  185. })
  186. }
  187. })
  188. },
  189. //圖片按比例居中裁剪
  190. calClipImg(oW,oH,mW,mH){
  191. var oR = parseFloat(oW/oH).toFixed(5);
  192. var mR = parseFloat(mW/mH).toFixed(5);
  193. if(oR == mR){
  194. return [0,0,oW,oH]
  195. }else if(oR > mR){
  196. var ratio = parseFloat(mH/oH).toFixed(5);
  197. return [((oW*ratio-mW)/2)/ratio,0,mW/ratio,mH/ratio];
  198. }else{
  199. var ratio = mW/oW;
  200. return [0,((oH*ratio-mH)/2)/ratio,mW/ratio,mH/ratio];
  201. }
  202. },
  203. //繪制圓角
  204. roundRect(x, y, w, h, r,ctx){
  205. var min_size = Math.min(w, h);
  206. if (r > min_size / 2) r = min_size / 2;
  207. // 開(kāi)始繪制
  208. ctx.beginPath();
  209. ctx.moveTo(x + r, y);
  210. ctx.arcTo(x + w, y, x + w, y + h, r);
  211. ctx.arcTo(x + w, y + h, x, y + h, r);
  212. ctx.arcTo(x, y + h, x, y, r);
  213. ctx.arcTo(x, y, x + w, y, r);
  214. ctx.closePath();
  215. },
  216. //繪制文本方法
  217. drawText(str,ctx,initX,initY,lineHeight,minusW,maxLine){
  218. var curLine = 1;
  219. var lineWidth = 0;
  220. var canvasWidth = 750;
  221. var lastSubStrIndex= 0;
  222. var d = 0;
  223. for(var i=0;i<str.length;i++){
  224. lineWidth += ctx.measureText(str[i]).width;
  225. //判斷當(dāng)前文字行是否超過(guò)一行 [減minusW,防止邊界溢出]
  226. if((d==0 && lineWidth>canvasWidth-minusW)||(d>0 && ((lineWidth>=canvasWidth-minusW) || ((lineWidth+ctx.measureText(str[i+1]).width)>canvasWidth-minusW)))){
  227. d++;
  228. ctx.fillText(str.substring(lastSubStrIndex,i),initX,initY);
  229. initY+=lineHeight;
  230. lineWidth=0;
  231. lastSubStrIndex=i;
  232. curLine = curLine+1;
  233. if(maxLine!=-1 && curLine>maxLine)break; //最多繪制六行
  234. }
  235. //最后一個(gè)字的時(shí)候 繪制一行
  236. if(i==str.length-1){
  237. ctx.fillText(str.substring(lastSubStrIndex,i+1),initX,initY);
  238. }
  239. }
  240. }
  241. }
  242. })

4.share.wxss

 

  1. .share-wrap{
  2. position:fixed;
  3. top:0;
  4. width:750rpx;
  5. height:100%;
  6. background:rgba(0,0,0,.4);
  7. overflow: hidden;
  8. z-index:1001;
  9. }
  10.  
  11. .share-mod{
  12. position:fixed;
  13. bottom:0;
  14. width:100%;
  15. background:#fff;
  16. z-index:1001;
  17. overflow: hidden;
  18. }
  19.  
  20. .share-mod .share-hd{
  21. padding-left:20rpx;
  22. height:80rpx;
  23. line-height:80rpx;
  24. background:#efefef;
  25. color:#666;
  26. font-size:32rpx;
  27. }
  28.  
  29. .share-mod .share-close{
  30. float:right;
  31. margin:15rpx 20rpx;
  32. height:50rpx;
  33. width:50rpx;
  34. }
  35.  
  36. .share-guide{
  37. padding:35rpx;
  38. width:680rpx;
  39. height:180rpx;
  40. }
  41.  
  42. .share-guide .share-wx,
  43. .share-guide .share-line{
  44. float:left;
  45. }
  46. .share-guide .share-line{
  47. margin-top:60rpx;
  48. height:160rpx;
  49. width:1rpx;
  50. color:#cdcdcd;
  51. }
  52. .share-guide .share-wx{
  53. width:339rpx;
  54. height:180rpx;
  55. text-align:center;
  56. font-size:24rpx;
  57. }
  58. .share-guide .share-wx image{
  59. display: block;
  60. margin:20rpx auto;
  61. padding:10rpx;
  62. width:64rpx;
  63. height:64rpx;
  64. border-radius:43rpx;
  65. border:1rpx solid #dedede;
  66. }
  67. .share-guide .share-btn{
  68. position: absolute;
  69. margin:0;
  70. padding:0;
  71. bottom:40rpx;
  72. left:35rpx;
  73. width:340rpx;
  74. height:180rpx;
  75. background:none;
  76. }
  77. .share-guide .share-btn:after{
  78. border:none;
  79. }
  80. .share-quan{
  81. margin:20rpx;
  82. overflow: hidden;
  83. }
  84. .share-quan .share-img{
  85. display:block;
  86. margin:10rpx auto 28rpx;
  87. height:600rpx;
  88. width:400rpx;
  89. border-radius:8rpx;
  90. box-shadow:0 0 10rpx #cdcdcd;
  91. }
  92. .share-quan .share-img-load{
  93. display:block;
  94. margin:260rpx auto 20rpx;
  95. height:80rpx;
  96. width:80rpx;
  97. }
  98. .share-quan .share-load-text{
  99. margin:0 auto 220rpx;
  100. display:block;
  101. widows:100%;
  102. text-align:center;
  103. font-size:28rpx;
  104. color:#b7b7b7;
  105. }
  106. .share-quan .save-btn{
  107. width:710rpx;
  108. height:80rpx;
  109. line-height:80rpx;
  110. color:#fff;
  111. text-align:center;
  112. letter-spacing:4rpx;
  113. background-color:#e2633f;
  114. border-radius:6rpx;
  115. font-size:34rpx;
  116. }
  117. .share-quan .save-tip{
  118. margin:18rpx;
  119. text-align:center;
  120. font-size:24rpx;
  121. }

↓組件開(kāi)發(fā)已經(jīng)完成,接下去是組件的使用↓

1.demo.json 備注:usingComponents加入對(duì)應(yīng)組件配置即可

 

  1. {
  2. "navigationBarBackgroundColor": "#ffffff",
  3. "navigationBarTextStyle": "black",
  4. "navigationBarTitleText": "xxx",
  5. "usingComponents": {
  6. "share-win": "/component/share/share"
  7. }
  8. }

2.demo.wxml 備注:點(diǎn)擊分享按鈕的時(shí)候 showShareWin值改變,shareInfo根據(jù)渲染需求賦值

 

  1. <view>
  2. <!-- S 其他業(yè)務(wù)代碼 -->
  3. <!-- E 其他業(yè)務(wù)代碼 -->
  4.  
  5. <!-- 分享 -->
  6. <canvas canvas-id="shareCanvas" style="position:fixed;top:0;left:999rpx;width:750px;height:1125px;"></canvas>
  7. <share-win wx:if="{{showShareWin}}" share-info="{{shareInfo}}" bindcloseshare="closeShareWin"></share-win>
  8.  
  9. </view>

3.demo.js 備注:刪除了其他業(yè)務(wù)代碼,僅剩和分享的交互,便于閱讀。shareInfo數(shù)據(jù)在load時(shí)就塞進(jìn)去了,下面沒(méi)有放出來(lái)~

 

  1. Page({
  2. data: {
  3. showTop:false
  4. },
  5. //點(diǎn)擊右側(cè)懸浮的分享按鈕
  6. doShare:function(){
  7. this.setData({
  8. showShareWin:true
  9. })
  10. },
  11. //觸發(fā)關(guān)閉分享彈框
  12. closeShareWin:function(){
  13. this.setData({
  14. showShareWin:false
  15. })
  16. },
  17. })

其他說(shuō)明: 步驟4為最終生成效果圖,微信識(shí)別二維碼就可定位到具體業(yè)務(wù)頁(yè)~

 


易優(yōu)小程序(企業(yè)版)+靈活api+前后代碼開(kāi)源 碼云倉(cāng)庫(kù):starfork
本文地址:http://22321a.com/wxmini/doc/course/25192.html 復(fù)制鏈接 如需定制請(qǐng)聯(lián)系易優(yōu)客服咨詢:800182392 點(diǎn)擊咨詢
QQ在線咨詢