作业要求

第一次作业

构建个人相册小程序(纯静态展示):

  1. 可以选择本地的图片 & 视频
  2. 图片有分类
  3. 图片本地可以预览

第二次作业

为个人相册增加在小程序端的上传、存储、图像处理(美图)功能:

  1. 图片需要上传至云端;
  2. 相册数据上传到云端,更换不同手机可以查看相册;
  3. 可以对图片进行基础的处理(如水印、美颜等)。

结课作业

基于你自己对于生活和学习过程中的观察,开发出一个小程序/H5应用。在这个小程序/H5 应用中,你需要使用到云函数、云数据库和云存储能力。应用如果涉及到用户上传信息,应当有基本的安全校验。
提交方式:

  1. 提交小程序的体验二维码(作业小程序不需要提交审核!设置体验版即可)
  2. 提交小程序的源码(用于做源码的查重)

小程序开发入门

开发前的准备

小程序的开发有两样东西必不可少,一个是小程序开发的技术文档;还有一个就是小程序的开发者工具。

开发者工具小程序开发者工具下载地址

技术文档官方小程序技术文档

注册微信小程序

小程序的注册非常方便,打开小程序注册页面,按照要求填入个人的信息,验证邮箱和手机号,扫描二维码绑定你的微信号即可,3 分钟左右的时间即可搞定。

注册页面小程序注册页面

当我们注册成功后,就可以自动登入到小程序的后台管理页面,如果不小心关掉了后台页面,也可以点击小程序后台管理登录页进行登录。

后台管理页小程序后台管理登录页

进入到小程序的后台管理页后,点击左侧菜单的开发进入设置页,然后再点击开发设置,在开发者 ID里就可以看到AppID(小程序 ID),这个待会我们有用。

新建一个模板小程序

安装完开发者工具之后,我们使用微信扫码登录开发者工具,然后使用开发者工具新建一个小程序的项目,

项目名称:这个可以根据自己的需要任意填写,可以是中文;
目录:大家需要先在电脑上新建一个空文件夹,然后选择这个空文件夹;
AppID:就是之前我们找到的AppID(小程序 ID)(也可以点击右边的下拉框,下拉选择 AppID)
开发模式为小程序
后端服务选择不使用云服务,注意为了教学的需要,先选择不使用云服务
语言为 JavaScript

点击新建确认之后就能在开发者工具的模拟器里看到一个简单的Hello World 模板小程序,在编辑器里看到这个小程序的源代码。接下来,我们点击开发者工具的工具栏里的预览图标,就会弹出一个二维码,使用你的手机微信扫描这个二维码就能在微信里看到这个小程序啦。以后我们要自己开发一个小程序都可以按照上面的操作新建一个模板小程序,然后在这个的基础上修改开发。

开通云开发服务

点击微信开发者工具的“云开发”图标,在弹出框里点击开通,同意协议后,会弹出创建环境的对话框。这时会要求你输入环境名称环境 ID,以及当前云开发的基础环境配额。按照对话框提示的要求填写完之后,点击创建,会初始化环境,环境初始化成功后会自动弹出云开发控制台,这样我们的云开发服务就开通啦。

第一次作业

参考资料

小程序开发入门小程序开发入门
WXML与WXSSWXML与WXSS
链接与图片链接与图片
WeUI框架WeUI框架
渐变与动画渐变与动画
数据绑定数据绑定
列表渲染与条件渲染列表渲染与条件渲染
小程序组件小程序组件
点击事件点击事件
页面渲染页面渲染
生命周期生命周期
数据表单数据表单
图片、缓存与文件图片、缓存与文件

小程序主页的制作

初步规划一共有六个相册,点击分别跳转到对应的wxml。使用的是链接与图片中的view、navigator、image 组件嵌套一节中的代码。
比如我们在 home.wxml 里输入以下代码:

