@langlibaitiao
2017-07-06T14:24:57.000000Z
字数 15643
阅读 1013
小程序
一 获取小程序的AppId
1 注册微信公众平台账号,登录:https://mp.weixin.qq.com,就可以在网站的“设置”-“开发者设置”中,查看到微信小程序的 AppID 。
注意:如果要以非管理员微信号在手机上体验该小程序,那么我们还需要操作“绑定开发者”。即在“用户身份”-“开发者”模块,绑定上需要体验该小程序的微信号。本文档默认注册帐号、体验都是使用管理员微信号。
二 微信开发者工具
1 我们需要通过开发者工具,来完成小程序创建和代码编辑。开发者工具集成了开发调试、代码编辑及程序发布等功能。
链接:开发者工具下载地址
三 创建项目
1 开发者工具安装完成后:
(1) 打开并使用微信扫码登录,
(2) 选择创建“项目”,填入上文获取到的AppID,
(3) 设置一个本地项目的名称(非小程序名称),比如“小程序demo”,并选择一个本地的文件夹作为代码存储的目录,
(4) 点击“新建项目”就可以了。
2 在创建过程中:
如果选择的本地文件夹是个空文件夹,开发者工具会提示,是否需要创建一个 quick start 项目。选择“是”,开发者工具会帮助我们在开发目录里生成一个简单的 demo。其中初始化了文件结构并包含了一些简单的文件。
3 项目创建成功后:
我们就可以点击该项目,进入并看到完整的开发者工具界面,点击左侧导航,在“编辑”里可以查看和编辑我们的代码,在“调试”里可以测试代码并模拟小程序在微信客户端效果,在“项目”里可以发送到手机里预览实际效果。
四 小程序文件目录结构介绍
在项目中我们可以看到四种文件类型:
(1) .js后缀的文件是脚本文件,页面的交互等代码在这里实现;
(2) .json后缀的文件是配置文件,主要是json数据格式存放,用于设置程序的配置效果;
(3) .wxss后缀的是样式表文件,类似于前端中的css,用于对界面进行美化;
(4) .wxml后缀的文件是页面结构文件,用于构建页面,在页面上增加控件。
1 该文件主要存放小程序的页面文件
2 注意:
(1) 小程序每个页面必须有.wxml和.js文件,其他两种类型的文件可以不需要。
(2) 文件名称必须与页面的文件夹名称相同,如index文件夹,文件只能是index.wxml、index.wxss、index.js和index.json.
(1) 该文件夹主要用于存放全局的一些.js文件,公共用到的一些事件处理代码文件可以放到该文件夹下,用于全局调用。
(2) 对于允许外部调用的方法,用module.exports进行声明,才能在其他js文件中用一下代码引入
function formatTime(date) {
var year = date.getFullYear()
var month = date.getMonth() + 1
var day = date.getDate()
var hour = date.getHours()
var minute = date.getMinutes()
var second = date.getSeconds()
return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}
function formatNumber(n) {
n = n.toString()
return n[1] ? n : '0' + n
}
//发送请求 post方式
var rootDocment = 'https://api.orangelife.com.cn/'; //正式
// var rootDocment = 'http://eastapi.swao.cn/'; //测试
function req(url, data, cb) {
wx.request({
url: rootDocment + url,
data: data,
method: 'POST',
header: { 'Content-Type': 'application/json' },
success: function (res) {
console.log(res)
return typeof cb == "function" && cb(res.data)
},
fail: function () {
return typeof cb == "function" && cb(false)
}
})
}
//发送请求 get方式
function getReq(url, data, cb) {
wx.request({
url: rootDocment + url,
data: data,
method: 'GET',
header: { 'Content-Type': 'application/x-www-form-urlencoded' },
success: function (res) {
return typeof cb == "function" && cb(res.data)
},
fail: function () {
return typeof cb == "function" && cb(false)
}
})
}
// 去前后空格
function trim(str) {
return str.replace(/(^\s*)|(\s*$)/g, "");
}
// 提示错误信息
function isError(msg, that) {
that.setData({
showTopTips: true,
errorMsg: msg
})
}
// 清空错误信息
function clearError(that) {
that.setData({
showTopTips: false,
errorMsg: ""
})
}
//上传文件
function uploadFile(url, filePath, name, formData, cb) {
console.log('a=' + filePath, formData)
wx.uploadFile({
url: rootDocment + url,
filePath: filePath,
name: name,
header: {
'content-type': 'multipart/form-data'
}, // 设置请求的 header
formData: formData, // HTTP 请求中其他额外的 form data
success: function (res) {
console.log(res)
console.log(res.head_image)
if (res.statusCode == 200 && !res.data.result_code) {
return typeof cb == "function" && cb(res.head_image)
} else {
return typeof cb == "function" && cb(false)
}
},
fail: function () {
return typeof cb == "function" && cb(false)
}
})
}
//用module.exports对外暴露接口
module.exports = {
formatTime: formatTime,
req: req,
getReq: getReq,
trim: trim,
isError: isError,
clearError: clearError,
uploadFile: uploadFile
}
//在需要使用这些模块的文件中,使用 require(path) 将公共代码引入
var util = require('../../utils/util.js')
4.1 app.js :
1 小程序的脚本代码
我们可以在这个文件中监听并处理小程序的生命周期函数、声明全局变量。调用框架提供的丰富的 API,想了解更多可用 API,可参考 [API文档]
2 小程序注册
App() 函数用来注册一个小程序。接受一个 object 参数,其指定小程序的生命周期函数等。
//app.js
App({
onLaunch: function () {
//调用API从本地缓存中获取数据
var logs = wx.getStorageSync('logs') || []
logs.unshift(Date.now())
wx.setStorageSync('logs', logs)
},
getUserInfo:function(cb){
var that = this
if(this.globalData.userInfo){
typeof cb == "function" && cb(this.globalData.userInfo)
}else{
//调用登录接口
wx.login({
success: function () {
wx.getUserInfo({
success: function (res) {
that.globalData.userInfo = res.userInfo
typeof cb == "function" && cb(that.globalData.userInfo)
}
})
}
})
}
},
//全局参数,可以在其他页面通过接口获取到,全局使用的参数可以在这里进行声明
globalData:{
userInfo:null
}
})
//全局参数可以在其他页面通过下面方法获取到
var app = getApp();
console.log(app. globalData);
4.2 app.json :
是对整个小程序的全局配置。我们可以在这个文件中配置小程序是由哪些页面组成,配置小程序的窗口背景色,配置导航条样式,配置默认标题。注意该文件不可添加任何注释。更多可配置项可参考[配置详解]
部分配置解释:
(1) 此处tabBar下的list为底部列表栏配置;注意:tabBar如果设置,最少要两个,最多不能超过五个。
(2) networkTimeout和debug可以设置各种网络请求的超时时间
(3) debug:可以在开发者工具中开启debug模式,在开发者工具的控制台面板,调用信息以info的形式给出,其信息有page注册、页面路由、数据更新和时间触发,可以帮开发者快速定位一些常见信息。
/**app.json**/
{
"pages": [
"pages/index/index",
"pages/mall/list/list",
"pages/login/login",
"pages/user/user",
"pages/mall/detail/detail",
"pages/location/location"
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "pink",
"navigationBarTitleText": "智橙生活",
"navigationBarTextStyle": "black"
},
"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "images/tabBar/index.png",
"selectedIconPath": "images/tabBar/index-select.png"
},
{
"pagePath": "pages/mall/list/list",
"text": "商城",
"iconPath": "images/tabBar/market.png",
"selectedIconPath": "images/tabBar/market-select.png"
},
{
"pagePath": "pages/user/user",
"text": "个人中心",
"iconPath": "images/tabBar/setting.png",
"selectedIconPath": "images/tabBar/setting-select.png"
}
],
"color": "#000",
"backgroundColor": "pink",
"selectedColor": "#f60",
"borderStyle": "#ccc"
},
"networkTimeout": {
"request": 20000,
"connectSocket": 20000,
"uploadFile": 20000,
"downloadFile": 20000
},
"debug": true
}
4.3 app.wxss :
全局的界面美化代码
/**app.wxss**/
@import "dist/style/weui.wxss";
.container {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 200rpx 0;
box-sizing: border-box;
}
1 注册一个页面
// detail.js
var app = getApp();
var util = require('../../../utils/util.js');
Page({//页面数据配置
data: {
msgDetail: {},
imgUrls:[],
autoplay: true,
indicatorDots: true,
interval: 4000,
duration: 1000
},
onLoad: function (options) {
console.log(options)
var that = this;
util.req('mall/getItemDetailV4', {//请求接口
// id: options.id
itemId: options.itemId,
activityId: options.activityId
}, function (res) {
that.setData({// 改变信息
msgDetail: res.data.itemDetail,
imgUrls: res.data.itemDetail.pics
})
});
},
onReady: function () {
// 页面渲染完成
},
onShow: function () {
// 页面显示
},
onHide: function () {
// 页面隐藏
},
onUnload: function () {
// 页面关闭
}
})
Page({}),注册一个页面,中间的代码为声明周期函数,可以不实现,但是Page({})结构必须创建。
注意:只有在data中声明的数据才能够正常使用
五 本demo中的一些方法与属性
整个系统分为两块视图层(View)和逻辑层(App Service)
框架可以让数据与视图非常简单地保持同步。当做数据修改的时候,只需要在逻辑层修改数据,视图层就会做相应的更新。
通过这个简单的例子来看:
index.wxml文件下:
<!--index.wxml-->
<view class="container">
<view bindtap="bindViewTap" class="userinfo">
<image class="userinfo-avatar" src="{{userInfo.avatarUrl}}" background-size="cover"></image>
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
</view>
<view class="usermotto">
<text class="user-motto">{{motto}}</text>
</view>
<button bindtap="changeName">{{clickData}}</button>
</view>
index.js文件如下:
//index.js
//获取应用实例
var app = getApp()
Page({
data: {
motto: '综合服务生活平台',
clickData: '点我试试',
userInfo: {}
},
changeName: function (e) {
this.setData({
motto: "智橙生活",
clickData: '试试就试试',
})
},
onLoad: function () {
var that = this
//调用应用实例的方法获取全局数据
app.getUserInfo(function(userInfo){
//更新数据
that.setData({
userInfo:userInfo
})
})
}
})
开发者通过框架将逻辑层数据中的 moto 与视图层的 moto 进行了绑定,所以在页面一打开的时候会显示 点我试试
当点击按钮的时候,视图层会发送 changeName 的事件给逻辑层,逻辑层找到对应的事件处理函数
逻辑层执行了 setData 的操作,将 moto 从 点我试试 变为 试试就试试,因为该数据和视图层已经绑定了,从而视图层会自动改变为 试试就试试。
路由:页面跳转
调用 API wx.navigateTo 或使用组件 < navigator open-type="navigateTo" />
(1) 上拉加载,下拉刷新, 分页
// 下拉刷新数据
pullDownRefresh: function () {
var that = this;
pageNum = 0;
//tab0
var objBuy0 = that.data.isBuying;
objBuy0.msgList = [];
//tab1
var objBuy1 = that.data.isBuying;
objBuy1.msgList = [];
that.setData({
isBuying: objBuy0,
futureBuying: objBuy1,
scrollTop: 0
});
loadMsgData0(that);
},
// 上拉加载数据
pullUpLoad: function () {
var that = this;
if (!that.data.isLastPage) {
loadMsgData0(that);
}
},
(2) 页面跳转
调用 API wx.navigateTo 或使用组件 <navigator open-type="navigateTo"/>
pages/mall/list/list.js
var util = require('../../../utils/util.js');
var app = getApp();
// 加载数据
var loadMsgData0 = function (that) {
//初始化隐藏列表
var objBuy0 = that.data.isBuying;
objBuy0.hidden = false;
that.setData({
isBuying: objBuy0
});
var allMsg = objBuy0.msgList;
util.req('mall/getPanicBuyItemList', {
"index": objBuy0.pageNum,
"size": objBuy0.pageSize,
"flag": "current"
}, function (res) {
//生成新的商品信息数组
allMsg = allMsg.concat(res.page.content);
objBuy0.hidden = true,
objBuy0.msgList = allMsg,
objBuy0.isLastPage = res.page.last,
that.setData({
isBuying: objBuy0
});
objBuy0.pageNum++;
if (!!res.page.last){
objBuy0.nomore = false;
that.setData({
isBuying: objBuy0
});
}
});
};
var loadMsgData1 = function(that){
//初始化隐藏列表
var objBuy1 = that.data.futureBuying;
objBuy1.hidden = false;
that.setData({
futureBuying: objBuy1
});
var allMsg = objBuy1.msgList;
util.req('squareDance/getSquareDanceVideoPage', {
"index": objBuy1.pageNum,
"size": objBuy1.pageSize
}, function (res) {
console.log(res)
//生成新的商品信息数组
allMsg = allMsg.concat(res.content);
objBuy1.hidden = true,
objBuy1.msgList = allMsg,
objBuy1.isLastPage = res.last,
that.setData({
futureBuying: objBuy1
});
objBuy1.pageNum++;
if (!!res.last) {
objBuy1.nomore = false;
that.setData({
futureBuying: objBuy1
});
}
});
};
var loadMsgData2 = function (that) {
//初始化隐藏列表
var objBuy2 = that.data.futureBuying1;
objBuy2.hidden = false;
that.setData({
futureBuying1: objBuy2
});
var allMsg = objBuy2.msgList;
util.req('mall/getPanicBuyItemList', {
"index": objBuy2.pageNum,
"size": objBuy2.pageSize,
"flag": "wait"
}, function (res) {
//生成新的商品信息数组
allMsg = allMsg.concat(res.page.content);
objBuy2.hidden = true,
objBuy2.msgList = allMsg,
objBuy2.isLastPage = res.page.last,
that.setData({
futureBuying1: objBuy2
});
objBuy2.pageNum++;
if (!!res.page.last) {
objBuy2.nomore = false;
that.setData({
futureBuying1: objBuy2
});
}
});
};
//页面数据配置
Page({
data: {
scrollTop: 0,
scrollHeight: 0,
//tab栏的下标
pageTab: {
curHdIndex: 0,
curBdIndex: 0
},
isBuying: {
hidden: true,
isLastPage: false,
nomore: true,
pageNum: 0,
pageSize: 7,
msgList: []
},
futureBuying: {
hidden: true,
isLastPage: false,
nomore: true,
pageNum: 0,
pageSize: 7,
msgList: []
},
futureBuying1: {
hidden: true,
isLastPage: false,
nomore: true,
pageNum: 0,
pageSize: 7,
msgList: []
}
},
pageHdtap: function (e) {
var that = this;
console.log(e)
//点击子元素
var _datasetId = e.target.dataset.id;
var _leftObj = {};
_leftObj.curHdIndex = _datasetId;
_leftObj.curBdIndex = _datasetId;
that.setData({
scrollTop: 0,
pageTab: _leftObj,
isBuying: {
hidden: true,
isLastPage: false,
nomore: true,
pageNum: 0,
pageSize: 7,
msgList: []
},
futureBuying: {
hidden: true,
isLastPage: false,
nomore: true,
pageNum: 0,
pageSize: 7,
msgList: []
}
});
if (_datasetId == 0) {
//初始化第0页数据
loadMsgData0(that);
} else if (_datasetId == 1){
//初始化第1页数据
loadMsgData1(that);
}else{
//初始化第2页数据
loadMsgData2(that);
}
},
onLoad: function (options) {
// 页面初始化 options为页面跳转所带来的参数
var that = this;
wx.getSystemInfo({
success: function (res) {
that.setData({
windowHeight: res.windowHeight,
windowWidth: res.windowWidth
})
}
});
loadMsgData0(that);
},
onReady: function () {
// 页面渲染完成
},
onShow: function () {
// 页面显示
},
// 下拉刷新数据
pullDownRefresh: function () {
var that = this;
//0
var objBuy0 = that.data.isBuying;
objBuy0.pageNum = 0;
objBuy0.msgList = [];
//1
var objBuy1 = that.data.futureBuying;
objBuy1.pageNum = 0;
objBuy1.msgList = [];
var objBuy2 = that.data.futureBuying1;
objBuy2.pageNum = 0;
objBuy2.msgList = [];
that.setData({
isBuying: objBuy0,
futureBuying: objBuy1,
futureBuying1: objBuy2,
scrollTop: 0
});
loadMsgData0(that);
loadMsgData1(that);
loadMsgData2(that);
},
// 上拉加载数据
pullUpLoad: function () {
var that = this;
if (!that.data.isBuying.isLastPage) {
loadMsgData0(that)
}
if (!that.data.futureBuying.isLastPage) {
loadMsgData1(that)
}
if (!that.data.futureBuying1.isLastPage) {
loadMsgData2(that)
}
},
// 定位数据
scroll: function (event) {
var that = this;
that.setData({
scrollTop: event.detail.scrollTop
});
},
onHide: function () {
// 页面隐藏
},
onUnload: function () {
// 页面关闭
}
})
pages/mall/list/list.json
{
"navigationBarTitleText": "商品列表",//当前页面的标题
}
pages/mall/list/list.wxml
<view class="page">
<view class="page__bd">
<!--用name 定义模版-->
<template name="msgTemp">
<view class="weui-panel__bd">
<!--页面路由跳转 -->
<navigator url="../detail/detail?itemId={{itemId}}&activityId={{activityId}}" class="weui-media-box weui-media-box_appmsg" hover-class="weui-cell_active">
<view class="weui-media-box__hd weui-media-box__hd_in-appmsg">
<image class="weui-media-box__thumb" src="{{coverPic}}" style="width: 60px; height: 60px;"/>
</view>
<view class="weui-media-box__bd weui-media-box__bd_in-appmsg">
<view class="">{{name}}</view>
<view class="weui-media-box__desc">{{discountPrice}}</view>
</view>
</navigator>
</view>
</template>
<view class="top" catchtap="pageHdtap">
<view class="tab01 {{pageTab.curHdIndex==0? 'active': ''}}" data-id="0">正在抢购</view>
<view class="tab02 {{pageTab.curHdIndex==1? 'active': ''}}" data-id="1">即将开抢</view>
</view>
<view class="tab-bd" style="height: 100%;">
<!--tab1 start--><!--三目运算符 -->
<view class="tab-bd01 {{pageTab.curBdIndex==0? 'show': 'hide'}}" style="height: 100%;">
<scroll-view scroll-top="{{scrollTop}}" style="height: {{windowHeight}}px; width: {{windowWidth}}px;" scroll-y="true" bindscrolltoupper="pullDownRefresh" bindscroll="scroll" bindscrolltolower="pullUpLoad" class="weui-panel weui-panel_access">
<view wx:for-items="{{isBuying.msgList}}" wx:key="{{item.itemId}}">
<view class="kind-list__item">
<!--用is 使用模版-->
<template is="msgTemp" data="{{...item}}"/>
</view>
</view>
<view hidden="{{isBuying.nomore}}" class="noMore-content">
没有更多了
</view>
</scroll-view>
<view>
<loading hidden="{{isBuying.hidden}}" bindchange="loadingChange">
加载中...
</loading>
</view>
</view>
<!--tab1 end-->
<!--tab2 start-->
<view class="tab-bd02 {{pageTab.curBdIndex==1? 'show': 'hide'}}" style="height: 100%;">
<scroll-view scroll-top="{{scrollTop}}" style="height: {{windowHeight}}px; width: {{windowWidth}}px;" scroll-y="true" bindscrolltoupper="pullDownRefresh" bindscroll="scroll" bindscrolltolower="pullUpLoad" class="weui-panel weui-panel_access">
<view wx:for-items="{{futureBuying.msgList}}" wx:key="{{item.itemId}}">
<view class="kind-list__item">
<!--用is 使用模版-->
<template is="msgTemp" data="{{...item}}"/>
</view>
</view>
<view hidden="{{futureBuying.nomore}}" class="noMore-content">
没有更多了
</view>
</scroll-view>
<view>
<loading hidden="{{futureBuying.hidden}}" bindchange="loadingChange">
加载中...
</loading>
</view>
</view>
<!--tab2 end-->
</view>
</view>
<view class="page__ft"></view>
</view>
//detail.wxml
<swiper class="detail-swiper" indicator-dots="{{indicatorDots}}" circular = "true"
autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}">
<block wx:for="{{imgUrls}}">
<swiper-item>
<image src="{{item}}" class="slide-image" width="355" height="250"/>
</swiper-item>
</block>
</swiper>
// detail.js
var app = getApp();
var util = require('../../../utils/util.js');
Page({
data: {
msgDetail: {},
imgUrls:[],
autoplay: true,
indicatorDots: true,
interval: 4000,
duration: 1000
},
onLoad: function (options) {
console.log(options)
var that = this;
util.req('mall/getItemDetailV4', {
// id: options.id
itemId: options.itemId,
activityId: options.activityId
}, function (res) {
that.setData({
msgDetail: res.data.itemDetail,
imgUrls: res.data.itemDetail.pics
})
});
},
onReady: function () {
// 页面渲染完成
},
onShow: function () {
// 页面显示
},
onHide: function () {
// 页面隐藏
},
onUnload: function () {
// 页面关闭
}
})
(1) 获取位置
wx.getLocation(OBJECT) 获取当前的地理位置、速度。
wx.getLocation({
type: 'gcj02', // 默认为 wgs84 返回 gps 坐标,gcj02 返回可用于 wx.openLocation 的坐标
success: function (res) {
that.setData({
hasLocation: true,
location: {
longitude: res.longitude,
latitude: res.latitude
}
})
}
})
(2)wx.openLocation(OBJECT) 使用微信内置地图查看位置
openLocation: function (e) {
var value = e.detail.value
wx.openLocation({
longitude:value.longitude,
latitude: value.latitude,
scale: 28
})
}
formSubmit: function (e) {
var account = e.detail.value.account;
var password = e.detail.value.password;
var that = this;
wx.login({
success: function(res){
if (res.code){
wx.getUserInfo({
success: function (res1) {//获取userinfo成功
wx.request({
url: 'https://api.orangelife.com.cn/loginV4',
data: {
appCode: null,
mobile: account,
password: password,
captcha_code: '',
captcha_token: ''
},
method: 'POST',
// header: {}, // 设置请求的 header 默认是application/json
success: function (res) {
console.log(res)
// 操作json数据
if (res.statusCode == 200) {
wx.showModal({
title: '登陆状态',
content: '登陆成功',
success: function (res) {
console.log(res)
if (res.confirm) {
// 点击确定后跳转页面并关闭当前页面
wx.switchTab({
url: '../user/user'
})
}
}
})
}
},
fail: function () {
// fail
},
complete: function () {
// complete
}
})
},
fail: function () {
// 调用微信弹窗接口
wx.showModal({
title: '警告',
content: '您点击了拒绝授权,将无法正常使用***的功能体验。请10分钟后再次点击授权,或者删除小程序重新进入。',
success: function (res) {
if (res.confirm) {
console.log('用户点击确定')
}
}
})
}
})
}else{
console.log('获取用户登录态失败!' + res.errMsg)
}
}
})
}
更多信息
[微信公众平台开发者社区]
[框架、组件、API、工具]
[微信小程序联盟]