开发移动端常见的问题集合

简介: 开发移动端常见的问题集合

ios滑动不流畅

  • 上下滑动页面会产生卡顿,手指离开页面,页面立即停止运动。整体表现就是滑动不流畅,没有滑动惯性。
  • 原来在 iOS 5.0以及之后的版本,滑动有定义有两个值 autotouch,默认值为 auto

    -webkit-overflow-scrolling: touch; /* 当手指从触摸屏上移开,会保持一段时间的滚动 */
    
    -webkit-overflow-scrolling: auto; /* 当手指从触摸屏上移开,滚动会立即停止 */
  • 在滚动容器上增加滚动 touch 方法

    .wrapper {
        -webkit-overflow-scrolling: touch;
    }
  • 设置 overflow

    设置外部 overflowhidden,设置内容元素 overflowauto。内部元素超出 body 即产生滚动,超出的部分 body 隐藏。

    body {
        overflow-y: hidden;
    }
    .wrapper {
        overflow-y: auto;
    }

页面放大或缩小不确定性行为

  • 双击或者双指张开手指页面元素,页面会放大或缩小。
  • 移动端常规写法

    <meta name="viewport" content="width=device-width, initial-scale=1.0">
  • 因此我们可以设置 maximum-scaleminimum-scaleuser-scalable=no 用来避免这个问题

    <meta name=viewport
      content="width=device-width, initial-scale=1.0, minimum-scale=1.0 maximum-scale=1.0, user-scalable=no">

click 点击事件延时与穿透

  • 监听元素 click 事件,点击元素触发时间延迟约 300ms
  • 点击蒙层,蒙层消失后,下层元素点击触发。
  • iOS中的 safari,为了实现双击缩放操作,在单击 300ms 之后,如果未进行第二次点击,则执行 click 单击操作。也就是说来判断用户行为是否为双击产生的。但是,在 App中,无论是否需要双击缩放这种行为,click 单击都会产生 300ms 延迟。
  • 使用 touchstart 替换 click

el.addEventListener("touchstart", () => { console.log("ok"); }, false);
  • `vue 中使用

    <button @touchstart="handleTouchstart()">点击</button>
  • 使用fastclick

    import FastClick from 'fastclick';
    
    FastClick.attach(document.body, options);

iPhone X系列安全区域适配问题

  • 头部刘海两侧区域或者底部区域,出现刘海遮挡文字,或者呈现黑底或白底空白区域。
  • 设置viewport-fitcover

    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes, viewport-fit=cover">
    
    • 使用 safe area inset 变量
    /* 适配 iPhone X 顶部填充*/
    @supports (top: env(safe-area-inset-top)){
      body,
      .header{
          padding-top: constant(safe-area-inset-top, 40px);
          padding-top: env(safe-area-inset-top, 40px);
          padding-top: var(safe-area-inset-top, 40px);
      }
    }
    /* 判断iPhoneX 将 footer 的 padding-bottom 填充到最底部 */
    @supports (bottom: env(safe-area-inset-bottom)){
        body,
        .footer{
            padding-bottom: constant(safe-area-inset-bottom, 20px);
            padding-bottom: env(safe-area-inset-bottom, 20px);
            padding-top: var(safe-area-inset-bottom, 20px);
        }
    }
    • safe-area-inset-left:安全区域距离左边边界距离
    • safe-area-inset-right:安全区域距离右边边界距离
    • safe-area-inset-top:安全区域距离顶部边界距离
    • safe-area-inset-bottom:安全区域距离底部边界距离

    safe-area-inset-top, safe-area-inset-right, safe-area-inset-bottom, safe-area-inset-left safe-area-inset-*由四个定义了视口边缘内矩形的 top, right, bottomleft 的环境变量组成,这样可以安全地放入内容,而不会有被非矩形的显示切断的风险。对于矩形视口,例如普通的笔记本电脑显示器,其值等于零。对于非矩形显示器(如圆形表盘,iPhoneX` 屏幕),在用户代理设置的四个值形成的矩形内,所有内容均可见。

