首先下载微信开发者工具Nightly Build
,该工具可以编译小程序代码,预览功能,真机调试等,话不多说,直奔主题!
打开微信开发者工具,新建一个小程序即可。
一,元素的使用
1,分析文件
app.json
,全局配置文件app.wxss
,全局样式文件
在app.json
文件中进行全局配置,大体配置如下
pages
中括号中的内容是页面路径,window
中的内容是对小程序最上面的内容进行设置,tabBar
是最下面的导航栏切换,iconPath
是点击之前的图标,selectedIconPath
是点击之后的图标。
注意:pagePath
的路径一定要和上面pages
中的路径保持一致。
{
"pages": [
"pages/mine/mine",
"pages/home/home",
"pages/index/index",
"pages/logs/logs"
],
"window": {
"backgroundTextStyle": "dark",
"navigationBarBackgroundColor": "#0094ff",
"navigationBarTitleText": "垃圾分类系统",
"navigationBarTextStyle": "white",
//开启全局下拉刷新功能
"enablePullDownRefresh":true
},
"tabBar": {
"list": [{
"pagePath": "pages/home/home",
"text": "首页",
"iconPath": "icon/定位.png",
"selectedIconPath": "icon/定位.png"
}, {
"pagePath": "pages/mine/mine",
"text": "我的",
"iconPath": "icon/垃圾桶.png",
"selectedIconPath": "icon/垃圾桶.png"
}]
},
"usingComponents": {},
"style": "v2",
"sitemapLocation": "sitemap.json"
}
2,如何快速新建页面?
直接在上面的全局配置文件app.json
的pages
中添加一个路径并保存,微信开发者工具会自动生成一套页面模板。
生成的一套页面中,home.js
写方法,home.json
文件写配置,home.wxml
文件写页面(元素),home.wxss
文件写样式。
3,行级元素text
和块级元素view
text
元素相当于html
的span
标签,属于行级元素,而view
元素相当于html
的div
标签,属于块级元素。
使用方法如下
哈哈 嘿嘿
你好 我不好
4,复选框checkbox
复选框
5,运算
{{1+1}}
{{'1'+'1'}}
{{10%2==0 ? '偶数' : '奇数'}}
6,列表循环
首先在js
文件的data
中写一个list
数组
/**
* 页面的初始数据
*/
data: {
msg:"微信小程序,你好!",
ischeck:false,
gender:"",
list:[
{
id:1,
name:"孙悟空"
},
{
id:2,
name:"唐僧"
}
],
obj: {
id:3,
name:"蜘蛛侠"
}
}
然后在wxml
文件中这样循环取值
索引:{{index}}
值:{{item.name}}
7,对象循环
首先在js
文件的data
中写一个对象
obj: {
id:3,
name:"蜘蛛侠"
}
然后在wxml
文件中这样循环取值
属性:{{key}}
值:{{value}}
8,数据绑定
在js
文件中初始化数据。
/**
* 页面的初始数据
*/
data: {
msg:"微信小程序,你好!",
ischeck:false,
gender:"",
---省略
在wxml
文件中绑定数据
{{msg}}
9,条件渲染if
,else
,elif
登录
已登录,退出
隐藏元素
哈哈
10,绑定事件
通过bindtap
进行绑定点击事件。
handleInput
:input改变触发bindtap
:点击触发
然后在js
文件中写触发事件
handleInput(e){
console.log(e.detail.value)
},
//触发事件弹出小弹框
login(){
wx.showToast({
title: '登录成功',
icon: 'succes',
duration: 1000,
mask:true
})
11,button
的开发能力
contact 直接打开客服对话功能 需要在微信小程序的后台配置
share 转发当前的小程序到微信朋友中
getPhoneNumber 获取当前用户的手机号码信息
绑定一个事件 bindgetphonenumber 回调函数中通过参数获取手机号(已被加密的,需到后台进行解密)
getUserInfo 获取当前用户的个人信息
绑定一个事件 bindgetuserinfo 回调函数中通过参数获取用户个人信息,没有加密
launchApp 在小程序中直接打开app
openSetting 打开小程序内置的授权页面
feedback 打开小程序内置的意见反馈页面
设置按钮的类型,可以触发上面各种情况。
重要:getPhoneNumber
获取当前用户的手机号码信息以及getUserInfo
获取当前用户的个人信息的使用方法很特殊,需要两个触发事件,如上,触发事件如下。
getPhone(e){
console.log(e)
},
getUser(e){
console.log(e.detail.userInfo.nickName)
},
12,单选框radio
现在实现一个效果,选择一个单选框,并把单选框的value
值设置到text
标签中进行显示。
bindchange
是触发单选的事件。
男
女
您选中的是{{gender}}
js
文件的方法
change(e){
console.log(e.detail.value);
const val=e.detail.value;
// 把值赋给data中的变量
this.setData({gender:val})
},
前提是数据要先在data
中进行初始化。
13,点击事件传递参数
首先 bindtap
绑定点击事件,
在标签中利用 data-xxx
来定义你要传入的参数,,
然后事件中传入event
用 event.currentTarget.dataset.xxx
来取你传入的值
14,搜索框input
回车搜索事件
在微信小程序里的搜索框,按软键盘回车键触发搜索事件。
bindconfirm
即为回车事件,为它绑定上需要触发的事件,search
是对应的搜索方法。
15,列表双重循环
使用场景:遍历朋友圈(包括每条朋友圈下面的评论列表)
//#################第一次循环,遍历朋友圈的全部说说列表####################
{{item.name}}
{{item.content}}
{{item.pingluncount}}
{{item.zan_num}}
评论
//###############第二次循环,对第一次循环的pinglunlist值再次进行二次循环,展示该说说的评论列表###############
{{items.name}} :{{items.content}}
二,组件的使用
1,轮播图swiper
这里提一点,微信小程序中的像素是 rpx,750rpx 是屏幕的宽, rpx是自适应的,也就是不管使用多大的手机,750rpx总是宽度 100%,其实 px 也可以用,但是不是自适应。
在微信小程序中的轮播图其实都已经被微信封装好了,直接使用swiper
标签即可,建议图片使用图床上的图片路径。
swiper高度是要计算的
原图高度 352px 原图宽度 1125px
swiper高度 / swiper宽度 = 原图高度 / 原图宽度
swiper高度=swiper宽度 * 原图高度 / 原图宽度
height: 100vw * 352 / 1125
autoplay 自动播放
circular 是否循环轮播 true/false
interval 切换时间间隔
indicator-dots true/false 面板指示点
这样,一个轮播图就出来了,但是图片的宽高和swiper
的宽高不一致,所以高度需要计算,计算方法如上。
因此在wxss
样式文件中写样式。
image{
width: 100%;
height: 100%;
}
swiper{
width: 100%;
height: calc(100vw * 352 / 1125);
}
2,跳转页面navigator
open-type 跳转的方式
1,navigate 默认值 保留当前页面,跳转到应用内的某个页面,但不能跳tabbar页面
2, redirect 关闭当前页面,跳转到应用内的某个页面,但不能跳tabbar页面
3,switchTab 跳转到TabBar页面,并关闭所有非tabbar页面
4,reLaunch 关闭所有页面,打开到应用内的某个页面
5,navigateBack 返回上一级页面,关闭当前页面
6,退出小程序
跳转页面
js
跳转页面并传值
下面是一个普通按钮触发事件,让它跳转页面并传值。
denglu(){
const index="测试参数";
wx.navigateTo({
url: '../logs/logs?params='+index
})
}
然后在logs.js
文件中接收参数
这里接收到参数之后,可以发起ajax
请求列表数据,在data
中初始化一个数组,然后把请求到的数据通过 this.setData
赋值给数组,然后在页面让元素进行遍历,显示数据。
//声明周期函数,监听页面加载
onLoad: function (options) {
console.log(options.params)
}
3,新建组件和页面引用组件的方式
组件的作用在于多页面复用,举个例子,下面蓝色区域可以抽出来一个组件,多页面公用一个头部。(原创,分类,关于导航栏, 切换不同页面,导航栏公用)
创建组件的方法,在微信开发者工具中右键新建component
,然后就创建出来了一套组件模板。
该组件名字就叫Tabs
。
比如home.wxml
页面要引用该组件,就在home.json
文件中配置组件。
{
"usingComponents": {
"Tabs":"../../components/Tabs/Tabs"
}
}
然后在home.wxml
最上面(因为要把组件放最上面啊)写组件标签引入组件。
这样该页面就有这个组件了。
4,写一个导航栏的组件
首先到Tabs.js
组件的js
文件中初始化导航栏信息
/**
* 组件的初始数据
*/
data: {
list:[
{
id:1,
name:"原创",
isActive:true
},
{
id:2,
name:"分类",
isActive:false
},
{
id:3,
name:"关于",
isActive:false
}
]
},
然后在Tabs.wxml
文件中遍历循环取值。
bindtap="handle" 绑定点击事件
{{item.name}}
{{aaa}}
Tabs.wxss
样式
.tabs_title{
display: flex;
padding: 10rpx;
}
.tabs_item{
flex: 1;
display: flex;
/* 文字左右对齐 */
justify-content: center;
/* 上下对齐 */
align-items: center;
}
/*点击之后的样式*/
.hover{
border-bottom: 5rpx solid red;
}
然后动态切换导航栏组件,更改对应的样式(下边框变红)
在组件中的事件方法一定要写在组件js
文件的methods
里面。
methods: {
handle(e){
console.log(e)
//获取索引
const index=e.currentTarget.dataset.index;
//获取data数组
let list=this.data.list;
//循环数组并设置值
list.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);
this.setData(
{list}
)
}
}
5,父组件向子组件传值
父组件,也就是页面,子组件就是使用的组件了。
现在,是home.wxml
页面使用Tabs
组件,那么home.wxml
页面怎么把一个值传给Tabs
组件呢?
首先,在父组件(页面)的组件标签中添加一个自定义属性
然后在组件的Tabs.js
文件中接收参数值
/**
* 组件的属性列表
* 接收父组件的传值
*/
properties: {
aaa:{
type:String, //参数数据类型
value:"" //默认值
}
},
然后在组件的Tabs.wxml
中写标签绑定数据(取数据)
{{aaa}}
6,子向父传递数据
在组件的元素中绑定点击事件,并给父组件(页面)传递参数。
这里就还说上面的导航栏的组件吧。
上面的组件是遍历出来的,现在实现点击每个导航按钮,传递index
索引值给父组件(页面)
{{item.name}}
触发方法,在组件的js
中
/**
* 组件的方法列表
*/
methods: {
handle(e){
// console.log(e)
//获取被点击导航按钮的索引
const index=e.currentTarget.dataset.index;
this.triggerEvent("methodName",index);
}
this.triggerEvent("methodName",index);
然后在父组件的wxml
页面的组件标签中绑定事件
不是bindmethodName
事件,而是bind
拼接上methodName
,然后在页面的js
文件写bindmethodName
事件方法。
bindmethodName(e){
console.log(e.detail)
}
控制台就打印出了传递过来的索引值了。
7,导航栏切换页面slot
标签
在上面写好的组件中加入slot
标签,这个标签编译后不会显示出来,会被替换掉。
{{item.name}}
这里就利用上面 子向父传递数据 的索引了,页面拿到组件传过来的索引值,然后进行判断赋值。
首先在页面的js
文件初始化三个boolean
类型。
index1:true,
index2:false,
index3:false,
然后在页面js
的获取索引的方法中判断赋值
bindmethodName(e){
console.log(e.detail);
const dex=e.detail;
if(dex==0){
this.setData({index1:true,index2:false,index3:false})
}else if(dex==1){
this.setData({index1:false,index2:true,index3:false})
}else if(dex==2){
this.setData({index1:false,index2:false,index3:true})
}
},
然后回到页面的home.wxml
文件的组件标签里面,添加几个block
标签(你有几个导航分类就添加几个block
标签)
使用条件渲染,切换效果就完成了。
在block
标签中再写自己想要展示的页面即可。
1
2
3
8,页面生命周期函数
/**
* 生命周期函数--监听页面加载
*/
onLoad: function () {},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {}
三,前后端分离
1,微信小程序的ajax
前端就是微信小程序的前端页面,后端则是springboot
项目,为微信小程序提供接口,springboot
使用idea
快速构建,过程就不说了,springboot
项目搭建起来之后前后端就可以连通了。
下面是我的springboot
项目的一个测试方法
@Controller
@RequestMapping("/test")
public class TestController {
@RequestMapping("/one")
@ResponseBody
public User one(){
User user=new User();
user.setId("18838030468");
user.setName("樊江锋");
user.setAge(24);
return user;
}
}
现在测试在微信小程序页面发起请求这个接口并拿到响应数据并回显在页面上。
mine.wxml
页面
{{obj.id}}
{{obj.name}}
{{obj.age}}
mine.js
文件写方法
首先把obj
对象初始化
/**
* 页面的初始数据
*/
data: {
obj:''
},
ask(e){
//必须赋值,否则会报错
var th=this;
console.log("发出请求")
wx.request({
url: 'http://localhost:8088/test/one',
method:'POST',
success(data){
console.log(data.data)
//把拿到的对象数据赋给obj
th.setData({
obj:data.data
})
}
})
},
然后obj
在页面进行回显(数据绑定嘛)
前提:在微信开发者工具要把请求放开,否则不行!
把这个勾选上就行了!
2,表单提交form
首先在微信小程序写一个表单,bindsubmit
是绑定一个提交表单的事件。
在js
文件中添加表单提交事件的方法
formsubmit(e){
console.log(e)
const phone=e.detail.value.phone;
const address=e.detail.value.address;
wx:wx.request({
url: 'http://localhost:8088/test/one',
data: {'phone':phone,'address':address},
dataType: 'json',
method: 'GET',
success(data){
console.log(data)
}
})
},
会把参数传到后端接口(springboot
项目),然后就正常操作。
后端接口
@Controller
@RequestMapping("/test")
public class TestController {
@RequestMapping("/one")
@ResponseBody
public User one(@RequestParam("phone") String phone, @RequestParam("address") String address){
System.out.println("手机号:"+phone+" 地址:"+address);
User user=new User();
user.setId("18838030468");
user.setName("樊江锋");
user.setAge(24);
return user;
}
}
后端控制台打印
手机号:18838030468 地址:河南郑州
3,js
获取input
框的值
现在写一个不使用表单提交的方式来登录。
给input
框绑定bindinput
事件,该事件是每次输入input
框,都可以监听到内容。
手机号:
地址:
然后在js
文件中初始化数据
/**
* 页面的初始数据
*/
data: {
phone:'',
address:''
}
然后写给input
框绑定的bindinput
事件来获取手机号值和地址值。
//获取手机号
getValue(e){
const phone=e.detail.value;
this.setData({
phone:phone
})
},
//获取地址
getAddress(e){
const address=e.detail.value;
this.setData({
address:address
})
},
//登录事件
denglu(){
console.log(this.data.phone+"#####"+this.data.address)
},
前台打印
4,使用缓存技术
在页面的js
文件中,页面一加载就执行的方法中使用缓存技术,如果请求的数据量很大,很影响用户体验。
onLoad: function () {
//去缓存拿存储的数据(键值对形式)
const data=wx.getStorageSync('catch');
this.setData({
swiperList:data
})
//如果缓存数据为空,发送新的请求并把数据存储到缓存中
if(!data){
console.log("发出请求了")
wx:wx.request({
url: 'https://api.zbztb.cn/api/public/v1/home/swiperdata',
success: (result) => {
this.setData({
swiperList:result.data.message,
//赋给初始化的缓存
Catch:result.data.message
})
//存入本地存储
wx.setStorageSync("catch",{time:Date.now(),data:this.Catch});
}
})
}
5,页面发送请求渲染页面显示加载中
微信小程序内置了加载中的效果。
wx.showLoading ({}) 调出加载中
wx.hideLoading () 隐藏加载中效果
onLoad: function () {
wx.showLoading({
title: '加载中',
})
wx:wx.request({
url: 'https://api.zbztb.cn/api/public/v1/home/catitems',
success: (result) => {
console.log(result)
this.setData({
daohang:result.data.message
})
wx.hideLoading();
}
})
6,小程序登录功能
微信进入小程序时要进行授权登录,然后才能获取到用户的个人信息,才可以使用小程序。
这里使用缓存实现小程序登录。
首先新建一套login
登录页面,然后在login.wxml
写一个登录按钮,点击按钮触发login.js
的方法。
在login.json
文件中添加一个标题!
{
"usingComponents": {},
"navigationBarTitleText": "登录"
}
按钮
open-type="getUserInfo" 是点击按钮获取个人信息,bindgetuserinfo是绑定的一个事件。
方法
bindgetuserinfo(e){
console.log(e)
//拿到用户信息
const userInfo=e.detail.userInfo;
//把用户信息放入缓存
wx:wx.setStorageSync('userInfo', userInfo);
//返回上一层页面
wx:wx.navigateBack({
delta: 1
})
},
然后登录页面就写好了,因为小程序默认会进入首页,因此在首页进行判断是否登录
首先在index.js
的data
初始化一个isLogin:false
标志未登录状态。
在index.js
的onLoad
方法中进行判断
//页面加载就执行的函数
onLoad: function () {
//判断是否登录(从缓存中获取用户信息)
const userInfo=wx.getStorageSync('userInfo');
//如果用户信息为空
if(userInfo!=null && userInfo!=''){
console.log("已登录状态")
this.setData({
//登录状态设置为true
isLogin:true
})
}else{
console.log("该账号未登录")
this.setData({
//登录状态设置为false
isLogin:false
})
}
这就简单了,使用条件渲染对index.wxml
的内容进行渲染。
登录
跳转到登录页面登录之后,会navigateBack
返回上一层页面,这时页面是不会自动刷新的,还需要最后一个操作:上一层页面(首页嘛)页面刷新,展示登录之后的内容。
在index.js
中添加方法
//页面被看见就执行的方法
onShow(){
this.onLoad()
}
登录完成,不过这样实现有一个BUG
不可避免,就是每个页面都需要上面的操作,因此并不完美,后续在完善吧!
后续补充:上面的登录只是假象,真正登录操作如下:
首先,微信小程序前台点击登录按钮之后,触发登录方法
bindgetuserinfo(e){
//取用户信息,如果登录成功,把用户信息存入缓存
const userInfo=e.detail.userInfo;
wx.login({
success: res => {
//res.code拿到code值
// 发送 res.code 到后台换取 openId, sessionKey, unionId
if (res.code) {
wx.request({
url: 'http://localhost:8080/weixin/getOpenId',
method: 'POST',
data: {
code: res.code
},
header: {
'content-type': 'application/x-www-form-urlencoded'
},
success(res) {
console.log("openid:"+res.data.openid);
wx:wx.setStorageSync('userInfo', userInfo);
if (res.data.openid != "" || res.data.openid!=null){
// 登录成功
wx.setStorageSync("openid", res.data.openid);//将用户id保存到缓存中
wx.setStorageSync("session_key", res.data.session_key);//将session_key保存到缓存中
wx:wx.navigateBack({
delta: 1
})
}else{
// 登录失败
// TODO 跳转到错误页面,要求用户重试
return false;
}
}
})
} else {
console.log('获取用户登录态失败!' + res.errMsg)
}
}
})
},
前台把code
传到后台,后台通过code
、appID
、appSecret
请求微信接口,换取得到用户唯一标识open_id
。
appid
和appsecret
要到微信公众平台的开发模块中进行获取,然后微信开发者工具也要配置appid
,不能再使用测试号了。请求微信接口使用HttpClient
请求。
@RestController
@RequestMapping("/weixin")
public class WxController {
//微信code换取open_id
private String appID = "wxb44d77c8ddc418c6";
private String appSecret = "5fd925d791680d3444b96db6c7c9da32";
@RequestMapping("/getOpenId")
@JsonIgnoreProperties(ignoreUnknown = true)
public String getOpenId(@RequestParam("code") String code) throws JsonProcessingException {
String result = "";
try{
//请求微信服务器,用code换取openid。HttpUtil是工具类,后面会给出实现,Configure类是小程序配置信息,后面会给出代码
String url="https://api.weixin.qq.com/sns/jscode2session?appid="
+ "wxb44d77c8ddc418c6" + "&secret="
+ "5fd925d791680d3444b96db6c7c9da32" + "&js_code="
+ code
+ "&grant_type=authorization_code";
RequestConfig rc = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).build();
CloseableHttpClient httpclient = HttpClients.createDefault();
if(url!=null){
try {
// 创建HttpGet对象,将URL通过构造方法传入HttpGet对象
HttpGet httpGet=new HttpGet(url);
// 将配置好请求信息附加到http请求中
httpGet.setConfig(rc);
// 执行DefaultHttpClient对象的execute方法发送GET请求,通过CloseableHttpResponse接口的实例,可以获取服务器返回的信息
CloseableHttpResponse response = httpclient.execute(httpGet);
try {
// 得到返回对象
HttpEntity entity = response.getEntity();
if(entity!=null){
// 获取返回结果
result = EntityUtils.toString(entity);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
// 关闭到客户端的连接
response.close();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
// 关闭http请求
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
catch (Exception e) {
e.printStackTrace();
}
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
OpenIdJson openIdJson = mapper.readValue(result, OpenIdJson.class);
System.out.println(result.toString());
String tenderId = openIdJson.getOpenid();
login(tenderId);
return result;
}
@Autowired
WxMapper wxMapper;
//查询小程序登录用户信息进行登录
private void login(String tenderId){
Map map = wxMapper.selectWxuser(tenderId);
if(map!=null){
}else{
wxMapper.insertWxuser(tenderId);
}
}
}
7,授权获取地理位置信息
wx:wx.chooseLocation({
success: (result) => {
console.log(result)
}
})
上面只是获取地理位置信息的操作,真机调试下,如果不授权使用地理位置,则地理位置是获取不了的。
点击获取地理位置按钮,先授权,授权之后才能获取地理位置信息。
如果拒绝授权之后就再也不会弹出授权框了!
获取地理位置
locations(e){
//进行授权(就是弹框允许授权位置信息)
wx.authorize({
scope: 'scope.userLocation',
//授权成功的操作
success: (res) => {
console.log('成功:' , res)
//再获取地理位置信息
wx:wx.chooseLocation({
success: (result) => {
console.log(result)
const location=result.address;
this.setData({
locations:location,
isShowLocation:true
})
}
})
},
//授权失败的操作
fail: (res) => {
console.log('失败:', res)
},
})