share.vue 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. <template>
  2. <view class="content">
  3. <!-- <view class="qrimg">
  4. <tki-qrcode
  5. :cid="cid"
  6. ref="qrcode"
  7. :val="val"
  8. :size="size"
  9. :unit="unit"
  10. :background="background"
  11. :foreground="foreground"
  12. :pdground="pdground"
  13. :icon="icon"
  14. :iconSize="iconSize"
  15. :lv="lv"
  16. :onval="onval"
  17. :loadMake="loadMake"
  18. :usingComponents="usingComponents"
  19. @result="qrR"
  20. />
  21. </view> -->
  22. <!-- #ifndef MP-ALIPAY -->
  23. <canvas :class="{ qrimg: !loading }" @longtap="alertCanv" id="qrShareBox" canvas-id="qrShareBox" class="tki-qrcode-canvas" />
  24. <!-- #endif -->
  25. <!-- #ifdef MP-ALIPAY -->
  26. <canvas :class="{ qrimg: !loading }" @longtap="alertCanv" id="qrShareBox" class="tki-qrcode-canvas" />
  27. <!-- #endif -->
  28. <view :style="{ display: loading ? 'none' : 'block' }" class="tki-qrcode-canvas"><image :src="ctxSrc" mode="scaleToFill" class="tki-qrcode-canvas"></image></view>
  29. <!-- #ifdef H5 -->
  30. <view class="share-bottom flex" :class="{ 'action-share-bottom': !loading }" @click="loading ? showImg() : ''">
  31. <text>{{ loading ? '点击生成图片' : '长按二维码下载' }}</text>
  32. </view>
  33. <!-- #endif -->
  34. <!-- #ifdef MP -->
  35. <view class="share-bottom flex" @click="loading ? showImg() : seav(ctxSrc)">
  36. <text>{{ loading ? '点击生成图片' : '点击下载图片' }}</text>
  37. </view>
  38. <!-- #endif -->
  39. </view>
  40. </template>
  41. <script>
  42. // import tkiQrcode from '@/components/tki-qrcode/tki-qrcode.vue';
  43. import { spreadBanner } from '@/api/shareQrCode.js';
  44. import { mapState } from 'vuex';
  45. export default {
  46. // components: { tkiQrcode },
  47. data() {
  48. return {
  49. cid: 'tki-qrcode-canvas', //canvasId,页面存在多个二维码组件时需设置不同的ID
  50. size: 180, //生成的二维码大小
  51. unit: 'upx', //大小单位尺寸
  52. // show: true,//默认使用组件中的image标签显示二维码
  53. val: '', //要生成的内容
  54. background: '#ffffff', //二维码背景色
  55. foreground: '#333333', //二维码前景色
  56. pdground: '#333333', //二维码角标色
  57. icon: '', //二维码图标URL(必须是本地图片,网络图需要先下载至本地)
  58. iconSize: 40, //二维码图标大小
  59. lv: 3, //容错级别
  60. onval: false, //监听val值变化自动重新生成二维码
  61. loadMake: false, //组件初始化完成后自动生成二维码,val需要有值
  62. usingComponents: false, //是否使用了自定义组件模式(主要是为了修复非自定义组件模式时 v-if 无法生成二维码的问题)
  63. showLoading: false, //是否显示loading
  64. loadingText: '二维码生成中', //loading文字
  65. src: '', // 二维码生成后的图片地址或base64
  66. ratio: 1, //页面比例用于计算
  67. ctxSrc: '', //要显示的图片
  68. loading: true, //是否载入图片中
  69. canHeight: '',
  70. canWeidth: ''
  71. };
  72. },
  73. computed: {
  74. ...mapState(['baseURL','urlFile', 'userInfo'])
  75. },
  76. onLoad() {
  77. uni.showLoading({
  78. title: '邀请图生成中',
  79. mask: true
  80. });
  81. this.loadCodeList();
  82. // #ifdef MP-WEIXIN
  83. uni.authorize({
  84. scope: 'scope.writePhotosAlbum',
  85. complete() {}
  86. });
  87. // #endif
  88. },
  89. onReady() {
  90. let obj = this;
  91. let query = uni.createSelectorQuery();
  92. // 获取页面比例
  93. query
  94. .select('.content')
  95. .fields(
  96. {
  97. size: true
  98. },
  99. e => {
  100. // 保存比例
  101. this.ratio = e.width / 750;
  102. }
  103. )
  104. .exec();
  105. // 获取画布宽高信息
  106. query
  107. .select('#qrShareBox')
  108. .fields(
  109. {
  110. size: true
  111. },
  112. e => {
  113. obj.canHeight = e.height;
  114. obj.canWeidth = e.width;
  115. }
  116. )
  117. .exec();
  118. },
  119. methods: {
  120. loadCodeList() {
  121. let obj = this;
  122. // 加载二维码信息
  123. spreadBanner({
  124. // #ifdef H5
  125. type: 2,
  126. // #endif
  127. // #ifdef MP
  128. type: 1
  129. // #endif
  130. })
  131. .then(e => {
  132. // #ifdef H5
  133. // 保存二维码图片
  134. obj.src = e.data[0].qrcode;
  135. // 生成画布
  136. obj.loadImg(e.data[0].qrcode);
  137. uni.hideLoading();
  138. // #endif
  139. // #ifdef MP
  140. // 保存二维码图片
  141. uni.downloadFile({
  142. url: e.data[0].qrcode,
  143. success(res) {
  144. if (res.errMsg == 'downloadFile:ok') {
  145. obj.src = res.tempFilePath;
  146. obj.loadImg(obj.src);
  147. uni.hideLoading();
  148. }
  149. },
  150. fail(e) {
  151. console.log(e);
  152. }
  153. });
  154. // #endif
  155. })
  156. .catch(e => {
  157. uni.showModal({
  158. title: '生成失败请刷新页面',
  159. showCancel: false
  160. });
  161. uni.hideLoading();
  162. });
  163. },
  164. // 长按画布事件
  165. alertCanv() {
  166. uni.showModal({
  167. title: '请先点击生成图片再下载',
  168. showCancel: false
  169. });
  170. },
  171. // 生成图片
  172. showImg() {
  173. uni.showLoading({
  174. title: '图片生成中',
  175. mask: true
  176. });
  177. let obj = this;
  178. //因为和uni.showLoading载入效果冲突需要延迟执行生成图片方法
  179. setTimeout(function() {
  180. uni.canvasToTempFilePath({
  181. x: 0,
  182. y: 0,
  183. width: obj.canWeidth,
  184. height: obj.canHeight,
  185. destWidth: obj.canWeidth,
  186. destHeight: obj.canHeight,
  187. fileType: 'jpg',
  188. quality: 1,
  189. canvasId: 'qrShareBox',
  190. success: res => {
  191. uni.hideLoading();
  192. // #ifdef MP
  193. obj.seav(res.tempFilePath)
  194. // #endif
  195. // #ifdef H5
  196. uni.showModal({
  197. title: '创建成功,长按二维码下载图片',
  198. showCancel: false
  199. });
  200. // #endif
  201. // 显示生成的图片
  202. obj.loading = false;
  203. obj.ctxSrc = res.tempFilePath;
  204. },
  205. fail(e) {
  206. console.log(e);
  207. }
  208. });
  209. }, 50);
  210. },
  211. // 开始渲染画布
  212. loadImg(src) {
  213. let obj = this;
  214. let ctxBg = ''; //画布背景
  215. uni.downloadFile({
  216. url: obj.baseURL+obj.urlFile+'/img/img1.jpg',
  217. success(res) {
  218. if (res.errMsg == 'downloadFile:ok') {
  219. ctxBg = res.tempFilePath;
  220. let context = uni.createCanvasContext('qrShareBox');
  221. const codeSize = obj.size * obj.ratio; //计算二维码大小
  222. const codeX = ((523 - obj.size) * obj.ratio) / 2; //二维码所在x轴位置
  223. const codeY = 700 * obj.ratio; //二维码所在y轴位置
  224. const codeBoxColor = '#FFFFFF'; //包裹框颜色
  225. const codeBoxWidht = 0; //包裹边框宽度
  226. const codeBoxSize = (codeBoxWidht / 2) * obj.ratio; //计算二维码白色包裹框大小
  227. const codeBoxX = codeX - codeBoxSize; //包裹框初始X轴
  228. const codeBoxY = codeY - codeBoxSize; //包裹框初始Y轴
  229. const codeBoxEnd = codeSize + codeBoxWidht * obj.ratio; //计算包裹框大小
  230. const fontTop = codeY + codeBoxEnd + (codeBoxWidht + 20) * obj.ratio; //文字距离上边距高度
  231. const fontSize = 24 * obj.ratio; //文字大小
  232. const fontText = ''; //文字内容
  233. const fontLeft = (codeSize - fontSize * fontText.length) / 2 + codeX; //文字左侧距离
  234. // 插入背景图片
  235. context.drawImage(ctxBg, 0, 0, obj.canWeidth, obj.canHeight);
  236. // // 插入文字
  237. context.setFontSize(fontSize);
  238. context.fillText(fontText, fontLeft, fontTop);
  239. // 插入边框
  240. context.beginPath();
  241. context.setLineJoin('round'); //边框类型
  242. context.setLineWidth(codeBoxWidht * obj.ratio);
  243. context.setStrokeStyle(codeBoxColor); //设置包裹框颜色
  244. context.strokeRect(codeBoxX, codeBoxY, codeBoxEnd, codeBoxEnd);
  245. context.stroke();
  246. // 插入二维码
  247. context.drawImage(src, codeX, codeY, codeSize, codeSize);
  248. // 开始渲染
  249. context.draw();
  250. }
  251. },
  252. fail(e) {
  253. console.log(e);
  254. }
  255. });
  256. },
  257. // 創建二维码
  258. creatQrcode() {
  259. this.$refs.qrcode._makeCode();
  260. },
  261. // 保存二维码到图库
  262. saveQrcode() {
  263. this.$refs.qrcode._saveCode();
  264. },
  265. // 生成二维码后返回base64
  266. qrR(res) {
  267. this.src = res;
  268. },
  269. //清空二维码(清空二维码会触发result回调 返回值为空)
  270. clearQrcode(e) {
  271. this.$refs.qrcode._clearCode();
  272. this.val = '';
  273. },
  274. // #ifdef MP-WEIXIN
  275. // 保存画图图片到本地
  276. seav(url) {
  277. uni.showLoading({
  278. title: '生成中...',
  279. mask: true
  280. });
  281. uni.saveImageToPhotosAlbum({
  282. filePath: url,
  283. complete(result) {
  284. uni.hideLoading();
  285. console.log(result);
  286. uni.showToast({
  287. title: '保存图片成功!',
  288. duration: 2000,
  289. icon: 'none'
  290. });
  291. }
  292. });
  293. }
  294. // #endif
  295. }
  296. };
  297. </script>
  298. <style lang="scss">
  299. .content {
  300. padding-top: 30rpx;
  301. }
  302. // #qrShareBox {
  303. // position: absolute;
  304. // left: -9999rpx;
  305. // top: -9999rpx;
  306. // }
  307. .qrimg {
  308. position: absolute;
  309. left: -9999rpx;
  310. top: -9999rpx;
  311. }
  312. .tki-qrcode-canvas {
  313. // width: 700rpx;
  314. // height: 1245rpx;
  315. width: 555rpx;
  316. height: 988rpx;
  317. margin: 0 auto;
  318. }
  319. .share-bottom {
  320. width: 560rpx;
  321. height: 80rpx;
  322. color: #ffffff;
  323. background: $base-color;
  324. margin: 0 auto;
  325. font-size: $font-lg - 2rpx;
  326. margin-top: 30rpx;
  327. border-radius: 99rpx;
  328. justify-content: center;
  329. &.action-share-bottom {
  330. background-color: $color-gray;
  331. }
  332. }
  333. </style>