H5调试相关方案策略

  • vconsole 控制台插件

    import Vconsole from 'vconsole'
    
    new Vconsole()
  • eruda手机端调试
  • 只要在我们的`html文件中写入下面这些代码,在手机上,也能想浏览器控制台一样进行查看。
<script src="//cdn.jsdelivr.net/npm/eruda"></script>
<script>
   eruda.init();
</script>

H5页面播放视频

  • H5页面播放视频,不全屏播放,在video标签添加playsinlinex5-playsinline设置为true就行

    <video id="my-video" class="video-js" controls preload="auto" 
                                data-setup=" {} " playsinline="true" x5-playsinline="true"> </video>

横屏适配

  • 很多视口我们要对横屏和竖屏显示不同的布局,所以我们需要检测在不同的场景下给定不同的样式:

    • JavaScript检测横屏
    window.addEventListener('resize',() =>{
        if(window.orientation === 180 || window.orientation === 0) {
            //正常方向或屏幕旋转180度
            console.log('竖屏')
        }
        
        if(window.orientation === 80 || window.orientation === -90) {
            //屏幕顺时钟旋转90度或屏幕逆时针旋转90度
            console.log('横屏')
        }
    })

    CSS检测横屏

    @media screen and (orientation:portrait){
        /*竖屏...*/
    }
    
    @media screen and (orientation:landscape){
        /*横屏...*/
    } 

移动端解决0.5px方案

  • 设备像素比:dpr=window.devicePixelRatio,也就是设备的物理像素与逻辑像素的比值
  • 0.5px 方案

    /*这是css方式*/
    .border { border: 1px solid #999 }
    @media screen and (-webkit-min-device-pixel-ratio: 2) {
        .border { border: 0.5px solid #999 }
    }
    /*ios dpr=2和dpr=3情况下border相差无几,下面代码可以省略*/
    @media screen and (-webkit-min-device-pixel-ratio: 3) {
        .border { border: 0.333333px solid #999 }
    }
  • viewport + rem

  • 同时通过设置对应viewportrem基准值,这种方式就可以像以前一样轻松愉快的写1px了。
    devicePixelRatio=2 时,设置meta

    <meta name="viewport" content="width=device-width,initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">
    

    实现

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <title>移动端1px问题</title>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
        <meta name="viewport" id="WebViewport"
            content="width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
        <style>
            html {
                font-size: 11px;
            }
            body {
                padding: 1rem;
            }
            * {
                padding: 0;
                margin: 0;
            }
            .item {
                padding: 1rem;
                border-bottom: 1px solid gray;
                font-size: 1.2rem;
            }
        </style>
        <script>
            var viewport = document.querySelector("meta[name=viewport]");
            var dpr = window.devicePixelRatio || 1;
            var scale = 1 / dpr;
            //下面是根据设备dpr设置viewport
            viewport.setAttribute(
                "content", +
                "width=device-width," +
                "initial-scale=" +
                scale +
                ", maximum-scale=" +
                scale +
                ", minimum-scale=" +
                scale +
                ", user-scalable=no"
            );
    
            var docEl = document.documentElement;
            var fontsize = 10 * (docEl.clientWidth / 320) + "px";
            docEl.style.fontSize = fontsize;
        </script>
    </head>
    <body>
        <div class="item">border-bottom: 1px solid gray;</div>
        <div class="item">border-bottom: 1px solid gray;</div>
    </body>
    </html>

移动端适配方案

  • rem适配

    rem适配的本质是布局等比例的缩放,通过动态设置htmlfont-size来改变rem的大小。

    <meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1; minimum-scale=1; user-scalable=no;">
  • 引入flexible

    • flexible方案是阿里早期开源的一个移动端适配解决方案,引用 flexible后,我们在页面上统一使用 rem`来布局。

      (function(win, lib) {
          var doc = win.document;
          var docEl = doc.documentElement;
          var metaEl = doc.querySelector('meta[name="viewport"]');
          var flexibleEl = doc.querySelector('meta[name="flexible"]');
          var dpr = 0;
          var scale = 0;
          var tid;
          var flexible = lib.flexible || (lib.flexible = {});
          
          if (metaEl) {
              console.warn('将根据已有的meta标签来设置缩放比例');
              var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/);
              if (match) {
                  scale = parseFloat(match[1]);
                  dpr = parseInt(1 / scale);
              }
          } else if (flexibleEl) {
              var content = flexibleEl.getAttribute('content');
              if (content) {
                  var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
                  var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
                  if (initialDpr) {
                      dpr = parseFloat(initialDpr[1]);
                      scale = parseFloat((1 / dpr).toFixed(2));    
                  }
                  if (maximumDpr) {
                      dpr = parseFloat(maximumDpr[1]);
                      scale = parseFloat((1 / dpr).toFixed(2));    
                  }
              }
          }
      
          if (!dpr && !scale) {
              var isAndroid = win.navigator.appVersion.match(/android/gi);
              var isIPhone = win.navigator.appVersion.match(/iphone/gi);
              var devicePixelRatio = win.devicePixelRatio;
              if (isIPhone) {
                  // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
                  if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {                
                      dpr = 3;
                  } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
                      dpr = 2;
                  } else {
                      dpr = 1;
                  }
              } else {
                  // 其他设备下,仍旧使用1倍的方案
                  dpr = 1;
              }
              scale = 1 / dpr;
          }
      
          docEl.setAttribute('data-dpr', dpr);
          if (!metaEl) {
              metaEl = doc.createElement('meta');
              metaEl.setAttribute('name', 'viewport');
              metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
              if (docEl.firstElementChild) {
                  docEl.firstElementChild.appendChild(metaEl);
              } else {
                  var wrap = doc.createElement('div');
                  wrap.appendChild(metaEl);
                  doc.write(wrap.innerHTML);
              }
          }
      
          function refreshRem(){
              var width = docEl.getBoundingClientRect().width;
              if (width / dpr > 540) {
                  width = 540 * dpr;
              }
              var rem = width / 10;
              docEl.style.fontSize = rem + 'px';
              flexible.rem = win.rem = rem;
          }
      
          win.addEventListener('resize', function() {
              clearTimeout(tid);
              tid = setTimeout(refreshRem, 300);
          }, false);
          win.addEventListener('pageshow', function(e) {
              if (e.persisted) {
                  clearTimeout(tid);
                  tid = setTimeout(refreshRem, 300);
              }
          }, false);
      
          if (doc.readyState === 'complete') {
              doc.body.style.fontSize = 12 * dpr + 'px';
          } else {
              doc.addEventListener('DOMContentLoaded', function(e) {
                  doc.body.style.fontSize = 12 * dpr + 'px';
              }, false);
          }
          
      
          refreshRem();
      
          flexible.dpr = win.dpr = dpr;
          flexible.refreshRem = refreshRem;
          flexible.rem2px = function(d) {
              var val = parseFloat(d) * this.rem;
              if (typeof d === 'string' && d.match(/rem$/)) {
                  val += 'px';
              }
              return val;
          }
          flexible.px2rem = function(d) {
              var val = parseFloat(d) / this.rem;
              if (typeof d === 'string' && d.match(/px$/)) {
                  val += 'rem';
              }
              return val;
          }
      
      })(window, window['lib'] || (window['lib'] = {}));
    • 使用vw,vh布局
    • vh、vw方案即将视觉视口宽度 window.innerWidth和视觉视口高度 window.innerHeight 等分为 100 份。
    • 如果视觉视口为 375px,那么 1vw=3.75px,这时 UI给定一个元素的宽为 75px(设备独立像素),我们只需要将它设置为 75/3.75=20vw
    • 这里的比例关系我们也不用自己换算,我们可以使用 PostCSSpostcss-px-to-viewport 插件帮我们完成这个过程。写代码时,我们只需要根据 UI给的设计图写 px单位即可。

      module.exports = {
        plugins: [
          require('autoprefixer'),
          require('postcss-import'),
          require('postcss-url'),
          require('postcss-preset-env'),
          require('postcss-aspect-ratio-mini'),
          require('postcss-write-svg'),
          require('postcss-px-to-viewport')({
            viewportWidth: 750,
            viewportHeight: 1334,
            unitPrecision: 3,
            viewportUnit: 'vw',
            selectorBlackList: [ '.ignore', '.hairlines', '.footer' ],
            minPixelValue: 1,
            mediaQuery: true
          }),
          require('cssnano')
        ]
      }
      

