美文网首页H5开发
H5 开发实战记录(持续更新)

H5 开发实战记录(持续更新)

作者: 风之化身呀 | 来源:发表于2017-08-27 23:09 被阅读20次

    1、瀑布流

    • 图片高度不固定
      这种方式实现的原理是用一个数组保存每一列的高度,新来的图片总是追加在高度值最小的那一列,结合绝对定位设置图片的left和top值即可。
    • 图片高度固定(webview的h5页面中很常见)
      这种高度固定不是说只有一种高度,而是有固定种类的高度,比如只有两种高度,一高一矮,两列布局,四个图片组成一个循环。这种方式的原理在于抓住四个一循环的规律,只要正确设置四张图片的位置,接下来的图片只是在已布局好的四张图片上加top而已。

    2、-webkit-overflow-scrolling : touch;
    IOS下用这个属性可以实现流畅滑动,但要注意和这几个属性一起用

    .container{
       -webkit-overflow-scrolling : touch; 
       overflow-y:auto;
        height:固定高度
    }
    

    如果.container有同级元素,且该元素用fixed定位,那么.container也必须使用定位属性,且设置z-index值,否则该属性可能不会生效。
    注:Android下要实现类似流畅滑动,可尝试使用iScroll.js,地址在这

    3、IOS下input问题

    • 输入框被弹起的系统键盘挡住
      当输入框在底部时,往往会使用固定定位fixed,当输入框获得焦点时,系统键盘会弹起,有时键盘会挡住输入框。
      解决办法:当输入框获得焦点时,用setInterval定时器不断调整input上方元素的scrollTop
      当输入框失去焦点时,取消该setInterval定时器
    • 输入框弹起后,点返回按钮键盘没有收起
      解决方法:路由切换时,使用document.activeElement.blur()手动触发blur事件
    • input几个常用事件
      change:开始输入时触发
      input:每次输入新值都会触发,对于根据input是否有内容来实时设置button样式很有用
      关于手机端IOS系统微信中虚拟键盘遮挡input输入框问题的解决方案
      IOS fixed input focus bug
      4、实用css
    -webkit-tap-highlight-color: rgba(0,0,0,0);            //去除点击阴影,IOS私有
    user-select:none;         //禁止用户选择文本
    -webkit-touch-callout: none   //禁止图片长按弹出菜单,img和a标签都要加
    pointer-events: none;            //禁止一切鼠标事件
    -webkit-appearance: none;   //消除输入框和按钮的原生外观,在iOS上加上这个属性才能给按钮和输入框自定义样式 
    // 实现谷歌浏览器支持<12px字体,比如显示7px,可采用如下方案
    .test_tag{  
        font-size:12px;  
        -webkit-transform-origin-x: 0;  
        -webkit-transform: scale(0.5833333333333334);   //  7/12=0.5833
    }  
    

    5、使用content做一个三个点加载动画
    本技巧来源于这里

    <a href="javascript:" class="grebtn">订单提交中<dot>...</dot></a>
    
    dot {
        display: inline-block; 
        height: 1em; line-height: 1;
        vertical-align: -.25em;
        overflow: hidden;
    }
    dot::before {
        display: block;
        content: '...\A..\A.';
        white-space: pre-wrap;
        animation: dot 3s infinite step-start both;
    }
    @keyframes dot {
        33% { transform: translateY(-2em); }
        66% { transform: translateY(-1em); }
    }
    

    原理:1 \A可以换行;2 before元素可以覆盖其寄生元素;3 用动画调整每次显示的content;4 不支持animation时只显示三个点(优雅降级&渐进增强)

    6、奇怪bug

    • 微信或QQ webview里尽量少用display:none,比如这样:
    .hide{
       display:none;
    }
    

    假如你给一个元素A运用了.hide,那么当你移除.hide,想让A显示出来时,A会有一定概率显示不出来

    • calc和display:flex一起使用时可能会失效

    7、事件代理是个好的事件处理技巧,但是要特别注意代理元素的选取,一般选取body,如果出现这种层级结构body>main>button,且main设置了opacity:1,那么想在body上代理button的点击事件是做不到的,因为body被main挡住了(PC端不会,但移动端会),解决方式是将代理设到main元素上,其实这个问题的根源在于opacity会挡住比他层级底的元素,使得事件冒泡无法进行。此外不要重复执行绑定操作,否则会被绑定多次(场景:A页面跳到B页面,在B页面做了修改A页面数据的操作,修改完返回到A页面,A页面需要重新拉数据渲染页面。这时应该只执行页面渲染操作,不能再执行事件绑定操作),浏览器对匿名函数的绑定会重复绑定,对命名函数的绑定不会多次绑定。

    8、monitorEvents(dom,eventName),可以模拟某元素上所有事件


    eventName可取值.png

    9、webpack设置代理问题:


    代理路径.png

    不能把backend放在backend2前面,根源在于不能使用正则匹配,导致/backend2会被/backend代理。

    10、正则
    要写一个复杂的正则,不一定要写成一个完整的形式;还可以通过分布的形式来实现,比如

    var hasNumberReg = /[0-9]/g,
          hasLetterReg = /[a-zA-Z]/g,
          hasSpecialReg = /[~!@#¥\$%\^&\*\(\)-_+=:;'",\.\<\>\/\|\\?\[\]{}]/g;
    // 必须包含字母数字和特殊符号的密码,可以这样分步写
    hasNumberReg.test(value) && hasLetterReg.test(value)&&hasSpecialReg.test(value)
    

    11、image-set
    image-set解决苹果的高平请显示图片问题,不支持image-set的浏览器下,他们解析background-image中的背景图像;
    支持image-set:
    如果你的浏览器支持image-set,而是普通屏下,此时浏览器选择image-set中1x背景图像
    如果你的设备是高清屏幕下(ppi大于320时)时浏览器会选择image-set中@2x背景图像。

            仅支持background-image属性,而不能使用在'<img>'标签中,老的安卓4.4以下的不支持
    
            优点:image-set不需要告诉浏览器使用什么图像,而是直接提供了图像让浏览器选择
    
        selector{
            background-image:url(no-image-set.png);
            background:image-set(url(foo-lowres.png) 1x,url(foo-highres.png) 2x) center;
        }
    

    12、移动端垂直居中问题(带四周边框)
    为了兼容IOS和Android,可设置line-height比height少1-2个像素

    13、REM布局
    设置html的font-size时机要很早才不会有闪烁的感觉,直接在head里内联以下脚本即可,rem布局可能会产生小数像素问题,这会导致使用background-img时被裁掉一点,解决方案是设置background-img时注意留点空白,也就1px的事情,具体参看这里

    <script>
    (function(doc, win) {
        var docEl = doc.documentElement,
            resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
            recalc = function() {
                var clientWidth = docEl.clientWidth;
                if (!clientWidth) return;
                docEl.style.fontSize = clientWidth / 7.5 + 'px';
            };
        if (!doc.addEventListener) return;
        win.addEventListener(resizeEvt, recalc, false);
        recalc();
    })(document, window);
        </script>
    

    14、对于scroll事件或mousewheel事件,使用passive模式的监听器,可使滑动更顺畅。如何不择手段提升scroll事件的性能

    window.addEventListeners('scroll',handler,{passive:true})
    
    兼容性

    15、DOMContentLoaded(蓝线),Loaded(红线),First Paint(绿线)


    image.png

    First Paint 一般位于二者之间,但最好在DOMContentLoaded之前
    对于defer的js文件会在DOMContentLoaded之前执行。js执行期间与页面渲染是一个竞态,若js操作了dom,以往的渲染会被取消。这个问题在首屏的骨架屏需要注意

    16、函数节流throttle和防抖debounce
    节流:保证m时间内必定执行一次,如图片懒加载,不希望滑动停止时才开始加载,而是在滑动过程中就要开始加载
    防抖:m时间内触发多次只执行一次,如scroll,resize等事件的触发

    // 简单的节流函数
    function throttle(func, wait, mustRun) {
        var timeout,
            startTime = new Date();
     
        return function() {
            var context = this,
                args = arguments,
                curTime = new Date();
     
            clearTimeout(timeout);
            // 如果达到了规定的触发时间间隔,触发 handler
            if(curTime - startTime >= mustRun){
                func.apply(context,args);
                startTime = curTime;
            // 没达到触发间隔,重新设定定时器
            }else{
                timeout = setTimeout(func, wait);
            }
        };
    };
    // 简单的防抖动函数
    function debounce(func, wait) {
        // 定时器变量
        var timeout;
        return function() {
            // 每次触发 scroll handler 时先清除定时器
            clearTimeout(timeout);
            // 指定 xx ms 后触发真正想进行的操作 handler
            timeout = setTimeout(func, wait);
        };
    };
    

    17、webworker使用方式

    // in html
    <script type="text/javascript">
    // we will use this function in-line in this page
    function isPrime(number)
    {
        if (number === 0 || number === 1) {
            return true;
        }
        var i;
        for (i = 2; i <= Math.sqrt(number); i++) {
            if (number % i === 0) {
                return false;
            }
        }
        return true;
    }
    
    // a large number, so that the computation time is sensible
    var number = "1000001111111111";
    // including the worker's code
    var w = new Worker('webworkers.js');
    // the callback for the worker to call
    w.onmessage = function(e) {
        if (e.data) {
            alert(number + ' is prime. Now I\'ll try calculating without a web worker.');
            var result = isPrime(number);
            if (result) {
                alert('I am sure, it is prime. ');
            }
        } else {
            alert(number + ' is not prime.');
        }
    };
    // sending a message to the worker in order to start it
    w.postMessage(number);
    
    </script>
    <p style="height: 200px; width: 400px; overflow: scroll;">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce blandit tristique risus, a rhoncus nisl posuere sed. Praesent vel risus turpis, et fermentum lectus. Ut lacinia nunc dui. Sed a velit orci. Maecenas quis diam neque. Vestibulum id arcu purus, quis cursus arcu. Etiam luctus, risus eu scelerisque scelerisque, sapien felis tincidunt ante, vel pellentesque eros nunc at magna. Nam tincidunt mattis velit ut condimentum. Vivamus ipsum ipsum, venenatis vitae placerat eu, convallis quis metus. Quisque tortor sapien, dapibus non vehicula quis, dapibus at purus. Nunc posuere, ligula sed facilisis sagittis, justo massa placerat nulla, nec pellentesque libero erat ut ligula. Aenean molestie, urna quis molestie auctor, lorem purus hendrerit nisi, vitae tincidunt metus massa et dolor. Sed leo velit, iaculis tristique elementum tincidunt, ornare et tellus. Quisque lacinia felis at est faucibus in facilisis dui consectetur. Phasellus sed ante id tortor pretium ornare. Aliquam ante justo, aliquam ut mollis semper, mattis sit amet urna. Pellentesque placerat, diam nec consectetur blandit, libero metus placerat massa, quis mattis metus metus nec lorem.
    </p>
    
    // in webworkers.js
    function isPrime(number)
    {
        if (number === 0 || number === 1) {
            return true;
        }
        var i;
        for (i = 2; i <= Math.sqrt(number); i++) {
            if (number % i === 0) {
                return false;
            }
        }
        return true;
    }
    
    // this is the point of entry for the workers
    onmessage = function(e) {
        // you can support different messages by checking the e.data value
        number = e.data;
        result = isPrime(number);
        // calling back the main thread
        postMessage(result);
    };
    

    18、requestAnimationFrame提升滚动动画

    const newScrollTop = this.getPosition(this.panes[index].$refs.content).top - this.distance
    
    function scrollStep() {
        document.documentElement.scrollTop += 5
        if (document.documentElement.scrollTop < newScrollTop) {
            window.requestAnimationFrame(scrollStep)
        }
    }
    window.requestAnimationFrame(scrollStep)
    

    可以将requestAnimationFrame看做一个钩子,刚好卡在浏览器重绘前向我们的操作伸出橄榄枝。实际上它更像定时器,每秒60次执行回调——符合屏幕的刷新频率,遇到耗时长的操作,这个数字会降到30来保证稳定的帧数。

    19、做弹窗时,会涉及到z-index问题,最好将弹窗的div层级与主内容并列

    相关文章

      网友评论

        本文标题:H5 开发实战记录(持续更新)

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