美文网首页
2021-03-04

2021-03-04

作者: kalrase | 来源:发表于2021-03-03 11:03 被阅读0次

    移动的端常见问题

    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-leftsafe-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>
      

    相关文章

      网友评论

          本文标题:2021-03-04

          本文链接:https://www.haomeiwen.com/subject/mjohqltx.html