快速生成HTML代码结构

#page>div.logo+ul#navigation>li*5>a{Item $}

可以转换为

<div id="page">
    <div class="logo"></div>
    <ul id="navigation">
        <li><a href="">Item 1</a></li>
        <li><a href="">Item 2</a></li>
        <li><a href="">Item 3</a></li>
        <li><a href="">Item 4</a></li>
        <li><a href="">Item 5</a></li>
    </ul>
</div>
  • 使用>运算符将元素相互嵌套

    div>ul>li 生成
    <div>
        <ul>
            <li></li>
        </ul>
    </div>
  • 使用+运算符将元素彼此放置在同一水平上:

    div+p+bq 生成
    <div></div>
    <p></p>
    <blockquote></blockquote>
  • 使用括号将复杂缩写的子树分组

    div>(header>ul>li*2>a)+footer>p  生成
    <div>
        <header>
            <ul>
                <li><a href=""></a></li>
                <li><a href=""></a></li>
            </ul>
        </header>
        <footer>
            <p></p>
        </footer>
    </div>
目录
相关文章
|
3天前
|
移动开发 前端开发 JavaScript
惊!这些前端技术竟然能让你的网站在移动端大放异彩!
随着互联网技术的发展,移动设备成为主要的上网工具。本文介绍了几种关键的前端技术,包括响应式设计、图片优化、字体选择、HTML5和CSS3的应用、性能优化及手势操作设计,帮助开发者提升网站在移动端的显示效果和用户体验。示例代码展示了如何实现简单的双向绑定功能。
12 3
|
6月前
|
数据安全/隐私保护
那些酷炫的网页你也可以做到——第六篇,小型公司web开发
那些酷炫的网页你也可以做到——第六篇,小型公司web开发
|
2月前
|
图形学 iOS开发 Android开发
从Unity开发到移动平台制胜攻略:全面解析iOS与Android应用发布流程,助你轻松掌握跨平台发布技巧,打造爆款手游不是梦——性能优化、广告集成与内购设置全包含
【8月更文挑战第31天】本书详细介绍了如何在Unity中设置项目以适应移动设备,涵盖性能优化、集成广告及内购功能等关键步骤。通过具体示例和代码片段,指导读者完成iOS和Android应用的打包与发布,确保应用顺利上线并获得成功。无论是性能调整还是平台特定的操作,本书均提供了全面的解决方案。
150 0
|
3月前
|
开发者 图形学 iOS开发
掌握Unity的跨平台部署与发布秘籍,让你的游戏作品在多个平台上大放异彩——从基础设置到高级优化,深入解析一站式游戏开发解决方案的每一个细节,带你领略高效发布流程的魅力所在
【8月更文挑战第31天】跨平台游戏开发是当今游戏产业的热点,尤其在移动设备普及的背景下更为重要。作为领先的游戏开发引擎,Unity以其卓越的跨平台支持能力脱颖而出,能够将游戏轻松部署至iOS、Android、PC、Mac、Web及游戏主机等多个平台。本文通过杂文形式探讨Unity在各平台的部署与发布策略,并提供具体实例,涵盖项目设置、性能优化、打包流程及发布前准备等关键环节,助力开发者充分利用Unity的强大功能,实现多平台游戏开发。
97 0
|
存储 人工智能 算法
MATIC马蹄链佛萨奇2.0系统源码搭建|现成案例|成熟技术
function _setImplementation(address newImplementation)internal{
|
数据可视化 JavaScript 物联网
ThingJS之3D开发:如何做颜值高的设计?
不要把关于设计的这些内容看得太过严肃。
ThingJS之3D开发:如何做颜值高的设计?
|
存储 JavaScript 定位技术
ThingJS的3D渲染功能,让你拥有高颜值的项目
线条有分长短、曲直、粗细,不同的语素表达不同的情感。
ThingJS的3D渲染功能,让你拥有高颜值的项目
|
开发者
小视频APP源码开发者对小视频平台的三个忠告
作为一个小视频APP开发人员,向各位想要开发短视频APP的朋友们提出几点忠告
|
Android开发 UED iOS开发
安卓设计师不容错过的15款实用UI界面设计工具
最近刮起了一股“养蛙儿子”的风潮。独特的UI设计、萌萌的画风和简洁的用户体验吸引了大批的用户。在不少人直呼“哇,我的蛙儿子好可爱,好萌”的背后,我们可以看到一个高质量的UI设计对于提高应用下载量有着非常重要的作用。
2496 0
|
移动开发 前端开发 JavaScript
移动端H5多页开发拍门砖经验
两年前刚接触移动端开发,刚开始比较疑惑,每次遇到问题都是到社区里提问或者吸取前辈的经验分享,感谢热衷于分享的开发者为前端社区带来欣欣向上的生命力。本文结合先前写的文章和开发经验分享给大家,希望也能帮助刚步入移动端开发的新人解惑。
2331 0