• 单页应用SPA开发最佳实践


    最近用vue+vue-router做了个单页应用的项目,页面大概有15个左右。积累了一些开发经验在此做一些记录.本文主要从可维护性方面来考虑SPA的开发实践

    全站的颜色定义放在一个less或者scss的文件里,其他组件和页面import这个配置来引用颜色。

    示例代码:define.scss

    $bgColor: #fff;
    $color:#619eee;
    $fontColor:#333333;
    $fontColor01:#A5A5A5;
    $fontColor02:#4a4a4a;
    $fontColor03:#448CFF;
    $color300:#ed5630;
    $color3001:#fbfbfb;
    $accpetColor:#2fbe27;
    $refusedColor: #de0101;
    $hrefColor:#4a90e2;
    $redColor:#ff4c4c;

    好处:

    方便维护整站的色彩风格,后续遇到VI升级改版等,你就偷着乐吧。

    vue,vue-router单独抽出来,用script标签引入

    bad case

    npm install vue
    npm install vue-router
    //js
    import Vue from 'vue'
    import VueRouter from 'vue-router'

    good case

    <script src="/path/to/vue.js"></script>
    <script src="/path/to/vue-router.js"></script>

    或者

    <script src="https://g.alicdn.com/cn-yz/bmw/0.2.5/vendor/vue??2.2.0.js,vue-router.min.js“></script>

    好处:

    import过来的js会和你的业务代码打包在一起。无谓的增加代码的体积,而且vue这类基础包的更新频率是低于业务代码的。单拆出来加载有利于浏览器缓存

    拆出来的会比import在一起的体积减小30k左右

    把你的异步请求方法封装在一个基础组件里

    ex:

    //myTool.js
    
    function get(param){
        $.get(param);
    }
    function post(param){
        $.post(param)
    }

    你可能会质疑。。这样有什么用

    • 1.当你的应用跑在在多个容器的场景,比如手淘,他有个mtop的请求模式(一种接口调用方式),比如还需要跑在钉钉里面。你只需要在里判断一下容器环境就可以区分对应的api调用方式

    ex:

    function get(param) {
        switch (container) {
            case "taobao":
                mtop.request(param);
                break;
            case "web":
                $.get(param)
                break;
            case "weixin":
                //balabala
                break;
            default:
                break;
        }
    }
    • 2.当你遇到csrf攻击需要给每个请求添加token。如果你不知道什么是csrf,请点击这里

    • 3.你可以在这里给每个请求添加一个loading模态框,免去每个方法调用前自己添加的烦恼

    ex:

    function get(param){
        var show = param.showloading===undefined?true:param.showloading;
        if(show){
            $.showPreloader();
        }
        $.get(param);
    }
    • 4.v-model与v-on:input的坑

    ex:vue 2.2.0+

    <input type="text" v-model="a" v-on:input="myInput"/>
    <script>
    function myInput(){
        this.a = "abc";
    }
    </script>

    当你在myInput方法里做一些操作,比如校验输入值,你会发现数据并没有更新到对应的input,这是因为v-model也监听了输入框的input事件

    解决办法:绑定value值,js更新value

    <input type="text" :value="a" v-on:input="myInput"/>
    <script>
    function myInput(){
        var formattedValue = "abc";
        this.a = formattedValue;
        this.$refs.input.value = formattedValue
        this.$emit('input', Number(formattedValue))
      }
    </script>

    对于中文:v-model也不是很适用

    对于要求 IME (如中文、 日语、 韩语等) (IME意为’输入法’)的语言,你会发现v-model不会在 ime 输入中得到更新。如果你也想实现更新,请使用 input事件。

    详见链接使用自定义事件的表单输入组件

    5. 优雅解决ios的fixed问题

    ios的fixed问题由来已久,在单页应用中我们免不了需要处理这样的bug。如何优雅解决这个问题

    如图:TB1H4VrdgMPMeJjy1XbXXcwxVXa-628-1052.jpg这是一个经典的移动端布局。header和footer相对于浏览器固定,body高度可变。

    这样的布局单独一个页面没什么难度。不过当你把footer设为fixed的时候会在ios上看到奇异的效果。

    当单页应用里有很多个这样的页面,而且header的高度也不是固定的时候,你就会发现每个页面都需要搞定body的高度css还是有点繁琐的。。

    有没有一个优雅的方式来做这个事情。让代码可维护性更好。

    这个布局的难点在于如何搞定body在不同机型上的高度。如果用纯css来做,可能需要用到calc,或者boder等之类的,而且针对每个页面不header不同,需要重新计算body的高度。

    虽然我们在布局方面不推荐使用js来处理,不过在是个时候是使用js处理body的高度的时候了。

    步骤:

    • 我们需要获取容器的高度。

    var w_height = $(window).height();
    • 获取header和footer的等fixed元素的高度

    这里我们可以给需要fixed的元素加个自定义属性

    fixed-box="true"

    <div class="header" fixed-box="true"></div>
    <div class="body " fixed-box="scroll">
    //balabalaba
    </div>
    <div class="footer" fixed-box="true"></div>
    • 在每个页面被路由到加载的时候mounted触发一个事件,告知js需要计算处理body高度

    mounted: function() {
                _body.trigger("mounted");        
             },
    • 在main.js等入口函数里监听这个事件处理相关逻辑

    jWin.on("mounted", function () {  
      //元素加载后计算可滚动元素的区域宽度    
          var height = 0;    
          $("[fixed-box='true']").each(function () {
                                  height = height + $(this).height();   
                                 }); 
          var h = w_height - height; 
          $('[fixed-box="scroll"]').height(h);
      });

    这样整个页面的布局都可以在这个js里处理,后续新增页面只需要做两个事情:

    1.给页面加fixed属性。
    
    2.在mounted方法里触发事件。
    

    6.如何拉起其他app

    webapp拉起其他native app是常见的场景,通常我们都通过scheme来拉起其他app

    不过在ios中偶尔会遇到这个拉起的动作偶尔会被一些web容器记录在history里。为了处理这个情况通常在ios里面我们都是建立一个iframe的元素然后把iframe的src指向这个schema,然后把iframe插入dom,在延时删除这个元素。这样history里就不会有这个记录了。不过此方法对安卓无效。


    同步更新在我的个人博客https://www.56way.com/p/108.html

  • 相关阅读:
    【js】字符串反转可实现的几种方式
    【js】深拷贝一文中的几个错误点
    关于js浅拷贝与深拷贝的理解
    chrome内核浏览器插件的使用--Tampermonkey(油猴插件)
    react复习总结(2)--react生命周期和组件通信
    react复习总结(1)--react组件开发基础
    对gulp的理解和使用(一)
    [luogu3391][文艺平衡树]
    [Splay][学习笔记]
    [bzoj1116][POI2008][CLO]
  • 原文地址:https://www.cnblogs.com/10manongit/p/12209863.html
Copyright © 2020-2023  润新知