开发者社区> y0umer> 正文

jQuery Mobile页面返回无需重新get

简介: 最近公司的web app项目,使得我有幸一直接触和学习jQuery Mobile。这确实是一个很不错的移动开发库,有助于擅长web开发的工程师,快速入门并构建自己的移动应用。但是在前两天,我碰到了一个问题,使我查了很多资料都没有找到很好的解决方案,最终只能逼着我读jQuery Mobile的源码,再写了个扩展,才得以解决。
+关注继续查看

最近公司的web app项目,使得我有幸一直接触和学习jQuery Mobile。这确实是一个很不错的移动开发库,有助于擅长web开发的工程师,快速入门并构建自己的移动应用。但是在前两天,我碰到了一个问题,使我查了很多资料都没有找到很好的解决方案,最终只能逼着我读jQuery Mobile的源码,再写了个扩展,才得以解决。下面请让我娓娓道来。

问题描述

假设在项目中,有三个页面,分别是main.html、test1.html、test2.html(后面分别简称main、test1、test2),其中main页面是包含一个转向到test1页面的链接(即a标签),test1中有一个属性为data-rel=”back”的链接和一个转向到test2的链接,test2只有一个属性为data-rel=”back”的链接。main转向到test1后,点击back链接返回main(相当于点击浏览器的返回按钮),无需重新发送get请求;但是当test1转向到test2,在test2页面点击back链接想返回test1时,会重新发送一个get请求。这样导致的问题就是:test1做的所有操作,在test2返回后,都会失效。比如A是一个分页的列表页面,翻到第二页后转向到B,那么当返回A后,就无法地位到第二页

原因分析

我首先用firebug看了一下html的结构,发现jQuery Mobile会把main和test1加入到页面结构中去,当从test1转向到test2后,test1会被自动删除,这样dom树中,只包含了main和test2,所以在test2返回test1就会在发送一个get请求。那么是不是意味着,只要能把历史页面缓存到dom中(就像main和test1一样),就可以解决这个问题。

解决问题

经过一番查找,在jQuery Mobile官网看到一段《Caching pages in the DOM》的描述:

Caching pages in the DOM

To keep all previously-visited pages in the DOM, set the domCache option on the page plugin to true, like this:

$.mobile.page.prototype.options.domCache = true;


Alternatively, to cache just a particular page, you can add the data-dom-cache="true" attribute to the page's container:

<div data-role="page" id="cacheMe" data-dom-cache="true">


You can also cache a page programmatically like this:

pageContainerElement.page({ domCache: true });


The drawback of DOM caching is that the DOM can get very large, resulting in slowdowns and memory issues on some devices. If you enable DOM caching, take care to manage the DOM yourself and test thoroughly on a range of devices.

从这段引文中应该可以看到,这三种方法都可以缓存页面到dom中,于是我就使用了第二种方法,即在page的div上增加了data-dom-cache=”true”属性,但是却出现了以下两个问题:

1、如下图所示,当我的访问路径是main->test1->test2->test1(test2是history.back()返回的)时,用firebug可以看到,test2仍然存在于dom中,这样的结果就如红色部分描述的:DOM会变得很大,结果会使页面变慢和一些设备上的内存错误。

dom_cache

2、当我存在这样一个页面,它通过不同的参数显示不同的内容,并且页面上,有一段js脚本,会对页面上的元素做些处理,而我们常用的方式就是用id来获得目标元素,由于我们是用了cache缓存page,就会导致js事件或者操作混乱。比如在这里我增加了一个test1_1页面,它的内容几乎和test1一样,他们都有相同id的div和相同事件处理的button,这个事件做的事情就是往这个div中增加内容,当访问路径为main->test1->test1_1,在test1_1上点击按钮,会发现好像没有触发这个事件,其实它已经触发了,只是内容增加到test1中的div中了,分别入下图

dom_cache_test1_1

dom_cache_test1

所以对于目前大多数应用,这个方案是不可取的,除非自己管理dom中页面的生命周期。

优化方案

通过上面的实验,我也知道了需要满足我的需求,就只能自己管理dom中页面的生命周期了。那么就涉及到一个问题:页面什么时候过期(即从dom中删除)呢?根据我的需求,当从test2返回到test1时,就应该从dom中删除test2,同理从test1返回main时,从dom中删除test1。如果再次从main导航到test1,就得发起一个get请求,我认为这是合理的,因为用户不会认为点击链接到新页面还需要缓存。所以我应该在页面显示前或者显示后,删除它之后的history,于是我就在pagebeforeshow、pageshow的时候做了删除操作,即如下脚本(插件形式):

