微信小程序(下)

微信小程序

云开发简介

  • 小程序:云开发是微信团队联合腾讯云推出的专业的小程序开发服务。
  • 开发者可以使用云开发快速开发小程序、小游戏、公众号网页等,并且原生打通微信开放能力。
  • 开发者无需搭建服务器,可免鉴权直接使用平台提供的API进行业务开发小程序云开发又简称tcb,是微信官方给我们提供的基于腾讯云的云服务器。
  • 目前云开发包含:云数据库,云函数,云存储,云调用。

云开发优势

  • 无需搭建服务器快速构建小程序、公众号
    • 无需搭建服务器,只需使用平台提供的各项能力,即可快速开发业务
  • 免登陆、免鉴权调用微信开放服务
    • 无需管理证书、签名、私钥、直接调用微信API。复用微信私有协议及链路,保证业务安全性
  • 统一开发多端应用
    • 支持环境共享,一个后端环境可开发多个小程序、公众号、网页等,便捷复用业务代码与数据
  • 不限开发语言和框架
    • 开发者可以使用任意语言和框架进行代码开发,构建为容器后,快速将其托管至云开发
  • 按量计费,成本更低
    • 支持按量计费模式,后端资源根据业务流量自动扩容,先使用后付费,无需支付闲置成本

能力概览

  • 存储数据与文件
    • 云数据库:文档型数据库、稳定可靠;支持在小程序端和云函数中调用
    • 存储:云端文件存储,自带CDN加速,支持在前端直接上传/下载,可在云开发控制台可视化管理
  • 运行后端代码
    • 云函数:在云函数运行的代码,微信私有协议天然鉴权,开发者只需编写自身业务逻辑代码。
    • 云托管:支持托管服务容器,不限框架和语言,常驻运行、天然鉴权,可快速进行业务迁移
  • 扩展能力
    • 静态网站:快速部署网站,支持自定义域名、网站防刷等配置
    • 内容管理(CMS):一键部署,可视化管理文本、Markdown、图片等多种内容,使用云数据库读取数据并使用数据
  • 打通微信生态
    • 云调用:云函数内免鉴权调用小程序开放接口,包括服务端调用、获取开发数据等能力
    • 微信支付:免鉴权、免签名计算、免access_token,在云函数内原生调用微信支付接口
    • 环境共享:跨账号资源和能力复用,可授权云开发资源给其他小程序/公众号使用

云开发和传统服务器对比

——云开发传统服务器
开发语言node.jsjava,python,php
难易程度简单复杂
开发周期1-5 周1-5 月
部署难易基本上不用部署部署费事费力
是否需要域名不需要需要
是否需要备案不需要需要
是否支持 https不需要需要
适合公司中小型公司大公司
学习难易容易上手学习起来比较久
费用免费版基本够用200-2000/年

云开发环境的创建与初始化

  • 必须注册小程序后才可以开通云开发(要有AppId)

    在这里插入图片描述

  • 一个小程序可以创建两个云开发环境

  • 和创建普通小程序一样, 需要注意的就是这里必须要填写自己的appid,不可以用测试号

  • 如果你不使用自己的appid创建项目,就会出现一些报错现象

    在这里插入图片描述

  • 所以一定要先去注册一个小程序,然后用自己的appid

开通云开发

  • 点击下图箭头所示,如果你第一步创建项目时,没有使用自己的appid这里不会有下图箭头所示的云朵

    在这里插入图片描述

  • 给云开发环境取名

    在这里插入图片描述

  • 等待创建

  • 创建成功

  • 获取云开发环境id

    在这里插入图片描述

初始化云开发环境(重要)

  • app.js里写入环境id,注意这里要用你自己的云开发环境id

  • 初始化云开发环境前,先去云开发控制台,拿到云开发环境id,如下图

    在这里插入图片描述

  • 这里的环境id建议直接复制,不要手写,很容易写错。

  • 拿到环境id以后,就去app.js里做云开发环境初始化,如下

    • app.js

      // app.js
      App({
        onLaunch() {
          // 初始化云开发环境
          wx.cloud.init({
            env: 'cloud1-5g4o3xfv164a262d' // 云开发环境ID
          })
        },
      })
      

云开发~云数据库

  • 在数据库里新建集合(数据表)

    • 我们这里以新建一个水果列表为例

      在这里插入图片描述

    • 然后点击添加记录

      在这里插入图片描述

    • 最后添加展现的结果视图

      在这里插入图片描述

  • 数据库权限管理

    • 要想让用户查询到我们创建的水果数据,需要把权限改为所有用户可读,仅创建者可读写。(相当于:张三创建的只有张三可以修改,李四创建的只有李四可以修改,但是张三可以查询李四创建的,李四也可以查询张三创建的)

      在这里插入图片描述

数据库的增删改查

  • 查询get()

  • 传统写法

    • 目录结构

      在这里插入图片描述

    • app.js中初始化云开发环境

      // app.js
      App({
        onLaunch() {
          // 初始化云开发环境
          wx.cloud.init({
            env: 'cloud1-5g4o3xfv164a262d' // 云开发环境ID
          })
        },
      })
      
    • 在页面index里面的index.js

      // 获取数据库连接
      const db = wx.cloud.database().collection('fruits')
      
      Page({
      
        /**
         * 页面的初始数据
         */
        data: {
          fruits:[]
        },
      
        /**
         * 生命周期函数--监听页面加载
         */
        onLoad(options) {
          this.queryFruits()
        },
        // 查询商品列表
        queryFruits() {
          // 查询所有商品(传统写法)
          db.get({
            success:(res)=>{
              // console.log(res.data);
              this.setData({fruits:res.data})
            }
          })
        }
      })
      
    • 这个时候可以在控制台的AppData中可以看到(这里我在数据库里面添加了两条记录,苹果和香蕉)

      在这里插入图片描述

    • 这个时候就可以渲染页面了

    • 在页面index里面的index.wxml

      <view>
        <view class="fruits-item">
          <text>商品名称</text>
          <text>商品价格</text>
          <text>商品数量</text>
          <text>小计</text>
          <text>操作</text>
        </view>
        <view class="fruits-item" wx:for="{{fruits}}" wx:key="index">
          <text>{{item.name}}</text>
          <text>{{item.price}}</text>
          <text>{{item.num}}</text>
          <text>{{item.num*item.price}}</text>
          <text>删除</text>
        </view>
      </view>
      
    • 在页面index里面的index.wxss

      .fruits-item {
        display: flex;
        height: 100rpx;
        align-items: center;
        text-align: center;
        border-bottom: 1px dotted;
      }
      .fruits-item text {
        flex: 1;
      }
      
    • 页面渲染结果

      在这里插入图片描述

  • ES6简洁写法

    • 在页面index里面的index.js中。(其余不变,和上面的一样)

      // 获取数据库连接
      const db = wx.cloud.database().collection('fruits')
      
      Page({
      
        /**
         * 页面的初始数据
         */
        data: {
          fruits: []
        },
      
        /**
         * 生命周期函数--监听页面加载
         */
        onLoad(options) {
          this.queryFruits()
        },
        // 查询商品列表
        queryFruits() {
          // 查询所有商品(Promise写法)
          db.get().then(res => this.setData({
            fruits: res.data
          }))
        }
      })
      
      // 获取数据库连接
      const db = wx.cloud.database().collection('fruits')
      
      Page({
      
        /**
         * 页面的初始数据
         */
        data: {
          fruits: []
        },
      
        /**
         * 生命周期函数--监听页面加载
         */
        onLoad(options) {
          this.queryFruits()
        },
        // 查询商品列表
        async queryFruits() {
          // 查询所有商品(async/await写法)
          const {
            data
          } = await db.get()
          this.setData({
            fruits: data
          })
        }
      })
      

