微信原生小程序基础架构
项目介绍
做了哪些事
一、基本目录结构
├─assets
│ ├─images
│ └─img
├─component 公共组件
│ ├─footer
│ └─slot
│ └─pop-center
├─config 配置文件
│ ├─config 存放基础配置
│ └─constants 存储常量
├─pages
│ ├─index 首页
│ ├─login 登录
│ ├─member 权益
│ ├─my 我的
│ └─store 门店
├─serve 请求
│ ├─home 模块api
│ └─user 模块api
├─style 公共样式
└─utils 工具类
复制代码
二、登录鉴权部分
- wx.login获取code换取openid
login() {
// 登录
return new Promise((resolve, reject) => {
wx.login({
success: (res) => {
// 发送 res.code 到后台换取 openId
this.store.setStorage({
key: 'code',
value: res.code,
})
// 获取openId
Api.GetOpenId({ code: res.code })
.then((res) => {
let _openId = null
if (res.result) {
if (res.data) {
_openId = res.data
this.store.setStorage({
key: 'openId',
value: _openId,
})
}
}
resolve(res)
})
.catch((err) => {
reject(res)
})
},
})
})
},
// 服务端通过auth.code2Session API 获取openid/session_key/unionid等信息
复制代码
- 验证是否已经登录,并返回用户信息
基于系统是C端且是永久登录的,当用户信息已经缓存直接读缓存,否则读接口
validateLogin() {
let _openId = this.store.getStorage('openId') || ''
let _token = this.store.getStorage('token') || ''
let _userInfo = this.store.getStorage('userInfo') || ''
if (_token && _userInfo) {
return new Promise((resolve, reject) => {
// 读缓存时,返回的用户信息模拟接口返回的数据结构
let result = {
result: true,
data: {
userToken: _token,
user: _userInfo,
},
}
resolve(result)
})
} else {
return new Promise((resolve, reject) => {
Api.GetValidateLogin({ openId: _openId })
.then((res) => {
if (res.result) {
this.store.setStorage({
key: 'token',
value: res.data.userToken,
})
this.store.setStorage({
key: 'userInfo',
value: res.data,
})
}
resolve(res)
})
.catch((err) => {
reject(err)
})
})
}
},
复制代码
- 基于业务,决定在app.js里获取openid还是在页面入口获取openid,
基于我们业务是入口免登录的,可以直接先在app.js的onLaunch获取openid,然后在需要进行验证的地方再验证是否登录
// app.js
onLaunch({ path, scene, query, shareTicket }) {
this.login().then((res) => {
if (!res.result) {
utils.showToast(res.errorMessage)
}
})
}
// 在需要判断是否登录的页面
// onLoad里或函数内部
app.validateLogin().then((res) => { //...处理登录成功和失败事件 })
复制代码
如业务需要在入口页就要判断是否登录
// 入口页 如index.js
const app = getApp()
onLoad(options) {
app.login().then((res) => {
if (res.result) {
app.validateLogin().then((res) => {//...处理登录成功和失败事件})
}
})
}
复制代码
- 获取用户个人信息
获取用户个人信息可以直接调用Api唤起授权弹窗
// 获取用户个人信息
// 1. 一键登录
clickLogin(e) {
wx.getUserProfile({
desc: "用于完善会员资料", // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
success: (res) => {
this.setData({
userInfo: res.userInfo,
isOpen: true, // 获取用户手机号需要使用button组件,所以需要打开个弹窗
});
},
fail: (err) => {
console.log(err);
},
});
},
复制代码
- 获取用户手机号
获取用户手机号需要使用button组件,因此加了个弹窗
<button style="width: 520rpx; padding: 0; margin: 65rpx auto 36rpx auto;" class="authorize" open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber" bindtap="clickCloseMask">授权登录开启美发之旅</button>
复制代码
// 2. 获取手机号
getPhoneNumber(e) {
let _phoneInfo = e.detail;
if (_phoneInfo.errMsg == "getPhoneNumber:ok") {
this.setData(
{
isOpen: false,
phoneInfo: e.detail,
},
() => {
this.postLogin();
}
);
}
},
// 3. 暂不授权-关闭弹窗
clickCloseMask() {
this.setData({
isOpen: false,
});
},
// 4. 登录
postLogin() {
// ...调用登录接口
}
复制代码
三、位置授权部分
入口页调起位置授权弹窗,当用户拒绝授权,再次进入入口页需引导用户打开位置授权
- 封装WXAPI
// api.js
/*
apiName 方法名
options 参数
*/
function Api(apiName, ...options){
// 调用wx方法
if(wx[apiName]){
wx[apiName](...options);
}else{
console.log('ERRO:apiName=>'+ apiName +' is not wx function');
}
}
export default Api;
复制代码
- 封装引导打开位置授权部分
// check-auth.js
const App = getApp();
import WxApi from './api.js';
/**
* @param {option.scope} String, 必填, description: 需要验证的权限名
* @param {option.title} String, 可选, description: 跳转打开权限页面的标题
* @param {option.msg} String, 可选, description: 跳转打开权限页面的文本
* @param {option.success} Object, 可选, description: 取得权限成功(权限的请求需自行在callback中执行)
* @param {option.fail} String, 可选, description: 取得权限失败
* @param {option.showModalTitle} String, 可选,
* @param {option.showModalMsg} String, 可选,
*/
function start(option) {
// 获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限
WxApi('getSetting', {
complete: (res) => {
if (!res.authSetting[option.scope]) {
// 提前向用户发起授权请求
WxApi('authorize', {
scope: option.scope,
success: () => {
if (option.success) option.success();
},
fail: (err) => {
WxApi('showModal', {
title: (option.showModalTitle) ? option.showModalTitle : option.title,
content: (option.showModalMsg) ? option.showModalMsg : option.msg,
showCancel: (!option.showCancel) ? option.showCancel : true,
success: (smRes) => {
if (smRes.confirm) {
// 调起客户端小程序设置界面,返回用户设置的操作结果
WxApi('openSetting', {
success: (res) => {
if (res.authSetting[option.scope]) {
if (option.success) option.success();
} else {
if (option.fail) option.fail();
}
},
})
} else {
if (option.fail) option.fail();
}
},
fail: (err) => {}
})
}
})
} else {
if (option.success) option.success();
}
}
})
}
const CheckAuth = {
start: start
}
export default CheckAuth;
复制代码
- 定位授权
// 定位授权
initCheckGps() {
return new Promise((resolve, reject) => {
CheckAuth.start({
scope: 'scope.userLocation',
title: '获取你的地理位置',
msg: '您的位置信息将用于获取附近服务门店',
showModalMsg:
'柯蕾洛需要你的位置信息才能提供优质服务,请打开手机GPS,并允许获取你的位置信息。',
showModalTitle: '友情提示',
showCancel: false,
success: (res) => {
wx.getLocation({
type: 'gcj02',
success: (res) => {
// qqMap存在频率限制,暂不使用
let _gps = {
longitude: res.longitude,
latitude: res.latitude,
}
this.globalData.location = _gps
this.store.setStorage({
key: 'location',
value: _gps,
})
resolve(_gps)
// 此为QQMap定位,因存在频率限制已弃用,
// qqMap
// .regionAddress(res.latitude, res.longitude)
// .then((val) => {
// let _gps = {
// longitude: val.result.location.lng,
// latitude: val.result.location.lat,
// }
// this.globalData.location = _gps
// // console.log(_gps)
// this.store.setStorage({
// key: 'location',
// value: _gps,
// })
// resolve(_gps)
// })
},
})
},
fail: (err) => {
reject(err)
},
})
})
},
复制代码
- 使用
app.initCheckGps().then(res => {
// ...处理逻辑
})
复制代码
- 番外
鉴于QQMap定位所表现的良好定位效果,后续可能会沿用,也将代码粘出来
// location.js
import configApi from "../serve/config"
var QQMapWX = require('qqmap/qqmap-wx-jssdk.js'); // 直接去官方下载 https://lbs.qq.com/miniProgram/jsSdk/jsSdkGuide/jsSdkOverview
function regionAddress(lat, lng) {
return new Promise(function (resolve, reject) {
console.log("位置加载中")
var qqmapsdk = new QQMapWX({
key: configApi.mapKey, //柯蕾洛 IQGBZ-J5PKR-ZXMWS-WQXN6-LAD63-XQFXI 蒂梵尼 4XUBZ-SSICG-DQPQR-I7D34-WNEAV-H3BIG
})
var options = {
"location": {
"latitude": lat,
"longitude": lng
}
}
qqmapsdk.reverseGeocoder({
options: options,
success: function (res) {
resolve(res)
},
fail: function (res) {
console.log(res);
resolve(null)
},
complete: function (res) {
resolve(null)
}
})
})
}
module.exports={
regionAddress:regionAddress
}
复制代码
四、版本升级部分
目前正式有效,体验码暂时无效
onLaunch({ path, scene, query, shareTicket }) {
if (wx.canIUse('getUpdateManager')) {
const updateManager = wx.getUpdateManager()
updateManager.onCheckForUpdate(function (res) {
// 请求完新版本信息的回调
if (res.hasUpdate) {
updateManager.onUpdateReady(function () {
wx.showModal({
title: '更新提示',
content: '新版本已经准备好,是否重启应用?',
success: function (res) {
// res: {errMsg: "showModal: ok", cancel: false, confirm: true}
if (res.confirm) {
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
updateManager.applyUpdate()
}
},
})
})
updateManager.onUpdateFailed(function () {
// 新的版本下载失败
wx.showModal({
title: '已经有新版本了哟~',
content:
'新版本已经上线啦~,请您删除当前小程序,重新搜索打开哟~',
})
})
}
})
}
}
复制代码
五、工具部分
MD5加密
- md5.js
function Md5(string) {
var x = Array();
var k, AA, BB, CC, DD, a, b, c, d;
var S11 = 7,
S12 = 12,
S13 = 17,
S14 = 22;
var S21 = 5,
S22 = 9,
S23 = 14,
S24 = 20;
var S31 = 4,
S32 = 11,
S33 = 16,
S34 = 23;
var S41 = 6,
S42 = 10,
S43 = 15,
S44 = 21;
string = uTF8Encode(string);
x = convertToWordArray(string);
a = 0x67452301;
b = 0xEFCDAB89;
c = 0x98BADCFE;
d = 0x10325476;
for(k = 0; k < x.length; k += 16) {
AA = a;
BB = b;
CC = c;
DD = d;
a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
a = FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
d = FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
c = FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
b = FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
a = FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
d = FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
c = FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
b = FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
a = FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
d = FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
c = FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
b = FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
a = GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
d = GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
c = GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
b = GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
a = GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
d = GG(d, a, b, c, x[k + 10], S22, 0x2441453);
c = GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
b = GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
a = GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
d = GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
c = GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
b = GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
a = GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
d = GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
c = GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
b = GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
a = HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
d = HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
c = HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
b = HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
a = HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
d = HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
c = HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
b = HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
a = HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
d = HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
c = HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
b = HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
a = HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
d = HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
c = HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
b = HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
a = II(a, b, c, d, x[k + 0], S41, 0xF4292244);
d = II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
c = II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
b = II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
a = II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
d = II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
c = II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
b = II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
a = II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
d = II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
c = II(c, d, a, b, x[k + 6], S43, 0xA3014314);
b = II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
a = II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
d = II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
c = II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
b = II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
a = addUnsigned(a, AA);
b = addUnsigned(b, BB);
c = addUnsigned(c, CC);
d = addUnsigned(d, DD);
}
var tempValue = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);
return tempValue.toLowerCase();
}
var rotateLeft = function (lValue, iShiftBits) {
return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
}
var addUnsigned = function (lX, lY) {
var lX4, lY4, lX8, lY8, lResult;
lX8 = (lX & 0x80000000);
lY8 = (lY & 0x80000000);
lX4 = (lX & 0x40000000);
lY4 = (lY & 0x40000000);
lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
if (lX4 & lY4) return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
if (lX4 | lY4) {
if (lResult & 0x40000000) return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
else return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
} else {
return (lResult ^ lX8 ^ lY8);
}
}
var F = function (x, y, z) {
return (x & y) | ((~x) & z);
}
var G = function (x, y, z) {
return (x & z) | (y & (~z));
}
var H = function (x, y, z) {
return (x ^ y ^ z);
}
var I = function (x, y, z) {
return (y ^ (x | (~z)));
}
var FF = function (a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(F(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var GG = function (a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(G(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var HH = function (a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(H(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var II = function (a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(I(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var convertToWordArray = function (string) {
var lWordCount;
var lMessageLength = string.length;
var lNumberOfWordsTempOne = lMessageLength + 8;
var lNumberOfWordsTempTwo = (lNumberOfWordsTempOne - (lNumberOfWordsTempOne % 64)) / 64;
var lNumberOfWords = (lNumberOfWordsTempTwo + 1) * 16;
var lWordArray = Array(lNumberOfWords - 1);
var lBytePosition = 0;
var lByteCount = 0;
while (lByteCount < lMessageLength) {
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
lByteCount++;
}
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
return lWordArray;
};
var wordToHex = function (lValue) {
var WordToHexValue = '',
WordToHexValueTemp = '',
lByte, lCount;
for (lCount = 0; lCount <= 3; lCount++) {
lByte = (lValue >>> (lCount * 8)) & 255;
WordToHexValueTemp = '0' + lByte.toString(16);
WordToHexValue = WordToHexValue + WordToHexValueTemp.substr(WordToHexValueTemp.length - 2, 2);
}
return WordToHexValue;
};
var uTF8Encode = function (string) {
string = string.replace(/\x0d\x0a/g, '\x0a');
var output = '';
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
output += String.fromCharCode(c);
} else if ((c > 127) && (c < 2048)) {
output += String.fromCharCode((c >> 6) | 192);
output += String.fromCharCode((c & 63) | 128);
} else {
output += String.fromCharCode((c >> 12) | 224);
output += String.fromCharCode(((c >> 6) & 63) | 128);
output += String.fromCharCode((c & 63) | 128);
}
}
return output;
};
export default Md5;
复制代码
- login.js
import Md5 from '../../utils/md5.js';
let md5Password = Md5(this.data.password)
复制代码
六、系统信息部分
- 获取系统信息
wx.getSystemInfo({
success: (res) => {
this.globalData.systemInfo = res
},
})
复制代码
- 获取appid
wx.getAccountInfoSync() // object { miniProgram }
复制代码
- miniProgram 的结构
属性 | 类型 | 说明 |
---|---|---|
appId | string | 小程序 appId |
envVersion | string | 小程序版本 develop(开发)/trial(体验)/release(正式) |
version | string | 线上小程序版本号 |
七、缓存处理
// store.js
//合法的strage储存key值
const StorageKeys = [
'code', // 登录code
'openId', //用户openId信息
'unionId', //
'token', //
'userInfo', //
'location', // 位置经纬度
]
const Store = {
/**
* 储存storage
* @param {option.key} String, 必填, description: Storage数据对应的key值,只能存放在StorageKeys中声明过的值
* @param {option.value} Any, 必填, description: 需要存放的数据
*/
setStorage: (option) => {
if (StorageKeys.indexOf(option.key) >= 0) {
try {
wx.setStorageSync(option.key, option.value)
} catch (e) {}
} else {
console.log('ERRO:key=>' + key + ' is uncreate in option')
}
},
/**
* 获取storage
* @param {key} String, 必填, description: 获取Storage数据对应的key值
*/
getStorage: (key) => {
try {
let _val = wx.getStorageSync(key)
if (_val) return _val
} catch (e) {
console.log('ERRO:key=>' + key + ' is undefined')
}
},
/**
* 删除storage
* @param {key} String, 必填, description: 删除torage数据对应的key值
*/
removeStorage: (key) => {
try {
wx.removeStorageSync(key)
} catch (e) {
console.log('ERRO:key=>' + key + ' is undefined')
}
},
/**
* 清理所有本地数据缓存
*/
clearStorage: () => {
try {
wx.clearStorageSync()
} catch (e) {
// Do something when catch error
}
},
/**
* 获取当前storage的相关信息
* @returns {res.keys} Array.<string>, 当前 storage 中所有的 key
* @returns {res.keys} number, 当前占用的空间大小, 单位 KB
* @returns {res.keys} number, 限制的空间大小,单位 KB
*/
getStorageInfo: () => {
try {
const res = wx.getStorageInfoSync()
return res
} catch (e) {
// Do something when catch error
}
},
}
export default Store
复制代码
八、CSS兼容问题处理与公共样式
@charset "UTF-8";
/**flex 布局 公共样式**/
.flex-rowaCenter {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
}
.flex-rowajCenter {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
}
.flex-rowaCenterjSpaceb {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
justify-content: space-between;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
}
.flex-flexstart {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-pack: start;
-webkit-justify-content: flex-start;
justify-content: flex-start;
}
.flex-rowaCenterjFlexs {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-pack: start;
-webkit-justify-content: flex-start;
justify-content: flex-start;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
}
.flex-rowaCenterjFlexe {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-pack: end;
-webkit-justify-content: flex-end;
justify-content: flex-end;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
}
.flex-columnaCenter {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
flex-direction: column;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
}
.flex-columnajCenter {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
flex-direction: column;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
}
.flex-columnajEnd {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
flex-direction: column;
/* justify-content: flex-end; */
-webkit-box-align: end;
-webkit-align-items: flex-end;
align-items: flex-end;
}
.flex-column {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
flex-direction: column;
}
.flex-columnaCenterjSpaceb {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
flex-direction: column;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
justify-content: space-between;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
}
.flex-columnSpaceAround {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-justify-content: space-around;
justify-content: space-around;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-webkit-flex-direction: row;
flex-direction: row;
}
/**超出缩略**/
.over-elipse {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
/* 超出两行缩略 */
.over-two-elipse {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
}
复制代码
九、数据清洗与容错
- 示例
/**
* 功能:处理列表
* @param list
* @returns {Array}
*/
authorList: function (list = []) {
let result = [];
list.forEach(item => {
result.push({
guid: item.recommend_obj_id || '',
type: item.recommend_type || '',
logo: (item.theme_pic || '').trim() || '',
title: item.title || ''
});
});
return result;
}
复制代码
- 作用:
- 清洗数据,避免setData()时有过多的脏数据
- 错误数据的兼容,添加数据缺省值,增加代码健壮性
十、动态组件的渲染
方案的选择: template 和 component
- template更简洁,更适合本页面小组件,逻辑处理少的组件,不便于复用
- component,有自己的生命周期,便于复用
component方式
- index.json
"usingComponents": {
"home-swiper": "../../component/home/homeSwiper/homeSwiper",
"home-address": "../../component/home/homeAddress/homeAddress",
"home-hot-activity":"../../component/home/homeHotActivity/homeHotActivity",
"home-group-work": "../../component/home/homeGroupWork/homeGroupWork",
"group-popup": "../../component/home/groupPopup/groupPopup"
}
复制代码
- index.wxml
<view class="home">
<block wx:for="{{templateList}}" wx:key="index">
<block wx:if="{item.moduleType === 'home-swiper'}}" >
<home-swiper info="{{item}}" />
</block>
<block wx:if="{{item.moduleType === 'home-address'}}" >
<home-address info="{{item}}" />
</block>
<block wx:if="{{item.moduleType === 'home-hot-activity'}}" >
<home-hot-activity info="{{item}}"></home-hot-activity>
</block>
<block wx:if="{{item.moduleType === 'home-group-work'}}">
<home-group-work info="{{item}}"></home-group-work>
</block>
</block>
</view>
复制代码
template
- index.wxml
<template name="time">
<view>
<text> Time组件: {{time}} </text>
</view>
</template>
<template name="msg-item">
<view>
<text> {{index}}通知组件: {{msg}} </text>
<text> Time: {{time}} </text>
</view>
</template>
<view class="warp">
<block wx:for="{{list}}" wx:key="index">
<view class="tmp">
<template is="{{item.name}}" data="{{...info}}"/>
</view>
</block>
</view>
复制代码
- index.js
data: {
info: {
index: 0,
msg: 'this is a template',
time: '2016-09-15'
},
list: [
{name: 'msg-item'},
{name: 'time'},
{name: 'msg-item',data: []},
{name: 'time'},
{name: 'msg-item'},
{name: 'time'},
]
},
复制代码
- wxss
.warp {
margin-top: 30rpx;
}
.tmp {
margin-bottom: 20rpx;
}
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END