<view class="event-list">
    <navigator url="/pages/home/imgshow/imgshow" class="event-link">
        <view class="event-img">
            <image mode="widthFix" src="https://hackwork.oss-cn-shanghai.aliyuncs.com/lesson/weapp/4/weapp.jpg"></image>
        </view>
        <view class="event-content">
            <view class="event-title">零基础学会小程序开发</view>
            <view class="event-desc">通过两天集中的学习,你会循序渐进的开发出一些具有实际应用场景的小程序。 </view>
            <view class="event-box">
                <view class="event-address">深圳南山</view>
                <view class="event-time">2018922-23</view>
            </view>
        </view>
    </navigator>
</view>

在 home.wxss 里输入以下样式:

.event-list{
  background-color: #fafbfc;
  padding: 20px 0;
  }
.event-link{
  margin: 10px;
  border-radius: 5px;
  background-color: #fff;
  box-shadow:5rpx 8rpx 10rpx rgba(53,178,225,0.26);
  overflow: hidden;
}
.event-img image{
  width: 100%;
  }
.event-content{
  padding: 25rpx;
  }
.event-title{
  line-height: 1.7em;
  }
.event-desc{
  font-size: 14px;
  color: #666;
  line-height: 1.5em;
  font-weight: 200;
  }
.event-box{
  margin-top: 15px;
  overflow: hidden;
  }
.event-address,.event-time{
  float: left;
  color: #cecece;
  font-size: 12px;
  padding-right: 15px;
  }

我的个人相册主页如下所示:
个人相册主页

相册的制作

图片的存储

起初,我的图片存储在腾讯云的存储桶中。这样一来,我们可以把一张图片以链接的方式让其他人看到。

免费的图床:腾讯云对象存储 COS
由于我们之前注册过小程序,可以选择其他登录方式里的微信公众号登录,登录后点击右上角控制台,即可进入后台,在工具栏里下拉云产品,找到存储下面的对象存储,在左侧菜单存储桶列表创建存储桶,只需注意将访问权限改为公有读私有写,其他按说明自行操作。

存储桶示例:
存储桶示例

列表渲染

我们首先将需要渲染的图片的链接放入.js文件的data中:

  data: {
    image:[
      {imgurl:"https://image-1302635214.cos.ap-chengdu.myqcloud.com/image1.jpg"},
      {imgurl:"https://image-1302635214.cos.ap-chengdu.myqcloud.com/image2.jpg"},
      {imgurl:"https://image-1302635214.cos.ap-chengdu.myqcloud.com/image3.jpg"},
      {imgurl:"https://image-1302635214.cos.ap-chengdu.myqcloud.com/image4.jpg"},
      {imgurl:"https://image-1302635214.cos.ap-chengdu.myqcloud.com/image5.jpg"},
      {imgurl:"https://image-1302635214.cos.ap-chengdu.myqcloud.com/image6.jpg"},
      {imgurl:"https://image-1302635214.cos.ap-chengdu.myqcloud.com/image7.jpg"},
      {imgurl:"https://image-1302635214.cos.ap-chengdu.myqcloud.com/image8.jpg"},
      {imgurl:"https://image-1302635214.cos.ap-chengdu.myqcloud.com/image9.jpg"},
      {imgurl:"https://image-1302635214.cos.ap-chengdu.myqcloud.com/image10.jpg"},
      {imgurl:"https://image-1302635214.cos.ap-chengdu.myqcloud.com/image11.jpg"},
      {imgurl:"https://image-1302635214.cos.ap-chengdu.myqcloud.com/image12.jpg"},
    ],
  },

接着在.wxml文件中输入以下代码:

<view id="imgsection">
  <view class="imglist">
    <block wx:for="{{image}}" wx:for-item="image" wx:key="*this">
      <image class="imgitem" mode="widthFix" src="{{image.imgurl}}" />
    </block>
  </view>
</view>

微信开发文档之列表渲染列表渲染

图片美化

我们经常在一些 app 里看到很多图片它有圆角或者阴影,那这个是怎么实现的呢?这些效果是通过 wxss边框属性来实现的。下面是我相册的所有wxss样式。