数据库的增删改查

  • 条件查询where()

    • 在页面index里面的index.wxml

      <view>
        <view class="search">
          <input type="text" model:value="{{name}}" placeholder="输入商品名称" />
          <text bindtap="seach">搜索</text>
        </view>
        <view class="fruits-item">
          <text>商品名称</text>
          <text>商品价格</text>
          <text>商品数量</text>
          <text>小计</text>
          <text>操作</text>
        </view>
        <view class="fruits-item" wx:for="{{fruits}}" wx:key="index">
          <text>{{item.name}}</text>
          <text>{{item.price}}</text>
          <text>{{item.num}}</text>
          <text>{{item.num*item.price}}</text>
          <text>删除</text>
        </view>
      </view>
      
    • 在页面index里面的index.wxss

      .fruits-item {
        display: flex;
        height: 100rpx;
        align-items: center;
        text-align: center;
        border-bottom: 1px dotted;
      }
      .fruits-item text {
        flex: 1;
      }
      .search {
        display: flex;
        justify-content: center;
        height: 160rpx;
        align-items: center;
      }
      .search input {
        border: 1px solid;
        width: 400rpx;
        margin-right: 40rpx;
        padding-left: 24rpx;
      }
      
    • 在页面index里面的index.js

      // 获取数据库连接
      const db = wx.cloud.database().collection('fruits')
      
      Page({
      
        /**
         * 页面的初始数据
         */
        data: {
          name:'',
          fruits: []
        },
      
        /**
         * 生命周期函数--监听页面加载
         */
        onLoad(options) {
          this.queryFruits()
        },
        // 查询商品列表
        async queryFruits() {
          // 查询所有商品(传统写法)
          // db.get({
          //   success:(res)=>{
          //     // console.log(res.data);
          //     this.setData({fruits:res.data})
          //   }
          // })
          // 查询所有商品(Promise写法)
          // db.get().then(res => this.setData({
          //   fruits: res.data
          // }))
          // 查询所有商品(async/await写法)
          const {
            data
          } = await db.get()
          this.setData({
            fruits: data
          })
        },
        // 根据name查询商品
        async seach() {
          // where 条件查询
          const {data} = await db.where({
            name:this.data.name.trim()
          }).get()
          // console.log(data);
          this.setData({fruits:data})
        }
      })
      
    • 页面展示结果

      在这里插入图片描述

数据库的增删改查

  • 查询单条数据doc()

  • doc是用来查询单条数据的。比如商品详情页。

  • doc里面用到的参数就是我们数据里的_id字段

    • 这里新建了一个商品详情fruitDetail

    • 目录结构展示

      在这里插入图片描述

    • app.js中添加fruitDetail页面

      {
        "pages": [
          "pages/index/index",
          "pages/fruitDetail/index"
        ],
        "window": {
          "backgroundTextStyle": "light",
          "navigationBarBackgroundColor": "#fff",
          "navigationBarTitleText": "Weixin",
          "navigationBarTextStyle": "black"
        },
        "style": "v2",
        "sitemapLocation": "sitemap.json"
      }
      
    • index页面中的index.wxml

      <view>
        <view class="search">
          <input type="text" model:value="{{name}}" placeholder="输入商品名称" />
          <text bindtap="seach">搜索</text>
        </view>
        <view class="fruits-item">
          <text>商品名称</text>
          <text>商品价格</text>
          <text>商品数量</text>
          <text>小计</text>
          <text>操作</text>
        </view>
        <view class="fruits-item" data-_id="{{item._id}}" bindtap="queryOne" wx:for="{{fruits}}" wx:key="index">
          <text>{{item.name}}</text>
          <text>{{item.price}}</text>
          <text>{{item.num}}</text>
          <text>{{item.num*item.price}}</text>
          <text>删除</text>
        </view>
      </view>
      
    • index页面中的index.js

      // 获取数据库连接
      const db = wx.cloud.database().collection('fruits')
      
      Page({
      
        /**
         * 页面的初始数据
         */
        data: {
          name: '',
          fruits: []
        },
      
        /**
         * 生命周期函数--监听页面加载
         */
        onLoad(options) {
          this.queryFruits()
        },
        // 查询商品列表
        async queryFruits() {
          // 查询所有商品(传统写法)
          // db.get({
          //   success:(res)=>{
          //     // console.log(res.data);
          //     this.setData({fruits:res.data})
          //   }
          // })
          // 查询所有商品(Promise写法)
          // db.get().then(res => this.setData({
          //   fruits: res.data
          // }))
          // 查询所有商品(async/await写法)
          const {
            data
          } = await db.get()
          this.setData({
            fruits: data
          })
        },
        // 根据name查询商品
        async seach() {
          // where 条件查询
          const {
            data
          } = await db.where({
            name: this.data.name.trim()
          }).get()
          // console.log(data);
          this.setData({
            fruits: data
          })
        },
        // 根据_id查询
        async queryOne(e) {
          // console.log(e);
          const {_id} = e.currentTarget.dataset
          const {data} = await db.doc(_id).get()
          // console.log(JSON.stringify(data));
          const fruit = JSON.stringify(data)
          wx.navigateTo({
            url: `/pages/fruitDetail/index?fruit=${fruit}`,
          })
        }
      }) 
      
    • index页面中的index.wxss

      .fruits-item {
        display: flex;
        height: 100rpx;
        align-items: center;
        text-align: center;
        border-bottom: 1px dotted;
      }
      .fruits-item text {
        flex: 1;
      }
      .search {
        display: flex;
        justify-content: center;
        height: 160rpx;
        align-items: center;
      }
      .search input {
        border: 1px solid;
        width: 400rpx;
        margin-right: 40rpx;
        padding-left: 24rpx;
      }
      
    • fruitDetail页面的index.js

      // pages/fruitDetail/index.js
      Page({
      
        /**
         * 页面的初始数据
         */
        data: {
          fruit:{}
        },
      
        /**
         * 生命周期函数--监听页面加载
         */
        onLoad(options) {
          // console.log(options.fruit);
        	const fruit = JSON.parse(options.fruit)
        	this.setData({fruit})
        },
      
      })
      
    • fruitDetail页面的index.wxml

      <label for="">
        名称:<input type="text" value="{{fruit.name}}" />
      </label>
      <label for="">
        价格:<input type="text" value="{{fruit.price}}" />
      </label>
      <label for="">
        数量:<input type="text" value="{{fruit.num}}" />
      </label>
      
    • fruitDetail页面的index.wxss

      label {
        display: flex;
        justify-content: center;
      }
      input {
        border-bottom: 1px solid;
        padding-left: 24rpx;
        font-size: 24rpx;
      }
      
    • 页面渲染结果

      在这里插入图片描述

      在这里插入图片描述

