前端填坑小指南

前端 0 86938
01759463
01759463 版主 - 前端 关注 2021年11月22日 17:38 编辑
[TOC]

cookies相关问题

1. 谷歌本地localhost无法登录,线上都没有问题

定位问题:

  • 验证码生成的cookies,无法发送到登录接口
  • 见下图
    • 感叹号中会提示sameSite属性问题,
    • 严格的 SameSite 属性意味着只能加载同一个网站的 cookies,宽松或缺省意味着可以加载跨站 cookies

解决方法:

  • 打开chrome 输入chrome://flags/搜索 SameSite by default cookies
  • 找到SameSite by default cookies和Cookies without SameSite must be secure
  • 将上面两项设置为 Disable

webpack配置相关

1. 跨域访问https

devServer属性

2. 提前在所有文件加载指定的less或scss

pluginOptions属性

  • pluginOptions: {
          'style-resources-loader': {
              preProcessor: 'less', // 可改成scss
              patterns: [
                  path.resolve(__dirname, 'src/assets/styles/var.less'),
                  path.resolve(__dirname, 'src/assets/styles/mixin.less')
              ]
          }
      }
    
  • 提前加载后,每一个vue文件都可以直接使用var.less中的变量,及mixin.less里的mixin方法

3. webpack设置全局变量

chainWebpack属性

