移动端常见问题总结

912 阅读5分钟

前言

开发移动端的项目也有一段时间了,平时踩的坑也不少,有些坑由于解决之后忘记总结,导致还不止踩一次,所以决定好好总结下移动端开发遇到的一些问题及解决办法

总结

去掉ios的input的圆角
border-radius:0;
-webkit-appearance:none;/*清除ios默认圆角*/

这个是在input输入框设置border-bottom: 1px solid #C3C3C3;发现这根线在ios上2侧存在一个弧度。

某些安卓中input获取焦点之后,border-bottom消失

场景:在某些安卓机(乐视)中,发现只设置input的border-bottom。在input框获取到焦点之后,border-bottom消失了。解决办法:

border-bottom: 1px solid #C3C3C3;
border-color: #fff #fff #C3C3C3 #fff;
html2canvas

有时我们需要实现在浏览器端直接对整个或部分页面进行截屏,比如移动端常见的“长按网页保存为图片”功能。这个借助 html2canvas 这个第三方 js 库即可实现。这个库在使用中还是踩不少坑,这里主要说2个常见的:

  1. 图片跨域的解决 在使用html2canvas生成图片的时候,图片资源跨域是会报错的,我们可以在nginx中配置解决跨域问题,但是今天来介绍一种不需要nginx配置的解决办法:
    var canvas = document.createElement('canvas');
    var ctx = canvas.getContext('2d');
    var image = new Image();
    var dataUrl = '';
    image.src = 'https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/6/8/17293c387554b8bd~tplv-t2oaga2asx-image.image';
    image.onload = ()=>{
        ctx.drawImage(image, 0, 0);
        dataUrl = canvas.toDataURL('image/png');
        this.$refs.imgs.src = dataUrl;
    }

通过canvas把我们图片资源转成base64的格式。本以为这样就大功告成了,兴奋去跑代码,结果控制台报如下错误:

Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement':
Tainted canvases may not be exported.

这是什么原因呢:这是受限于 CORS 策略,会存在跨域问题,虽然可以使用图像,但是绘制到画布上会污染画布,一旦一个画布被污染,就无法提取画布的数据,比如无法使用使用画布toBlob(),toDataURL(),或getImageData()方法;当使用这些方法的时候 会抛出上面的安全错误

解决办法:img新增了crossorigin属性,这个属性决定了图片获取过程中是否开启CORS功能。

image.setAttribute('crossorigin', 'anonymous');
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var image = new Image();
var dataUrl = '';
image.setAttribute('crossorigin', 'anonymous');
image.src = 'https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/6/8/17293c387554b8bd~tplv-t2oaga2asx-image.image';
image.onload = ()=>{
    ctx.drawImage(image, 0, 0);
    dataUrl = canvas.toDataURL('image/png');
    this.$refs.imgs.src = dataUrl;
}
  1. 图片的清晰度问题

在我们生成的海报图片后,发现图片很模糊,网上的推荐方法发现一般推荐的是如下方法:

/*图片跨域及截图模糊处理*/
  let shareContent = domObj,//需要截图的包裹的(原生的)DOM 对象
  width = shareContent.clientWidth,//shareContent.offsetWidth; //获取dom 宽度
  height = shareContent.clientHeight,//shareContent.offsetHeight; //获取dom 高度
  canvas = document.createElement("canvas"), //创建一个canvas节点
  scale =  window.devicePixelRatio; //定义任意放大倍数 支持小数。
  canvas.width = width * scale; //定义canvas 宽度 * 缩放
  canvas.height = height * scale; //定义canvas高度 *缩放
  canvas.style.width = shareContent.clientWidth * scale + "px";
  canvas.style.height = shareContent.clientHeight * scale + "px";
  canvas.getContext("2d").scale(scale, scale); //获取context,设置scale
let opts = {
      scale: scale, // 添加的scale 参数
      canvas: canvas, //自定义 canvas
      logging: false, //日志开关,便于查看html2canvas的内部执行流程
      width: width, //dom 原始宽度
      height: height,
      useCORS: true // 【重要】开启跨域配置
};
html2canvas(shareContent,opts).then() 

但是使用如上的方法之后,发现还是没有改变,生成的图片还是很模糊,不清晰。

百思不得其解,运营小姐姐说:之前的活动生成图片都很清晰呀,为什么你的这个模糊,咦,之前的很清晰,后来去参考了之前做过的活动页面生成的海报发现之前海报的图片都是用的img标签,但是我的用的是background-image。那么问题就简单了:只要使用img来实现background-image的效果,问题就迎刃而解了。

滚动穿透问题

问题描叙:弹出层内容滚动时,body跟随滚动。