数据库的增删改查

  • 添加数据add()

  • 效果展示图

    在这里插入图片描述

  • 目录结构展示

    在这里插入图片描述

  • 在页面index里面的index.js

    // 获取数据库连接
    const db = wx.cloud.database().collection('fruits')
    
    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
        isShow:false,
        name: '',
        fruits: []
      },
    
      /**
       * 生命周期函数--监听页面加载
       */
      onLoad(options) {
        this.queryFruits()
      },
      // 查询商品列表
      async queryFruits() {
        // 查询所有商品(传统写法)
        // db.get({
        //   success:(res)=>{
        //     // console.log(res.data);
        //     this.setData({fruits:res.data})
        //   }
        // })
        // 查询所有商品(Promise写法)
        // db.get().then(res => this.setData({
        //   fruits: res.data
        // }))
        // 查询所有商品(async/await写法)
        const {
          data
        } = await db.get()
        this.setData({
          fruits: data
        })
      },
      // 根据name查询商品
      async seach() {
        // where 条件查询
        const {
          data
        } = await db.where({
          name: this.data.name.trim()
        }).get()
        // console.log(data);
        this.setData({
          fruits: data
        })
      },
      // 根据_id查询
      async queryOne(e) {
        // console.log(e);
        const {_id} = e.currentTarget.dataset
        const {data} = await db.doc(_id).get()
        // console.log(JSON.stringify(data));
        const fruit = JSON.stringify(data)
        wx.navigateTo({
          url: `/pages/fruitDetail/index?fruit=${fruit}`,
        })
      },
      // 添加数据 展示模态框
      showModal() {
        const {isShow} = this.data
        this.setData({isShow:!isShow})
      },
      // 添加
      async add(e) {
        // console.log(e.detail);
        const {_id} = await db.add({
          data:e.detail
        })
        if(_id) wx.showToast({
          title: '添加成功',
        })
        this.close()
        this.queryFruits()
      },
      close() {
        this.setData({isShow:false})
      }
    }) 
    
  • 在页面index里面的index.wxml

    <view>
      <view class="search">
        <input type="text" model:value="{{name}}" placeholder="输入商品名称" />
        <text bindtap="seach">搜索</text>
        <text bindtap="showModal" class="btn">添加</text>
      </view>
      <view class="fruits-item">
        <text>商品名称</text>
        <text>商品价格</text>
        <text>商品数量</text>
        <text>小计</text>
        <text>操作</text>
      </view>
      <view class="fruits-item" data-_id="{{item._id}}" bindtap="queryOne" wx:for="{{fruits}}" wx:key="index">
        <text>{{item.name}}</text>
        <text>{{item.price}}</text>
        <text>{{item.num}}</text>
        <text>{{item.num*item.price}}</text>
        <text>删除</text>
      </view>
    </view>
    
    <i-modal title="添加商品" show="{{isShow}}" bindadd="add" bindclose="close" ></i-modal>
    
  • 在页面index里面的index.wxss

    .fruits-item {
      display: flex;
      height: 100rpx;
      align-items: center;
      text-align: center;
      border-bottom: 1px dotted;
    }
    .fruits-item text {
      flex: 1;
    }
    .search {
      display: flex;
      justify-content: center;
      height: 160rpx;
      align-items: center;
    }
    .search input {
      border: 1px solid;
      width: 400rpx;
      margin-right: 40rpx;
      padding-left: 24rpx;
    }
    .btn {
      margin-left: 30rpx;
    }
    
  • 在页面fruitDetail里面的index.js

    // pages/fruitDetail/index.js
    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
        fruit:{}
      },
    
      /**
       * 生命周期函数--监听页面加载
       */
      onLoad(options) {
        // console.log(options.fruit);
      const fruit = JSON.parse(options.fruit)
      this.setData({fruit})
      },
    })
    
  • 在页面fruitDetail里面的index.wxml

    <label for="">
      名称:<input type="text" value="{{fruit.name}}" />
    </label>
    <label for="">
      价格:<input type="text" value="{{fruit.price}}" />
    </label>
    <label for="">
      数量:<input type="text" value="{{fruit.num}}" />
    </label>
    
  • 在页面fruitDetail里面的index.wxss

    label {
      display: flex;
      justify-content: center;
    }
    input {
      border-bottom: 1px solid;
      padding-left: 24rpx;
      font-size: 24rpx;
    }
    
  • 在自定义组件i-modal里面的index.js

    Component({
      /**
       * 组件的属性列表
       */
      properties: {
        title:String,
        show:Boolean
      },
    
      /**
       * 组件的初始数据
       */
      data: {
      },
    
      /**
       * 组件的方法列表
       */
      methods: {
        add() {
          const {name,price,num} = this.data
          price = Number.parseInt(price)
          num = Number.parseInt(num)
          // 子组件给父组件传值
          this.triggerEvent('add',{name,price,num})
        },
        close() {
          this.triggerEvent('close')
        }
      }
    })
    
  • 在自定义组件i-modal里面的index.wxml

    <view class="i-model" wx:if="{{show}}">
      <view class="tltle">{{title}}</view>
      <view class="i-model-item"> 
        商品名称:<input class="input" type="text" model:value="{{name}}" />
      </view>
      <view class="i-model-item">
        商品价格:<input class="input" type="text" model:value="{{price}}" />
      </view>
      <view class="i-model-item">
        商品数量:<input class="input" type="text" model:value="{{num}}" />
      </view>
      <view class="btn-group">
        <text class="btn" bindtap="add">添加</text>
        <text class="btn" bindtap="close">取消</text>
      </view>
    </view>
    
  • 在自定义组件i-modal里面的index.wxss

    page {
      height: 100vh;
      position: relative;
    }
    .i-model {
      width: 550rpx;
      min-height: 400rpx;
      background: rgba(0, 0, 0, 0.3);
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%,-50%);
      border-radius: 20rpx;
    }
    .tltle {
      text-align: center;
      line-height: 60rpx;
      color: white;
    }
    .i-model-item {
      display: flex;
      height: 100rpx;
      align-items: center;
      color: white;
      justify-content: center;
    }
    .i-model-item .input {
      border-bottom: 1px solid white;
      padding-left: 26rpx;
      font-size: 26rpx;
    }
    .btn {
      font-size: 28rpx;
      display: block;
      height: 60rpx;
      background: #fe551d;
      width: 200rpx;
      line-height: 60rpx;
      text-align: center;
      border-radius: 20rpx;
      margin: 0 auto 30rpx auto;
      color: white;
      cursor: pointer;
    }
    .btn-group {
      display: flex;
      justify-content: space-evenly;
    }
    .btn:last-child {
      background: #ddd;
    }
    

数据库的增删改查

  • 更新数据update()

  • 修改数据库里已存在的数据,结合doc进行修改单条数据

    • 上面是代码不变,我们修改单条数据先点击跳转到详情页在修改

    • 页面效果展示

      在这里插入图片描述

      在这里插入图片描述

    • 以上的代码不变。这里只修改一下fruitDetail页面内容

    • 在页码fruitDetail里面的index.wxml

      <label for="">
        名称:<input type="text" value="{{fruit.name}}" bindinput="updateValue" data-key="name" />
      </label>
      <label for="">
        价格:<input type="text" value="{{fruit.price}}" bindinput="updateValue" data-key="price" />
      </label>
      <label for="">
        数量:<input type="text" value="{{fruit.num}}" bindinput="updateValue" data-key="num" />
      </label>
      <button bindtap="edit">修改</button>
      
    • 在页码fruitDetail里面的index.js

      // pages/fruitDetail/index.js
      Page({
      
        /**
         * 页面的初始数据
         */
        data: {
          fruit: {}
        },
      
        /**
         * 生命周期函数--监听页面加载
         */
        onLoad(options) {
          // console.log(options.fruit);
          const fruit = JSON.parse(options.fruit)
          this.setData({
            fruit
          })
        },
        // 更新input中的值 input中的value === data
        updateValue(e) {
          const {key} = e.currentTarget.dataset
          // console.log(key);
          const {value} = e.detail
          const {fruit} = this.data
          fruit[key] = value
          this.setData({fruit})
        },
        // 修改
        async edit() {
          const {fruit} = this.data
          const {_id,_openid,...data} = fruit
          // 获取数据库连接
          const db = wx.cloud.database().collection('fruits')
          const {stats} = await db.doc(_id).update({data})
          // 不可以修改苹果和香蕉
          if(stats.updated === 0) {
            wx.showToast({
              title: '修改失败',
              icon:'error'
            })
          }else{
            wx.redirectTo({
              url: '/pages/index/index',
            })
          }
        }
      })
      

数据库的增删改查

  • 删除数据remove()

  • 删除数据,结合doc删除单条数据

    • 页面效果展示

      在这里插入图片描述

    • 其余代码不变和上面一样。

    • 在页面index里面的index.wxml

      <view>
        <view class="search">
          <input type="text" model:value="{{name}}" placeholder="输入商品名称" />
          <text bindtap="seach">搜索</text>
          <text bindtap="showModal" class="btn">添加</text>
        </view>
        <view class="fruits-item">
          <text>商品名称</text>
          <text>商品价格</text>
          <text>商品数量</text>
          <text>小计</text>
          <text>操作</text>
        </view>
        <view class="fruits-item" data-_id="{{item._id}}" bindtap="queryOne" wx:for="{{fruits}}" wx:key="index">
          <text>{{item.name}}</text>
          <text>{{item.price}}</text>
          <text>{{item.num}}</text>
          <text>{{item.num*item.price}}</text>
          <!-- 这里不使用 bindtap 因为使用会造成冒泡事件 -->
          <!-- 所以使用 catchtap 防止产生冒泡 -->
          <text catchtap="del" data-_id="{{item._id}}">删除</text>
        </view>
      </view>
      
      <i-modal title="添加商品" show="{{isShow}}" bindadd="add" bindclose="close" ></i-modal>
      
    • 在页面index里面的index.js

      // 获取数据库连接
      const db = wx.cloud.database().collection('fruits')
      
      Page({
      
        /**
         * 页面的初始数据
         */
        data: {
          isShow:false,
          name: '',
          fruits: []
        },
      
        /**
         * 生命周期函数--监听页面加载
         */
        onLoad(options) {
          this.queryFruits()
        },
        // 查询商品列表
        async queryFruits() {
          // 查询所有商品(传统写法)
          // db.get({
          //   success:(res)=>{
          //     // console.log(res.data);
          //     this.setData({fruits:res.data})
          //   }
          // })
          // 查询所有商品(Promise写法)
          // db.get().then(res => this.setData({
          //   fruits: res.data
          // }))
          // 查询所有商品(async/await写法)
          const {
            data
          } = await db.get()
          this.setData({
            fruits: data
          })
        },
        // 根据name查询商品
        async seach() {
          // where 条件查询
          const {
            data
          } = await db.where({
            name: this.data.name.trim()
          }).get()
          // console.log(data);
          this.setData({
            fruits: data
          })
        },
        // 根据_id查询
        async queryOne(e) {
          // console.log(e);
          const {_id} = e.currentTarget.dataset
          const {data} = await db.doc(_id).get()
          // console.log(JSON.stringify(data));
          const fruit = JSON.stringify(data)
          wx.navigateTo({
            url: `/pages/fruitDetail/index?fruit=${fruit}`,
          })
        },
        // 添加数据 展示模态框
        showModal() {
          const {isShow} = this.data
          this.setData({isShow:!isShow})
        },
        // 添加
        async add(e) {
          // console.log(e.detail);
          const {_id} = await db.add({
            data:e.detail
          })
          if(_id) wx.showToast({
            title: '添加成功',
          })
          this.close()
          this.queryFruits()
        },
        close() {
          this.setData({isShow:false})
        },
        // 删除
        async del(e) {
          const {_id} = e.currentTarget.dataset
          try {
            const {stats}  = await db.doc(_id).remove()
            wx.showToast({
              title: stats.removed ===0?'删除失败':'删除成功',
              icon:stats.removed ===0?'error':'success'
            })
            this.queryFruits()
          } catch (error) {
            wx.showToast({
              title: '没有权限',
              icon:'error'
            })
          }
        }
      }) 
      