/* pages/home/imgshow/imgshow.wxss */
.imglist{
  text-align: center;
}
.imglist .imgicon{
  width: 200px;
  height: 200px;
  margin: 20px;
}
/*在小程序里,所有的手机屏幕的宽度都为 750rpx,我们可以把图片等比缩小*/
.imglist .imgitem{
  width: 700rpx;
  height: 415rpx;
  margin: 20rpx;
  border-radius: 8px;
  box-shadow: 5px 8px 30px rgba(53,178,225,0.26);
}
/*图片全屏显示,但高度预留很小,这里需要裁剪图片*/
.imglist .imgfull{
  width: 100%;
  height: 100px;
}
/*图片的边款美化:圆角*/
.imglist .img{
  border-radius: 8px;
  box-shadow: 5px 8px 30px rgba(53,178,225,0.26);
}
/*把图片做成圆形*/
.imglist .circle{
  width: 200px;
  height: 200px;
  border-radius: 100%;
}

wxss设置好后,图片样式如下所示:
在这里插入图片描述

图片有了圆角,有了阴影就有了一些现代感啦。

世界级难题(?)之Grid为什么会多6.4px

列表渲染与条件渲染Grid 九宫格样式参考一节中,我尝试性地用Grid将照片设置为4个一排。但是遇到了外层不是正方形的问题:
Grid为什么会多6.4px

调试方法:在调试器中选择Wxml,点击代码能够看到对应组件的有关信息,在右下角的Styles中取消勾选能够实时了解对应wxss代码的作用,但是退出调试后无法保存,需要自行在wxss文件中修改并保存,这样才能真正生效。

调试界面:调试

老师教会了我调试方法,在我调试半天,老师直播调试十多分钟后,仍然无法解决这个问题,故弃Grid而不用。我个人的猜测是WeUI中的Grid组件预留了文字的位置,这多出来的6.4px是强制性为文字空出来的空间。

第二次作业

参考资料

云开发快速入门云开发快速入门
云开发能力云开发能力
存储、数组、对象存储、数组、对象
云开发与 Node.js云开发与 Node.js

上传一张图片到data.imgurl

技术文档wx.chooseImage()

使用开发者工具新建一个 file 的页面,然后在 file.wxml 里输入以下代码:

<button bindtap="chooseImg">选择图片</button>
<image mode="widthFix" src="{{imgurl}}"></image>
<view>上传的图片</view>

然后在 file.js 的 data 里给 imgurl 设置一个初始值,由于链接 src 是一个字符串类型,我们这里可以设置为一个字符串空值,完成 imgurl 的初始化:

  data: {
    imgurl:"",
  },

再在 file.js 里添加事件处理函数 chooseImg,在 chooseImg 里我们来调用上传函数的 API wx.chooseImage(),其中 count、sizeType、sourceType 都是 API 已经写好的属性,API 调用成功(图片上传成功)之后,会在 success 回调函数里返回图片的一些信息,返回的信息可以看技术文档。

  chooseImg:function(){
    let that=this
    wx.chooseImage({
      count: 1,
      sizeType: ['original', 'compressed'],
      sourceType: ['album', 'camera'],
      success(res) {
        const imgurl = res.tempFilePaths
        that.setData({
          imgurl
        })
      }
    })
  },

虽然在开发者工具的模拟器也可以看到效果,但是 wx.chooseImage()是一个与手机客户端交互性很强的 API,我们最好在手机上体验。点击开发者工具的预览,在手机微信里查看效果,点击选择图片按钮,上传一张图片或拍照看看。

count:可以选择的照片数量,默认为 9 张(由于 imgurl 声明的是字符串,多张照片需为数组 Array,后面有上传多张图片的案例)
sourceType:选择图片的来源,album 就是图片可以来自手机相册;而 camera 是可以来自手机拍照,两个都写就是来自相册或拍照都可以;
sizeType:所选的图片的尺寸,original 为原图,compressed 为压缩图,为了减轻服务器压力,建议为压缩图;
tempFilePaths:临时文件的路径列表,tempFiles 为临时文件列表,注意这两个值都为数组。

