借助云开发数据库实现小程序列表上拉刷新功能丨云开发101

上一期101专栏中,我们介绍了如何借助云开发数据库实现小程序的列表触底自动加载功能,相对应的,小程序列表上拉刷新又该如何实现呢?本期专栏就来为大家解答。 原理说明在小程序中,如果我们希望实现上拉刷新的功能,则需要我们监听小程序页面的 onPullDownRefresh 事件,我们可以在这个方法中实现数据的加载和替换,从而实现数据的刷新和页面的更新。 实现代码正常情况下的上拉刷新首先,我们先来看一看一般情况下的上拉刷新功能的实现。这里的「一般情况」是指你没有使用 scroll-view 组件的场景,或者使用的是横向的 scroll-view 的场景,列表是直接构建在页面内部的,而不是构建在 scroll-view 内部的。 在这种情况下,我们如果希望在页面上实现上拉刷新,需要在 app.json 中的 window 选项中,或者是页面的配置中加入 enablePullDownRefresh,并将其配置为 true。 // app.json{ ... "window":{ "enablePullDownRefresh":true } ...}// page.json{ "enablePullDownRefresh":true}配置好以后,我们就可以开始配置了。进入到我们需要实现下拉刷新的页面,在这个页面中,我们需要在 Page 的构造函数中添加 onPullDownRefresh 函数的监听。 Page({ onPullDownRefresh:function(){ // 这里我们需要进行页面的加载。 }})我们需要在 onPullDownRefresh 函数中,加入我们查询数据的代码,从而实现数据的更新和替换,大体上写好的代码如下: Page({ onPullDownRefresh:function(){ let db = wx.cloud.database(); // 查询数据 db.collection('records').get().then(res => { // 更新数据 this.setData({ data: res.data },()=>{ wx.stopPullDownRefresh(); // 数据同步完成后,停止掉上拉刷新的动画效果。 }) }).catch(err => { console.error(err) }) }})在上面这段代码中,我们在 onPullDownRefresh 方法中加入了 云开发的数据库查询方法,并在数据库查询方法的成功回调中加入了 setData 的方法来更新数据,从而确保我们的小程序的页面数据可以完成更新。 ...

October 8, 2019 · 1 min · jiezi

小程序云开发的HTTP-API调用丨实战