数据库的增删改查

  • 增删改查综合案例
    • 能查看商品列表
    • 更动态添加商品
    • 能进入商品详情页
    • 能删除某个商品
    • 能修改某个商品的价格
  • 注意:更新和删除时的权限问题
    • 如果这条商品不是你创建的,当你对这条商品做删除或者更新操作时,虽然也会返回成功,但是可以看到我们更新或者删除的条数是0
    • 其实这个时候也意味着没有更新或者删除成功,这里是因为操作权限的问题,因为这条数据不是你创建的。所以你只能对这条数据做查询操作,而不能做修改和删除操作。要想解决这个问题,就要借助云函数了。

数据库的增删改查

  • 数据库排序orderBy

  • orderBy方法在做排序的时候,接受两个参数

    • 根据那个字段排序
    • 排序规则(升序或者降序)。升序用asc,降序用desc
  • 目录结构新增了一个降序和升序的图标,工具文件夹添加了处理时间的dayjs库,其余不变

    在这里插入图片描述

  • 在页面index里面的index.wxml

    <view>
      <view class="search">
        <input type="text" model:value="{{name}}" placeholder="输入商品名称" />
        <text bindtap="seach">搜索</text>
        <text bindtap="showModal" class="btn">添加</text>
      </view>
      <view class="fruits-item">
        <view style="display: flex;align-items: center;">
          商品名称
          <image src="{{by==='asc'?'/images/down.png':'/images/up.png'}}" class="icon" bindtap="orderBy"></image>
        </view>
        <text>时间</text>
        <text>商品价格</text>
        <text>商品数量</text>
        <text>小计</text>
        <text>操作</text>
      </view>
      <view class="fruits-item" data-_id="{{item._id}}" bindtap="queryOne" wx:for="{{fruits}}" wx:key="index">
        <text>{{item.name}}</text>
        <text>{{item.time}}</text>
        <text>{{item.price}}</text>
        <text>{{item.num}}</text>
        <text>{{item.num*item.price}}</text>
        <!-- 这里不使用 bindtap 因为使用会造成冒泡事件 -->
        <!-- 所以使用 catchtap 防止产生冒泡 -->
        <text catchtap="del" data-_id="{{item._id}}">删除</text>
      </view>
    </view>
    
    <i-modal title="添加商品" show="{{isShow}}" bindadd="add" bindclose="close" ></i-modal>
    
  • 在页面index里面的index.js中(这里我是根据价格排序的)

    // 处理时间的库
    // 网址:https://dayjs.fenxianglu.cn/
    import dayjs from '../../utils/dayjs.min'
    
    // 获取数据库连接
    const db = wx.cloud.database().collection('fruits')
    
    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
        isShow:false,
        name: '',
        fruits: [],
        by:'asc'
      },
      /**
       * 生命周期函数--监听页面加载
       */
      onLoad(options) {
        this.queryFruits()
      },
      // 查询商品列表
      async queryFruits() {
        // 查询所有商品(传统写法)
        // db.get({
        //   success:(res)=>{
        //     // console.log(res.data);
        //     this.setData({fruits:res.data})
        //   }
        // })
        // 查询所有商品(Promise写法)
        // db.get().then(res => this.setData({
        //   fruits: res.data
        // }))
        // 查询所有商品(async/await写法)
        const {
          data
        } = await db.get()
        data.map(item=>{
          item.time = dayjs(item.time).format('HH:mm:ss')
          return item
        })
        this.setData({
          fruits: data
        })
      },
      // 根据name查询商品
      async seach() {
        // where 条件查询
        const {
          data
        } = await db.where({
          name: this.data.name.trim()
        }).get()
        // console.log(data);
        this.setData({
          fruits: data
        })
      },
      // 根据_id查询
      async queryOne(e) {
        // console.log(e);
        const {_id} = e.currentTarget.dataset
        const {data} = await db.doc(_id).get()
        // console.log(JSON.stringify(data));
        const fruit = JSON.stringify(data)
        wx.navigateTo({
          url: `/pages/fruitDetail/index?fruit=${fruit}`,
        })
      },
      // 添加数据 展示模态框
      showModal() {
        const {isShow} = this.data
        this.setData({isShow:!isShow})
      },
      // 添加
      async add(e) {
        const data = {...e.detail,time:new Date()}
        // console.log(e.detail);
        const {_id} = await db.add({
          data
        })
        if(_id) wx.showToast({
          title: '添加成功',
        })
        this.close()
        this.queryFruits()
      },
      close() {
        this.setData({isShow:false})
      },
      // 删除
      async del(e) {
        const {_id} = e.currentTarget.dataset
        try {
          const {stats}  = await db.doc(_id).remove()
          wx.showToast({
            title: stats.removed ===0?'删除失败':'删除成功',
            icon:stats.removed ===0?'error':'success'
          })
          this.queryFruits()
        } catch (error) {
          wx.showToast({
            title: '没有权限',
            icon:'error'
          })
        }
      },
      // 排序
      async orderBy() {
        let {by} = this.data
        // asc 升序 desc 降序
        by = by==='asc'?'desc':'asc'
        const {data} = await db.orderBy('price',by).get()
        data.map(item=>{
          item.time = dayjs(item.time).format('HH:mm:ss')
          return item
        })
        this.setData({fruits:data,by})
      }
    }) 
    
  • 页面效果展示

    在这里插入图片描述

数据库的增删改查

  • 返回指定条数的数据limit
  • limit用来指定查询结果集数量上限,比如我们有100条数据,只想返回前20条,我们可以通过limit(20)来指定只返回20条数据。
  • 注意:limit在小程序端默认及最大上限为20,在云函数端默认及最大上限为100
  • 上面代码不变,具体代码看下面分页

