微信小程序快速入门和踩坑记录
对云开发的一些个人认识
常规开发的缺点:开发网络应用常常需要花费大量精力在基础设备环境的搭建上。例如要建立一个个人网站,必须要先买一个公网IP,购买云主机还比较简单,自己本地搭建服务器更复杂。搭好主机配好IP后还得自己安装配置网络服务软件,如tomcat,apache,nginx等,得去下载数据库软件,比如mariadb,mysql等,在命令行里一行一行的去创建数据库,创建表,定义属性。然后还得去管理安全策略,防范各种攻击。这些操作非常繁琐,需要投入大量精力。
这就体现了云开发的优点:
所有配套的服务,例如主机,数据库,代码运行环境,存储库全部给开发者配好,只用很少的时间进行一些针对自己软件的配置,例如数据库索引。传统后端的大量工作都由云开发服务商完成,同时服务商会提供大量的易于使用的api,开发者可以利用这些api快速完成功能实现。开发者可以将主要精力集中于代码的实现,而不用再去操心tomcat半天初始化不了,apache开机启动怎么失效了以及数据库怎么起不来之类的操蛋的问题。
1.微信小程序的基本介绍
小程序类似于微信内的网页应用,与一般网页应用不同的是,小程序可以调用微信的一些功能,同时微信官方提供了JDK,可以帮助开发者更快速的构建应用,而不用自己写大量的代码来实现一些常用的功能。因此,小程序开发与前端开发有很多相似之处。云数据库,云函数,云存储都可以帮助开发者避免冗长的基础环境搭建,将精力集中于提升页面的表现和逻辑功能的实现。
2.微信小程序的基本结构
- 页面(pages):页面就是展现给用户的小程序的界面,包含四个文件:xxx.wxml(类似于html文件) xxx.wxss(类似于css文件) xxx.js xxx.json。
- app.xxx文件:小程序的全局配置文件,app.json内的pages内部就是小程序的页面路径,第一项就是小程序的默认登入页面,windows内部是小程序标题栏的配置信息,app.js包含小程序的全局函数和全局变量(globalData),app.wxss是小程序的默认全局样式。
- 云函数:运行于云端的函数,对数据库进行增删改的敏感操作的代码只能运行在服务器上,用户只被允许在终端设备上进行查询操作。云函数运行在服务器上,允许用户调用接口来传递参数,云函数在服务器上执行相关操作。
- 云数据库:提供数据库服务
- 云存储:提供一个便利的云端存储服务,可以存储用户文件和资源文件等
3.微信小程序快速搭建
这就不多说了,还是看官方文档好
微信小程序官方文档
4.踩坑记录
1.button组件的宽度和高度设置:在wxss文件里设置button的宽度是不起作用的,必须在wxml的组件内直接设置
例如:
<button class='bt' bindtap="login" style='width:100rpx'>登录</button>
2.数据库查询结果是一个JSON数组,要获取某个类型的值,需要确定数组下标,例如
var name=''
var db=wx.cloud.database()
db.collection('数据库名').where({}).get({
success=>{
name=res.data[0]["username"] //在结果数组中选取下标为0的元素的username的值
}
})
3.在js内修改data的变量值时不能直接使用this.data.变量名=值,通常会导致数据修改失败,而要使用如下代码
var that=this
that.setData({
变量名:值
})
4.在云函数中操作数据库并需要将结果传递给变量时,需用await等待数据库操作完成并返回结果值,否则变量将会显示为undifined
let check=await db.collection('userinfo').where({
userid:event.userid
}).count();
5.组件的data如果不是字符串,作为参数传递给其他页面时会发生变量类型默认为string的情况,可以将该变量转换为string类型后传递给其他页面或者函数,再在函数或者页面内部将string转化为原本设置的数据类型,如下应用场景:
需要用bool类型的值来控制checkbox的是否勾选,数据库中保存的对应值的类型为boolean,由true和false两个有效值,在页面传递参数时,传递"true"和"false"字符串,而在云函数内再将其转换为boolean类型传入数据库
(讲得专业一点,这叫文本化编程,即采用字符串传递参数,避免类型的限制,参考《Linux编程艺术》)
var thedone=false
if(event.done=="true"){
thedone=true
}
6.安装Node.Js后一定要重启一次,不然用不了npm
7.云数据库一定要看看权限,不然设置为仅创建者可读写,你可能会发现在页面里面的操作云数据库返回的结果总是空的
8.云函数调用api时不要用wx.前缀,例如不使用wx.cloud.database(),而使用cloud.database()
5.常用功能实现总结
1.选择图片
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res){
that.setData({
photo:res.tempFilePaths,//用于本地显示
photopath:res.tempFilePaths[0] //用于上传
})
}
})
var filePath=that.data.photopath;
var cloudPath=文件夹名+'/'+文件名+filePath.match(/\.[^.]+?$/)[0];//后面这个是文件后缀
wx.cloud.uploadFile({
cloudPath,//云存储路径,如果云端没有相应的文件夹,会自动创建
filePath,//本地路径,用于上传
})
//之后用于获取云端图片的路径是
https://云存储链接/"+cloudPath
云存储链接这样获取:先上传一个图片,然后在云存储里点击这个图片文件,获取一个https://开头的那个网址链接,然后把后面的cloudPath去掉,然后把这个路径存在云数据库里,以后都可以通过这个链接获取图片
2.调用云函数
//新建立的云函数一定要按照官方教程,右键点击云函数文件夹-》在终端中打开,再执行npm install
//写好后右键点击上传到云端(不上传moduel)
//定义云函数接受参数和返回值
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
// 云函数入口函数
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
let {userid, username, userpassword} = event //定义接口参数
let { OPENID, APPID } = cloud.getWXContext()
let result=''
var db=cloud.database();
let check=await db.collection('userinfo').where({
userid:event.userid
}).count();
if(check.total!=0){
result='账号已存在'
} else{
let addresult = await db.collection('userinfo').add({
data:{
userid:event.userid,
username:event.username,
userpassword:event.userpassword
}
})
result='注册成功'
}
return {
result
}
}
//调用云函数
wx.cloud.callFunction({
name:'register',
data:{
userid:that.data.userid,
username:that.data.username,
userpassword:that.data.userpassword
}
}).then(res=>{
console.log(res.result["result"])
}
)
3.在不同页面传参
//传递参数
wx.navigateTo({
url: '../edit/edit?stamp='stamp+"&id="+id //参数与页面链接间以问号分割,不同参数间以&分割
})
//接受参数
onLoad: function (options) {
var that=this
that.setData({
stamp:options.stamp
id:options.id
})
}
4.为组件设置值并在事件中获取相应值
//设置值
<view class="newlist" bindtap="editlist" data-id="{{item.id}}">新建</view>
//data-名称="xxx"
//在点击事件中获取组件值
editlist:function(e){
wx.navigateTo({
url: "../edit/edit?id="+e.currentTarget.dataset.id
})
},
//e.currentTarget.dataset.名称
5.给数组添加元素
//例如
Page({
data: {
todolist:[]
},}
//要向todolist添加元素
var that=this
var newlist=[]
newlist=that.data.todolist
newlist.push(新元素)
that.setData({
todolist:newlist
})
6.父组件和子组件都设置了点击事件,但是点击子组件时要避免触发父组件的点击事件,示例如下
<view bindtap="editlist">
<checkbox catchtap="clicked"></checkbox>
</view>
//使用catchtap,避免点击子组件同时触发触发父组件的点击事件
菜鸟一枚,欢迎大佬指正