小程序云开发之httpApi调用。小程序云开发之httpApi调用(返回“47001处理”) 技术栈采用 nodejs + express 搭建web服务器,采用 axios 请求第三方 httpApinodejs express axios 项目结构通过应用生成器工具 express-generator 可以快速创建一个应用的骨架。 主要的核心文件 routes/base.js(api设置),util/rq.js(axios封装),views/base.pug(接口文档) |---bin (框架生成,服务启动命令文件夹)|---public (框架生成,静态资源存储)|-------images|-------javascripts|-------stylesheets|---routes (框架生成,路由配置/api)|-------base.js // base相关接口及文档说明页|---util (自行添加文件夹,放置公用js)|-------result.js // 最终返回结果包装js|-------rq.js // axios封装|---views (框架生成,页面存放)|-------error.pug|-------base.pug (自行添加pug模板页面,用于base接口说明)|-------index.pug|-------layout.pug|---app.js (框架生成,项目核心)axios封装(util/rq.js)// 模块引用let axios = require("axios")let qs = require("qs")// 变量声明const CONFKEY = "dev"const BASECONF = { "dev":{ baseUrl:'https://api.weixin.qq.com/', }, "prod":{ baseUrl:'https://api.weixin.qq.com/' }}[CONFKEY]// 创建rq请求并设置基础信息const rq = axios.create({ baseURL: BASECONF.baseUrl, timeout: 10000, headers: { // 请求头设置,(微信云开发数据APi采用application/json格式入参,否则导致47001错误) "Content-Type":"application/json; charset=utf-8" }})// axios 请求头拦截器rq.interceptors.request.use(req => { // 有需要的,在此处拦截请求入参进行处理 return req},error => { return Promise.reject(error)})// axios 返回信息拦截器rq.interceptors.response.use(res => { return res.data},error => { return Promise.reject(error)})const $rq = { // 封装get,post请求 get(url,params) { // axios.get(url,config) return rq.get(url,{ params: params }) }, post(url,params={}) { return rq({ // axios(config) url: url, method: 'post', data:params }) }}module.exports = { $rq}api设置 (routes/base.js)var express = require('express');var router = express.Router();var { $rq } = require("../util/rq")let result = require("../util/result.js")/* GET base page. */router.get('/', function(req, res, next) { // base pugApi说明文档 res.render('base', { title: 'baseApi', apiList:[ { url:"base/getAccessToken(请求第三方Api,获取access_token)", method:"GET", params:{ key:"grant_type", appid:"小程序appid", secret: "小程序密钥" }, result:{ "success": true, "data":`{ "access_token":"23_w0OtD1X72LIQo4dwctVsp99kjtIRRk9Gw5bx7UOglotfL7k9LqB1gKbZw86CNht6cnCv9oKBcFEcPg5u4seXN0hJMSEocsbun2dQxCTyZarP06YcToVbdP-MOLc7o7EhMSzqR4URT__BdZc-NMLbAIARQP", "expires_in":7200 }` } }, { url:"base/getdatabase(获取指定云环境集合信息)", method:"post", params:{ env:"云开发数据库环境id", limit:"获取数量限制,默认10", offset:"偏移量,默认0" }, result:{ "success": true, "data":`{ { "errcode": 0, "errmsg": "ok", "collections": [ { "name": "geo", "count": 13, "size": 2469, "index_count": 1, "index_size": 36864 }, { "name": "test_collection", "count": 1, "size": 67, "index_count": 1, "index_size": 16384 } ], "pager": { "Offset": 0, "Limit": 10, "Total": 2 } } }` } } ] });});router.get('/getAccessToken', function(req, res, next) { // 请求第三方Api,获取access_token let urlParam = { // appID,secret信息最好是不暴露在外故在此处直接写死即可 grant_type:"client_credential", appid: "appid", secret: "secret" }; $rq.get("cgi-bin/token",urlParam).then(response=>{ global.TOKEN_INFO = response // global nodejs 全局对象,占用内存 let r = result.createResult(true, response); // 返回结果包装成固定格式 res.json(r); }).catch(err=>{ let r = result.createResult(false, err); res.json(r); console.log(err) })});router.get('/getdatabase', function(req, res, next) { // 获取指定云环境集合信息 let urlParam = { // 获取access_token之后才能调用其他接口,其他接口的入参就无需传入access_token因为皆须要拼接在接口后 // access_token: req.query.access_token?req.query.access_token:"", env: req.query.env?req.query.env:"test-3b6a08", limit: req.query.limit?req.query.limit:10, offset: req.query.offset?req.query.offset:0 }; $rq.post("tcb/databasecollectionget?access_token="+global.TOKEN_INFO.access_token,urlParam).then(response=>{ let r = result.createResult(true, response); res.json(r); }).catch(err=>{ let r = result.createResult(false, err); res.json(r); // console.log(err) })});module.exports = router;配置app.js 使路由及接口生效(仅)var createError = require('http-errors'); // 处理错误var express = require('express');var path = require('path'); // 路径var cookieParser = require('cookie-parser'); // cookievar logger = require('morgan'); // 日志var sassMiddleware = require('node-sass-middleware'); // sass 中间件var indexRouter = require('./routes/index'); // index 路由var baseRouter = require('./routes/base') // base 路由var app = express();// view engine setupapp.set('views', path.join(__dirname, 'views')); // 设置视图根目录app.set('view engine', 'pug'); // 使用 pug 模板// 声明使用中间件app.use(logger('dev'));app.use(express.json());app.use(express.urlencoded({ extended: false }));app.use(cookieParser());app.use(sassMiddleware({ src: path.join(__dirname, 'public'), dest: path.join(__dirname, 'public'), indentedSyntax: true, // true = .sass and false = .scss sourceMap: true}));app.use(express.static(path.join(__dirname, 'public')));app.all('/*',function (req, res, next) { // 解决跨越问题 res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With'); res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS'); if (req.method == 'OPTIONS') { res.sendStatus(200); } else { next(); }});// 声明路由app.use('/', indexRouter);app.use('/base', baseRouter);// catch 404 and forward to error handler 自定义404中间件app.use(function(req, res, next) { next(createError(404));});// error handler 自定义错误抛出中间件app.use(function(err, req, res, next) { // set locals, only providing error in development res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; // render the error page res.status(err.status || 500); res.render('error');});module.exports = app;至此,小程序云开发----httpApi调用已完成。 ...