数据库的增删改查

  • 分页方法skip

  • skip指定查询返回结果时从指定序列后的结果开始返回,常用于分页。比如我们有100条数据,想从第10条开始返回数据,可以通过skip(10)来实现

  • 比如我们有100条数据,每次返回20条数据。那么就可以分5页返回。

    • 第1页limit(20).skip(0)
    • 第2页limit(20).skip(20)
    • 第3页limit(20).skip(40)
    • 第4页limit(20).skip(60)
    • 第5页limit(20).skip(80)
  • 上面代码不变

  • 在页面index里面的index.wxml

    <view>
      <view class="search">
        <input type="text" model:value="{{name}}" placeholder="输入商品名称" />
        <text bindtap="seach">搜索</text>
        <text bindtap="showModal" class="btn">添加</text>
      </view>
      <view class="fruits-item">
        <view style="display: flex;align-items: center;">
          商品名称
          <image src="{{by==='asc'?'/images/down.png':'/images/up.png'}}" class="icon" bindtap="orderBy"></image>
        </view>
        <text>时间</text>
        <text>商品价格</text>
        <text>商品数量</text>
        <text>小计</text>
        <text>操作</text>
      </view>
      <view class="fruits-item" data-_id="{{item._id}}" bindtap="queryOne" wx:for="{{fruits}}" wx:key="index">
        <text>{{item.name}}</text>
        <text>{{item.time}}</text>
        <text>{{item.price}}</text>
        <text>{{item.num}}</text>
        <text>{{item.num*item.price}}</text>
        <!-- 这里不使用 bindtap 因为使用会造成冒泡事件 -->
        <!-- 所以使用 catchtap 防止产生冒泡 -->
        <text catchtap="del" data-_id="{{item._id}}">删除</text>
      </view>
    </view>
    
    查询指定条数的数据
    <input type="text" placeholder="输入数字回车查询指定条数" model:value="{{num}}" />
    <button bindtap="limit">查询</button>
    <view style="text-align: center; padding: 20rpx 0;">
      <button bindtap="queryPage" data-page="1" size="mini">1</button>
      <button bindtap="queryPage" data-page="2" size="mini">2</button>
      <button bindtap="queryPage" data-page="3" size="mini">3</button>
      <button bindtap="queryPage" data-page="4" size="mini">4</button>
      <button bindtap="queryPage" data-page="5" size="mini">5</button>
    </view>
    
    <i-modal title="添加商品" show="{{isShow}}" bindadd="add" bindclose="close"></i-modal>
    
  • 在页面index里面的index.js

    // 处理时间的库
    import dayjs from '../../utils/dayjs.min'
    
    // 获取数据库连接
    const db = wx.cloud.database().collection('fruits')
    
    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
        isShow:false,
        name: '',
        fruits: [],
        by:'asc',
        num:''
      },
      /**
       * 生命周期函数--监听页面加载
       */
      onLoad(options) {
        this.queryFruits()
      },
      // 查询商品列表
      async queryFruits() {
        // 查询所有商品(传统写法)
        // db.get({
        //   success:(res)=>{
        //     // console.log(res.data);
        //     this.setData({fruits:res.data})
        //   }
        // })
        // 查询所有商品(Promise写法)
        // db.get().then(res => this.setData({
        //   fruits: res.data
        // }))
        // 查询所有商品(async/await写法)
        const {
          data
        } = await db.get()
        data.map(item=>{
          item.time = dayjs(item.time).format('HH:mm:ss')
          return item
        })
        this.setData({
          fruits: data
        })
      },
      // 根据name查询商品
      async seach() {
        // where 条件查询
        const {
          data
        } = await db.where({
          name: this.data.name.trim()
        }).get()
        // console.log(data);
        this.setData({
          fruits: data
        })
      },
      // 根据_id查询
      async queryOne(e) {
        // console.log(e);
        const {_id} = e.currentTarget.dataset
        const {data} = await db.doc(_id).get()
        // console.log(JSON.stringify(data));
        const fruit = JSON.stringify(data)
        wx.navigateTo({
          url: `/pages/fruitDetail/index?fruit=${fruit}`,
        })
      },
      // 添加数据 展示模态框
      showModal() {
        const {isShow} = this.data
        this.setData({isShow:!isShow})
      },
      // 添加
      async add(e) {
        const data = {...e.detail,time:new Date()}
        // console.log(e.detail);
        const {_id} = await db.add({
          data
        })
        if(_id) wx.showToast({
          title: '添加成功',
        })
        this.close()
        this.queryFruits()
      },
      close() {
        this.setData({isShow:false})
      },
      // 删除
      async del(e) {
        const {_id} = e.currentTarget.dataset
        try {
          const {stats}  = await db.doc(_id).remove()
          wx.showToast({
            title: stats.removed ===0?'删除失败':'删除成功',
            icon:stats.removed ===0?'error':'success'
          })
          this.queryFruits()
        } catch (error) {
          wx.showToast({
            title: '没有权限',
            icon:'error'
          })
        }
      },
      // 排序
      async orderBy() {
        let {by} = this.data
        // asc 升序 desc 降序
        by = by==='asc'?'desc':'asc'
        const {data} = await db.orderBy('price',by).get()
        data.map(item=>{
          item.time = dayjs(item.time).format('HH:mm:ss')
          return item
        })
        this.setData({fruits:data,by})
      },
      // 查询指定的条数的记录
      async limit() {
        const {num} = this.data
        const {data} = await db.limit(Number.parseInt(num)).get()
        this.setData({fruits:data})
      },
      // 分页查询
      async queryPage(e) {
        const {num} = this.data
        // 页码数
        const {page} = e.currentTarget.dataset
        // 计算查询的起始位置
        const startNum = (page-1)*num
        // 这里的num是字符串,改为number类型
        const {data} = await db.limit(Number.parseInt(num)).skip(startNum).get()
        this.setData({fruits:data})
      }
    }) 
    
  • 页面展示效果

    在这里插入图片描述

Command数据库操作符

  • Command数据库操作符

  • 上面学完了数据库的增删改查,但是这些都是最基础最简单的操作,如果我们想实现复杂的数据查询操作,该怎么办呢

    • 比如查询价格大于100的商品?
    • 查询年龄小于18岁的学生?
    • 如何同时修改多条数据?
    • 如何同时删除多条数据?
  • 我们如果想实现上面这些复杂的操作,就需要用到数据库里的Command数据库操作符

  • 如下是我们的页面数据商品展示

    在这里插入图片描述

Command数据库操作符

  • gt查询大于指定值的数据

  • 上面数据库增删改查代码不变,只在页面index里面的index.js中添加gt查询

  • 在页面index里面的index.js

    // 处理时间的库
    import dayjs from '../../utils/dayjs.min'
    
    // 获取数据库
    const database = wx.cloud.database()
    // 获取数据库连接
    const db = database.collection('fruits')
    // 获取操作符
    const {gt} = database.command
    
    
    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
        isShow:false,
        name: '',
        fruits: [],
        by:'asc',
        num:''
      },
      /**
       * 生命周期函数--监听页面加载
       */
      onLoad(options) {
        this.queryFruits()
        this.commandQuery()
      },
      // 查询商品列表
      async queryFruits() {
        // 查询所有商品(传统写法)
        // db.get({
        //   success:(res)=>{
        //     // console.log(res.data);
        //     this.setData({fruits:res.data})
        //   }
        // })
        // 查询所有商品(Promise写法)
        // db.get().then(res => this.setData({
        //   fruits: res.data
        // }))
        // 查询所有商品(async/await写法)
        const {
          data
        } = await db.get()
        data.map(item=>{
          item.time = dayjs(item.time).format('HH:mm:ss')
          return item
        })
        this.setData({
          fruits: data
        })
      },
      // 根据name查询商品
      async seach() {
        // where 条件查询
        const {
          data
        } = await db.where({
          name: this.data.name.trim()
        }).get()
        // console.log(data);
        this.setData({
          fruits: data
        })
      },
      // 根据_id查询
      async queryOne(e) {
        // console.log(e);
        const {_id} = e.currentTarget.dataset
        const {data} = await db.doc(_id).get()
        // console.log(JSON.stringify(data));
        const fruit = JSON.stringify(data)
        wx.navigateTo({
          url: `/pages/fruitDetail/index?fruit=${fruit}`,
        })
      },
      // 添加数据 展示模态框
      showModal() {
        const {isShow} = this.data
        this.setData({isShow:!isShow})
      },
      // 添加
      async add(e) {
        const data = {...e.detail,time:new Date()}
        // console.log(e.detail);
        const {_id} = await db.add({
          data
        })
        if(_id) wx.showToast({
          title: '添加成功',
        })
        this.close()
        this.queryFruits()
      },
      close() {
        this.setData({isShow:false})
      },
      // 删除
      async del(e) {
        const {_id} = e.currentTarget.dataset
        try {
          const {stats}  = await db.doc(_id).remove()
          wx.showToast({
            title: stats.removed ===0?'删除失败':'删除成功',
            icon:stats.removed ===0?'error':'success'
          })
          this.queryFruits()
        } catch (error) {
          wx.showToast({
            title: '没有权限',
            icon:'error'
          })
        }
      },
      // 排序
      async orderBy() {
        let {by} = this.data
        // asc 升序 desc 降序
        by = by==='asc'?'desc':'asc'
        const {data} = await db.orderBy('price',by).get()
        data.map(item=>{
          item.time = dayjs(item.time).format('HH:mm:ss')
          return item
        })
        this.setData({fruits:data,by})
      },
      // 查询指定的条数的记录
      async limit() {
        const {num} = this.data
        const {data} = await db.limit(Number.parseInt(num)).get()
        this.setData({fruits:data})
      },
      // 分页查询
      async queryPage(e) {
        const {num} = this.data
        // 页码数
        const {page} = e.currentTarget.dataset
        // 计算查询的起始位置
        const startNum = (page-1)*num
        // 这里的num是字符串,改为number类型
        const {data} = await db.limit(Number.parseInt(num)).skip(startNum).get()
        this.setData({fruits:data})
      },
      // 操作符查询
      // 这里没有设置页面格式什么的 直接在页面加载时调用 然后通过控制台打印结果
      async commandQuery() {
        const {data} = await db.where({
          price:gt(5)
        }).get()
        console.log(data); // 苹果 火龙果 西瓜 圣女果
      }
    }) 
    

