0基础入门微信小程序开发
、理解微信小程序的开发流程
、理解小程序云开发的使用
、独立完成小程序全栈项目
html
、css
、JavaScript
多敲代码
、多看官方文档
基础内容 > 注册申请 > 开发工具
代码构成 > JSON > WXML > WXSS > JS
云开发 > 云数据库 > 云函数 > 云存储
电影案例 > 上线审核
电影小程序 | |
---|---|
用户登录 | 如何通过云函数获取openid |
传统微信登录 VS 云开发微信登录 | |
如何获取用户信息 | |
电影列表 | 如何云函数调用第三方API |
云函数调用API VS 小程序调用API | |
渲染列表 | |
电影评价 | 云数据库插入数据 |
选择相册图片或拍照 | |
云存储的图片上传 |
mp.weixin.qq.com
developers.weixin.qq.com
.json:配置文件,以json格式存储一些配置
.wxml:模板文件,描述页面结构,相当于HTML
.wxss:样式文件,调整页面样式,相当于css
.js:脚本逻辑文件,页面和用户的交互逻辑
project.config.json:项目配置
app.json:全局配置
page.json:页面配置
WXML 全程是WeiXin MarkUp Language,是小程序框架设计的一套标签语言,结合小程序的基础组件、事件系统,可以构建出页面的结构,充当的就是类似HTML的角色。
数据从动态的服务端获取,渲染到页面
数据绑定使用 Mustache 语法(双大括号)将变量包起来
wx:for="{{list}}"
wx:if="{{isLogin}}"
、很长时间不改变的场景
hidden="{{!isLogin}}"
、频繁切换场景
base.wxml
<view>Hi {{msg}}view>
<view wx:for="{{arr}}" wx:key="*this">{{index}} {{item}}view>
<view wx:for="{{list}}" wx:key="*this">{{item.name}} {{item.age}}view>
<view>
<view wx:if="{{isLogin}}">Bob已登录view>
<view wx:else>请登录view>
<view hidden="{{!isLogin}}">hiddenview>
view>
base.js
Page({
data: {
msg: 'Vue',
arr:['a','b'],
list:[
{
name:'bob1',
age:19
},{
name:'bob2',
age:29
}
],
isLogin:true
}
})
WXSS (WeiXin Style Sheets)是一套用于小程序的样式语言,用于描述WXML的组件样式,也就是视觉上的效果。
尺寸单位:rpx(responsive pixel):可以根据屏幕宽度进行自适应,适配不同宽度的屏幕。
引入外部wxss:@import './test.wxss'
第三方样式库:WeUI
、iView Weapp
、Vant Weapp
JS负责逻辑交互
计数器demo
this.setData({
count:this.data.count+1
})
事件是对用户的交互操作行为的相应
bind VS catch
事件对象
base.wxml
<view class="box" catchtap="onbox" data-id='onbox父'>
<view class="child" catchtap="onchild">view>
view>
<view>
<button bindtap="handle">点我+1button>
<view>{{count}}view>
view>
base.js
Page({
data: {
count:0
},
handle:function(){
this.setData({
count:this.data.count+1
})
},
onbox:function(e){
console.log('onbox 父');
console.log(e);
console.log(e.currentTarget.dataset.id);
},
onchild:function(e){
console.log('onchild 儿');
console.log(e);
},
})
云函数 云数据库 云存储
数据库初始化
初始化 const db = wx.cloud.database()
切换环境 const testDB = wx.cloud.database({ env:'test' })
通过小程序控制,插入数据会默认插入openid、通过控制台插入不会默认插入openid
cloud.wxml
<button type="warn">小程序控制button>
<button type="primary" bindtap="insert">增加数据button>
<button type="primary" bindtap="update">更新数据button>
<button type="primary" bindtap="search">查找数据button>
<button type="primary" bindtap="delete">删除数据button>
cloud.js
// 初始化数据库
const db = wx.cloud.database();
Page({
data: {
},
insert: function () {
// 普通写法
/*
db.collection('userss').add({
data: {
name: 'bob',
age: 20
},
success: res => {
console.log(res);
},
fail: err => {
console.log(err);
}
})
*/
// Promise写法
db.collection('userss').add({
data: {
name: 'bob',
age: 20
}
}).then(res=>{
console.log(res);
}).catch(err=>{
console.log(err);
})
},
update:function(){
db.collection('userss').doc('8937eaa96117afc104b0a4b6145d825c')
.update({
data:{
age:210
}
}).then(res=>{
console.log(res);
}).catch(err=>{
console.log(err);
})
},
search:function(){
db.collection('userss').where({
name:'bob'
}).get().then(res=>{
console.log(res);
}).catch(err=>{
console.log(err);
})
},
delete:function(){
db.collection('userss').doc('8937eaa96117b09304b0d7d23131e328')
.remove().then(res=>{
console.log(res);
}).catch(err=>{
console.log(err);
})
},
})
求和函数 sum()
获取当前用户的openid
批量删除云数据库的数据
上传并部署:云端安装依赖(不上传node_modules)
云函数更新一次,就要右键上传并部署一次
cloud.wxml
<button type="warn">云函数控制button>
<button type="primary" bindtap="sum">调用云函数sumbutton>
<button type="primary" bindtap="getOpenId">获取当前用户openidbutton>
<button type="primary" bindtap="batchDelete">批量删除button>
cloud.js
// 初始化数据库
const db = wx.cloud.database();
Page({
data: {
},
sum: function () {
wx.cloud.callFunction({
name: 'quickstartFunctions',
config: {
env: this.data.envId
},
data: {
type: 'sum',
a:2,
b:3
}
}).then(res=>{
console.log(res);
}).catch(err=>{
console.log(err);
})
},
getOpenId:function(){
wx.cloud.callFunction({
name: 'quickstartFunctions',
config: {
env: this.data.envId
},
data: {
type: 'getOpenId'
}
}).then(res=>{
console.log(res);
}).catch(err=>{
console.log(err);
})
},
batchDelete:function(){
wx.cloud.callFunction({
name: 'quickstartFunctions',
config: {
env: this.data.envId
},
data: {
type: 'batchDelete'
}
}).then(res=>{
console.log(res);
}).catch(err=>{
console.log(err);
})
},
})
sum index.js
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
// 获取openId云函数入口函数
exports.main = async (event, context) => {
return {
sum: event.a + event.b
}
}
getOpenid index.js
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
// 获取openId云函数入口函数
exports.main = async (event, context) => {
// 获取基础信息
const wxContext = cloud.getWXContext()
return {
openid: wxContext.OPENID,
appid: wxContext.APPID,
unionid: wxContext.UNIONID,
}
}
batchDelete index.js
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
const db = cloud.database();
// 获取openId云函数入口函数
exports.main = async (event, context) => {
try {
return await db.collection('userss').where({
name: 'bob'
}).remove();
} catch (e) {
console.error(e);
}
}
cloud.wxml
<button type="warn">云存储button>
<button type="primary" bindtap="upload">上传图片button>
<button type="primary" bindtap="getFile">文件展示button>
<block wx:for="{{imgs}}" wx:key="*this">
<image src="{{item.fileID}}">image>
<button type="primary"
data-fileID="{{item.fileID}}"
bindtap="downloadFile">文件下载button>
block>
cloud.js
// 初始化数据库
const db = wx.cloud.database();
Page({
data: {
imgs:[]
},
upload: function () {
// 选择图片
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
// tempFilePath可以作为img标签的src属性显示图片
const tempFilePaths = res.tempFilePaths;
console.log(tempFilePaths);
//
wx.cloud.uploadFile({
// 指定上传到的云路径
cloudPath: new Date().getTime()+'.png',
// 指定要上传的文件的小程序临时文件路径
filePath: tempFilePaths[0],
// 成功回调
success: res => {
// console.log('上传成功', res)
console.log('上传成功', res.fileID)
//
db.collection('demoImg').add({
data:{
fileID:res.fileID
}
}).then(res=>{
console.log(res);
}).catch(err=>{
console.log(err);
})
},
fail:console.error
})
}
})
},
getFile:function(){
wx.cloud.callFunction({
name: 'quickstartFunctions',
data: {
type: 'getOpenId'
}
}).then(res => {
console.log(res.result.openid);
db.collection('demoImg').where({
_openid:res.result.openid
}).get().then(res2=>{
console.log(res2.data);
this.setData({
imgs:res2.data
})
})
}).catch(err => {
console.log(err);
})
},
downloadFile:function(e){
console.log(e);
wx.cloud.downloadFile({
fileID: e.target.dataset.fileid, // 文件 ID
success: res => {
// 返回临时文件路径
console.log(res.tempFilePath);
// 保存图片到手机相册
wx.saveImageToPhotosAlbum({
filePath:res.tempFilePath,
success(res) {
wx.showToast({
title:'保存成功'
})
}
})
},
fail: console.error
})
}
})
developers.weixin.qq.com
mp.weixin.qq.com
iconfont.cn
https://youzan.github.io/vant-weapp
1、在miniprogram目录下 npm init
2、通过 npm 安装 npm i @vant/weapp -S --production
3、工具 > 构建npm
4、详情 > 本地设置 > 使用npm模块
5、"usingComponents": { "van-button": "@vant/weapp/button" }
6、
http://github.com
https://github.com/request/request-promise
在对应云函数文件夹里安装 npm install --save request
继续 npm install --save request-promise
package.json
{
"name": "quickstartFunctions",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"request": "^2.88.2",
"request-promise": "^4.2.6",
"wx-server-sdk": "~2.4.0"
}
}
movielist.js
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV
})
// 电影列表 http://api/douban.com/v2/movie/in_theaters
// 电影详情 http://api/douban.com/v2/movie/subject/id
/*
https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=10&page_start=10
https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=10&page_start=10
page_limit 是一次请求数
page_start 是从第几条开始重新请求
start 是从第几条开始重新请求
count 是一次请求数
http://api.douban.com/v2/movie/subject/${event.movieid}?apikey=0df993c66c0c636e29ecbb5344252a4a
`http://api.douban.com/v2/movie/subject/${event.movieid}?apikey=0df993c66c0c636e29ecbb5344252a4a`
*/
var rp = require('request-promise');
exports.main = async (event, context) => {
return rp(`https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=${event.count}&page_start=${event.start}`)
.then(function (res) {
console.log(res);
return res
})
.catch(function (err) {
console.err(err);
});
}
movie.wxml
<view class='movie' wx:for="{{movieList}}" wx:key="{{index}}">
<image class='movie-img' src=" {{item.cover}}">
image>
<view class="movie-info">
<view class="movie-title">{{item.title}}view>
<view class="">观众评分:
<text class="movie-score">{{item.rate}}分text>
view>
<button bindtap="gotoComment" data-movieid="{{item.id}}">评价button>
view>
view>
movie.js
Page({
data: {
movieList: []
},
getMovieList:function() {
wx.showLoading({
title: '加载中',
})
wx.cloud.callFunction({
name: 'quickstartFunctions',
data: {
type: 'movielist',
start: this.data.movieList.length, // 第一次0-9 第二次 10-19 开始的地方 page_start
count: 10 // page_limit
}
}).then(res => {
console.log(res);
this.setData({
// this.data.movieList是数组,在原有数组拼接新的
movieList: this.data.movieList.concat(JSON.parse(res.result).subjects)
})
wx.hideLoading();
}).catch(err => {
console.err(err);
wx.hideLoading();
})
},
gotoComment:function(e){
console.log(e.target.dataset.movieid);
wx.navigateTo({
url: `../comment/comment?movieid=${e.target.dataset.movieid}`,
})
},
onLoad: function (e) {
this.getMovieList();
},
onReachBottom:function(){
this.getMovieList();
}
})
<view class="bg1">
<view class="userinfo">
<block wx:if="{{!hasUserInfo}}">
<button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile">
点击登录
button>
block>
<block wx:else>
<view class="userinfo">
<view class="userinfo-avatar">
<image src="{{userInfo.avatarUrl}}" mode="widthFix" class="png">image>
view>
<view class="userinfo-NickName">
{{userInfo.nickName}}
view>
view>
block>
view>
view>
<view class="userinfo">
<view class="userinfo-avatar">
<open-data type='userAvatarUrl'>open-data>
view>
<view class="userinfo-NickName">
<open-data type='userNickName'>open-data>
view>
view>
.bg1 {
border-bottom: 10rpx solid #ccc;
}
/* */
.userinfo {
font-size: 14px;
border-radius: 40%;
}
.userinfo-avatar {
overflow: hidden;
display: block;
width: 100rpx;
height: 100rpx;
margin-top: 32rpx;
border-radius: 50%;
border: 2px solid #fff;
box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.2);
}
.userinfo-NickName {
margin: -50rpx 0rpx 0rpx 150rpx;
color: #aaa;
}
/* */
.userinfo {
position: relative;
width: 750rpx;
height: 320rpx;
color: #fff;
display: flex;
flex-direction: column;
align-items: center;
}
.userinfo-avatar {
overflow:hidden;
display: block;
width: 160rpx;
height: 160rpx;
margin: 20rpx;
margin-top: 50rpx;
border-radius: 50%;
border: 2px solid #fff;
box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.2);
}
.userinfo text {
color: #fff;
font-size: 14px;
background-color: #c0c0c0;
border-radius:40%;
}
const app = getApp();
const db = wx.cloud.database();
const _ = db.command;
var that;
wx.cloud.init()
// 在页面中定义插屏广告对象
var interstitialAd = null;
Page({
data: {
hasRegistered: false, //true是update,false是add
openid: '',
userInfo: [],
hasUserInfo: false,
canIUseGetUserProfile: true,
},
onLogin:function(){ // 开发者如需获取用户身份标识符只需要调用wx.login接口即可
wx.login({
timeout: 0,
success:res=>{
console.log(res);
}
})
},
getUserProfile(e) {
// 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
// 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
wx.getUserProfile({
desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
success: (res) => {
console.log(res);
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
});
// 判断,获取userInfo,存入storage,新增或者更新时使用
wx.setStorageSync('userInfo', res.userInfo);
},
fail: function (res) { //用户点了“拒绝”
wx.showModal({
title: '登陆后获取更多功能',
content: "点击确定重新登陆",
cancelText: "取消",
confirmText: "确定",
success: function (res) {
if (res.cancel) {
//点击取消,默认隐藏弹框
console.log("no");
} else {
//点击确定
console.log("ok");
wx.getUserProfile({
desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
success: (res) => {
console.log(res);
that.setData({
userInfo: res.userInfo,
hasUserInfo: true
});
// 判断,获取userInfo,存入storage,新增或者更新时使用
wx.setStorageSync('userInfo', res.userInfo);
},
})
}
}
})
}
})
// 已注册,更新用户信息;没注册,新增用户
let that = this
if (that.data.hasRegistered) {
// true是update,false是add
// console.log("updateUser");
this.updateUser()
} else {
// true是update,false是add
// console.log("addUser");
this.addUser()
}
//
},
getUserInfo(e) {
// 不推荐使用getUserInfo获取用户信息,预计自2021年4月13日起,getUserInfo将不再弹出弹窗,并直接返回匿名的用户个人信息
this.setData({
userInfo: e.detail.userInfo,
hasUserInfo: true
})
},
onLoad: function () {
if (wx.getUserProfile) {
this.setData({
canIUseGetUserProfile: true
})
}
//Load过程中,判断用户是否已经注册
let that = this
// 调用login云函数获取openid,存入storage
wx.cloud.callFunction({
name: 'login',
data: {},
success: res => {
app.globalData.openid = res.result.openid;
wx.setStorageSync('openid', res.result.openid);
var openid = wx.getStorageSync('openid');
// console.log(openid);
},
fail: err => {
console.error('[云函数] [login] 调用失败', err);
}
})
//使用缓存中的openid判断是否已经注册过,返回值 > 0说明有已有数据,注册过,直接调用update方法
db.collection('user').where({
_openid: wx.getStorageSync('openid')
}).get({
success(res) {
// console.log(res.data);
console.log(res.data.length);
if (res.data.length > 0) {
that.setData({
hasRegistered: true //将hasRegistered更新为true是update
})
}
}
})
},
//新增用户,并将hasReigstered设置为true
addUser() {
var userInfo = {
name: wx.getStorageSync('userInfo').nickName,
avatarUrl: wx.getStorageSync('userInfo').avatarUrl,
gender: wx.getStorageSync('userInfo').gender,
punchsNumber: 0,
shareNumber: 0,
likesNumber: 0,
start: new Date()
}
let that = this
db.collection('user').add({
data: userInfo,
success(res) {
that.setData({
hasRegistered: true
})
console.log("新增用户成功", res)
}
})
},
//更新用户数据
updateUser() {
var userInfo = {
name: wx.getStorageSync('userInfo').nickName,
avatarUrl: wx.getStorageSync('userInfo').avatarUrl,
gender: wx.getStorageSync('userInfo').gender
}
db.collection('user').where({
_openid: wx.getStorageSync('openid')
}).update({
data: userInfo,
success(res) {
console.log("更新用户信息成功", res)
}
})
},
})
版本号、项目备注、提交审核、确定上线
小程序基础知识 > 小程序云开发 > 电影小程序案例
关掉视频,独立完成案例
反复看小程序官方文档