微信小程序
微信小程序账号注册
- 访问【微信公众平台】,注册一个微信小程序账号
-
申请账号需要准备一个邮箱,该邮箱要求:
- 未被微信公众平台注册
- 未被微信开放平台注册
- 未被个人微信号绑定过
- 如果被绑定了需要解绑 或 使用其他邮箱
-
获取 小程序id
AppID(小程序ID) wxd63f21a664e8009b
AppSecret(小程序密钥) 513e6cd6ea1a2692c9727004af729f1c
创建项目
- 下载【微信开发工具】--需要联网才能使用
https://developers.weixin.qq.com/miniprogram/dev/devtools/stable.html
- 本地开发支持http
小程序默认只支持https,我们需要做如下配置,让其支持http,方便我们本地开发
项目目录结构
介绍
# 1 项目主配置文件
项目主配置文件必须放到项目的根目录下,控制整个项目
- app.js: 小程序入口文件
- app.json:小程序的全局配置文件
- app.wxss:小程序的全局样式
-app.js 和 app.json 文件是必须的,不能没有
# 2 页面文件
小程序有一个个页面,每个页面所需的文件,都存放在 pages 目录下,一个页面一个文件夹
-xx.js: 页面逻辑 js代码存放位置
-xx.wxml:页面结构 类html文件存放位置
-xx.wxss:页面样式 css存放位置
-xx.json:小页面配置
-xx.js 文件和 xx.wxml 文件是必须的,不能没有
# 3 相关配置文档
https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html
结构
├── components 【页面中使用的组件】
├── pages 【页面文件目录】
│ ├── index 【页面】
│ │ ├── index.js 【页面JS】
│ │ ├── index.json 【页面配置】
│ │ ├── index.wxml 【页面HTML】
│ │ └── index.wxss 【页面CSS】
│ └── logs 【页面】
│ ├── logs.js ...
│ ├── logs.json ...
│ ├── logs.wxml ...
│ └── logs.wxss ...
├── utils 【自定义工具】
│ └── utils.js 【功能的定义】
├── app.js 【全局JS】
├── app.json 【全局配置】
├── app.wxss 【全局CSS】
├── project.config.json 【开发者工具默认配置】
├── project.private.config.json 【开发者工具用户配置,在这里修改,优先用这个,可以删除】
├── .eslintrc.js 【ESlint语法检查配置】
├── sitemap.json 【微信收录页面,用于搜索,上线后,搜索关键字就可以搜到我们】
常用组件
# 参考地址:
https://developers.weixin.qq.com/miniprogram/dev/component/
text,类似于span
<text>Justin</text>
view,类似于div
<view>
<view>Python山顶会</view>
<view>Justin</view>
<view>微信:616564099</view>
</view>
image,类似于img标签
<image src="/images/1.png" style="width: 750rpx;height: 400rpx;"></image>
icon
<icon type="success" size='198rpx' color="red"/>
<icon type="download" size='198rpx' color="#ddd"/>
success, success_no_circle, info, warn, waiting, cancel, download, search, clear
跳转,类似于a标签
<navigator class="menu" url="/pages/login/login">
<label class="fa fa-superpowers" style="color:#32CD32"></label>
<view>登录</view>
</navigator>
绑定事件,在js中跳转:
<view bindtap="clickMe" data-nid="123" >点我跳转</view>
Page({
clickMe:function(e){
var nid = e.currentTarget.dataset.nid;
console.log(nid);
wx.navigateTo({
url: '/pages/login/login'
})
}
})
跳转到其他页面之后,可以在onLoad中获取参数
wx.navigateTo({
url: '/pages/login/login?name=justin'
})
Page({
onLoad: function (options) {
console.log(options);
}
})
尺寸单位 和样式
- rpx 可以根据不同的手机屏幕进行自动调整,自适应缩放
- 无论什么手机--》屏幕宽度都是 750rpx
- 局部样式: xxx.wxss
- 全局样式: app.wxss
tabbar配置
"tabBar": {
"selectedColor": "#b4282d",
# 放置位置只有两个,top:顶部;bottom:底部
"position": "bottom",
# list是数组,里面的tabbar至少2个至多5个
"list": [
{
# 页面的路径
"pagePath": "pages/index/index",
# 文字的内容
"text": "首页",
# 默认图标路径
"iconPath": "images/home.png",
#选中的图标路径
"selectedIconPath": "images/home_select.png"
},
...
]
},
实现轮播图 swiper+swiper-item
<swiper
autoplay
interval="2000"
indicator-dots
indicator-color="#00FF00"
indicator-active-color="#70DB93"
circular
>
<swiper-item>
<image src="/images/banner1.jpg" mode="widthFix"/>
</swiper-item>
<swiper-item>
<image src="/images/banner2.png" mode="widthFix"/>
</swiper-item>
<swiper-item>
<image src="/images/banner3.jpg" mode="widthFix"/>
</swiper-item>
</swiper>
引入矢量图标库
# 1 搜索想要的图标
-加入购物车
-在购物车中添加至项目
# 2 我的项目--项目设置--》打开base64
# 3 选择font class --》生成代码--》点击链接地址打开
# 4 把打开的链接地址内容复制到项目中
-static/css/iconfont.wxss
# 5 在app.wxss中引入
@import "/static/css/iconfont.wxss";
# 6 在想用图标的位置,加入text组件
<text class="iconfont icon-anquan">
事件绑定
- bind:tab bindtab
# 1 方式一
<view bind:tab="showLog"></view>
# 2 方式二
<view bindtab="showLog"></view>
# 3 js中写方法
showLog(){
console.log("我被点了")
}
阻止事件冒泡
catch:tap
<view style="height:300rpx;display: flex;justify-content: center;align-items: center; background-color: orange;" bind:tap="handleView">
<button type="primary" plain catch:tap="handleButton">阻止事件冒泡</button>
</view>
handleView() {
console.log("view被点了")
},
handleButton() {
console.log("button被点了")
},
事件对象和传参
data-*方案
mark:自定义属性
target :事件触发者 :dataset data定义的属性
currentTarget:事件绑定者 :dataset data定义的属性
页面跳转
- 使用 navigator 组件实现跳转
open-type :跳转方式
navigate:保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面redirect: 关闭当前页面,跳转到应用内的某个页面。但不能跳转到 tabbar 页面
switchTab:跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
reLaunch:关闭所有页面,打开到应用内的某个页面
navigateBack:关闭当前页面,返回上一页面或多级页面
wxml语法
# 1 在页面 xx.js 的 Page() 方法的 data 对象中进行声明定义
# 2 在xx.wxml 中使用 {{}} 包裹,显示数据
# 3 可以显示如下,不能编写js语句或js方法
-变量
-算数运算
-三元运算
-逻辑判断
# 4 只是单纯通过赋值,js中变量会变化,但是wxml中的页面不会变化,没有联动效果,需要使用setData()方法修改
setData案例 修改对象
data: {
name: 'justin',
age: 19,
userinfo: {
name: 'qcc',
age: 99
}
},
handleChangeName() {
// 增加数据
this.setData({
'userinfo.hobby': '篮球'
})
// 修改数据
this.setData({
'userinfo.name': '彭于晏'
})
// 修改多个数据--》简便方案--》展开运算符
// const userinfo = {
// ...this.data.userinfo,
// name: '新名字',
// hobby: '乒乓球'
// }
// this.setData({
// // userinfo:userinfo
// userinfo //简写形式
// })
// 修改多个数据--》简便方案-->assign
const userinfo = Object.assign(this.data.userinfo, {
name: 'xxzz',
hobby: 'aa'
})
this.setData({
// userinfo:userinfo
userinfo //简写形式
})
//删除数据-->单个
delete this.data.userinfo.name // 页面删除不了,需要用setData更新
this.setData({
userinfo:this.data.userinfo
})
//删除数据-->多个--解构赋值
const {name,age,...res}=this.data.userinfo
this.setData({
userinfo:res
})
},
setData 修改数组
data: {
names:['刘亦菲','迪丽热巴','古力娜扎','马尔扎哈']
},
handleChangeList(){
//1 增加再设置值
this.data.names.push('xxx')
this.setData({
names:this.data.names
})
// 1.2 通过数组拼接
const newList=this.data.names.concat("aaa")
this.setData({
names:newList
})
// 1.3 通过解构赋值
const newList=[...this.data.names,"李白"]
this.setData({
names:newList
})
// 2 修改数组
this.setData({
'names[1]':'justin'
})
// 3 删除数组
this.data.names.slice(1)
this.setData({
names:this.data.names.slice(1)
})
},
双向数据绑定:input checkbox
<input type="text" model:value='{{name}}'/>
<checkbox model:checked="{{isCheck}}"/>
列表渲染
- 默认每个对象是item,默认每个下标是index
- wx:key 提升性能,不写会警告 可以用 index或 *this:代指item本身 要唯一
<view wx:for="{{List}}" wx:key="*this">
{{item}}</text> -->
</view>
修改wx:for-index wx:for-item
<view wx:for="{{List}}" wx:key="*this" wx:for-item="info">
<text>{{info}}</text>
</view>
条件渲染 wx:if wx:elif wx:else
<view>
<input type="text" model:value='{{score}}' style="border:orange solid 1rpx"/>
<view wx:if="{{score>=90&&score<=100}}">优秀</view>
<view wx:elif="{{score>=80&&score<90}}">良好</view>
<view wx:elif="{{score>=60&&score<80}}">及格</view>
<view wx:else>不及格</view>
</view>
发送网络请求
发送网络请求的域名,必须在微信公众平台配置
handleLoadData(){
wx.showLoading({
title: '加载中,稍后',
mask:true // 显示透明蒙层
})
wx.request({
url: 'http://192.168.71.100:5000',
method:'GET',
data:{},
header:{},
success:(res)=>{
wx.hideLoading()
console.log(res.data)
this.setData({
userinfo:res.data,
})
console.log(this.data.name)
},
fail:(err)=>{},
complete:(res)=>{}
})
},
loading提示框
# 显示
wx.showLoading({
title: '加载中,稍后',
mask:true // 显示透明蒙层
})
#关闭
wx.hideLoading()
对话框
模态对话框
##### wxml
<button type="default" size="mini" bind:tap="showModel">弹出模态框</button>
### js ###
showModel(){
wx.showModal({
title: '这是标题',
content: '这是内容部分~~',
complete: (res) => {
if (res.cancel) {
console.log('用户取消了')
}
if (res.confirm) {
console.log('用户确认了')
}
}
})
}
消息对话框
#### wxml
<button type="default" size="mini" bind:tap="showToast">弹出消息框</button>
### js
showToast(){
wx.showToast({
title: '恭喜您,秒杀成功',
icon:"success",
duration:2000
})
}
存储
#### wxml####
<button type="default" plain bind:tap="handleSave">存储数据</button>
<button type="primary" plain bind:tap="handleGet">获取数据</button>
<button type="default" plain bind:tap="handleDelete">删除数据</button>
<button type="primary" plain bind:tap="handleClear">清空数据</button>
###js### 同步####
handleSave() {
wx.setStorageSync('name', "justin")
wx.setStorageSync('userinfo', {name:'lqz',age:19})
},
handleGet() {
const name=wx.getStorageSync('name')
const userinfo=wx.getStorageSync('userinfo')
console.log(name)
console.log(userinfo)
},
handleDelete() {
wx.removeStorageSync('name')
},
handleClear() {
wx.clearStorageSync()
}
###js### 异步####
handleSave() {
wx.setStorage({
key:'name',
data:"justin"
})
wx.setStorage({
key:'userinfo',
data:{name:'lqz',age:19}
})
},
async handleGet() {
const name= await wx.getStorage({key:'name'})
const userinfo= await wx.getStorage({key:'userinfo'})
console.log(name)
console.log(userinfo)
},
handleDelete() {
wx.removeStorage({key:'name'})
},
handleClear() {
wx.clearStorage()
}
上拉下拉加载
方式一
###### js####
// index.js
Page({
data: {
page: 1,
goods: []
},
refresh(page) {
wx.showLoading({
title: '加载中',
mask: true
})
wx.request({
url: 'http://127.0.0.1:8000/api/v1/course/actual/?page=' + page,
method: 'GET',
success: res => {
console.log(res.data.code == 100);
if (page == 1) {
this.setData({
goods: res.data.results
})
} else {
const resData = this.data.goods.concat(res.data.results)
this.setData({
goods: resData
})
}
},
complete: () => {
wx.hideLoading()
}
})
},
onLoad() {
this.refresh(this.data.page)
},
onReachBottom() {
this.data.page++
console.log('上拉了');
},
onPullDownRefresh() {
this.data.page = 1
this.refresh(this.data.page)
if (this.data.goods.length == 3) {
wx.stopPullDownRefresh()
}
}
})
####wxml#####
<view wx:for="{{goods}}" wx:key="index">{{item.name}}</view>
### wxss###
view{
height: 400rpx;
display: flex;
justify-content: center;
align-items: center;
}
/* 奇数 */
view:nth-child(odd){
background-color: pink;
}
/* 偶数 */
view:nth-child(even){
background-color: green;
}
#### json####
{
"usingComponents": {},
"onReachBottomDistance": 50,
"enablePullDownRefresh": true,
"backgroundColor": "#efefef",
"backgroundTextStyle":"dark"
}
方式二 scroll-view
##### wxml####
<scroll-view
class="scroll"
scroll-y
lower-threshold="100"
bindscrolltolower="handleGetData"
refresher-enabled="true"
refresher-default-style="black"
refresher-background="#f0f0f0"
bindrefresherrefresh="handleReload"
refresher-triggered="{{isRefresh}}"
enable-back-to-top="true"
>
<view wx:for="{{goods}}" wx:key="index">{{item.name}}</view>
</scroll-view>
### wxss####
.scroll{
/* 100vh就是指元素的高度等于当前浏览器的视窗高度,即浏览器内部的可视区域的高度大小 */
height: 100vh;
background-color: grey;
}
view{
height: 400rpx;
display: flex;
justify-content: center;
align-items: center;
}
/* 奇数 */
view:nth-child(odd){
background-color: pink;
}
/* 偶数 */
view:nth-child(even){
background-color: green;
}
### js#####
// pages/my/my.js
Page({
data: {
page: 0,
goods: [],
isRefresh: false
},
refresh(page) {
wx.showLoading({
title: '加载中',
mask: true
})
wx.request({
url: 'http://127.0.0.1:8000/api/v1/course/actual/?page=' + page,
method: 'GET',
success: res => {
if (page == 1) {
this.setData({
goods: res.data.results
})
} else {
const resData = this.data.goods.concat(res.data.results)
this.setData({
goods: resData
})
}
},
complete: () => {
wx.hideLoading()
}
})
},
handleGetData() {
this.data.page++
console.log('上拉了')
this.refresh(this.data.page)
},
handleReload() {
console.log('下拉刷新了')
wx.showToast({
title: '下拉刷新',
})
this.data.page = 1
this.refresh(this.data.page)
this.setData({
isRefresh: false
})
}
})
更新
强制更新
- 访问小程序,微信会将小程序代码包,下载到微信本地,打开使用
- 当小程序更新版本后,微信会检查小程序版本有没有更新,并下载最新小程序
- 更新方式:启动时同步更新,启动时异步更新
### 同步更新####
启动时同步更新:微信运行时,会定期检查最近使用的小程序是否有更新。如果有更新,下次小程序启动时会同步进行更新,更新到最新版本后再打开小程序。如果 用户长时间未使用小程序时,会强制同步检查版本更新
-如果更新失败,还是会使用本地版本
-新版本发布24小时后,基本会覆盖全部用户
### 异步更新####
启动时异步更新:在启动前没有发现更新,小程序每次 冷启动 时,都会异步检查是否有更新版本。如果发现有新版本,将会异步下载新版本的代码包,将新版本的小程序在下一次冷启动进行使用,当前访问使用的依然是本地的旧版本代码
## 强制更新###
在启动时异步更新的情况下,如果开发者希望立刻进行版本更新,可以使用 wx.getUpdateManager API 进行处理。在有新版本时提示用户重启小程序更新新版本
在app.js中加入
App({
// 生命周期函数,启动小程序就会执行
onLaunch(){
const update=wx.getUpdateManager()
update.onUpdateReady(function(){
wx.showModal({
title: '发现新版本',
content: '重启应用,更新版本新版本?',
success:(res)=>{
if(res.confirm){
update.applyUpdate()
}
}
})
})
}
})
生命周期
应用生命周期
// app.js
App({
/**
* 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
*/
onLaunch: function () {
console.log('小程序启动了')
},
/**
* 当小程序启动,或从后台进入前台显示,会触发 onShow
*/
onShow: function (options) {
console.log('后台切前台了')
},
/**
* 当小程序从前台进入后台,会触发 onHide
*/
onHide: function () {
console.log('进后台了')
},
})
页面生命周期
Page({
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log('1 页面加载了')
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
console.log('3 初次渲染完成')
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
console.log('2 页面显示')
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
console.log('4 页面隐藏')
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
console.log('5 页面卸载')
},
})
转发给朋友
方式一:通过右上方 ...
Page({
onShareAppMessage() {
return {
title:"是朋友就点一下",
query: 'name=justin&age=19',
imageUrl:'/images/b.jpg'
}
},
})
方式二:通过按钮, 需要给button设置 open-type="share"
####wxml####
<button open-type="share">转发</button>
####js####
onShareAppMessage() {
return {
title:"是朋友就点一下",
path:"/pages/my/my", //当前转发的页面
imageUrl:'/images/b.jpg'
}
},
分享到朋友圈
- 必须有分享给朋友
onShareTimeline(){
return {
title:"这是一个神奇的页面",
query:'name=justin&age=19',
imageUrl:'/images/b.jpg'
}
},
获取头像
#### js###
Page({
data:{
phono: '/static/img/b.jpg'
},
choosePhoto(event){
console.log(event.detail.avatarUrl)
this.setData({
phono:event.detail.avatarUrl
})
}
})
#####wxml###
<button class="btn" open-type="chooseAvatar" bindchooseavatar="choosePhoto">
<image src="{{phono}}" class="photo"/>
</button>
###wxss###
.btn{
/* 透明的 */
background-color: transparent;
}
/* 去掉边框 */
.btn::after{
border: none;
}
.photo{
height: 250rpx;
width: 250rpx;
border-radius: 50%;
}
获取昵称
### wxml###
<input type="nickname" placeholder="输入或获取昵称" model:value="{{username}}"/>
<button type="primary" plain bind:tap="showName">提交</button>
###js####
Page({
data:{
username:"",
},
showName(){
console.log(this.data.username)
}
})
###wxss##
input {
border: 1rpx solid pink;
border-radius: 10rpx;
padding: 10rpx;
margin: 10rpx;
}
手机号快速验证
# 步骤1:需要将 button 组件 open-type 的值设置为 getPhoneNumber,当用户点击并同意之后,通过 bindgetphonenumber 事件获取回调信息;
# 步骤2:将 bindgetphonenumber 事件回调中的动态令牌code传到开发者后台,并在开发者后台调用微信后台提供的 phonenumber.getPhoneNumber 接口,消费code来换取用户手机号。每个code有效期为5分钟,且只能消费一次。
# 步骤3:后端拿到code --》调用getuserphonenumber 换取手机号
https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-info/phone-number/getPhoneNumber.html
# 步骤4:去咱们自己用户表中查
-能查到---之前用过,注册了--》签发token
-查不到--》第一次用--执行注册--》签发token
手机号实时验证
# 步骤1:需要将 button 组件 open-type 的值设置为 getRealtimePhoneNumber,当用户点击并同意之后,通过 bindgetrealtimephonenumber 事件获取回调信息;
# 步骤2:将 bindgetrealtimephonenumber 事件回调中的动态令牌code传到开发者后台,并在开发者后台调用微信后台提供的 phonenumber.getPhoneNumber 接口,消费code来换取用户手机号。每个code有效期为5分钟,且只能消费一次
###wxml###
<button type="warn" open-type="getPhoneNumber"
bindgetphonenumber="getPhoneNumber">快速手机号</button>
<button type="default" plain open-type="getRealtimePhoneNumber"
bindgetrealtimephonenumber="getRealPhoneNumber"
>快速手机号</button>
###js###
getPhoneNumber(event) {
console.log(event)
// 通过获取手机号返回的code--传递给后端--后端调用:POST https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=ACCESS_TOKEN -->获取手机号--》后端签发token给前端
云调用
wx.request({
url: '我们后端地址',
method:'POST',
data:{
code:event.detail.code
},
success:(res)=>{
//在此返回登录信息,用户登录
}
})
},
getRealPhoneNumber(event) {
console.log(event)
}
客服功能
微信为小程序提供客服消息能力,以便小程序用户可以方便快捷地与小程序服务提供方进行沟通
https://developers.weixin.qq.com/miniprogram/introduction/custom.html
## wxml##
<button type="default" plain open-type="contact">联系客服</button>
vant-app
https://vant-ui.github.io/vant-weapp/#/home
使用npm包
- 项目根目录,打开终端【在内建终端打开】
npm init -y # 会生成package.json文件
- 安装vant
npm i @vant/weapp -S
# package.json 能看到下载完成,项目目录下有node_modules
#(可以使用cnpm:npm install -g cnpm --registry=https://registry.npm.taobao.org)
-
将 app.json 中的 "style": "v2" 去除,小程序的新版基础组件强行加上了许多样式,难以覆盖,不关闭将造成部分组件样式混乱
-
project.config.json 的settings中加入
"packNpmManually": true,
"packNpmRelationList": [
{
"packageJsonPath": "./package.json",
"miniprogramNpmDistDir": "./"
}
]
- 构建 工具---》构建npm