Command数据库操作符

  • gte查询大于等于指定值的数据

  • 上面数据库增删改查代码不变,只在页面index里面的index.js中添加gte查询

  • 在页面index里面的index.js

    // 处理时间的库
    import dayjs from '../../utils/dayjs.min'
    
    // 获取数据库
    const database = wx.cloud.database()
    // 获取数据库连接
    const db = database.collection('fruits')
    // 获取操作符
    const {gt,gte} = database.command
    
    
    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
        isShow:false,
        name: '',
        fruits: [],
        by:'asc',
        num:''
      },
      /**
       * 生命周期函数--监听页面加载
       */
      onLoad(options) {
        this.queryFruits()
        this.commandQuery()
      },
      // 查询商品列表
      async queryFruits() {
        // 查询所有商品(传统写法)
        // db.get({
        //   success:(res)=>{
        //     // console.log(res.data);
        //     this.setData({fruits:res.data})
        //   }
        // })
        // 查询所有商品(Promise写法)
        // db.get().then(res => this.setData({
        //   fruits: res.data
        // }))
        // 查询所有商品(async/await写法)
        const {
          data
        } = await db.get()
        data.map(item=>{
          item.time = dayjs(item.time).format('HH:mm:ss')
          return item
        })
        this.setData({
          fruits: data
        })
      },
      // 根据name查询商品
      async seach() {
        // where 条件查询
        const {
          data
        } = await db.where({
          name: this.data.name.trim()
        }).get()
        // console.log(data);
        this.setData({
          fruits: data
        })
      },
      // 根据_id查询
      async queryOne(e) {
        // console.log(e);
        const {_id} = e.currentTarget.dataset
        const {data} = await db.doc(_id).get()
        // console.log(JSON.stringify(data));
        const fruit = JSON.stringify(data)
        wx.navigateTo({
          url: `/pages/fruitDetail/index?fruit=${fruit}`,
        })
      },
      // 添加数据 展示模态框
      showModal() {
        const {isShow} = this.data
        this.setData({isShow:!isShow})
      },
      // 添加
      async add(e) {
        const data = {...e.detail,time:new Date()}
        // console.log(e.detail);
        const {_id} = await db.add({
          data
        })
        if(_id) wx.showToast({
          title: '添加成功',
        })
        this.close()
        this.queryFruits()
      },
      close() {
        this.setData({isShow:false})
      },
      // 删除
      async del(e) {
        const {_id} = e.currentTarget.dataset
        try {
          const {stats}  = await db.doc(_id).remove()
          wx.showToast({
            title: stats.removed ===0?'删除失败':'删除成功',
            icon:stats.removed ===0?'error':'success'
          })
          this.queryFruits()
        } catch (error) {
          wx.showToast({
            title: '没有权限',
            icon:'error'
          })
        }
      },
      // 排序
      async orderBy() {
        let {by} = this.data
        // asc 升序 desc 降序
        by = by==='asc'?'desc':'asc'
        const {data} = await db.orderBy('price',by).get()
        data.map(item=>{
          item.time = dayjs(item.time).format('HH:mm:ss')
          return item
        })
        this.setData({fruits:data,by})
      },
      // 查询指定的条数的记录
      async limit() {
        const {num} = this.data
        const {data} = await db.limit(Number.parseInt(num)).get()
        this.setData({fruits:data})
      },
      // 分页查询
      async queryPage(e) {
        const {num} = this.data
        // 页码数
        const {page} = e.currentTarget.dataset
        // 计算查询的起始位置
        const startNum = (page-1)*num
        // 这里的num是字符串,改为number类型
        const {data} = await db.limit(Number.parseInt(num)).skip(startNum).get()
        this.setData({fruits:data})
      },
      // 操作符查询
      // 这里没有设置页面格式什么的 直接在页面加载时调用 然后通过控制台打印结果
      async commandQuery() {
        const {data} = await db.where({
          price:gte(10)
        }).get()
        console.log(data); // 火龙果 西瓜 圣女果
      }
    }) 
    

Command数据库操作符

  • lt查询小于指定数值的数据

  • 上面数据库增删改查代码不变,只在页面index里面的index.js中添加lt查询

  • 在页面index里面的index.js

    // 处理时间的库
    import dayjs from '../../utils/dayjs.min'
    
    // 获取数据库
    const database = wx.cloud.database()
    // 获取数据库连接
    const db = database.collection('fruits')
    // 获取操作符
    const {gt,gte,lt} = database.command
    
    
    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
        isShow:false,
        name: '',
        fruits: [],
        by:'asc',
        num:''
      },
      /**
       * 生命周期函数--监听页面加载
       */
      onLoad(options) {
        this.queryFruits()
        this.commandQuery()
      },
      // 查询商品列表
      async queryFruits() {
        // 查询所有商品(传统写法)
        // db.get({
        //   success:(res)=>{
        //     // console.log(res.data);
        //     this.setData({fruits:res.data})
        //   }
        // })
        // 查询所有商品(Promise写法)
        // db.get().then(res => this.setData({
        //   fruits: res.data
        // }))
        // 查询所有商品(async/await写法)
        const {
          data
        } = await db.get()
        data.map(item=>{
          item.time = dayjs(item.time).format('HH:mm:ss')
          return item
        })
        this.setData({
          fruits: data
        })
      },
      // 根据name查询商品
      async seach() {
        // where 条件查询
        const {
          data
        } = await db.where({
          name: this.data.name.trim()
        }).get()
        // console.log(data);
        this.setData({
          fruits: data
        })
      },
      // 根据_id查询
      async queryOne(e) {
        // console.log(e);
        const {_id} = e.currentTarget.dataset
        const {data} = await db.doc(_id).get()
        // console.log(JSON.stringify(data));
        const fruit = JSON.stringify(data)
        wx.navigateTo({
          url: `/pages/fruitDetail/index?fruit=${fruit}`,
        })
      },
      // 添加数据 展示模态框
      showModal() {
        const {isShow} = this.data
        this.setData({isShow:!isShow})
      },
      // 添加
      async add(e) {
        const data = {...e.detail,time:new Date()}
        // console.log(e.detail);
        const {_id} = await db.add({
          data
        })
        if(_id) wx.showToast({
          title: '添加成功',
        })
        this.close()
        this.queryFruits()
      },
      close() {
        this.setData({isShow:false})
      },
      // 删除
      async del(e) {
        const {_id} = e.currentTarget.dataset
        try {
          const {stats}  = await db.doc(_id).remove()
          wx.showToast({
            title: stats.removed ===0?'删除失败':'删除成功',
            icon:stats.removed ===0?'error':'success'
          })
          this.queryFruits()
        } catch (error) {
          wx.showToast({
            title: '没有权限',
            icon:'error'
          })
        }
      },
      // 排序
      async orderBy() {
        let {by} = this.data
        // asc 升序 desc 降序
        by = by==='asc'?'desc':'asc'
        const {data} = await db.orderBy('price',by).get()
        data.map(item=>{
          item.time = dayjs(item.time).format('HH:mm:ss')
          return item
        })
        this.setData({fruits:data,by})
      },
      // 查询指定的条数的记录
      async limit() {
        const {num} = this.data
        const {data} = await db.limit(Number.parseInt(num)).get()
        this.setData({fruits:data})
      },
      // 分页查询
      async queryPage(e) {
        const {num} = this.data
        // 页码数
        const {page} = e.currentTarget.dataset
        // 计算查询的起始位置
        const startNum = (page-1)*num
        // 这里的num是字符串,改为number类型
        const {data} = await db.limit(Number.parseInt(num)).skip(startNum).get()
        this.setData({fruits:data})
      },
      // 操作符查询
      // 这里没有设置页面格式什么的 直接在页面加载时调用 然后通过控制台打印结果
      async commandQuery() {
        const {data} = await db.where({
          price:lt(10)
        }).get()
        console.log(data); // 苹果 香蕉
      }
    }) 
    

