一、通用
-
ajax
原生ajax封装
ajax({
url: bms_api + '/member/getPayResultCycle',
type: 'POST',
header: {
Authorization: token, // 用户token,过期重新登录
tenant: tenant, // 租户区分渠道
}
}
function ajax(opt) {
// console.log(opt.api.api)
!opt.type ? opt.type = 'get' : null; // 默认get请求
!opt.async ? opt.async = true : null; // 异步会阻断程序
var xmlHttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('microsoft.XMLHTTP');
// xmlHttp.timeout = opt.timeout ? opt.timeout : 5000;
var API = opt.api;
var url = IPCONFIG.base + PORTCONFIG[API['class']] + API['class'] + '_api' + API.api;
if (!opt.params["timestamp"]) {
opt.params["timestamp"] = new Date().getTime();
}
var postData = setURLparams(opt.params);
// console.log(opt.api)
if (opt.type.toUpperCase() === 'POST') {
xmlHttp.open(opt.type, url, opt.async);
xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8');
if (opt.header) {
for (var item in opt.header) {
xmlHttp.setRequestHeader(item, opt.header[item]);
}
}
xmlHttp.setRequestHeader('tenant',tenant);
xmlHttp.send(postData);
} else if (opt.type.toUpperCase() === 'GET') {
url = url + '?' + postData;
xmlHttp.open(opt.type, url, opt.async);
// 只有需要token的接口传自定义header
if (API['class'] == 'urm' || API['class'] == 'crm') {
// console_log("API['class'] "+API['class']+' '+API.api);
if (opt.header) {
for (var item in opt.header) {
xmlHttp.setRequestHeader(item, opt.header[item]);
}
}
xmlHttp.setRequestHeader('tenant',tenant);
}
xmlHttp.send(null);
}
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == 4) {
dataHandler(xmlHttp, opt);
} else {
// 请求中。。。
// console.log(url, xmlHttp.readyState, xmlHttp.status)
}
};
// xmlHttp.ontimeout = function () {
// console_log('ontimeout: '+opt.api.errorCode+' '+xmlHttp.status);
// if (typeof opt.error != 'undefined') {
// opt.error(xmlHttp);
// } else if (opt.api.errorCode) {
// // 请求失败
// BadGateWay({
// code: opt.api.errorCode,
// status: xmlHttp.status,
// });
// }
// }
}
-
ajax自定义header跨域问题
问题原因
添加自定义header会导致发送ajax后浏览器自动先发送一个预检请求(OPTIONS),预检请求中的内容是空的,所有后端的拦截器不需要对预检请求中的数据进行校验,此时的校验肯定是不通过的,导致拦截器无法放行,后续的实际请求就无法发送了,浏览器就会认为跨域出现了问题,所以就产生了跨域问题.
在设置了自定义header后,浏览器到后端请求将分为两步进行
1.发送预请求 OPTIONS 请求
浏览器将先发送一个预请求OPTIONS到后端,这里后端需要对OPTIONS请求做出正确响应,可以直接返回200(我司是204)状态码,不用返回内容信息。
2.发送真正的数据请求
浏览器接收到OPTIONS正确响应后会自动执行发送get或post请求。可此时依旧没有请求到后端数据,F12查看控制台输出,会发现报错了。这就是接下来要处理的跨域问题。
- 跨域的处理主要是服务器端设置响应头
Access-Control-Allow-Origin; //支持全域名访问,不安全,部署后需要固定限制为客户端网址
Access-Control-Allow-Methods; //支持的http 动作
Access-Control-Allow-Headers; //响应头 请按照自己需求添加
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization, tenant");
- ie浏览器兼容问题
Access-Control-Allow-Headers多行设置或者配的值有空格就会报错请求不通
-
尺寸适配
1. rem
rem是CSS3新增的一个相对单位(root em,根em)
1rem=根元素html的font-size值。当页面中所有元素都使用rem单位时,你只需要改变根元素font-size值,所有元素就会按比例放大或者缩小。因此我们只需要写一小段js代码,根据屏幕宽度改变html的font-size值,就可以做到弹性布局。这种方法确实便捷,兼容性也很好,是目前非常主流的弹性布局方案。
rem布局的本质是等比缩放,一般是基于宽度
弊端与优点
弊端之一:和根元素font-size值强耦合,系统字体放大或缩小时,会导致布局错乱
弊端之二:html文件头部需插入一段js代码
rem的优点:移动端rem布局比vw主流的原因 兼容性
vw单位兼容性比rem稍差,ios8、安卓4.4及以上才完全支持。
2. vw
w3c的官方解释
viewpoint width,视窗宽度,1vw=视窗宽度的1%
viewpoint height,视窗高度,1vh=视窗高度的1%
viewport即浏览器可视区域大小
我们可以这样理解 100vw = window.innerwidth, 100vh = window.innerheight
在移动端我们一般都可以认为,100vw就是屏幕宽度。若使用vw布局,就不需要再像rem那样,在js中去动态设置根元素的font-size了,sass中只需要使用这个函数做转换即可
//以iphone7尺寸@2x 750像素宽的视觉稿为例
@function vw($px) {
@return ($px / 750) * 100vw;
}
//假设一个div元素在视觉稿中,宽度为120px,字体大小为12px
div {
width: vw(120);
font-size: vw(12);
}
vw单位和百分比%单位对比
百分比%是根据父元素宽度或者高度进行计算,而vw vh固定按照viewport来计算,不会受父元素宽高度影响。
100vw包括了页面滚动条宽度(页面滚动条属于viewport范围内,100vw当然包括了页面滚动条宽度)。但把body或者html设置为width:100%时,是不包括页面滚动条的宽度的。也就是说100vw在有纵向滚动条的情况下,会比100%宽
3. 媒体查询
@media是css3的新属性,它的原理是监控移动端设备的宽度,然后根据不同的宽度,适配不同的css样式,来实现移动端适配
应用场景:
部分pad屏幕高度较小,单独调整垂直间距
小米小爱pad新设备-6寸屏 960x480
@media screen and (max-height: 540px) {
.content .title .title2 {
margin-top: -0.7rem;
}
.content .durationArea {
top: 1.8rem;
}
.explanation {
top: 7.24rem;
}
}
-
android ios交互
1. android
// 获取参数
var params = android.getData();
var paramsObj = JSON.parse(params);
var versionName = android.getVersionName();
packageName = android.getPackageName()
// 方法调用
// 按返回-关闭h5
android.isFinish(true);
// 按返回-上一页h5
android.isFinish(false);
2. ios
DSBridge
DSBridge是目前地球上最好的IOS/Android javascript bridge. DSBridge有四大特点: 支持同步调用、跨平台、三端皆易用。
bridge.call(method,[args,callback])
功能:调用Native api
method: api函数名
args:参数,类型:json, 可选参数
callback(String returnValue):仅调用异步api时需要
html
js
// 接收参数 同步
if (isIOS) {
var res = dsBridge.call("getParam","getData");
var params = JSON.parse(res);
paramObj = params;
} else if (typeof android === 'object') {
var params = android.getParam();
paramObj = JSON.parse(params);
}
// 异步
// 对于一些比较耗时的api, DSBridge提供了异步支持,正如上面代码所示,此时你需要传一个回调(如果没有参数,回调可作为第二个参数),当api完成时回调将会被调用,结果以字符串的形式传递。
dsBridge.call("getParam","getData", function (res) {
console.log(res);
})
// 回传
if (isIOS) {
dsBridge.call("setOrderNum", code, function (res) {
console.log(res);
});
} else if (typeof android === 'object') {
android.setOrderNum(code);
}
-
h5支付
场景:app内嵌页 支付宝、微信支付
ios上线审核
function wechatPay() { // 微信支付
selects.payType = 2;
console.log(selects);
$('.pay1').addClass('select');
$('.pay2').removeClass('select');
}
function aliPay() { //支付宝支付
selects.payType = 1;
console.log(selects);
$('.pay2').addClass('select');
$('.pay1').removeClass('select');
}
function goPay(code) {
var timestamp = Date.parse(new Date());
console.log('timestamp:'+timestamp);
ajax({
url: bms_api+'/member/createPrePayOrder',
type: 'post',
header: {
'Authorization': paramObj.token
},
params: {
preOrderCode: code,
ip: IP,
requestTime: timestamp,
payType: selects.payType,
tradeType: 'MWEB',
},
success: function (data) {
if(data.retCode == '00000000') {
console.log(data);
if (data.retMsg.form) { // 支付宝
var content = $('.confirm');
var div = creatDom('div', content);
div.innerHTML = (data.retMsg.form); //res.data是返回的表单
var forms = document.getElementsByTagName('form');
console.log(forms);
document.forms[0].submit();
} else if (data.retMsg.mweb_url) {// 微信
location.href = data.retMsg.mweb_url;
payResult();
}
} else {
var toast = data.retMsg;
showToast(toast);
}
isClick = true;
},
error: function (err) {
console.log(err);
isClick = true;
var toast = '服务器开小差';
showToast(toast);
}
})
}
二、微信小程序
-
ios显示时间为NaN
小程序中的时间数据在安卓上能正常显示,但在ios系统上会显示NaN
原因是ios不支持在数据库中传递 2019-07-02这种格式的日期,必须转换为2019/07/02这种格式才会显示正常;
data.retInfo.activityList.forEach((item,index) => {
// console.log(new Date(item.expireTime.replace(/-/g, "/")).getTime());
// console.log(Number(new Date(item.expireTime.replace(/-/g, "/"))));
if(new Date(item.expireTime.replace(/-/g, "/")).getTime() < new Date(data.retInfo.serverTime.replace(/-/g, "/")).getTime()) {
item.isEnd = 1
} else {
item.isEnd = 0
}
})