在正式开发支付宝小程序之前,我们要做一些准备工作,比如说封装一下config文件、request请求、api接口集中定义,自定义的工具脚本等。文末还有彩蛋哈~
第一步:在支付宝开发者工具中新增支付宝小程序。
第二步:在小程序文件的根目录创建utils目录。
创建自定义的相关js文件(或者直接从以前定义好的项目中拷贝过来),如apis.js、config.js、tools.js、http.js、tools.sjs
1.小程序中调用接口的集中展示,加上备注信息,这样在后台查看的时候方便一些吧。
//apis.js
//此处为封装的请求方法
import { getJSON } from './http'
const apis = {
// 用户登录
userLogin(params, method = 'GET') {
return getJSON('/api/login?r=' + new Date().getTime(), params, method)
},
}
module.exports = apis
2.配置文件,开发的时候难免遇到接口地址切换开发环境、测试环境、生产环境等各种环境,我们事先配置好文件,在切换的时候直接修改环境参数即可。
// 后台不同环境
const ENV = {
SIT: 'sit',
UAT: 'uat',
PRD: 'prd'
};
//后台环境对应的接口目录
const BUILD_INFO = {
sit: {
api: 'http://127.0.0.1:8080',
domain: ''
},
uat: {
api: 'https://**.com',
domain: 'https://**.com'
},
prd: {
api: 'https://**.com',
domain: 'https://**.com'
}
}
// 小程序APP_id
const APP_ID = {
sit: '',
uat: '',
prd: ''
}
// 不同环境的版本
const VERSION = {
sit: '1.2.1',
uat: '1.0.1',
prd: '1.0.16'
}
//实际使用的后台环境
const env = ENV.PRD;
const config = {
ENV: env,
API_URL: BUILD_INFO[env].api,
APP_ID: APP_ID[env],
DOMAIN_URL: BUILD_INFO[env].domain,
VERSION: VERSION[env]
};
module.exports = config;
3.封装一些常用的工具函数以便我们提升开发效率。比如小程序中的页面跳转一般情况下要绑定事件,然后定义事件方法,在其中定义跳转的页面,此处我封装了一个go2page的方法,这样就不用在小程序页面的脚本中定义各种跳转事件了。不过就是需要在引用go2page的地方添加参数到data中。
在使用go2page方法进行页面跳转后,我们需要从query中提取参数。使用下面的curPagePath方法即可。
const tools = {
isObject(obj) {
if (Object.prototype.toString.call(obj) === '[object Object]') {
return true
}
return false
},
isDefine(str) {
if (str === 0) {
return true
}
if (str == '' || (!str)) {
return false
}
return true
},
isIDCard(str) {
const reg = /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/
return reg.test(str)
},
isPhone(str) {
const myreg = /^1[3|4|5|6|7|8|9][0-9]\d{8}$/
return myreg.test(str)
},
isFullName(str) {
const reg = /^[\u4E00-\u9FA5\uf900-\ufa2d·s]{2,20}$/
return reg.test(str)
},
getUrlParam(href) {
const indexWen = href.indexOf('?')
const indexJing = href.indexOf('#')
const theRequest = {}
if (indexWen === -1) {
return theRequest
}
if (indexJing < indexWen) { // 如果#号在问好前面
href = href.substring(indexWen + 1)
} else {
href = href.substring(indexWen + 1, indexJing)
}
const strArr = href.split('&')
for (let i = 0; i < strArr.length; i++) {
theRequest[strArr[i].split('=')[0]] = unescape(strArr[i].split('=')[1])
}
return theRequest
},
stringifyParam(param = {}) {
let paramString = ''
for (let key in param) {
if (paramString === '') {
paramString += key + '=' + param[key]
} else {
paramString += '&' + key + '=' + param[key]
}
}
return paramString
},
// 生成随机码
getRandom(num) {
const char = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
const result = []
for (let i = 0; i < num - 1; i++) {
const index = Math.random() * char.length - 1
const value = char.charAt(index)
result.push(value)
}
return result.join('')
},
desensitizing(str = '', from = 0, length = 0, replaceStr = '*') { // 隐藏某些字符串
if (str.length === 0) {
return str
}
// 变成数组
const strArr = str.split('')
// 更改数组
strArr.splice(from, length, replaceStr.repeat(length))
return strArr.join('')
},
htmlEncode(str = '') {
if (str === '') {
return str
}
let s = str.replace(/&/g, '&')
s = s.replace(/</g, '<')
s = s.replace(/>/g, '>')
s = s.replace(/\'/g, ''')
s = s.replace(/\"/g, '"')
return s
},
getDay(day) {
var today = new Date();
var targetday_milliseconds = today.getTime() + 1000 * 60 * 60 * 24 * day;
today.setTime(targetday_milliseconds); //注意,这行是关键代码
var tYear = today.getFullYear();
var tMonth = today.getMonth();
var tDate = today.getDate();
tMonth = this.doHandleMonth(tMonth + 1);
tDate = this.doHandleMonth(tDate);
return tYear + "-" + tMonth + "-" + tDate;
},
doHandleMonth(month) {
var m = month;
if (month.toString().length == 1) {
m = "0" + month;
}
return m;
},
getWeek(dateString) {
var dateArray = dateString.split("-");
var date = new Date(dateArray[0], parseInt(dateArray[1] - 1), dateArray[2]);
return "周" + "日一二三四五六".charAt(date.getDay());
},
getUserInfo() {
my.getStorage({
key: 'userInfo',
success: function (res) {
console.log('获取缓存中用户信息', res)
return res.data
},
fail: function (res) {
console.log('获取缓存中用户信息失败', res)
return {}
}
});
},
checkToken(callback, param = {}) {
let that = this
var app = getApp()
if (app.globalData.userId) {
callback.call(this, param);
} else {
setTimeout(function () {
param = Object.assign(param, app.globalData)
that.checkToken(callback, param);
}, 200);
}
},
go2page(e) {
const { dataset } = e.target
let params = []
for (let key in dataset) {
if (key != 'url') {
params.push(key + '=' + dataset[key])
}
}
if (!this.isDefine(e.target.dataset.url)) {
my.showToast({
type: 'success',
content: '建设中,敬请期待',
duration: 3000,
success: () => {
},
});
} else {
let url = e.target.dataset.url
if (params.length > 0) {
url = url + '?' + params.join('&')
}
my.navigateTo({
url: url
});
}
},
round(str) {
if(!str){return ''}
return str.toFixed(2)
},
curPagePath(query){
let pages = getCurrentPages();
let currPage = null;
// console.log(pages) 的到一个数组
if (pages.length) {
// 获取当前页面的对象(上边所获得的数组中最后一项就是当前页面的对象)
currPage = pages[pages.length - 1];
}
// 获取当前页面的路由
let route = currPage.route
let params = []
if(query){
for (let key in query) {
params.push(key + '=' + query[key])
}
}
if(params.length>0){
route += '?' + params.join('&')
}
console.log('当前页面路径==>',route)
},
getTimeList(start, end, step,restStart,restEnd,selectDate) {
var curDate = new Date(),
curFullYear = curDate.getFullYear(),
curMonth = curDate.getMonth() + 1,
curDay = curDate.getDate()
curMonth = curMonth < 10 ? '0' + curMonth : curMonth
curDay = curDay < 10 ? '0' + curDay : curDay
var ymd = curFullYear + '/' + curMonth + '/' + curDay
selectDate = selectDate.replace(/-/g,'/')
console.log('selectDate',selectDate)
var startTime = new Date(ymd + ' ' + start).getTime(),
endTime = new Date(ymd + ' ' + end).getTime(),
restStartTime = new Date(ymd + ' ' + restStart).getTime(),
restEndTime = new Date(ymd + ' ' + restEnd).getTime()
var returnArr = []
while (startTime + step * 60 * 1000 <= endTime) {
// 中途休息的时间阶段
if(startTime + step * 60 * 1000>restStartTime && startTime + step * 60 * 1000<=restEndTime){
startTime += step * 60 * 1000
continue
}
// 如果时间小于当前时间则跳过显示
if(startTime + step * 60 * 1000<new Date().getTime() && ymd == selectDate){
startTime += step * 60 * 1000
continue
}
returnArr.push(this.getTime(startTime) + '-' + this.getTime(startTime+step*60*1000))
startTime += step * 60 * 1000
}
return returnArr
},
getTime(timestamp) {
var date = new Date(timestamp);//时间戳为10位需*1000,时间戳为13位的话不需乘1000
var Y = date.getFullYear() + '-';
var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
var D = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' ';
var h = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':';
var m = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + '';
var s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds();
return h + m;
},
isIphoneX(){
var u = navigator.userAgent;
var isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
if (isIOS) {
if (screen.height == 812 && screen.width == 375) {
return true;
}
else {
return false;
}
}
}
}
module.exports = tools;
4.常用的请求方法,根据实际项目中约定的接口规范进行修改。
import config from './config';
function isApiSuccess(result) {
const status = result.success || result.stat || result.status || ''; // 接口状态字段
if (status == true || status == '000' || status === 'ok' || status === 'success' || status === 'succeed') {
return true;
} else {
return false;
}
}
export function getJSON(url, params, method = 'GET', mockSetting = {}) {
let path = '';
const { on = false, mockData = {} } = mockSetting;
if (url.indexOf('http') > -1 || url.indexOf('https') > -1) {
path = url;
} else {
path = config.API_URL + url;
}
return new Promise((resolve, reject) => {
my.showLoading();
if (on) {
console.log('-------返回 mock 数据-------', url, params, mockData);
if (isApiSuccess(mockData)) {
resolve(mockData);
} else {
reject(mockData);
}
my.hideLoading();
return;
}
let token = params.token
let headers = {
"Content-Type": "application/json",
}
if (params.headers) {
headers = Object.assign(headers, params.headers)
delete params.headers
}
if (token) {
headers['Authorization'] = 'Bearer ' + token
delete params.token
}
if (method.toLocaleLowerCase() != 'get') {
headers['content-type'] = 'application/json'
}
if (method.toLocaleLowerCase() == 'delete') {
headers['content-type'] = 'application/x-www-form-urlencoded'
}
my.request({
url: path,
method: method,
data: params,
dataType: 'json',
headers: headers,
success: (result) => {
// console.log(`--返回数据--接口地址=>${url},结果=>${JSON.stringify(result)}`);
my.hideLoading();
if (isApiSuccess(result.data)) {
resolve(result.data);
} else {
reject(result.data);
}
},
fail: (err) => {
console.log('-------返回错误-------', url, err);
my.hideLoading();
if (err.status == 401) {
console.log('未登录权限')
}
my.showToast({
type: 'fail',
content: '请求异常,请稍后再试!'
});
reject(err);
},
});
});
}
5.在页面中引用方法时需要用到sjs文件。
const desensitizing = (str,from,length,replaceStr = '*')=>{
if (str.length === 0) {
return str
}
// 变成数组
const strArr = str.split('')
let replace_str = ''
for(var i=0;i<length;i++){
replace_str += replaceStr
}
// 更改数组
strArr.splice(from, length, replace_str)
return strArr.join('')
}
const repeat = (length,repeatStr='*') =>{
var str = ''
for(let i=0;i<length;i++){
str += repeatStr
}
return str
}
const desensitizing2 = (str,type,isdes=false,replaceStr = '*')=>{
if(!isdes){
return str
}
if(str == '' || !str){
return ''
}
switch(type){
case 'name':
str = str.replace(getRegExp('·','g'),replaceStr);
if(str.length == 1){
return replaceStr
}
if(str.length>=2){
if(str.length>=5){
return repeat(4,replaceStr) + str[str.length-1]
}
return desensitizing(str,0,str.length-1)
}
return replaceStr;
break;
case 'sfz':
return desensitizing(str,1,str.length-2)
break;
case 'phone':
return desensitizing(str,3,6)
break;
}
}
const substring = (str,from,length=0)=>{
if(str.length == 0){
return ''
}
return str.substring(from,from+length)
}
const isDefine = (str)=>{
if (str === '' || !str) {
return false
}
return true
}
const round = (str,len=2)=>{
if(!str){return ''}
let point_index = str.lastIndexOf('.')
if(len == 0){
return str.substring(0,1)
}
if(str.length > len + point_index + 1){
return str.substring(0,len + point_index + 1)
}
return str
}
const str2date = (str,separater='-') => {
if(str === '' || !str || str.length<8) {
return ''
}
return str.substring(0,4) + separater + str.substring(4,6) + separater + str.substring(6,8)
}
export default {
desensitizing,
substring,
isDefine,
round,
desensitizing2,
str2date
}
以上准备工作完成之后,需要引用一下支付宝小程序的ui组件,我用的是mini-ali-ui。
这下终于可以开发愉快地写页面了吧。此时此刻你在想什么呢。
作为一个经常使用mac、linux系统的程序猿,想借助于开发工具中的控制台进行页面创建,怎么办呢?
这时候要用到node的功能了,在根目录下添加package.json
{
"dependencies": {
"iconv-lite": "^0.6.3"
},
"scripts": {
"page": "node scripts/page"
}
}
然后在根目录添加scripts目录,在scripts目录中添加page.js
示例代码如下:此程序仅支持 “pages/分组名称/页面名称”这种结构的页面创建,若需要减小层级或增加层级自行修改哈。
/**
* pages页面快速生成脚本
* 用法:npm run tep `文件名`
* npm run page product/ProductClass
*/
const fs = require('fs');
var iconv = require('iconv-lite');
const dirName = process.argv[2];
const cover = process.argv[3];
console.log(dirName)
const dirNameArr = dirName.split('/')
const folder = dirNameArr[0]
const fileName = dirNameArr[1]
const capPirName = dirName.substring(0, 1).toUpperCase() + dirName.substring(1);
console.log(folder, fileName, capPirName, __dirname)
if (!dirName) {
console.log('文件夹名称不能为空!');
console.log('示例:npm run page product/ProductClas');
process.exit(0);
}
var curPath = __dirname.substring(0, __dirname.lastIndexOf('/'))
console.log('curPath==', curPath)
function loadjson(filepath) {
var data;
try {
var jsondata = iconv.decode(fs.readFileSync(curPath + '/' + filepath, "binary"), "utf8");
data = JSON.parse(jsondata);
}
catch (err) {
console.log(err);
}
return data;
}
function savejson(filepath, data) {
var datastr = JSON.stringify(data, null, 4);
if (datastr) {
try {
fs.writeFileSync(curPath + '/' + filepath, datastr);
}
catch (err) {
}
}
}
//model模板
const wxmlTemp = `
<view>
</view>
`
const jsTemp = `
import tools from '/utils/tools'
import { getJSON } from '/utils/http'
import apis from '/utils/apis'
const app = getApp()
Page({
data: {
},
onLoad: function (options) {
tools.curPagePath(options)
},
onShow: function () {
},
go2page(e){
tools.go2page(e)
}
})
`
const wxssTemp = `
`
const jsonTemp = `
{
"usingComponents": {}
}
`
if (!fs.existsSync(`pages/${folder}`)) {
fs.mkdirSync(`pages/${folder}`)
}
if (!fs.existsSync(`pages/${folder}/${fileName}`)) {
fs.mkdirSync(`pages/${folder}/${fileName}`)
} else {
// 如果文件夹存在则说明页面已创建,不能再操作了,否则会覆盖已有页面
if (cover && cover != 1) {
process.exit(0);
}
}
process.chdir(`pages/${folder}/${fileName}`); // cd $1
fs.writeFileSync(`${fileName}.axml`, wxmlTemp)
fs.writeFileSync(`${fileName}.json`, jsonTemp)
fs.writeFileSync(`${fileName}.acss`, wxssTemp)
fs.writeFileSync(`${fileName}.js`, jsTemp)
var jsonPath = 'app.json'
var appJson = loadjson(jsonPath)
if (appJson) {
var pages = appJson.pages
if (pages.indexOf(`pages/${folder}/${fileName}/${fileName}`) == -1) {
pages.push(`pages/${folder}/${fileName}/${fileName}`)
}
savejson(jsonPath, appJson)
}
process.exit(0);
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。