工作总结3.0

一、通用

  • 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");
lQLPJxZiSE3YHfXNAQ3NA4mw3V4s90wBVnkCohedpcDWAA_905_269.png
  • ie浏览器兼容问题
    Access-Control-Allow-Headers多行设置或者配的值有空格就会报错请求不通
lQLPJxZi8-lynFHMts0EzrAWsA3ei8QOZQKjMMfLgPgA_1230_182.png
  • 尺寸适配

    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
            }
      })

你可能感兴趣的:(工作总结3.0)