(function($, undefined) {
    $.fn.subpage = function(options) {
        $(document).bind(
            "pagebeforeshow",
            function() {
                var forword = $.mobile.urlHistory.getNext();
                if (forword) {
                    var dataUrl = forword.url;
                    var forwordPage=$.mobile.pageContainer
                            .children(":jqmData(url='" + dataUrl + "')");
                    if(forwordPage){
                        forwordPage.remove();
                    }
                }
                $.mobile.urlHistory.clearForward();
            });
    };
    $(document).bind("pagecreate create", function(e) {
        $(":jqmData(role='page')", e.target).subpage();
    });
})(jQuery);

结果事与愿违,在页面返回时,出现了js脚本错误,如下图:

JQuery.mobile.subpage

那么是什么原因呢?不在这个事件里做处理,那在哪里处理呢?于是我仔细研读了一下jQuery Mobile源码,发现了下面一段:

transitionPages( toPage, fromPage, settings.transition, settings.reverse )
    .done(function() {
        removeActiveLinkClass();

        //if there's a duplicateCachedPage, remove it from the DOM now that it's hidden
        if ( settings.duplicateCachedPage ) {
            settings.duplicateCachedPage.remove();
        }

        //remove initial build class (only present on first pageshow)
        $html.removeClass( "ui-mobile-rendering" );

        releasePageTransitionLock();

        // Let listeners know we're all done changing the current page.
        mpc.trigger( "pagechange", triggerData );
    });

页面在切换完后,会触发pagechange事件,于是我把pagebeforeshow改成了pagechange,一切都按预期运行,并且没有错误,终于大功告成了。

总结

在使用该插件时,请注意以下几点:

1、必须在引用该脚本之前,引用jquery和jquery mobile脚本文件;

2、必须在page上增加data-dom-cache="true"。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
lagou 爪哇 1-2 spring 笔记
任务一 自定义IoC&AOP框架 1.1 IoC IoC 全称为 Inversion of Control,翻译为 “控制反转”,它还有一个别名为 DI(Dependency Injection),即依赖注入。 1. 谁控制谁 (由 Spring IoC 容器来负责对象的生命周期和对象之间的关系) 2. 控制什么 (bean对象创建,属性注入) 3. 为何是反转 (依赖的对象由原来的主动获取变成被动接受,所以是反转) 4. 哪些方面反转了(所依赖对象的获取被反转了) hibernate中的inverse也是一种IoC
7 0
ESLint 是如何使用和实现的?
前言 今天这篇文章,主要聊聊什么是ESLint,为什么要用它?它的实现原理是什么?工作中如何使用的ESLint,以及如何自定义ESLint规则。 本文整理自以下文章: • 掘金:eslint工作原理探讨 • 手摸手教你写eslint插件 • 慕课网:《大前端》第七周「团队协作」
6 0
面试题24解析-详谈DNS域名解析过程
题目:描述一下DNS域名解析的过程?
6 0
iOS-底层原理 34:界面优化方案
iOS-底层原理 34:界面优化方案
6 0
Google应该这样玩,你知道这些技巧吗?
网络让世界变成了“地球村”,拉近了世界各地人与人之间的距离;搜索引擎更是让我们在互联网上没有秘密可言,查找网页,查找信息,查找人,我们都离不开它。
8 0
【JavaSE基础】包装类全解析以及使用(详解装箱与拆箱)
今天为大家讲解包装类的由来和使用知识,以及它的自动装箱和拆箱。文章将以常用Integer来讲解,同时会讲解Integer的特点。看完这篇保证你收获满满
6 0
为什么不让用join?《死磕MySQL系列 十六》
为什么不让用join?《死磕MySQL系列 十六》
9 0
1. Spring 简介 + Hello World
Spring 框架简介 在 Java 近20年的历史中,它经历过很好的时代,也经历过饱受诟病的时代。尽管有很多粗糙的地方,如 applet、企业级JavaBean(Enterprise JavaBean,EJB)、Java 数据对象(Java Data Object,JDO)以及无数的日志框架,但是作为一个平台,Java的历史是丰富多彩的,有很多的企业级软件都是基于这个平台构建的。Spring是Java历史中很重要的组成部分。
9 0
SpringBoot入门整合 上手 简单易解
SpringBoot入门整合 上手 简单易解
11 0
Win 独享 WSL 并搭配 Oh My Zsh
Windows Subsystem for Linux(简称 WSL)是一个在 Windows 10/11 上能够运行原生 Linux 二进制可执行文件(ELF 格式)的兼容层。
7 0
+关注
y0umer
高级网络安全技术员
906
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
OceanBase 入门到实战教程
立即下载
阿里云图数据库GDB,加速开启“图智”未来.ppt
立即下载
实时数仓Hologres技术实战一本通2.0版(下)
立即下载