Command数据库操作符

  • lte查询小于等于指定数值的数据

  • 上面数据库增删改查代码不变,只在页面index里面的index.js中添加lte查询

  • 在页面index里面的index.js

    // 处理时间的库
    import dayjs from '../../utils/dayjs.min'
    
    // 获取数据库
    const database = wx.cloud.database()
    // 获取数据库连接
    const db = database.collection('fruits')
    // 获取操作符
    const {gt,gte,lt,lte} = database.command
    
    
    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
        isShow:false,
        name: '',
        fruits: [],
        by:'asc',
        num:''
      },
      /**
       * 生命周期函数--监听页面加载
       */
      onLoad(options) {
        this.queryFruits()
        this.commandQuery()
      },
      // 查询商品列表
      async queryFruits() {
        // 查询所有商品(传统写法)
        // db.get({
        //   success:(res)=>{
        //     // console.log(res.data);
        //     this.setData({fruits:res.data})
        //   }
        // })
        // 查询所有商品(Promise写法)
        // db.get().then(res => this.setData({
        //   fruits: res.data
        // }))
        // 查询所有商品(async/await写法)
        const {
          data
        } = await db.get()
        data.map(item=>{
          item.time = dayjs(item.time).format('HH:mm:ss')
          return item
        })
        this.setData({
          fruits: data
        })
      },
      // 根据name查询商品
      async seach() {
        // where 条件查询
        const {
          data
        } = await db.where({
          name: this.data.name.trim()
        }).get()
        // console.log(data);
        this.setData({
          fruits: data
        })
      },
      // 根据_id查询
      async queryOne(e) {
        // console.log(e);
        const {_id} = e.currentTarget.dataset
        const {data} = await db.doc(_id).get()
        // console.log(JSON.stringify(data));
        const fruit = JSON.stringify(data)
        wx.navigateTo({
          url: `/pages/fruitDetail/index?fruit=${fruit}`,
        })
      },
      // 添加数据 展示模态框
      showModal() {
        const {isShow} = this.data
        this.setData({isShow:!isShow})
      },
      // 添加
      async add(e) {
        const data = {...e.detail,time:new Date()}
        // console.log(e.detail);
        const {_id} = await db.add({
          data
        })
        if(_id) wx.showToast({
          title: '添加成功',
        })
        this.close()
        this.queryFruits()
      },
      close() {
        this.setData({isShow:false})
      },
      // 删除
      async del(e) {
        const {_id} = e.currentTarget.dataset
        try {
          const {stats}  = await db.doc(_id).remove()
          wx.showToast({
            title: stats.removed ===0?'删除失败':'删除成功',
            icon:stats.removed ===0?'error':'success'
          })
          this.queryFruits()
        } catch (error) {
          wx.showToast({
            title: '没有权限',
            icon:'error'
          })
        }
      },
      // 排序
      async orderBy() {
        let {by} = this.data
        // asc 升序 desc 降序
        by = by==='asc'?'desc':'asc'
        const {data} = await db.orderBy('price',by).get()
        data.map(item=>{
          item.time = dayjs(item.time).format('HH:mm:ss')
          return item
        })
        this.setData({fruits:data,by})
      },
      // 查询指定的条数的记录
      async limit() {
        const {num} = this.data
        const {data} = await db.limit(Number.parseInt(num)).get()
        this.setData({fruits:data})
      },
      // 分页查询
      async queryPage(e) {
        const {num} = this.data
        // 页码数
        const {page} = e.currentTarget.dataset
        // 计算查询的起始位置
        const startNum = (page-1)*num
        // 这里的num是字符串,改为number类型
        const {data} = await db.limit(Number.parseInt(num)).skip(startNum).get()
        this.setData({fruits:data})
      },
      // 操作符查询
      // 这里没有设置页面格式什么的 直接在页面加载时调用 然后通过控制台打印结果
      async commandQuery() {
        const {data} = await db.where({
          price:lte(10)
        }).get()
        console.log(data); // 苹果 香蕉 火龙果 圣女果
      }
    }) 
    

Command数据库操作符

  • and同时满足多个条件的查询

  • 上面数据库增删改查代码不变,只在页面index里面的index.js中添加add查询

  • 在页面index里面的index.js

    // 处理时间的库
    import dayjs from '../../utils/dayjs.min'
    
    // 获取数据库
    const database = wx.cloud.database()
    // 获取数据库连接
    const db = database.collection('fruits')
    // 获取操作符
    const {gt,gte,lt,lte,and,eq} = database.command
    
    
    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
        isShow:false,
        name: '',
        fruits: [],
        by:'asc',
        num:''
      },
      /**
       * 生命周期函数--监听页面加载
       */
      onLoad(options) {
        this.queryFruits()
        this.commandQuery()
      },
      // 查询商品列表
      async queryFruits() {
        // 查询所有商品(传统写法)
        // db.get({
        //   success:(res)=>{
        //     // console.log(res.data);
        //     this.setData({fruits:res.data})
        //   }
        // })
        // 查询所有商品(Promise写法)
        // db.get().then(res => this.setData({
        //   fruits: res.data
        // }))
        // 查询所有商品(async/await写法)
        const {
          data
        } = await db.get()
        data.map(item=>{
          item.time = dayjs(item.time).format('HH:mm:ss')
          return item
        })
        this.setData({
          fruits: data
        })
      },
      // 根据name查询商品
      async seach() {
        // where 条件查询
        const {
          data
        } = await db.where({
          name: this.data.name.trim()
        }).get()
        // console.log(data);
        this.setData({
          fruits: data
        })
      },
      // 根据_id查询
      async queryOne(e) {
        // console.log(e);
        const {_id} = e.currentTarget.dataset
        const {data} = await db.doc(_id).get()
        // console.log(JSON.stringify(data));
        const fruit = JSON.stringify(data)
        wx.navigateTo({
          url: `/pages/fruitDetail/index?fruit=${fruit}`,
        })
      },
      // 添加数据 展示模态框
      showModal() {
        const {isShow} = this.data
        this.setData({isShow:!isShow})
      },
      // 添加
      async add(e) {
        const data = {...e.detail,time:new Date()}
        // console.log(e.detail);
        const {_id} = await db.add({
          data
        })
        if(_id) wx.showToast({
          title: '添加成功',
        })
        this.close()
        this.queryFruits()
      },
      close() {
        this.setData({isShow:false})
      },
      // 删除
      async del(e) {
        const {_id} = e.currentTarget.dataset
        try {
          const {stats}  = await db.doc(_id).remove()
          wx.showToast({
            title: stats.removed ===0?'删除失败':'删除成功',
            icon:stats.removed ===0?'error':'success'
          })
          this.queryFruits()
        } catch (error) {
          wx.showToast({
            title: '没有权限',
            icon:'error'
          })
        }
      },
      // 排序
      async orderBy() {
        let {by} = this.data
        // asc 升序 desc 降序
        by = by==='asc'?'desc':'asc'
        const {data} = await db.orderBy('price',by).get()
        data.map(item=>{
          item.time = dayjs(item.time).format('HH:mm:ss')
          return item
        })
        this.setData({fruits:data,by})
      },
      // 查询指定的条数的记录
      async limit() {
        const {num} = this.data
        const {data} = await db.limit(Number.parseInt(num)).get()
        this.setData({fruits:data})
      },
      // 分页查询
      async queryPage(e) {
        const {num} = this.data
        // 页码数
        const {page} = e.currentTarget.dataset
        // 计算查询的起始位置
        const startNum = (page-1)*num
        // 这里的num是字符串,改为number类型
        const {data} = await db.limit(Number.parseInt(num)).skip(startNum).get()
        this.setData({fruits:data})
      },
      // 操作符查询
      // 这里没有设置页面格式什么的 直接在页面加载时调用 然后通过控制台打印结果
      async commandQuery() {
        const {data} = await db.where(and([
          {price:gte(5)},
          {num:eq(5)}
        ])).get()
        console.log(data); // 苹果
      }
    }) 
    