上传多张图片到data.imgurl

如果上传的是多张照片,那么 imgurl 的初始值就不能是字符串了,而是一个数组 Array,

  data: {
    imgurl:[],
  },

而 file.wxml 的代码也要相应的改为列表渲染即可,这种写法在代码上通用性比较强,上传一张图片、多张图片都可以,不过具体还是要看实际产品开发需求。

<view wx:for-items="{{imgurl}}" wx:for-item="item" wx:key="*this">
  <image mode="widthFix" src="{{item}}"></image>
</view>

然后再把 count 的值修改为 2~9 张,编译之后,在手机微信上体验一下效果。

预览所有上传的图片

预览图片就是在新页面里全屏打开图片,预览的过程中用户可以进行保存图片、发送给朋友等操作。可以预览一张照片或者多张照片。

技术文档wx.previewImage()

使用开发者工具在 file.wxml 里输入以下代码,我们要预览的是从手机相册里上传的图片(保留上面的代码,接着写),如果没有上传图片,那就把预览图片的按钮给隐藏,我们来写一段完整的代码:

<view wx:if="{{hasImg === true}}">
    <button bindtap="previewImg">预览照片</button>
</view>

然后在 file.js 添加事件处理函数 previewImg,调用预览图片的 API wx.previewImage():

  previewImg:function() {
    wx.previewImage({
      current: '',
      urls: this.data.imgurl,
    })
  },

当上传图片之后点击预览图片按钮就能预览所有图片了。

这个场景主要用于让用户可以预览、保存或分享图片,毕竟image组件是不支持图片的放大预览、保存到本地、转发给好友,现在微信还支持预览小程序码,长按就可以打开小程序,这个API主要是为了增强用户的交互体验的。
那我们应该如何实现点击其中的某一张图片,就会弹出所有图片的预览呢?这里就要用到 current 了。

将之前 file.wxml 里图片上传的代码改成如下,把事件处理函数 previewImg 绑定在图片上面。

<button bindtap="chooseImg">选择图片</button>
<view wx:for-items="{{imgurl}}" wx:for-item="item" wx:key="*this">
  <image mode="widthFix" src="{{item}}" data-src="{{item}} " bindtap="previewImg" style="width:100px;float:left"></image>
</view>

然后将 file.js 的事件处理函数 previewImg 修改为:

  previewImg:function(e) {
    wx.previewImage({
      current: e.currentTarget.dataset.src,
      urls: this.data.imgurl,
    })
  },

这样点击图片就会弹出预览窗口来预览图片了。

将一张图片上传到云存储

要把图片上传到云存储,会使用到 wx.cloud.uploadFile,这个 API 是小程序端的 API,它是把本地资源也就是临时文件里的文件上传到云存储里。在图片、缓存与文件章节里我们已经了解到如何把图片上传到小程序的临时文件,而要把临时文件上传到云存储,则需要调用 wx.cloud.uploadFile API。

技术文档wx.cloud.uploadFile()

wx.cloud.uploadFile()可以将本地资源上传至云存储空间,如果上传至同一路径则是覆盖写。
cloudPath:云存储路径,命名限制见文件名命名限制
filePath:要上传文件资源的路径

在 wx.cloud.uploadFile 技术文档里,可以看到要调用 API,需要获取图片的 filePath,在小程序里为临时文件的路径,也就是要把上传到小程序的临时文件路径赋值给它;还有一个 cloudPath,这个为文件的云存储路径,这个是我们可以任意设置的。
使用开发者工具在 login.wxml 里添加以下代码,:

<button bindtap="chooseImg">选择图片</button>
<image mode="widthFix" src="{{imgurl}}"></image>

然后在 login.js 的 data 里初始化 imgurl,这里 imgurl 是一个字符串,

data: {
    imgurl: "",
  },

