前言
在《微信小程序云开发快速入门(2/4)》分享中,我们已经将列表的查询和分页全部搞定了,可以说对于备忘录来说已经非常好用了,此时此刻码仔在脑海中已经开始幻想自己走上了人生的巅峰场景了。
可现实往往是残酷无情的,正在码仔幻想的时候,码妞气冲冲的跑到了码仔的电脑面前,恨不得把码仔的电脑都给砸了!
码妞大声说道:
“哼,快把列表页面背景图,给我换了,别人看我用备忘录都说我暗恋你,天天看你的照片,还把你的照片设置成软件背景!!!”
“我可还是单身呢,你这是存心让我找不到对象吗?”
码仔:“既然选择公开给你使用,那就需要满足下你的需求吧”
听到码仔的回复,码妞很高兴说到“等功能上线了,我以后要把背景换我的美照,天天换一张不带重复!!!”
码仔内心:“哼,事真多!”
接下来那来分析下需求的具体步骤:
图片替换需求
- 选择图片
- 上传图片
- 再次上传
- 选择图片
- 删除图片
在这里需要对图片的数据管理,同时还需要上传到云存储当中去。
本地图片操作
布局走起
很久没有写布局样式了,是不是有些生疏了?感觉复习一下,温故知新。当我们要调试一个页面的样式的时候,首先需要锁定当前的编译模式:
先在头部使用 image 图片组件区域放上一个拍照的icon,当用户点击icon的时候我们就去选择图片。
<!-- 头部 -->
<view class="head-bg">
<!-- 省略无关布局 -->
<image class="img-add" src="../../images/img_add.png"></image>
</view>
然后再给它配置上样式把位置大概放在茶杯上面去,使用 position 定位。
.img-add{
width: 50rpx;
height: 50rpx;
position: absolute;
right: 65rpx;
top: 450rpx;
}
最终的效果
然后通过 bindtap 绑定一个点击事件起去选择图片。
<image bindtap="chooseImg" class="img-add" src="../../images/img_add.png" />
选择图片
在这个 chooseImg 方法中,可以通过 wx.chooseImage() 从本地相册选择图片或使用相机拍照。
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success (res) {
// 由于是数组然后只取一张图片,所以默认取下标为0的图片
console.log(res.tempFilePaths[0])
}
})
chooseImage 参数解释:
- count:可以选择的照片数量,默认为9张
- sourceType:选择图片的来源,默认可以从手机和相机中都支持。
- album:可以来自手机相册
- camera:可以来自手机拍照
- 支持两个都写
- sizeType:所选的图片的尺寸,默认是原图和压缩图都支持。
- original:原图
- compressed:压缩图
- 支持两个都写,建议使用压缩图
- success(res)
- tempFilePaths:临时文件的路径列表
- tempFiles:临时文件列表
- 两个值都为数组
替换图片
选择完成之后,接下里就要把图片来显示出来,先在data中定义一个变量存放已经选择好的图片路径。
data: {
topImgUrl:''
}
然后把获取到的值存放在这个变量中
chooseImg(){
let that = this
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success (res) {
that.data.topImgUrl = res.tempFilePaths[0]
}
})
}
之前背景图片是通过在 css 中使用 background-image 属性设置的。
.head-bg {
width: 750rpx;
height: 540rpx;
background-image: url('https://6465-demo-3gf9i3wu06a03ab1-1306451997.tcb.qcloud.la/head_bg.png');
background-size: 100% 100%;
}
小程序无法把参数传递到css里面只能在wxml里面,所以我们需要把写成行内样式。
<!-- 头部 -->
<view class="head-bg" style="background-image: url('https://6465-demo-3gf9i3wu06a03ab1-1306451997.tcb.qcloud.la/head_bg.png');" >
<!-- 省略无关布局 -->
</view>
然后把 topImgUrl 对图片路径进行替换
<!-- 头部 -->
<view class="head-bg" style="background-image: url('{{topImgUrl}}');" >
<!-- 省略无关布局 -->
</view>
然后运行一下看效果:
这个时候我们会发现一开始进来用户没有图片,所以需要给 topImgUrl 设置一个默认值。
data: {
topImgUrl:'https://6465-demo-3gf9i3wu06a03ab1-1306451997.tcb.qcloud.la/head_bg.png'
}
然后我们再选择相片试试看效果,我们会发现还是没有效果,因为不支持本地图片。那么这个时候我们就需要上传到云存储。
图片上传云存储
云端文件存储,自带 CDN 加速,支持在前端直接上传/下载,可在云开发控制台可视化管理。
云存储可视化
这张默认图片其实就是我们之前手动上传到云存储上面的,打开云开发控制面板选择「存储」可以看到之前上传的背景图和气泡图。
除了可以直接对文件进行管理之外,它还支持像云数据库一样设置权限。
以及还支持缓存配置,支持多种配置策略。
上传到云存储
话不多说,接下来通过小程序把选择好的图片上传到云存储中去,在这里要使用 wx.cloud.uploadFile 将本地资源上传至云存储空间。
wx.cloud.uploadFile({
cloudPath: 'example.png',
filePath: '', // 文件路径
}).then(res => {
// get resource ID
console.log(res.fileID)
})
uploadFile 参数解释:
- cloudPath:路径名称
- 建议使用时间戳+随机数来生成
- filePath:文件路径
- 不建议存放在根目录,不便于查找
- 返回值 res
- fileID:文件ID,可用于查找文件详情
通过上传代码结合刚才到选择图片代码
chooseImg: function () {
const that = this
wx.chooseImage({
count: 1, // 只选择一张图片
sizeType: ['compressed'], // 使用压缩图
sourceType: ['album', 'camera'], // 支持照相,相册
success: function (res) {
const filePath = res.tempFilePaths[0] //上传第一张图片
// 生成规则:文件夹路径 + 时间戳 + 随机数 + 文件后缀
const cloudPath = `top-img/${Date.now()}-${Math.floor(Math.random(0, 1) * 100000)}` + filePath.match(/.[^.]+?$/)[0]
wx.cloud.uploadFile({
cloudPath,
filePath,
success: res => {
console.log('上传成功后获得的res:', res)
that.setData({
topImgUrl:res.fileID
})
},
fail:err=>{
console.log(err)
}
})
}
})
}
上传成功 res
存储管理,自动生成了一个文件夹且图片上传到这里来了
删除在线文件
当然上传那就肯定有删除,因为总会有不喜欢的图片需要删除。需要使用 wx.cloud.deleteFile 从云存储空间删除文件。
wx.cloud.deleteFile({
fileList: ['cloud://demo-3gf9i3wu06a03ab1.6465-demo-3gf9i3wu06a03ab1-1306451997/top-img/1627462991919-39954.png']
}).then(res => {
console.log(res.fileList)
})
deleteFile 参数解释:
- fileList:文件ID数组
- 可以支持批量 ID 获取
- 返回值 res
- fileList:删除结果列表
- 通过找到对应下标的删除结果
- fileList:删除结果列表
接下来我来拿刚才的文件ID来使用看下返回结果
获取在线链接
当获取到FileID还是无法显示,这个时候需要通过FileID去获取图片路径,使用 wx.cloud.getTempFileURL 用云文件 ID 换取真实链接。
wx.cloud.getTempFileURL({
fileList: ['cloud://xxx', 'cloud://yyy'],
success: res => {
// get temp file URL
console.log(res.fileList)
},
fail: err => {
// handle error
}
})
getTempFileURL 参数解释:
- fileList:文件ID数组
- 可以支持批量 ID 获取
- 返回值 res
- fileList:路径列表
- 通过找到对应下标的 tempFileURL 获取图片路径
- fileList:路径列表
接下来我来拿刚才的文件ID来使用看下返回结果
接下来我们需要娶到路径,最终代码
chooseImg: function () {
const that = this
// 1. 选择图片
wx.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: function (res) {
const filePath = res.tempFilePaths[0] //上传第一张图片
const cloudPath = `top-img/${Date.now()}-${Math.floor(Math.random(0, 1) * 100000)}` + filePath.match(/.[^.]+?$/)[0]
console.log(cloudPath)
// 2. 上传图片
wx.cloud.uploadFile({
cloudPath,
filePath,
success: res => {
// 3. 获取链接
wx.cloud.getTempFileURL({
fileList: [res.fileID],
success: res => {
that.setData({
topImgUrl: res.fileList[0].tempFileURL
})
}
})
}
})
}
})
}
终于通过几经波折上传到图片显示出来了
相信你看到这里,肯定会吐槽为什么这么麻烦?能不能简单点?
当然可以,其实我们可以省略一步,就是去获取链接,因为 image 组件的 src 属性支持文件ID,这样机会你需要获取链接这一步骤了。
除此之外可以看到如果是自定义头部图片气泡就没有存在的意义了,因为会挡住图片本身的内容,所以我们就做个调整,如果有自定义图片就显示一张图片,如果没有就按照原来的设计来。
- 修改布局,抽象出来样式
/* 头部大小 */
.head {
width: 750rpx;
height: 540rpx;
}
/* 头部背景 */
.head-bg {
background-image: url('https://6465-demo-3gf9i3wu06a03ab1-1306451997.tcb.qcloud.la/head_bg.png');
background-size: 100% 100%;
}
- 具体布局结构变化,通过topImgUrl这个参数来控制显示隐藏
<!-- 头部 -->
<image wx:if="{{fileID}}" src="{{fileID}}" class="head"></image>
<view wx:if="{{! fileID}}" class="head head-bg" >
<view bindtap="randomMsg" class="head-bubble">
<!-- 头像 -->
<view class="user-avatar">
<open-data type="userAvatarUrl"></open-data>
</view>
<!-- 问候语 -->
<text>,{{message}}</text>
</view>
<image bindtap="chooseImg" class="img-add" src="../../images/img_add.png" />
</view>
- 上传图片完整代码
chooseImg: function () {
const that = this
// 选择图片
wx.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: function (res) {
const filePath = res.tempFilePaths[0] //上传第一张图片
const cloudPath = `top-img/${Date.now()}-${Math.floor(Math.random(0, 1) * 100000)}` + filePath.match(/.[^.]+?$/)[0]
// 上传图片
wx.cloud.uploadFile({
cloudPath,
filePath,
success: res => {
// 设置文件ID
that.setData({
fileID: res.fileID
})
}
})
}
})
},
虽然效果以及达到了,但是这样还是有个问题就是下次进来还是显示默认的图片,数据没有保存下来,所以这个时候要用到我们学到的数据库操作,如果将背景数据进行在云端数据库管理?
背景图片管理
别小看这个功能,这个功能虽然在之前我们已经实现了小程序端的业务,但是在数据逻辑处理,还是有些东西需要思考全面的。
按照惯例,先分析具体实现思路:
- 新建背景集合存放背景信息
- 保存背景的时候需添加记录
- 替换背景时候需删除再新增
- 删除背景时同时需删除图片
- 用户进入查询背景数据显示
以上所使用到的只是都是在之前分享内容学习过的内容,本次用同样的知识来实现下不一样的业务,相当于对大家之前知识的一个巩固复习的过程,加强大家对这些知识点的印象。
新建数据集合
用于存放背景图片信息
新建一个叫做 background 存放管理背景数据,然后我们看下权限:
因为实际业务需求中,这个背景只是当前用户可以看到,所以默认的权限就适合我们当前的业务,不需要再做调整。
定义操作接口
小程序端需要操作 background 数据库,所以我们在 api 文件夹在创建一个 background.js 来写相关的数据库操作方法。
// 获取背景
function getBackground() {
}
// 添加背景
function addBackground(data)
}
// 删除背景
function delBackground(id) {
}
// 导出声明
export {
getBackground,
addBackground,
delBackground
}
根据实际的需求,分贝定义来获取背景、添加背景、删除背景,然后为了让其他js能引入使用,在最后做了一个导出声明。
保存上传背景
首先实现下添加数据的方法
// 添加背景
function addBackground(data) {
// 1. 获取数据库引用
const db = wx.cloud.database()
// 2. 找到集合获取数据
const background = db.collection('background')
// 3. 添加创建时间
data.createTime = db.serverDate()
// 4. 集合添加数据
return background.add({data})
}
在这个我给大家做了一个小小的加餐,使用了 serverDate 获取服务端时间,可用于查询条件、更新字段值或新增记录时的字段值。
serverDate 参数说明:
- offset:单位毫米,可以设置时间偏移量
- 支持正数(延后时间)或负数(提前时间)
- 案例:往后一天
- db.serverDate({ offset: 24 * 60 * 60 * 1000 })
然后再到列表页面去进行使用,先引入文件方法:
添加到 list.js 头部
import {
addBackground
} from '../../api/background.js'
在选择完图片上传完成之后,使用添加方法:
chooseImg: function () {
const that = this
wx.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: function (res) {
const filePath = res.tempFilePaths[0] //上传第一张图片
const cloudPath = `top-img/${Date.now()}-${Math.floor(Math.random(0, 1) * 100000)}` + filePath.match(/.[^.]+?$/)[0]
console.log(cloudPath)
wx.cloud.uploadFile({
cloudPath,
filePath,
success: res => {
let data = {
fileID: res.fileID
}
that.setData(data)
addBackground(data)
}
})
}
})
},
经过添加操作后,数据被添加到了数据库:
我们可以编辑下 createTime 字段:
可以看到这个是一个时间类型的字段参数。
添加完成之后还需要做两件事情:
- 进入的时候去查询背景信息
- 替换背景时候先删除再添加
查询背景信息
首先实现查询数据方法:
// 获取背景
function getBackground() {
// 1. 获取数据库引用
const db = wx.cloud.database()
// 2. 找到集合获取数据
const background = db.collection('background')
// 3. 查询集合数据
return background.get()
}
在 list.js 引入查询方法:
import {
addBackground,
getBackground
} from '../../api/background.js'在 onLoad 进行查询调用:
在 onLoad 进行查询调用:
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
// 获取背景图
this.getBackground()
// 获取问候语
this.randomMsg()
},
// 获取背景图
getBackground(){
getBackground().then(res => {
// 判断是否有数据
if (res.data.length) {
this.setData({
fileID:res.data[0].fileID // 获取第一条数据
})
}
})
}
当用户进入列表页面就会显示显示已上传的背景。
替换背景信息
这里需要采用先删除后添加的方式,当然也可以采用修改的方式进行实现。在这里需要注意,无论采用什么方式都需要对之前背景文件进行删除,无用的图片就需要及时清理掉,要不然就会白白的占用服务器资源,存储资源是需要收费。虽然存储费用不贵,但是要保持一个良好的节约习惯。
先实现删除方法:
// 删除背景数据同时删除背景图片
function delBackground(id,fileID) {
// 1. 获取数据库引用
const db = wx.cloud.database()
// 2. 获取集合对象
const background = db.collection('background')
// 3. 删除背景图片
wx.cloud.deleteFile({
fileList: [fileID]
})
// 4. 删除当条背景数据
return background.doc(id).remove()
}
在 lis.js 引入删除方法:
import {
addBackground,
getBackground,
delBackground
} from '../../api/background.js'
在这里因为删除需要id,所以在获取的背景的时候需要保存id
getBackground(){
getBackground().then(res => {
if (res.data.length) {
const background = res.data[0]
this.data.background = background
this.setData({
fileID:background.fileID
})
}
})
}
然后在选择图片的逻辑中判断是否有id,如果有的话证明之前上传过图片则进行删除操作
chooseImg: function () {
const that = this
wx.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: function (res) {
const filePath = res.tempFilePaths[0] //上传第一张图片
const cloudPath = `top-img/${Date.now()}-${Math.floor(Math.random(0, 1) * 100000)}` + filePath.match(/.[^.]+?$/)[0]
console.log(cloudPath)
wx.cloud.uploadFile({
cloudPath,
filePath,
success: res => {
let data = {
fileID: res.fileID
}
that.setData(data)
addBackground(data)
// 判断是否之前上传过图片
if(that.data.background){
let id = that.data.background._id
let fileID = that.data.background.fileID
delBackground(id,fileID)
}
}
})
}
})
}
JS逻辑处理代码写完,意外发现上传完图片后居然发现拍照的ICON不见了,后来查看布局代码发现原来拍照ICON在未上传图片状态布局的里面,所以一并没隐藏了,我们需要把布局移除来。
<!-- 头部 -->
<image wx:if="{{fileID}}" src="{{fileID}}" class="head"></image>
<view wx:if="{{!fileID}}" class="head head-bg" >
<view bindtap="randomMsg" class="head-bubble">
<!-- 头像 -->
<view class="user-avatar">
<open-data type="userAvatarUrl"></open-data>
</view>
<!-- 问候语 -->
<text>,{{message}}</text>
</view>
<!-- 原来的位置 -->
<!-- <image bindtap="chooseImg" class="img-add" src="../../images/img_add.png" /> -->
</view>
<image bindtap="chooseImg" class="img-add" src="../../images/img_add.png" />
大功告成!码仔内心窃喜,于是偷偷的换上了一张它和码妞的合影。码仔前后想了想“这个功能,还是很有必要的!”。
总结
- 学习了小程序图片操作:wx.chooseImage() ,选择图片
- 小程序图片云存储管理:
- wx.cloud.uploadFile:上传文件
- wx.cloud.deleteFile :删除文件
- wx.cloud.getTempFileURL:获取在线链接
- 还对之前的学习过的数据库:新增、查询、删除操作通过实现一个需求进行了组合使用
前排学习