Command数据库操作符

  • or或者

  • 上面数据库增删改查代码不变,只在页面index里面的index.js中添加or查询

  • 在页面index里面的index.js

    // 处理时间的库
    import dayjs from '../../utils/dayjs.min'
    
    // 获取数据库
    const database = wx.cloud.database()
    // 获取数据库连接
    const db = database.collection('fruits')
    // 获取操作符
    const {gt,gte,lt,lte,and,eq,or} = database.command
    
    
    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
        isShow:false,
        name: '',
        fruits: [],
        by:'asc',
        num:''
      },
      /**
       * 生命周期函数--监听页面加载
       */
      onLoad(options) {
        this.queryFruits()
        this.commandQuery()
      },
      // 查询商品列表
      async queryFruits() {
        // 查询所有商品(传统写法)
        // db.get({
        //   success:(res)=>{
        //     // console.log(res.data);
        //     this.setData({fruits:res.data})
        //   }
        // })
        // 查询所有商品(Promise写法)
        // db.get().then(res => this.setData({
        //   fruits: res.data
        // }))
        // 查询所有商品(async/await写法)
        const {
          data
        } = await db.get()
        data.map(item=>{
          item.time = dayjs(item.time).format('HH:mm:ss')
          return item
        })
        this.setData({
          fruits: data
        })
      },
      // 根据name查询商品
      async seach() {
        // where 条件查询
        const {
          data
        } = await db.where({
          name: this.data.name.trim()
        }).get()
        // console.log(data);
        this.setData({
          fruits: data
        })
      },
      // 根据_id查询
      async queryOne(e) {
        // console.log(e);
        const {_id} = e.currentTarget.dataset
        const {data} = await db.doc(_id).get()
        // console.log(JSON.stringify(data));
        const fruit = JSON.stringify(data)
        wx.navigateTo({
          url: `/pages/fruitDetail/index?fruit=${fruit}`,
        })
      },
      // 添加数据 展示模态框
      showModal() {
        const {isShow} = this.data
        this.setData({isShow:!isShow})
      },
      // 添加
      async add(e) {
        const data = {...e.detail,time:new Date()}
        // console.log(e.detail);
        const {_id} = await db.add({
          data
        })
        if(_id) wx.showToast({
          title: '添加成功',
        })
        this.close()
        this.queryFruits()
      },
      close() {
        this.setData({isShow:false})
      },
      // 删除
      async del(e) {
        const {_id} = e.currentTarget.dataset
        try {
          const {stats}  = await db.doc(_id).remove()
          wx.showToast({
            title: stats.removed ===0?'删除失败':'删除成功',
            icon:stats.removed ===0?'error':'success'
          })
          this.queryFruits()
        } catch (error) {
          wx.showToast({
            title: '没有权限',
            icon:'error'
          })
        }
      },
      // 排序
      async orderBy() {
        let {by} = this.data
        // asc 升序 desc 降序
        by = by==='asc'?'desc':'asc'
        const {data} = await db.orderBy('price',by).get()
        data.map(item=>{
          item.time = dayjs(item.time).format('HH:mm:ss')
          return item
        })
        this.setData({fruits:data,by})
      },
      // 查询指定的条数的记录
      async limit() {
        const {num} = this.data
        const {data} = await db.limit(Number.parseInt(num)).get()
        this.setData({fruits:data})
      },
      // 分页查询
      async queryPage(e) {
        const {num} = this.data
        // 页码数
        const {page} = e.currentTarget.dataset
        // 计算查询的起始位置
        const startNum = (page-1)*num
        // 这里的num是字符串,改为number类型
        const {data} = await db.limit(Number.parseInt(num)).skip(startNum).get()
        this.setData({fruits:data})
      },
      // 操作符查询
      // 这里没有设置页面格式什么的 直接在页面加载时调用 然后通过控制台打印结果
      async commandQuery() {
        const {data} = await db.where(or([
          {price:gte(5)},
          {num:eq(5)}
        ])).get()
        console.log(data); // 苹果 火龙果 西瓜 圣女果
      }
    }) 
    

数据库的增删改查和Command数据库操作符

  • 以上编写的详细代码已经上传到gitee,查看地址:
    • https://gitee.com/didoe/database.git

云开发~云函数

  • 云函数即在云端(服务器端)运行的函数。在物理设计上,一个云函数可由多个文件组成,占用一定量的CPU内存等计算资源;各云函数完全独立;可分别部署在不同的地区。开发者无需购买、搭建服务器,只需编写函数代码并部署到云端即可在小程序端调用,同时云函数之间也可互相调用。
  • 一个云函数的写法与一个在本地定义的JavaScript方法无异,代码运行在云端Node.js中。当云函数被小程序端调用时,定义的代码会被放在Node.js运行环境中执行。我们可以如在Node.js 环境中使用JavaScript一样在云函数中进行网络请求等操作,而且我们还可以通过云函数后端 SDK搭配使用多种服务,比如使用云函数SDK中提供的数据库和存储API进行数据库和存储的操作,这部分可参考数据库和存储后端API文档。
  • 云开发的云函数的独特优势在于与微信登录鉴权的无缝整合。当小程序端调用云函数时,云函数的传入参数中会被注入小程序端用户的openid,开发者无需校验openid的正确性因为微信已经完成了这部分鉴权,开发者可以直接使用该openid

云开发~云函数

  • 其实通俗来讲,云函数也是运行在服务器上的,只不过和我们传统开发语言相比。微信官方为我们提供的傻瓜式的一键部署。也就是说你只需要把心思花在业务逻辑代码的编写上即可。无需关心写好如何部署,无需关心安全问题,无需关心鉴权问题。

  • 云函数获取openid

  • 用云函数的话,只需要3步

    • 编写云函数
    • 一键部署云函数
    • 调用云函数
  • 来看下云函数代码,只需要10行代码,即可轻松搞定

    // 云函数入口文件
    const cloud = require('wx-server-sdk')
    
    cloud.init()
    
    // 云函数入口函数
    exports.main = async (event, context) => {
      const wxContext = cloud.getWXContext()
    
      return {
        event,
        openid: wxContext.OPENID,
        appid: wxContext.APPID,
        unionid: wxContext.UNIONID,
      }
    }
    
  • 云函数的优势

    操作云函数云数据库
    返回数据上限100条20条
    更新数据都可以更新只有自己创建的才可以更新
    删除数据都可以删除只有自己创建的才可以删除
    运行环境运行在云端Node.js环境运行在小程序本地
    实现功能丰富度非常丰富只能实现数据库增删改查
  • 云函数属于管理端,在云函数中运行的代码拥有不受限的数据库读写权限和云文件读写权限。需特别注意,云函数运行环境即是管理端,与云函数中的传入的openId对应的微信用户是否是小程序的管理员 / 开发者无关。

  • 初始化云函数的环境

    • 创建一个文件夹cloud(这个名字可以自定义,但是我们一般使用cloud)和pages平行

    • project.config.json里面配置云函数所在目录为cloud

      "cloudfunctionRoot": "cloud/"
      
    • 然后点击保存,我们的cloud文件夹前面就有一个云朵(图标发生了变化),就代表我们云函数初始化成功啦。

      在这里插入图片描述

  • 新建云函数

    在这里插入图片描述

  • 云函数获取openid

    • 调用云函数有两种写法

      • 传统的successfail

            wx.cloud.callFunction({
              // name 必须和你创建的 Node.js 云函数名字一致
              name:'queryFruits',
              success:(res) => {
                console.log(res.result.openid);
              }
            })
        
      • promise写法thencatch

            wx.cloud.callFunction({
              name:'queryFruits',
            }).then(res => {
              this.setData({openid:res.result.openid})
            }).catch(res => {
              console.log(res);
            })
        
  • 数据的导出

    • 数据导出,做数据备份(点击打开云开发控制台,在数据库记录列表中)

      在这里插入图片描述

  • 数据的导入

    • 数据导入,为了快速的大量的创建一些数据。

      在这里插入图片描述

  • 云函数获取数据

    // 云函数入口文件
    const cloud = require('wx-server-sdk')
    
    // 导入
    cloud.init({
      env:'cloud1-5g4o3xfv164a262d'
    })
    
    // 云函数入口函数
    // 导出 event 参数
    exports.main = async (event, context) => {
      const {_id} = event
      return await cloud,cloud.database().collection('fruits').doc(_id).get()
    }
    
     // 在页面index中的index.js里面
     async queryOne(e) {
        const {_id} =e.currentTarget.dataset
        const {result} = await wx.cloud.callFunction({
          name:'queryOne',
          data:{
            _id
          }
        })
        console.log(result.res);
        wx.navigateTo({
          url: `/pages/fruitDetail/index?fruits=${JSON.stringify(result.data)}`,
        })
      }
    
  • 云函数修改数据

    // 云函数入口文件
    const cloud = require('wx-server-sdk')
    
    // 导入
    cloud.init({
      env:'cloud1-5g4o3xfv164a262d'
    })
    
    // 云函数入口函数
    // 导出 event 参数
    exports.main = async (event, context) => {
      const {_id} = event
      return await cloud,cloud.database().collection('fruits').doc(_id).update()
    }
    
  • 云函数删除数据

    // 云函数入口文件
    const cloud = require('wx-server-sdk')
    
    // 导入
    cloud.init({
      env:'cloud1-5g4o3xfv164a262d'
    })
    
    // 云函数入口函数
    // 导出 event 参数
    exports.main = async (event, context) => {
      const {_id} = event
      return await cloud,cloud.database().collection('fruits').doc(_id).remove()
    }
    
       // 在页面index中的index.js里面
      // 删除
      async del(e) {
        const {_id} = e.currentTarget.dataset
        const {result} = await wx.cloud.callFunction({
          name:'del',
          data:{
            _id
          }
        })
        // console.log(result);
        if(result.starts.removed == 1) {
          wx.showToast({
            title: '删除成功',
            icon:'success'
          })
        }
        this.queryFruits()
      },
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值