chainWebpack: config => {
        // webpack4.0以上,使用该方法
        // 设置全局变量VUE_APP_CURRENTMODE,供axios跨域使用
        config.plugin('define').tap(args => {
            // 执行参数:argv.deploy,即 --deploy=dev 操作
            args[0]['process.env'].VUE_APP_CURRENTMODE = JSON.stringify(appConfig[argv.deploy].path)
            return args
        })
    }
  • appConfig = { dev: { path: ‘http://172.168.200.11:8015‘ } }
  • package.json中,增加scripts命令 "serve:dev": "vue-cli-service serve --deploy=dev"
  • argv = require('yargs').argv ,argv.deploy取值为dev
  • axois中,axios.defaults.baseURL = process.env.VUE_APP_CURRENTMODE
  • 运行 npm run serve:dev,即可在请求接口时,直接请求dev环境的接口
  • 除dev外,可添加各种环境的接口地址(如test,uat等),直接使用npm命令执行

IE8-10相关

1、ie10及以下浏览器添加了绝对定位的元素,绑定事件无效

需要给元素添加背景色
方法一:
ie9-10:background:rgba(255,255,255,0);
ie8:background:url(about:blank)(ie8不兼容rgba)
方法二:
设置元素背景色后设置透明度为0,(ie8:filter:alpha(opacity=0))
但是这种方式有个缺点,如果元素内有其他内容,其他内容透明度也会变成0

2、ie8-9不兼容表单placeholder属性

通过模拟生成其它标签实现placeholder效果

function placeholderSupport() {
  return 'placeholder' in document.createElement('input');
}

function placeholderRender() {
  //兼容ie9不支持placeholder标签
  if (!placeholderSupport()) {   // 判断浏览器是否支持 placeholder
    function GetStringNumValue(pxstr) {
      return pxstr.substring(0, pxstr.length - 2);
    }

    if ($('input[placeholder],textarea[placeholder]').parents('#formBuild-ie8').length) {
      return false;
    }
    $('input[placeholder],textarea[placeholder]').each(function () {
      var $element = $(this),
        placeholder = $element.attr('placeholder');

      if (placeholder) {
        // 文本框ID
        var elementId = $element.attr('id');
        if (!elementId) {
          var now = new Date();
          elementId = 'lbl_placeholder' + now.getSeconds() + now.getMilliseconds();
          $element.attr('id', elementId);
        }
      }
       // 添加label标签,用于显示placeholder的值
      var $label = $('<label>', {
        html: $element.val() ? '' : placeholder,
        'for': elementId,
        css: {
          position: 'absolute',
          cursor: 'text',
          color: '#ccc',
          fontSize: $element.css('fontSize'),
          fontFamily: $element.css('fontFamily'),
          zIndex: 9,
        }
      }).insertAfter($element);
      // 绑定事件
      $label.addClass('ie-placeholder')
      var _setPosition = function () {
        $label.css({
          top: '7px',
          left: '30px',
        });
      };
      var _resetPlaceholder = function () {
        if ($element.val()) {
          $label.html(null);
        } else {
          _setPosition();
          $label.html(placeholder);
        }
      };
      _setPosition();
      $element.on('focus blur input keyup propertychange resetplaceholder', _resetPlaceholder);
      /**
      以下代码可省略,为了解决点击表单弹出复杂弹窗选中数据的问题,
      问题:ie9中,点击input弹出复杂弹窗后选中数据赋值到input中,模拟出来的placeholder内容还存在,导致选中的数据和placeholder内容重叠
      原因:ie9的propertychange在失去焦点后不会触发
      解决:使用定时器来绑定了此方法!如果认为此方式耗性能,建议不要给该项添加placeholder属性
      **/
      if (isIE9 && $element.attr('readonly')){
        $element.click(function(){
          var intervalName;
          intervalName = setInterval(function () {
            $element.trigger("propertychange");
            if ($element.val()){
              clearInterval(intervalName);
            }else{
            }
          },1000);
        });
      }
    });
  }
}

效果(ie8):
image.png
image.png

label为生成的模拟placeholder效果的标签。

上面css样式可根据项目需求自行设置。
如上面注释中存在的问题,ie9的propertychange在失去焦点后不会触发,面对类似注释中比较复杂特殊的交互,使用了这种比较耗性能的方式解决,或者可以不要给该项设置placeholder,有其他更好的解决方式可以一起讨论。

3、ie8-9中ajax请求不支持跨域

设置允许跨域 jQuery.support.cors = true 也不支持
原因:IE10+ 才支持withCredentials属性,IE9以下不支持,跨域对象只能用XDomainRequest对象,而jQuery并不兼容XDomainRequest。
解决:
方法一:设置ie浏览器配置,“工具->Internet 选项->安全->自定义级别”将“其他”选项中的“通过域访问数据源”选中为“启用”(不太现实,无法操控用户设置)
方法二:别跨域请求了,前端配个nginx转发代理吧。(目前的项目采用的这种方式)
方法三:插件 jQuery-ajaxTransport-XDomainRequest,这是一个基于 XDomainRequest 实现 jquery ajxa 的 jquery 插件,为了支持 IE8、9的cors
PS:这里只是说jquery的ajax请求,不包括XMLHttpRequest等。

4、ie8不兼容css :nth-child()

但是………它兼容jquery的:nth-child()…………
emmmmmmmm……..
所以css文件中正常这么设置的样式

.index_bg .mainmenu li:nth-child(8n+1) {background-color:#36A1DB}
.index_bg .mainmenu li:nth-child(8n+2) {background-color:#678ce1}
.index_bg .mainmenu li:nth-child(8n+3) {background-color:#8c67df}

要兼容ie8的话,在js中:

if (isIE8) { //isIE8为项目中设置的一个全局变量
      $('.index_bg .mainmenu li:nth-child(8n+1)').css('backgroundColor', '#36A1DB')
      $('.index_bg .mainmenu li:nth-child(8n+2)').css('backgroundColor', '#678ce1')
      $('.index_bg .mainmenu li:nth-child(8n+3)').css('backgroundColor', '#8c67df')
    }

ie8也不兼容很多css3新属性,border-radius、box-shadow、background 背景渐变等,如果需求有这些,要么干掉需求,要么百度。

5、ie8不兼容各种操作数组或者对象很顺手的api

比如filter、forEach、map、Object.assign()、Object.keys()等等等等。。。
兼容:

//filter
if (!Array.prototype.filter) {
    Array.prototype.filter = function (fun ) {
      if (this === void 0 || this === null)
        throw new TypeError();
      var t = Object(this);
      var len = t.length >>> 0;
      if (typeof fun !== "function")
        throw new TypeError();
      var res = [];
      var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
      for (var i = 0; i < len; i++) {
        if (i in t) {
          var val = t[i];
          if (fun.call(thisArg, val, i, t))
            res.push(val);
        }
      }
      return res;
    };
  }

//forEach
if (!Array.prototype.forEach) {

    Array.prototype.forEach = function forEach(callback, thisArg) {

      var T, k;

      if (this == null) {
        throw new TypeError("this is null or not defined");
      }
      var O = Object(this);
      var len = O.length >>> 0;
      if (typeof callback !== "function") {
        throw new TypeError(callback + " is not a function");
      }
      if (arguments.length > 1) {
        T = thisArg;
      }
      k = 0;
      while (k < len) {
        var kValue;
        if (k in O) {
          kValue = O[k];
          callback.call(T, kValue, k, O);
        }
        k++;
      }
    };
  }

//map
if (typeof Array.prototype.map != "function") {
    Array.prototype.map = function (fn, context) {
      var arr = [];
      if (typeof fn === "function") {
        for (var k = 0, length = this.length; k < length; k++) {
          arr.push(fn.call(context, this[k], k, this));
        }
      }
      return arr;
    };
  }

//Object.assign()
if (typeof Object.assign != 'function') {
    Object.assign = function(target) {
      'use strict';
      if (target == null) {
        throw new TypeError('Cannot convert undefined or null to object');
      }
      target = Object(target);
      for (var index = 1; index < arguments.length; index++) {
        var source = arguments[index];
        if (source != null) {
          for (var key in source) {
            if (Object.prototype.hasOwnProperty.call(source, key)) {
              target[key] = source[key];
            }
          }
        }
      }
      return target;
    };
  }

//Object.keys()
var DONT_ENUM = "propertyIsEnumerable,isPrototypeOf,hasOwnProperty,toLocaleString,toString,valueOf,constructor".split(","),
    hasOwn = ({}).hasOwnProperty;
  for (var i in {
    toString: 1
  }) {
    DONT_ENUM = false;
  }
  Object.keys = Object.keys || function (obj) {//ecma262v5 15.2.3.14
    var result = [];
    for (var key in obj) if (hasOwn.call(obj, key)) {
      result.push(key);
    }
    if (DONT_ENUM && obj) {
      for (var i = 0; key = DONT_ENUM[i++];) {
        if (hasOwn.call(obj, key)) {
          result.push(key);
        }
      }
    }
    return result;
  };

都是从网上撸来的兼容方案。

6、IE8不识别媒体查询media

百度文件respond.min.js,引入到用到的文件中的条件注释里

  <!--[if IE 8]>
  <script src="respond.min.js"></script>
  <![endif]-->

注意:媒体查询在IE8里简写不生效。

7、ie中a标签的disabled属性

实际上,a标签没有disabled属性
但是,如果a标签中添加disabled属性,在ie中a标签点击事件无效
(本来也没想到会给a标签添加disabled属性,奈何可爱的后端同事们自己写功能的时候以为disabled对所有标签有效就乱加,以至于发现了这个奇怪的现象。)

8、console.log()在ie8中的猫腻

比较坑的一个问题,现在都是用的ie11仿真模式调试ie8浏览器,一般都是打开控制台调试,控制台关了之后仿真的ie8其实不准确,所以开发是没有关控制台,就没发现问题。
直到项目组用的时候发现了问题,就装了个虚拟机用真实ie8调试,发现某个功能有问题,f12开发者工具打开之后就正常了(也是测了很久才发现f12打开才正常)。
解决:删掉console.log(),IE8会将console.log()默认处理为错误逻辑,但是在F12下处理为控制台输出

H5问题

1. H5分享、支付功能

在H5中,不像微信小程序有自带的api,因此我们需要引入微信jssdk
在uni可以使用

npm install jweixin-module --save
var jweixin = require('utils/weixin-js-sdk')
wxshare(){
    var that = this
    uni.request({
        url: this.$serve.qcloudUrl + "/lbyxWeChat/config/getConfig",
        method: 'POST',
        data: {
            url: that.url
        },
        success(res) {
            jweixin.config({
                debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
                appId: res.data.data.appId, // 必填,公众号的唯一标识
                timestamp: res.data.data.timestamp, // 必填,生成签名的时间戳
                nonceStr: res.data.data.nonceStr, // 必填,生成签名的随机串
                signature: res.data.data.signature,// 必填,签名
                jsApiList: [
                    "checkJsApi",
                    'updateAppMessageShareData',
                    'updateTimelineShareData'
                ] // 分享到朋友圈和微信好友
            });
            jweixin.ready(function () {
                //获取“分享给朋友”按钮点击状态及自定义分享内容接口
                jweixin.updateAppMessageShareData({
                    title: getMessage(that.url).title || '裂变营销', // 分享标题
                    desc: getMessage(that.url).desc, // 分享描述
                    link: getMessage(that.url).link || that.url, // 分享链接
                    imgUrl: getMessage(that.url).imgUrl, // 分享图标
                    type: '', // 分享类型,music、video或link,不填默认为link
                    dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
                    success: function () {
                        console.log("设置成功")
                    }
                })
                //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口
                jweixin.updateTimelineShareData({
                    title: getMessage(that.url).title || '裂变营销', // 分享标题
                    link: getMessage(that.url).link || that.url, // 分享链接
                    imgUrl: getMessage(that.url).imgUrl, // 分享图标
                    type: '', // 分享类型,music、video或link,不填默认为link
                    dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
                    success: function () {
                        console.log("设置成功")
                    }
                })
            })
            // that.$hideLoading()
            that.tipsVisible = true
        }
    }) 
    function getMessage(url) {
        return {
            title: that.shareData.title || '',
            desc:  that.shareData.desc || '',
            imgUrl: that.shareData.imgUrl || '',
            link:  that.shareData.link || ''
        }
    }
}

2. IOS获取url路径问题

在IOS中网页得URL不会随着路由得变化而改变,所以配置得URL 跟当前显示得URL不同
而Android中的URL会随着路由得变化而改变
当我们需要获取url做一些配置的时候,比如分享、支付,就会导致url不一致报错
解决:根据运行机型取值(如果有分享的话,建议在第一次进入时候保存url路径,做分享的时候,直接取,而非使用spilt方式)

var that = this
let os 
uni.getSystemInfo({
    success: function (res) {
       os = res.platform
    }
});
if(os == "ios"){
    that.url = window.location.href.split("#")[0]
}else if(os == "android"){
    that.url = window.location.href
}

延展:当我们重定向页面返回以后,会发现上述方法没有办法解决
解决:刷新当前页面

mounted () {
        this.$nextTick(()=>{
            //跳转至地图或者静默授权返回 IOS不兼容页面自动刷新问题
            var u = navigator.userAgent,
            app = navigator.appVersion;
            var isAndroid = u.indexOf('Android') > -1; //android终端
            var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
            if(isiOS){
                window.onpageshow = function(event) {
                    if (event.persisted) {
                        window.location.reload()
                    }
                };
            }
        })
    },

3. hash模式和history模式

3.1、如果选用history模式会有个问题就是刷新当前页面会报错,hash模式不会
3.2 微信授权重定向页面如果是history模式,重定向页面正常,如果是hash模式,因为微信不会解析#,回调以后微信传回参数会写在#前面,因此我们去参前需要对url进行处理,处理方式如下

const w = location.href.indexOf('?');
const j = location.href.indexOf('#');
let href = window.location.href;
// 处理微信回调url
if (w !== -1 && j > w) { 
    href = location.href.substr(0, w) + location.href.substr(j, location.href.length) + location.search;
    location.href = href;
}

4、关于可视化问题

uni可视化可以选择uCharts,更实用兼容性会更强,支持H5、APP、小程序(微信/支付宝/百度/头条/QQ/360)
eCharts更适合在vue项目中引入
uCharts官方网站
https://www.uCharts.cn
开源地址:
https://gitee.com/uCharts/uCharts
uni-app插件市场地址:
http://ext.dcloud.net.cn/plugin?id=271

5、H5引入百度地图

定义一个map.js

export function mymap(ak) { // 此处ak是百度地图获取的密钥
  return new Promise(function(resolve, reject) {
    window.init = function() {
      resolve(mymap)
    }
    var script = document.createElement('script')
    script.type = 'text/javascript'
    script.src = `//api.map.baidu.com/api?v=2.0&ak=${ak}&callback=init`
    script.onerror = reject
    document.head.appendChild(script)
  })
}

新增map.vue组件

<template>
    <view class="baiduMap">
        <cu-custom bgColor="bg-gradual-theme">
            <block slot="leftAction">百度地图</block>
            <view class="cuIcon-close" slot="right" @click="$emit('closeMap')"></view>
        </cu-custom>
        <view class="allmap-container" v-show="show">
            <view id="allmap"></view>
            <view class="posiTop">
                <view class="dis">
                    <view class="input">
                        <input ref='suggestInput' id="suggestId" placeholder='输入关键字搜索' height='58' type="text" :border="true" />
                    </view>
                    <view class="button">
                        <button type="primary" shape="square" size="mini" @click="$emit('closeMap', addrData)">确认</button>
                    </view>
                </view>
            </view>
        </view>
    </view>
</template>

<script module="allmap" lang="renderjs">
import { mymap } from '@/utils/map' // 引入方法
export default {
    data() {
        return {
            // city: '',
            map: null,
            ak: 'GFMn8UVkLLDdHbO8WZcTWuh9v4vDbl4Q',
            show: false,
            lng: '', // 当前位置
            lat: '', // 当前位置
            // localSearch:null,
            addrData: {}
        }
    },
    mounted() { 
        // 百度地图API功能

        // 动态引入较大类库避免影响页面展示
        this.$nextTick(() => {
            let _this = this;

             // 如需要弹窗授权,请写在此处


            mymap(_this.ak).then((mymap) => {
                // 创建地图实例
                var map = new BMap.Map( "allmap" );

                // 关键字输入提示  用户选择地址后 只能获取详细位置 不能获取经纬度 所以我们需要把详细地址转经纬度
                // this.$refs.suggestInput.$el.querySelector('input') 很重要
                // suggestInput 是input标签中属性 ref的值
                let ac = new BMap.Autocomplete({
                    "input": this.$refs.suggestInput.$el.querySelector('input'),
                    "location": map
                })

                var localSearch = new BMap.LocalSearch(map);

                /**
                 * 浏览器定位 获取当前位置
                 * 当前方法可以准确获取用户位置 经纬度信息
                 */
                var geolocation = new BMap.Geolocation();
                geolocation.getCurrentPosition(function (r) {
                    if (this.getStatus() == BMAP_STATUS_SUCCESS) {
                        getAddress(r.point.lng, r.point.lat);// 通过经纬度获取详细地址信息

                        let point = new BMap.Point(r.point.lng, r.point.lat) // 设置中心点坐标
                        map.centerAndZoom(point, 16); //地图初始化并设置缩放级别
                        map.addOverlay(new BMap.Marker(point)); //添加标注
                        map.enableScrollWheelZoom(true); // 允许缩放地图
                    }else {
                        setByCity() // 若浏览器定位失败 改用IP定位
                    }
                })

                /**
                 * IP定位 获取当前位置
                 * 相比浏览器定位精确度更高
                 */
                function setByCity() {
                    var myCity = new BMap.LocalCity();
                    myCity.get(r => {
                        var cityName = r.name;
                        map.setCenter(cityName);
                        getAddress(r.center.lng, r.center.lat);// 通过经纬度获取详细地址信息

                        let point = new BMap.Point(r.center.lng, r.center.lat) // 设置中心点坐标
                        map.centerAndZoom(point, 16); //地图初始化并设置缩放级别
                        map.addOverlay(new BMap.Marker(point)); //添加标注
                        map.enableScrollWheelZoom(true); // 允许缩放地图
                    });
                }

                _this.map = map;
                // 等地图加载好后显示地图
                _this.show = true

                var myValue;
                //鼠标点击下拉列表后的事件
                ac.addEventListener("onconfirm", function(e) {  
                    var _value = e.item.value;
                    myValue = _value.province +  _value.city +  _value.district +  _value.street +  _value.business;
                    setPlace() // 移动到选中位置
                    searchByStationName(myValue) // 获取经纬度
                });
                // 地图上点击事件
                map.addEventListener('click', function (e) { 
                    let clickPoint = {lng: e.point.lng, lat: e.point.lat}
                    setPlace(clickPoint) // 移动到选中位置
                    getAddress(e.point.lng, e.point.lat) // 获取地址描述
                });

                // 点击列表 移动到选中的位置
                function setPlace(clickPoint){
                    map.clearOverlays(); //清除地图上所有覆盖物
                    function myFun(){
                        let pp = clickPoint ? clickPoint : local.getResults().getPoi(0).point; //获取传值或获取第一个智能搜索的结果
                        map.centerAndZoom(pp, 20); // 放大
                        map.addOverlay(new BMap.Marker(pp)); // 添加标注
                    }
                    var local = new BMap.LocalSearch(map, { //智能搜索
                      onSearchComplete: myFun
                    });
                    local.search(myValue);
                }

                // 根据地址信息获取经纬度
                function searchByStationName(keyword) {
                  localSearch.setSearchCompleteCallback(function (res) {
                    var poi = res.getPoi(0);
                    map.centerAndZoom(poi.point,16);
                       getAddress(poi.point.lng, poi.point.lat); // 通过经纬度 重新获取详细地址
                  });
                  localSearch.search(keyword);
                }

                // 根据坐标得到地址描述    
                function getAddress(lng, lat) {
                    _this.lng = lng // 经纬度
                    _this.lat = lat
                    var myGeo = new BMap.Geocoder();
                    // 根据坐标得到地址描述    
                    myGeo.getLocation(new BMap.Point(lng, lat), function (result) {
                        if (result) {
                            _this.addrData = result
                        } 
                    });
                }
            });
        });
    },
    methods: {}
}
</script>

<style lang="scss" scoped>
.cuIcon-close {
    height: 90upx;
    line-height: 90upx;
    margin-right: 20upx;
}
.cuIcon-close:before {
    font-size: 40upx;
}
#allmap{
    height: 100vh;
    width: 100%;
}
.u-input--border{
    padding: 0 0 0 20upx !important;
}
.posiTop{
    position: fixed;
    width: 100%;
    top: 90upx;
    .dis{
        padding: 20upx;
        background-color: rgba(255,255,255,0.97);
        display: flex;
        justify-content: space-between;
        .input{
            width: 80%;
            input {
                height: 72upx;
                line-height: 72upx;
                min-height: 72upx;
                border: 2upx solid #e0e0e0;
                border-radius: 10upx;
                padding-left: 10upx;
            }
        }
        .button{
            height: 72upx;
            button {
                height: 60upx;
                line-height: 60upx;
                margin-top: 6upx;
            }
        }
    }
}
</style>
赞(1) 收藏(0)  分享
相关标签: 笔记 讨论
0个回复
  • 消灭零回复
Vaptcha启动中...