• simple-spa 一个简单的单页应用实例


    上两篇文章说过要写一个简单的单页应用例子的, 迟迟没有兑诺, 实在有愧 哈哈。这篇写给小白用户哈。

    正好趁今天风和日丽,事情不多, 把从项目里的代码扣取了一下, 整理了一个简单的例子。
    因为我们生产项目用到es6 还有构建工具,为了让例子足够简单和原生,除了一个zepto,连require都是我之前写的文章里的实现的,很简单70行代码。

    事例地址

    github:https://github.com/skyweaver213/simple-spa

    demo: https://skyweaver213.github.io/simple-spa/example/demo/index.html

    单页应用

    单页应用是指在浏览器中运行的应用,它们在使用期间不会重新加载页面。像所有的应用一样,它旨在帮助用户完成任务,比如“编写文档”或者“管理Web服务器”。可以认为单页应用是一种从Web服务器加载的富客户端。(摘自:http://blog.csdn.net/zuoninger/article/details/38842823

    如何实现

    单页应用 说白了就是不用刷新页面,例如首页点击 查询到 列表页,一般给一个过场动画,从而优化用户的体验。但是往往单页应用首次加载时间比较长,因为很多人往往把代码都打进首屏里了。

    然后能不能做到既要极速打开首屏体验,也要保留单页的流程用户体验呢?

    这时候  极致的按需, 能把这个问题 迎刃而解。

    截图为例, 例如绿色的其实就是用户打开这个页面首先最关心的部分,我们把这部分归入到首屏里,然后待首屏渲染成功后,再异步 require 其他首屏之额的模块,例如我蓝色框住的信息和操作。

    例如这样。

            //航班卡片渲染
            flightInfo.render(orderDetail, orderDetailInfo);
            //价格render
            pricetotal.render(orderDetail, orderDetailInfo);
        
            //异步模块加载  
            this.loadAsynModules();
            this.loadAsynXprdModules();    

    1、单页的核心实现

    利用了浏览器 支持历史记录操作,pushState 和popstate (如果不支持这个属性的浏览器可以用hashchange这个事件代替,移动端基本都支持了)

    没了解过这个属性的 可以看看 张鑫旭的 :http://www.zhangxinxu.com/wordpress/2013/06/html5-history-api-pushstate-replacestate-ajax/

    流程大概是这样

    拉取html:

     1                 var me = this;
     2                 //获取html
     3                 $.ajax({
     4                     url: htmlPath,
     5                     type: 'get',
     6                     success: function (data) {
     7                         //console.log('ss data ', data);
     8                         getScript(data, me);
     9                     },
    10                     error: function (e) {
    11                         console.log('error ', e);
    12                     }
    13 
    14                 });

    html 内容:

     1 <div class="main-viewport">
     2     <div class="viewport index-viewport" data-no-init="true">
     3         <style>
     4             .index-viewport {
     5                 background: cornflowerblue;
     6             }
     7         </style>
     8 
     9         <div class="viewport-content">
    10             index
    11 
    12             <button class="js_tolist"> to list </button>
    13         </div>
    14 
    15 
    16         <script type="text/fscript" data-src="./js/index.js" ></script>
    17     </div>
    18 </div>

    注意 script是 data-src ,因为是单页代码动态引入,然后拉取html成功后 会自动关联viewport下的script,再读取data-src的内容,然后动态引入script资源。

    动态引入js:

     1                 //取scripts的绝对路径 如果不是绝对路径 ,需要动态计算
     2                 var script_path = scripts[0].getAttribute('data-src') || '';
     3 
     4                 require([script_path], function (exports) {
     5 
     6                     var view = cloneObj(exports.view);
     7 
     8                     view.htmlPath = htmlPath;
     9                     view.viewPort = $("[page-path='" + htmlPath + "']");
    10                     view.$ = function (selector) {
    11                         return view.viewPort.find(selector);
    12                     };
    13                     //每创建一个view 把引用存起来
    14                     DF.VIEWREF[htmlPath] = view;
    15 
    16                     //如果上一个view存在
    17                     scope.preView && scope.preView.onHide.apply(scope.preView);
    18 
    19                     //加载页面完成后
    20                     scope.fishLoad(htmlPath, pushState, search);
    21 
    22 
    23                     view && view.onCreate.apply(view);
    24                     //绑定事件
    25                     if (view && view.events) {
    26                         DF.bindEventAction.call(view, view.events);
    27                     }
    28 
    29 
    30                     view && view.onShow.apply(view);
    31                     if (view.onAppear) {
    32                         DF.onAppear = view.onAppear;
    33                     }
    34                     scope.updatePageid(view);
    35 
    36 
    37                 });

    js动态引入成功后,再执行单页的生命周期。

    分别是

    onCreate 页面创建的时候执行, 只执行一次

    onShow  页面创建后会执行, 每次切换下一个页面会执行

    onHide   页面切换的时候,上一个页面隐藏的时候会执行

     然后资源加载成功,页面渲染成功后, 会pushSate,修改浏览器地址

     1     //fishLoad
     2     fishLoad: function (htmlPath, pushState, search) {
     3         //记录上一个页面
     4         if (this.curView) {
     5             this.preView = this.curView;
     6         } else {
     7             this.preView = DF.VIEWREF[htmlPath];
     8         }
     9 
    10         search = search || '';
    11 
    12         //设置当前view
    13         this.curView = DF.VIEWREF[htmlPath];
    14 
    15         //console.log('curview ', this.curView.htmlPath, ' preView ', this.preView.htmlPath)
    16 
    17         //渲染成功
    18         if (pushState) {
    19             history.pushState({
    20                 'viewPath': htmlPath,
    21                 'pro': 'spa',
    22                 'url': htmlPath
    23             }, "页面标题", htmlPath + search);
    24         }
    25 
    26     },

    back回退的:

     1        back: function () {
     2            history.back();
     3        },
     4 
     5         //history.back 会触发 popstate,然后会重新走loadView逻辑
     6         $(window).bind("popstate.pageview", function (e) {
     7 
     8             //是单页spa操作  才触发
     9             if (this.getViewPath(location.href) != this.curView.htmlPath) {
    10                 /*
    11                  * 该干嘛干嘛
    12                  */
    13                 var pat = new RegExp(FHYBRID.appPath, 'i');
    14                 DF.loadView(location.pathname.replace(pat, ''), false, false, true);
    15             }
    16 
    17         }.bind(this));

    动画过渡:

     1     //动画执行方法
     2     /**
     3      * @param animInitClass  动画初始化时候的class
     4      * @param animBeforeClass  动画执行前的class
     5      * @param animEndClass  动画执行后的class
     6      */
     7     viewAnimation: function (opt) {
     8         var $static_el = opt.staticView;
     9         var $anim_el = opt.animView;
    10         var $anim_init_class = opt.animInitClass;
    11         var $anim_before_class = opt.animBeforeClass;
    12         var $anim_end_rmclass = opt.animEndClass;
    13         var anim_type = opt.animType || 'in';  //动画是进入 还是  出  ;  in  or out
    14 
    15         $anim_el.addClass($anim_init_class);
    16 
    17         //进入 动画节点 显示, 出, 对上一个页面显示
    18         (anim_type == 'in') ? $anim_el.show() : $static_el.show();
    19 
    20 
    21         setTimeout(function () {
    22             $anim_el.addClass($anim_before_class);
    23 
    24             $anim_el.on('webkitTransitionEnd', function () {
    25                 //进入 对上一个页面隐藏;  出 动画节点 隐藏,
    26                 (anim_type == 'in') ? $static_el.hide() : $anim_el.hide();
    27 
    28                 $anim_el.removeClass($anim_end_rmclass);
    29                 $anim_el.off('webkitTransitionEnd');
    30             });
    31         }, 0);
    32 
    33 
    34     },

    调用:

    1                     //切换动画
    2                     this.viewAnimation({
    3                         staticView: this.preView.viewPort,
    4                         animView: this.curView.viewPort,
    5                         animType: 'in',
    6                         animInitClass: 'ui-page-right ui-transition',
    7                         animBeforeClass: 'ui-page-center-i',
    8                         animEndClass: 'ui-page-right ui-transition ui-page-center-i'
    9                     });

    最后  请看我上面的事例,一共三个页面:

    index.html
    list.html
    booking.html

    首先执行 index onCreate -> 然后执行 index onShow ;点击tolist; 执行 index onHide 然后执行 list onCreate-> list onShow;

  • 相关阅读:
    部署基于.netcore5.0的ABP框架后台Api服务端,以及使用Nginx部署Vue+Element前端应用
    20年就GPT3+ AlphaFold——21年机器学习的风向
    自由软件的真正意义——要么用户控制程序,要么程序控制用户。如果程序控制了用户,开发者控制了程序,那么程序就是一种不公正的权力工具。
    SSL代理——见图,利用SSL代理证书替换加密Web网站的数字证书,并将SSL代理证书发送到客户端的Web浏览器,中间代理以此获得加密通信的明文内容进行和真实服务器的交互转发
    深度森林gcForest模型
    网络安全相关证书有哪些?——就实战型看,OSCP、CISP-PTE (国家注册渗透测试工程师)最好
    CISP-PTE 注册渗透测试工程师考试 总结&&经验分享——TODO 待参加考试
    SLS机器学习最佳实战:日志聚类+异常告警 —— 这个就是splunk SQL+机器学习结合产物啊
    linux修改文件或目录的所有者(chown)和用户组
    linux修改用户id,组id
  • 原文地址:https://www.cnblogs.com/skyweaver/p/6402565.html
Copyright © 2020-2023  润新知