chooseImg 事件处理函数最终为以下代码:

  chooseImg: function() {
    wx.chooseImage({
      count: 1,
      sizeType: ['compressed'],
      sourceType: ['album', 'camera'],
      success: res=> {
        const filePath = res.tempFilePaths[0]
        const cloudPath = `cloudbase/${Date.now()}-${Math.floor(Math.random(0, 1) * 1000)}` + filePath.match(/\.[^.]+?$/)[0]
        wx.cloud.uploadFile({
          cloudPath,
          filePath,
          success: res => {
            console.log('上传成功后获得的res:', res)
            const imgurl=res.fileID
            this.setData({
              imgurl
            })
          },
        })
      }
    })
  },

res.tempFilePaths

res.tempFilePaths 是一个数组格式,而 wx.cloud.uploadFile 的 filePath 是一个字符串,所以我们在上传时,可以把第一张图片的路径(字符串)赋值给 filePath:

const filePath = res.tempFilePaths[0]

云存储的二级目录,文件名与后缀的处理

临时路径的文件名就不是原来的文件名,会变成一段长字符,但文件的格式还是原来的文件格式(后缀)。当文件的后缀相同时,文件会被覆盖。如果不希望文件被覆盖,我们需要给文件命不同的名字,我们可以这样处理:

const cloudPath = `cloudbase/${Date.now()}-${Math.floor(Math.random(0, 1) * 1000)}` + filePath.match(/\.[^.]+?$/)[0]

在 cloudPath 的前面加一个文件路径就可以建一个二级目录cloudbase
${Date.now()}是一个时间戳,以毫秒计算。
随机数是1000以内的正整数。
filePath.match()是临时文件的后缀,这里为.png。

这样一来,除非 1 秒钟(1 秒=1000 毫秒)上传几十万张照片,不然文件名是不会重复的。

云函数上传图片到云存储

云开发不仅在小程序端可以上传文件到云存储,还可以通过云函数也就是云端上传图片到云存储(这里会涉及到一点 Nodejs 的知识)。

技术文档uploadFile

注意云函数上传图片的 API 属于服务端 API,与 wx.cloud.uploadFile 是小程序端 API 不同。

使用开发者工具右键点击云函数根目录也就是 cloudfunctions 文件夹,选择新建 Node.js 云函数,云函数的名称命名为 uploadimg,右键点击 uploadimg 文件夹,选择硬盘打开,然后拷贝一张图片如 demo.jpg 进去,文件结构如下:

uploadimg云函数目录
├── index.js
├── package.json
├── demo.jpg

然后打开 index.js,输入以下代码:

const cloud = require('wx-server-sdk')
const fs = require('fs')
const path = require('path')
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV,
})
exports.main = async (event, context) => {
  const fileStream = fs.createReadStream(path.join(__dirname, 'demo.jpg'))
  return await cloud.uploadFile({
    cloudPath: 'tcbdemo.jpg',
    fileContent: fileStream,
  })
}

然后右键点击 uploadimg 文件夹,选择在终端中打开,输入 npm install 安装依赖,再点击 uploadimg 文件夹,选择上传并部署所有文件(这时图片也一并上传到了云端)。

由于云端测试无法获取用户登陆态信息,所以我们不能在云端测试里把图片上传到云存储,需要在小程序端调用,使用开发者工具在 login.wxml 输入以下代码,也就是新建一个绑定 uploadimg 事件处理函数的 button 用于触发:

<button bindtap="uploadimg">云函数上传图片</button>

然后在 login.js 里输入以下代码,在事件处理函数 uploadimg 里调用 uploadimg 云函数,并返回调用之后的 res 对象:

  uploadimg() {
    wx.cloud.callFunction({
      name: 'uploadimg',
      success: res => {
        console.log(res)
      }
    })
  },

编译之后,点击云函数上传图片按钮,就可以调用 uploadimg 云函数,从而调用 uploadFile API 将服务端/云端的图片上传到云存储里面啦,可以打开云开发控制台的云存储查看是否有 tcbdemo.jpg 这张图片。

注意,通过这种方式上传到云存储的图片,是没有上传者 Open ID的,在云存储里查看这张图片的详细信息,就可以了解到。

图片编辑