September 19, 2019 · 3 min · jiezi

借助云开发轻松实现后台数据批量导出丨实战

小程序导出数据到excel表,借助云开发后台实现excel数据的保存我们在开发小程序的过程中,可能会有这样的需求:如何将云数据库里的数据批量导出到excel表里?这个需求可以用强大的云开发轻松实现!这里需要用到云函数,云存储和云数据库。可以说通过这一个例子,把小程序云开发相关的知识都用到了。下面就来介绍如何实现实现思路1,创建云函数2,在云函数里读取云数据库里的数据3,安装node-xlsx类库(node类库)4,把云数据库里读取到的数据存到excel里5,把excel存到云存储里并返回对应的云文件地址6,通过云文件地址下载excel文件一、创建excel云函数关于如何创建云开发小程序,这里我就不再做具体讲解。不知道怎么创建云开发小程序的同学,可以去翻看腾讯云云开发公众号内菜单【技术交流-视频教程】中的教学视频。 创建云函数时有两点需要注意的,给大家说下1、一定要把app.js里的环境id换成你自己的 2,你的云函数目录要选择你对应的云开发环境(通常这里默认选中的)不过你这里的云开发环境要和你app.js里的保持一致 二、读取云数据库里的数据我们第一步创建好云函数以后,可以先在云函数里读取我们的云数据库里的数据。 1、先看下我们云数据库里的数据 2、编写云函数,读取云数据库里的数据(一定要记得部署云函数) 3、成功读取到数据 把读取user数据表的完整代码给大家贴出来。 // 云函数入口文件const cloud = require('wx-server-sdk')cloud.init({ env: "test-vsbkm"})// 云函数入口函数exports.main = async(event, context) => { return await cloud.database().collection('users').get();}三、安装生成excel文件的类库 node-xlsx通过上面第二步可以看到我们已经成功的拿到需要保存到excel的源数据,我们接下来要做的就是把数据保存到excel 1、安装node-xlsx类库这一步需要我们事先安装node,因为我们要用到npm命令,通过命令行 npm install node-xlsx 可以看出我们安装完成以后,多了一个package-lock.json的文件 四、编写把数据保存到excel的代码,下图是我们的核心代码:这里的数据是我们查询的users表的数据,然后通过下面代码遍历数组,然后存入excel。这里需要注意我们的id,name,weixin要和users表里的对应。 for (let key in userdata) { let arr = []; arr.push(userdata[key].id); arr.push(userdata[key].name); arr.push(userdata[key].weixin); alldata.push(arr) }还有下面这段代码,是把excel保存到云存储用的 //4,把excel文件保存到云存储里 return await cloud.uploadFile({ cloudPath: dataCVS, fileContent: buffer, //excel二进制文件 })下面把完整的excel里的index.js代码贴给大家,记得把云开发环境id换成你自己的。 const cloud = require('wx-server-sdk')//这里最好也初始化一下你的云开发环境cloud.init({ env: "test-vsbkm"})//操作excel用的类库const xlsx = require('node-xlsx');// 云函数入口函数exports.main = async(event, context) => { try { let {userdata} = event //1,定义excel表格名 let dataCVS = 'test.xlsx' //2,定义存储数据的 let alldata = []; let row = ['id', '姓名', '微信号']; //表属性 alldata.push(row); for (let key in userdata) { let arr = []; arr.push(userdata[key].id); arr.push(userdata[key].name); arr.push(userdata[key].weixin); alldata.push(arr) } //3,把数据保存到excel里 var buffer = await xlsx.build([{ name: "mySheetName", data: alldata }]); //4,把excel文件保存到云存储里 return await cloud.uploadFile({ cloudPath: dataCVS, fileContent: buffer, //excel二进制文件 }) } catch (e) { console.error(e) return e }}五、把excel存到云存储里并返回对应的云文件地址经过上面的步骤,我们已经成功的把数据存到excel里,并把excel文件存到云存储里。可以看下效果。接着,就可以通过上图的下载地址下载excel文件了。其实到这里就差不多实现了基本的把数据保存到excel里的功能了,但是为了避免每次导出数据都需要去云开发后台下载excel的麻烦,接下来介绍如何动态获取下载地址。 ...

September 10, 2019 · 2 min · jiezi