解决办法:

//打开模态框前调用
function fixedBody() {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
    document.body.style.cssText += 'position:fixed;top:-' + scrollTop + 'px;';
}

//关闭模态框后调用
function looseBody() {
    var body = document.body;
    body.style.position = 'static';
    var top = body.style.top;
    document.body.scrollTop = document.documentElement.scrollTop = -parseInt(top);
    body.style.top = '';
}

基于vue指令的写法:

directives: {
  fixed: {
    // inserted 被绑定元素插入父节点时调用
    inserted () {
        var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
        document.body.style.cssText += 'position:fixed;top:-' + scrollTop + 'px;';
    },
    // unbind 指令与元素解绑时调用
    unbind () {
        var body = document.body;
        body.style.position = 'static';
        var top = body.style.top;
        document.body.scrollTop = document.documentElement.scrollTop = -parseInt(top);
        body.style.top = '';
    }
  }
},
    
<div class="mask" v-if="show" v-fixed>
</div>
    

还有一种方案是:使用(overscroll-behavior: contain;) 滚动不会传播给祖先。

ios 短信验证码自动填充时被复制两遍

因为type的number不支持maxLen,故这里使用type=tel。

<input type="tel" maxlength="6">
ios 上1px的问题

为什么存在1px

首先需要明白物理像素和css像素的关系

dpr = 物理像素/css像素

一般iphone6的dpr是2,一般设计稿是750,这里的750是设备像素。那么对于iphone6来说,设计稿上的1px,对应的css像素就是0.5px。直接使用0.5px在某些手机上不行

1px的解决办法:

@mixin border-bottom($color) {
    position: relative;
    &::after {
        position: absolute;
        content: '';
        width: 100%;
        left: 0;
        bottom: 0;
        height: 0.02rem;
        background-color: $color;
        transform: scale(1,.5);
        transform-origin: center bottom
    }
}

@mixin border-top($color) {
    position: relative;
    &::before {
        position: absolute;
        content: '';
        width: 100%;
        left: 0;
        top: 0;
        height: 0.02rem;
        background-color: $color;
        transform: scale(1,.5);
        transform-origin: center top
    }
}

@mixin border-left($color) {
    position: relative;
    &::before {
        position: absolute;
        content: '';
        left: 0;
        top: 0;
        width: 0.02rem;
        height: 100%;
        background-color: $color;
        transform: scale(0.5,1);
        transform-origin: center top
    }
}

@mixin border($color, $radius) {
    position: relative;
    &::before {
        position: absolute;
        top: -50%;
        bottom: -50%;
        left: -50%;
        right: -50%;
        content: '';
        transform: scale(0.5);
        border: 0.02rem solid $color;
        border-radius: $radius
    }
}

css文本溢出
  1. 单行溢出
width: 300px;
overflow: hidden;
/*文本不会换行*/
white-space: nowrap;
/*当文本溢出包含元素时,以省略号表示超出的文本*/
text-overflow: ellipsis;
  1. 多行溢出
width: 300px;
overflow: hidden;
/*将对象作为弹性伸缩盒子模型显示*/
display: -webkit-box;
/*设置子元素排列方式*/
-webkit-box-orient: vertical;
/*设置显示的行数,多出的部分会显示为...*/
-webkit-line-clamp: 3;
ios 日期转换 NAN 的问题

ios 不支持例如2018-09-01 10:00:59这种"-"连接符。

这种方式在ios上获取的时间是NAN

let startTime = new Date('2019/01/17 15:28:00').getTime();

解决办法我们把“-” 替换为 “/”

let startTime = new Date('2019/01/17 15:28:00'.replace(/-/g, '/')).getTime();

修改光标的颜色
caret-color: red;
修改css的placeholder文字的颜色
input::-webkit-input-placeholder,
textarea::-webkit-input-placeholder {
  color: red;
}
input:-moz-placeholder,
textarea:-moz-placeholder {
  color: red;
}
input:-ms-input-placeholder,
textarea:-ms-input-placeholder {
  color: red;
}
微信公众号分享问题

页面内部点击分享按钮调用 SDK,方法不生效。

解决办法:点击按钮添加蒙层,做分享引导。

分享注意点:

  1. 需要代理到线上的JSSDK文件。
  2. 文案和图片在微信的开发者工具查看即可。
  3. 带中文的url在安卓中应该也是会出问题的,但是安卓会自动encodeURIComponent(),而ios不会。所以会出现安卓自定义可以正常分享,但是ios就不行。需要我们自行encodeURIComponent。
结尾

这个文章后面会陆续补充。

本文使用 mdnice 排版