支持图片的上传,编辑,移动,缩放,保存。选择好图片后进入贴图页面,共有五种可爱的动物贴纸可以选择,点击“点击保存”按钮后,处理后的图片将自动保存。
选择图片界面:
在这里插入图片描述
编辑和保存界面:
在这里插入图片描述

npm install 时出错的解决办法

我在上文云函数上传图片到云存储的实践过程中,在右键点击 uploadimg 文件夹,选择在终端中打开,输入 npm install 安装依赖这一步,遇到安装依赖失败的问题:
在这里插入图片描述
于是去询问老师,老师给出的解释是:出于安全考虑,ProgramFiles 下是没有写权限的,所以不能把Node.js安装在ProgramFiles里,应该把它安装在其他路径,比如 C:\Node.js。这与云开发快速入门中的下载 Nodejs一节的安装方法相违背。

正确的方法是到uploadimg 文件夹中,以管理员方式打开

在这里插入图片描述
再输入npm install,即可成功安装依赖:
在这里插入图片描述

第三次作业

参考资料

云数据库入门云数据库入门
存储、数组、对象存储、数组、对象

云数据库入门

任何一个大型的应用程序和服务,都必须会使用到高性能的数据存储解决方案,用来准确(ACID,原子性 Atomicity、一致性 Consistency、隔离性 Isolation、持久性 Durability,可以拓展了解一下)、快速、可靠地存储和检索用户的账户信息、商品以及商品交易信息、产品数据、资讯文章等等等等,而云开发就自带高性能、高可用、高拓展性且安全的数据库。

云数据库与 Excel、MySQL 的对应理解

云数据库MySQL 数据库Excel 文件
数据库 database数据库 database工作簿
集合 collection表 table工作表
字段 field数据列column数据表的每一列
记录 record/doc记录row数据表除开第一行的每一行

常见的数据库操作

操作集合里的数据涉及的知识点非常繁杂,下面的案例相对比较完整,便于大家有一个整体性的理解:

const db = wx.cloud.database()  //获取数据库的引用
const _ = db.command     //获取数据库查询及更新指令
db.collection("china")  //获取集合china的引用
  .where({              //查询的条件指令where
    gdp: _.gt(3000)     //查询筛选条件,gt表示字段需大于指定值。
  })
  .field({             //显示哪些字段
    _id:false,         //默认显示_id,这个隐藏
    city: true,
    province: true,
    gdp:true
  })
  .orderBy('gdp', 'desc')  //排序方式,降序排列
  .skip(0)                 //跳过多少个记录(常用于分页),0表示这里不跳过
  .limit(10)               //限制显示多少条记录,这里为10

  .get()                   //获取根据查询条件筛选后的集合数据
  .then(res => {
    console.log(res.data)
  })
  .catch(err => {
    console.error(err)
  })

我对于教程中对于.field的写法有一些自己的看法,以这里举例子:
_id:false,
city: true,
province: true,
gdp:true
我像这样把city,gdp和province设为true,在编译的时候报了错。而去掉为true的代码后就没有报错:
_id:false,
故我认为在.field里只需要写你不希望显示的字段,即只写xxx:false,不写xxx:true

调用数据库

数据库的导入

在调用数据库之前,我们需要先有一个比较贴近实际的数据库案例,为此把前面章节用到的知乎日报数据整理出了一个数据库文件。云开发数据库支持用文件的方式导入已有的数据(这里推荐大家使用 json)。

数据库下载知乎日报文章数据

右键点击链接,将 data.json 存储到电脑。为了方便大家阅读与编辑 data.json 文件的内容,推荐大家使用 Visual Studio Code 编辑器(不会还有人没下VScode吧,不会吧,不会吧)。

代码编辑器Visual Studio Code

使用 VS Code 编辑器打开 data.json,发现数据的内容与写法我们都比较熟悉,知识各个记录对象之间是使用回车 \n 分隔,而不是逗号,这一点需要大家注意。

打开云开发控制台,在数据库里新建一个集合 zhihu_daily,导入该 json 文件,导入时会有冲突模式选择,看下面的介绍,推荐大家使用 upsert:

Insert:总是插入新记录
Upsert:如果记录存在则更新,否则插入新记录

导入后,发现数据库自动给每一条数据(记录)都加了唯一的标识_id。

小程序端调用数据库

在小程序端调用数据库的方式很简单,我们可以把下面的代码写到一个事件处理函数里,然后点击组件触发事件处理函数来调用;也可以直接写到页面的生命周期函数里面;还可以把它写到 app.js 小程序的生命周期函数里面。

使用开发者工具,将下面的代码写到 login.js 的 onLoad 函数里面,我们
先使用 wx.cloud.database()获取数据库的引用(相当于连接数据库);再使用 db.collection()获取集合的引用;再通过 Collection.get 来获取集合里的记录。

const db = wx.cloud.database()
db.collection('zhihu_daily')
  .get()
  .then(res => {
    console.log(res.data)
  })
  .catch(err => {
    console.error(err)
  })

编译之后,就能在控制台看到调用的 20 条数据库记录了(如果没有指定 limit,则默认最多取 20 条记录)。
在这里插入图片描述

云函数调用数据库

使用云函数也可以调用数据库,使用开发者工具右键点击云函数根目录也就是 cloudfunctions 文件夹,选择新建 Node.js 云函数,云函数的名称命名为 zhihu_daily,然后打开 index.js,输入以下代码:

const cloud = require('wx-server-sdk')
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
})
const db = cloud.database()
exports.main = async (event, context) => {
  return await db.collection('zhihu_daily')
    .get()
}

然后右键点击 index.js,选择云函数增量上传:更新文件,我们既可以使用云函数的本地调试(要本地调试需要使用 npm install 安装 wx-server-sdk 依赖),也可以使用云端测试来了解云函数调用数据库的情况。
在这里插入图片描述

新增记录 Collection.add

在前面我们将知乎日报的数据导入到了 zhihu_daily 的集合里,接下来,我们就来给 zhihu_daily 新增记录。

技术文档Collection.add

使用开发者工具新建一个 zhihudaily 的页面,然后在 zhihudaily.wxml 里输入以下代码,新建一个绑定了事件处理函数为 addDaily 的 button 按钮:

<button bindtap="addDaily">新增日报数据</button>

然后再在 zhihudaily.js 里输入以下代码,在事件处理函数 addDaily 里调用 Collection.add,往集合 zhihu_daily 里添加一条记录,如果传入的记录对象没有 _id 字段,则由后台自动生成 _id;若指定了 _id,则不能与已有记录冲突。

  addDaily(){
    db.collection('zhihu_daily').add({
      data: {
        _id:"daily9718005",
        title: "元素,生生不息的宇宙诸子",
        images: [
    "https://pic4.zhimg.com/v2-3c5d866701650615f50ff4016b2f521b.jpg"
  ],
        id: 9718005,
        url: "https://daily.zhihu.com/story/9718005",
        image: "https://pic2.zhimg.com/v2-c6a33965175cf81a1b6e2d0af633490d.jpg",
        share_url: "http://daily.zhihu.com/story/9718005",
        body:"<p><strong><strong>谨以此文,纪念元素周期表发布 150 周年。</strong></strong></p>\r\n<p>地球,世界,和生活在这里的芸芸众生从何而来,这是每个人都曾有意无意思考过的问题。</p>\r\n<p>科幻小说家道格拉斯·亚当斯给了一个无厘头的答案,42;宗教也给出了诸神创世的虚构场景;</p>\r\n<p>最为恢弘的画面,则是由科学给出的,另一个意义上的<strong>生死轮回,一场属于元素的生死轮回</strong>。</p>"
      }
    })
      .then(res => {
        console.log(res)
      })
      .catch(console.error)
  }

点击新增日报数据的 button,会看到控制台打印的 res 对象里包含新增记录的_id 为我们自己设置的 daily9718005。打开云开发控制台的数据库标签,打开集合 zhihu_daily,翻到最后一页,就能看到我们新增的记录啦。
在这里插入图片描述

