這篇文章帶大家聊聊微信小程式儲存圖片元件開發(fā),希望對大家有幫助!
許多微信小程式透過保存海報讓用戶去分享活動讓更多的人知道自己的小程序,想必在平時開發(fā)小程序的時候應該有遇見過吧。 【相關(guān)學習推薦:小程式開發(fā)教學】
今天我就來分享下之前在公司做的一個小程式保存海報的功能。首先我先描述下之前在公司做的需求是什麼樣的。公司上線的小程式會有一個長期的活動目的就是去推廣新用戶,每個用戶都要有一張屬於自己的海報,透過個人海報去推廣則只是單純的一種方式。
接到任務後,我也先去萬能互聯(lián)網(wǎng)做了調(diào)查但是我的??師兄和我說這個做過類似的但是當時只是單純?yōu)榱送瓿扇蝿账源a很亂,然後他就從其他項目的程式碼找呀找,然後找到了給我~~~ 而當時給到我的時間緊任務重呀只好先用著調(diào)整一些並且交差了。之後呢我就根據(jù)網(wǎng)路上的文章然後一步一步踩坑,一步一步走實現(xiàn)了一個保存海報的組件。
想法
首先聲明下元件採用的是uniapp,具體實現(xiàn)了可以繪製圖片、繪製文字以及保存海報至相簿的基本功能,在開發(fā)中這些也完全夠用了。
透過canvas繪製海報。透過uni.canvasToTempFilePath
?將繪製好的 canvas轉(zhuǎn)為圖片。透過uni.saveImageToPhotosAlbum
?將本地臨時路徑的圖片儲存至手機相簿。 而我的想法是將所有採用的方法全部封裝到元件中,只透過父元件去呼叫需要使用的方法和調(diào)整相關(guān)的參數(shù)。 具體使用可以查看範例程式碼
透過canvas繪製海報內(nèi)容的順序先後問題
透過使用promise物件決定繪製海報內(nèi)容的順序先後。 promise.all()
方法進行canvas最後一步的繪畫操作?context.draw()
注意uni.getImageInfo()
-
#在繪製圖片和頭像時,元件透過
uni.getImageInfo()
?去取得圖片的相關(guān)信息,呼叫該方法成功的前提是需要在微信小程式後臺配置download域名和request域名當然最好把uploadFile域名也一起配置,防止出差錯。但是官方給出的提示是配置download域名白名單即可,但是獲取不到圖片信息,這算是一個大坑了。 如果沒有進行相關(guān)配置,在偵錯時 或 體驗版 正式版等 開啟了vconsole偵錯工具。 uni.getImageInfo() 是可以取得到圖片資訊的,一旦關(guān)閉了vconsole uni.getImageInfo() 將會fail, 也是個坑。
本元件方法,變數(shù)介紹
props
-
#canvasInfo Object (必要)
canvasWidth 畫布寬度
canvasHeight 畫布高度
canvasId 畫布識別
-
- #isFullScreen Boolean
- 為ture時表示畫布為手機螢幕全屏,canvasInfo設定的寬高將失效。
- 預設為false
- #methods
_circularX, _circularY, _circularR) 在canvas繪製一張圓形圖片
###drawText(options) 在canvas繪製單行、多行文字#################### startDrawToImage(context, promiseArr, callback) 將canvas操作draw()進行繪製############posterToPhotosAlbum(filePath) 儲存至手機相簿#############範例程式碼###<template> <view> <view class="savePosterItem"> <image v-show="tempFilePath" :src="tempFilePath"></image> <save-poster-com v-show="!tempFilePath" ref="savePoster" :canvasInfo="canvasInfo"></save-poster-com> </view> <button class="savePosterBtn" type="primary" @click="saveBtnFun">保存海報</button> </view> </template> <script> import SavePosterCom from '@/components/SavePosterCom/SavePosterCom.vue' export default { components: { SavePosterCom }, data() { return { canvasInfo: { canvasWidth: 620, canvasHeight: 950, canvasId: 'save-poster' }, tempFilePath: '', canvasBgUrl: 'https://images.pexels.com/photos/4065617/pexels-photo-4065617.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500', avatarUrl: 'https://p9-passport.byteacctimg.com/img/user-avatar/4dbf31fa6dec9c65b78a70d28d843c04~300x300.image' } }, onLoad() { let { drawCanvasImage, drawCircularAvatar, drawText } = this.$refs.savePoster.$options.methods this.$refs.savePoster.canvasInit(({ context, comThis }) => { // 獲取畫布寬高 let canvasWH = comThis.canvasWH // 繪制海報背景圖 let promise_1 = drawCanvasImage(context, this.canvasBgUrl, canvasWH.canvasWidth, canvasWH.canvasHeight) // 必須先繪制玩海報背景圖 再去操作其他繪制內(nèi)容 promise_1.then(res => { let promise_2 = drawCircularAvatar(context, this.avatarUrl, canvasWH.canvasWidth / 2, canvasWH.canvasHeight / 7, 70) let promise_3 = drawText({ context: context, text: '皮皮蝦仁', dx: (canvasWH.canvasWidth / 2) + 60, dy: canvasWH.canvasHeight / 4, fontSize: 30, fontColor: '#5D4037' }) let promise_4 = drawCanvasImage(context, this.avatarUrl, 150, 150, (canvasWH.canvasWidth / 2) + 85, (canvasWH.canvasHeight - 165)) this.$refs.savePoster.startDrawToImage(context, [promise_1,promise_2,promise_4], (tempFilePath) => { this.tempFilePath = tempFilePath }) }) }) }, methods: { saveBtnFun() { uni.showModal({ title: '保存海報', content: '海報將被保存至相冊中', confirmText: '保存', success: (res) => { if(res.confirm) { this.$refs.savePoster.posterToPhotosAlbum(this.tempFilePath) } } }) } } } </script> <style> .savePosterItem { text-align: center; } .savePosterItem > image { width: 620rpx; height: 950rpx; } .savePosterBtn { margin-top: 40rpx; width: 80%; } </style>###元件原始碼###
<template> <view> <canvas :canvas-id="canvasInfo.canvasId" :style="{width: canvasWH.canvasWidth + 'px', height: canvasWH.canvasHeight + 'px'}"></canvas> </view> </template> <script> export default { name: 'savePosterCom', data() { return { userPhoneWHInfo: {}, canvasWH: { canvasWidth: 0, canvasHeight: 0 } } }, props: { // 決定保存下來的圖片的寬高 canvasInfo: { type: Object, default: () => { return { canvasWidth: 0, canvasHeight: 0, canvasId: 'canvasId' } } }, // canvas畫布是不是全屏,默認是false。 false時使用必須傳 canvasInfo isFullScreen: Boolean }, created() { this.userPhoneWHInfo = this.getPhoneSystemInfo() if (this.isFullScreen) { // 畫布全屏 this.canvasWH.canvasWidth = this.userPhoneWHInfo.windowWidth this.canvasWH.canvasHeight = this.userPhoneWHInfo.windowHeight } else { // 指定寬高 this.canvasWH.canvasWidth = this.canvasInfo.canvasWidth this.canvasWH.canvasHeight = this.canvasInfo.canvasHeight } }, mounted() {}, methods: { /** * 獲取用戶手機屏幕信息 */ getPhoneSystemInfo() { const res = uni.getSystemInfoSync(); return { windowWidth: res.windowWidth, windowHeight: res.windowHeight } }, /** 獲取 CanvasContext實例 * @param {String} canvasId */ getCanvasContextInit(canvasId) { return uni.createCanvasContext(canvasId, this) }, /** 保存海報組件初始化 * @param {Function} callback(context) 回調(diào)函數(shù) */ canvasInit(callback) { let context = this.getCanvasContextInit(this.canvasInfo.canvasId) if (context) { callback({ context: context, comThis: this }) } }, /** 將上訴的繪制畫到畫布中 并且 將畫布導出為圖片 * @param context 畫布 * @param {Promise[]} 存放Promise的數(shù)組 * @param {Function} callback 保存圖片后執(zhí)行的回調(diào)函數(shù)(本地圖片臨時路徑) */ startDrawToImage(context, promiseArr, callback) { // 將之前在繪圖上下文中的描述(路徑、變形、樣式)畫到 canvas 中 let canvasId = this.canvasInfo.canvasId let tempFilePath = '' Promise.all(promiseArr).then(res => { context.draw(false, async () => { callback(await this.canvasToImage(canvasId)) }) }) }, /** * 在canvas繪制一張圖片 * @param context 畫布 * @param src 圖片資源 * @param _imageWidth 圖片寬度 * @param _imageHeight 圖片高度 */ drawCanvasImage(context, src, _imageWidth, _imageHeight, dx, dy) { return new Promise((resolve, reject) => { uni.getImageInfo({ src: src, success: res => { context.drawImage(res.path, (dx - _imageWidth), (dy - _imageHeight), _imageWidth, _imageHeight) resolve(context) }, }) }) }, /** 繪制一個圓形頭像 * @param context 畫布 * @param url 圖片地址 * @param _circularX 圓心X坐標 * @param _circularY 圓心Y坐標 * @param _circularR 圓半徑 */ drawCircularAvatar(context, url, _circularX, _circularY, _circularR) { let dx = _circularX - _circularR; let dy = _circularY - _circularR; let dwidth = _circularR * 2; let dheight = _circularR * 2 return new Promise((resolve, reject) => { uni.downloadFile({ url: url, success: res => { context.save() context.beginPath() // _circularX圓的x坐標 _circularY圓的y坐標 _circularR圓的半徑 context.arc(_circularX, _circularY, _circularR, 0, 2 * Math.PI) context.clip() // dx: 圖像的左上角在目標canvas上 X 軸的位置 // dy: 圖像的左上角在目標canvas上 Y 軸的位置 // dwidth: 在目標畫布上繪制圖像的寬度,允許對繪制的圖像進行縮放 // dheight: 在目標畫布上繪制圖像的高度,允許對繪制的圖像進行縮放 context.drawImage(res.tempFilePath, dx, dy, dwidth, dheight) context.restore() // context.draw() resolve(context) } }) }) }, /** 繪制多行文本 注:, 和 空格都算一個字 * @param context 畫布 * @param text 需要被繪制的文本 * @param dx 左上角x坐標 * @param dy 右上角y坐標 * @param rowStrnum 每行多少個字 (默認為text字體個數(shù)->單行) * @param fontSize 文字大小 (默認16) * @param fontColor 文字顏色 (默認black) * @param lineHeight 單行文本行高 (默認0) */ drawText(options) { let { context, text, dx, dy, rowStrnum = text.length, lineHeight = 0, fontSize = 16, fontColor = 'black' } = options return new Promise((resolve, reject) => { context.setFontSize(fontSize) context.setFillStyle(fontColor) context.setTextBaseline('middle') // 獲取需要繪制的文本寬度 let textWidth = Number(context.measureText(text).width) // console.log('textWidth',textWidth) // 獲取文本的字數(shù) let textNum = text.length // 獲取行數(shù) 向上取整 let lineNum = Math.ceil(textNum / rowStrnum) // console.log('textNum',textNum) // console.log('lineNum',lineNum) for (let i = 0; i < lineNum; i++) { let sliceText = text.slice(i * rowStrnum, (i + 1) * rowStrnum) // fillText 的 dx = 文字最左邊的距離到屏幕政策的距離 context.fillText(sliceText, dx - textWidth, dy + i * lineHeight); } resolve(context) }) }, /** 將畫布導出為圖片 * @param canvasId 畫布標識 */ canvasToImage(canvasId) { return new Promise((resolve, reject) => { uni.canvasToTempFilePath({ canvasId: canvasId, // 畫布標識 success: res => { // 在H5平臺下,tempFilePath 為 base64 resolve(res.tempFilePath) }, fail: err => { console.log('err', err) reject(err) } }, this) }) }, /** 保存生成的圖片到本地相冊中 * @param {String} filePath 圖片臨時路勁 */ posterToPhotosAlbum(filePath) { console.log('filePath',filePath) uni.showLoading({ title: '保存中...' }) uni.saveImageToPhotosAlbum({ filePath: filePath, success: (res) => { uni.showToast({ title: '保存成功,請前往手機相冊中查看', mask: true, icon: 'none', duration: 2000 }) }, fail: (err) => { console.log('err',err) if (err.errMsg.includes('deny')||err.errMsg.includes('denied')) { // 用戶選擇拒絕 this.openSetting() } else if (err.errMsg.includes('fail cancel')) { // 用戶在保存圖片時 取消了 uni.showToast({ title: '已取消保存,無法保存至相冊', mask: true, icon: 'none', duration: 2000 }) return } }, complete: () => { uni.hideLoading() } }) }, /** * 打開攝像頭設置權(quán)限頁面 */ openSetting() { uni.showModal({ title: '溫馨提示', content: '保存圖片至相冊中,需要您同意添加訪問相冊權(quán)限', cancelText: '拒絕', confirmText: '同意', success: res => { if (res.confirm) { uni.openSetting({ success: settingdata => { if (settingdata.authSetting['scope.writePhotosAlbum']) { console.log('獲取權(quán)限成功,給出再次點擊圖片保存到相冊的提示。') uni.showToast({ title: '授權(quán)成功,請再次點擊保存', icon: 'none', duration: 2000, }) } else { console.log('獲取權(quán)限失敗,給出不給權(quán)限就無法正常使用的提示') uni.showToast({ title: '需要訪問相冊權(quán)限', icon: 'none', duration: 2000, }) } }, fail: (res) => { console.log('err', err) } }) } else { uni.showToast({ title: '已拒絕授權(quán),無法保存至相冊', mask: true, icon: 'none', duration: 2000 }) return } } }) } } } </script> <style> </style>###效果################更多程式設計相關(guān)知識,請造訪:###程式設計入門###! ! ###
以上是手把手帶你在小程式中實現(xiàn)保存圖片組件功能的詳細內(nèi)容。更多資訊請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

熱AI工具

Undress AI Tool
免費脫衣圖片

Undresser.AI Undress
人工智慧驅(qū)動的應用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6
視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

閒魚官方微信小程式悄悄上線,在小程式中可以發(fā)布閒置與買家/賣家私訊交流、查看個人資料及訂單、搜尋物品等,有用好奇閒魚微信小程式叫什麼,現(xiàn)在快來看一下。閒魚微信小程式叫什麼答案:閒魚,閒置交易二手買賣估價回收。 1、在小程式中可以發(fā)布閒置、與買家/賣家私訊交流、查看個人資料及訂單、搜尋指定物品等功能;2、在小程式的頁面中有首頁、附近、發(fā)閒置、訊息、我的5項功能;3、想要使用的話必要要開通微信支付才可以購買;

實現(xiàn)微信小程式中的圖片濾鏡效果隨著社群媒體應用程式的流行,人們越來越喜歡在照片中應用濾鏡效果,以增強照片的藝術(shù)效果和吸引力。在微信小程式中也可以實現(xiàn)圖片濾鏡效果,為使用者提供更多有趣和創(chuàng)意的照片編輯功能。本文將介紹如何在微信小程式中實現(xiàn)圖片濾鏡效果,並提供具體的程式碼範例。首先,我們需要在微信小程式中使用canvas元件來載入和編輯圖片。 canvas元件可以在頁面

實現(xiàn)微信小程式中的下拉式選單效果,需要具體程式碼範例隨著行動互聯(lián)網(wǎng)的普及,微信小程式成為了網(wǎng)路開發(fā)的重要一環(huán),越來越多的人開始關(guān)注和使用微信小程式。微信小程式的開發(fā)相比傳統(tǒng)的APP開發(fā)更加簡單快捷,但也需要掌握一定的開發(fā)技巧。在微信小程式的開發(fā)中,下拉式選單是一個常見的UI元件,實現(xiàn)了更好的使用者操作體驗。本文將詳細介紹如何在微信小程式中實現(xiàn)下拉式選單效果,並提供具

閒魚官方微信小程式已經(jīng)悄悄上線,它為用戶提供了一個便捷的平臺,讓你可以輕鬆地發(fā)布和交易閒置物品。在小程式中,你可以與買家或賣家進行私訊交流,查看個人資料和訂單,以及搜尋你想要的物品。那麼閒魚在微信小程式中究竟叫什麼呢,這篇教學攻略將為您詳細介紹,想要了解的用戶們快來跟著本文繼續(xù)閱讀吧!閒魚微信小程式叫什麼答案:閒魚,閒置交易二手買賣估價回收。 1、在小程式中可以發(fā)布閒置、與買家/賣家私訊交流、查看個人資料及訂單、搜尋指定物品等功能;2、在小程式的頁面中有首頁、附近、發(fā)閒置、訊息、我的5項功能;3、

微信小程式實現(xiàn)圖片上傳功能隨著行動網(wǎng)路的發(fā)展,微信小程式已經(jīng)成為了人們生活中不可或缺的一部分。微信小程式不僅提供了豐富的應用場景,還支援開發(fā)者自訂功能,其中包括圖片上傳功能。本文將介紹如何在微信小程式中實作圖片上傳功能,並提供具體的程式碼範例。一、前期準備工作在開始編寫程式碼之前,我們需要先下載並安裝微信開發(fā)者工具,並註冊成為微信開發(fā)者。同時,也需要了解微信

使用微信小程式實現(xiàn)輪播圖切換效果微信小程式是一種輕量級的應用程序,具有簡單、高效的開發(fā)和使用特點。在微信小程式中,實作輪播圖切換效果是常見的需求。本文將介紹如何使用微信小程式實現(xiàn)輪播圖切換效果,並給出具體的程式碼範例。首先,在微信小程式的頁面檔案中,新增一個輪播圖元件。例如,可以使用<swiper>標籤來實現(xiàn)輪播圖的切換效果。在該組件中,可以透過b

實現(xiàn)微信小程式中的圖片旋轉(zhuǎn)效果,需要具體程式碼範例微信小程式是一種輕量級的應用程序,為用戶提供了豐富的功能和良好的用戶體驗。在小程式中,開發(fā)者可以利用各種元件和API來實現(xiàn)各種效果。其中,圖片旋轉(zhuǎn)效果是一種常見的動畫效果,可以為小程式增添趣味性和視覺效果。在微信小程式中實作圖片旋轉(zhuǎn)效果,需要使用小程式提供的動畫API。以下是一個具體的程式碼範例,展示如何在小程

實作微信小程式中的滑動刪除功能,需要具體程式碼範例隨著微信小程式的流行,開發(fā)者在開發(fā)過程中經(jīng)常會遇到一些常見功能的實作問題。其中,滑動刪除功能是常見、常用的功能需求。本文將為大家詳細介紹如何在微信小程式中實現(xiàn)滑動刪除功能,並給出具體的程式碼範例。一、需求分析在微信小程式中,滑動刪除功能的實作涉及以下要點:列表展示:要顯示可滑動刪除的列表,每個列表項目需要包