删除单条记录

技术文档:删除单个记录Document.remove()

更新单条记录

技术文档:删除单个记录Document.update()

替换更新记录

技术文档:替换单个记录Document.set()

上传一张图片到文件夹

相信大家都应该在其他小程序体验过文件上传的功能,在交互上这个功能虽然看起来简单,但是在代码的逻辑上却包含着四个关键步骤:

首先把文件上传到小程序的临时文件,并获取临时文件地址以及文件的名称;再将临时文件上传到云存储指定云文件里,并且取到文件的 FileID;其次将文件在云存储的 FileID 和文件的名称上传到数据库;最后获取文件夹内所有文件的信息。

这一段的教程将这四个步骤分成了四个独立的函数,不利于新手理解,而且有错误。所以我把前三个步骤合为一个函数:CUImage()。

  CUImage: function () {
    wx.chooseImage({
      count: 1,
      sizeType: ['compressed'],
      sourceType: ['album', 'camera'],
      success: res=> {
        const filePath = res.tempFilePaths[0]
        const cloudPath = `testupload/${Date.now()}-${Math.floor(Math.random(0,1)*1000)}`+filePath.match(/\.[^.]+?$/)[0]
        wx.cloud.uploadFile({
          cloudPath,
          filePath,
          success: res => {
            console.log("云存储上传成功", res)
            const db = wx.cloud.database()
            const name = `testupload-${Date.now()}-${Math.floor(Math.random(0,1)*1000)}`+filePath.match(/\.[^.]+?$/)[0]
            const fileID = res.fileID
            this.setData({
              fileID:fileID
            })
            db.collection('testupload').add({
              data: {
                name: name,
                fileID: fileID,
              }
            })
            .then(res => {
              console.log("数据库写入成功", res)
              wx.navigateBack()
            })
            .catch(err => {
              console.error("数据库写入失败", err)
            })
          },
        })
      },
    })
  },

实际操作后,打开云开发控制台,我们可以看到云存储中的testupload文件夹中有我们上传的图片:
在这里插入图片描述

云数据库中的testupload集合中也有图片的fileID等信息:
在这里插入图片描述

一个与fileID有关的悲伤故事

看过了数据库中有哪些字段后,getFiles()函数也很好写。我们首先在data中设置一个fileID:

  data: {
    fileID:[],
  },

再用一个按钮调用getFiles():

  getFiles() {
    const db = wx.cloud.database()
    db.collection('testupload')
    .field({
      _id:false,
      _openid:false,
      name:false
    })
    .get()
    .then(res => {
      console.log("数据库中所有图片的 fileID: ", res.data)
      const length = res.data.length
      for(let i=0;i<length;i++) {
        this.data.fileID = [{imgurl: res.data[i]}].concat(this.data.fileID)
        // this.data.fileID = [res.data[i]].concat(this.data.fileID)
      }
      this.setData({
        fileID: this.data.fileID
      })
    })
    .catch(err => {
      console.error(err)
    })
  },

在wxml中列表渲染:

<block wx:for="{{fileID}}" wx:for-item="fileID" wx:key="imgurl">
	<image class="imgitem" mode="widthFix" src="fileID.imgurl" />
</block>

编译运行之后,调试器中打印出了数据库中testupload集合中所有图片的 fileID:
在这里插入图片描述
但是渲染失败,报错信息为:
在这里插入图片描述
报错说渲染层网络层错误,在网上找原因,有一种解释是后台data.fileID还是空的时候,前端就渲染了,所以就出了错误。于是,我在列表渲染的外层加了一个判断: data.fileID.length>0 ,等data.fileID里有数据再渲染,但还是出错。
于是去询问老师:
在这里插入图片描述
看报错的信息,我认为老师说的是对的,但是我没能从老师的只言片语中领悟老师的用意,私聊老师也没能得到进一步的指点,自己后面又尝试了一些渲染方法,无果,遂弃getFiles()而不用。

小程序源码

Github网址个人相册ByUestcXiye

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