zhangxinxu / mobilebone

Single Page Switching bone(include page manage, events manage) for mobile web APP, Hybrid APP, Phonegap, PPT, Single-Screen PC page...
http://www.zhangxinxu.com/wordpress/?p=4381
MIT License
1.4k stars 327 forks source link

mobilebone.js与Ajax切换地址栏没有正确变化的问题,导致事件绑定失效问题 #53

Closed woaixiangbao closed 9 years ago

woaixiangbao commented 9 years ago

其实就是普通的ajax请求,假如有这么一个页面地址栏里的地址是:www.xxx.com/order/firm 这个页面里有个a连接:< a href="ajax.html" >,点击这个连接以后,按照正常的情况,页面会切换到ajax.html这个page去,并且当前连接就会变化为:www.xxx.com/order/firm?#&ajax.html

但是:有时候某些情况下,地址url没有变化啊!依然是www.xxx.com/order/firm,

然后你就刷新一下,这时候地址url才会变成www.xxx.com/order/firm?#&ajax.html

这是什么情况?

这个问题,我很难从你test里面的demo里复现出来,我就说下我实际项目里的问题吧。

我当前是一个电商页面的订单提交页面,里面有个添加地址的a连接,此时订单提交页的ur是:http://www.xxx.com/order/firm?redirect_url=aHR0cDovL3d3dy5qaW5yaXRlbWFpLmNvbS9wcm9kdWN0L2RldGFpbD9waWQ9MTQwMTEyNTI5NDIzODM=&buy_now=1

添加地址的连接地址是:http://www.xxx.com/address/index

如果我从pc浏览器里点击添加地址的连接的话,就会切换到另外一个page,并且地址栏里的url就会变成下面这样的:http://www.xxx.com/order/firm?redirect_url=aHR0cDovL3d3dy5qaW5yaXRlbWFpLmNvbS9wcm9kdWN0L2RldGFpbD9waWQ9MTQwMTEyNTI5NDIzODM=&buy_now=1#&http://www.xxx.com/address/index

这一切都很正常,但是一旦到了手机里去这么操作,也就是点击了地址添加页的连接以后,页面有个切换,内容也换到了地址添加的内容,而去看地址栏里的url却没有变化,除非你刷新页面才能看到变化。

其实地址栏没有变化也没啥大不了的,可问题是,刷新页面以后我绑定的事件就会失效。我猜这和地址栏里的url变化有关。这个页面我只绑定了一次onfirstpageinto事件,如果地址栏都一切正常,那么刷新页面事件绑定都是没有问题的。一旦地址栏发生变化,事件绑定就失效了。

woaixiangbao commented 9 years ago

补充一点,假如页面切换到新的page去以后,这个时候url没有变化,刷新以后url有了变化,我发现,刷新的同时,又生成了一个新的page页面,这个新的page页面与原来的page页面内容是相同的,只是因为我绑定事件是用得onfirstpageinto,所以刷新以后,我当前页面的page已经不是绑定过事件的那个page了,所以当前page的事件都失效了。而我又不能重新再次绑定,因为请求的page是同一个,我不能用callback绑定,防止同一个元素被多次绑定事件造成重复绑定。

dancinglone commented 9 years ago

我也遇到过同样的刷新问题,不能再次绑定事件不知道怎么办

woaixiangbao commented 9 years ago

我觉得我描述里的page出现太多次,估计看问题的人已经晕了,我再重复一遍吧。

刚刚进入订单提交页面的时候有个page,id是home,然后我点击了< a href="ajax.html" >,页面中新生成了一个page,这个page的id是add,这个时候页面的url和刚刚进入订单提交页的时候比较没有变化,此时我刷新页面,url变化了,后面多了#$ajax.html,同时我查看页面代码,发现又生成了一个page,id依然是add,而且当前显示的是新生成的这个page,刷新前的那个page隐藏掉了。而我的事件是绑定在第一次进入的id为add的page里面的,所以刷新以后的page里面的事件都失效了。我绑定事件的方法是onfirstpageinto.

好像是描述清楚了。

woaixiangbao commented 9 years ago

我觉得我遇到的主要的问题是,为什么第一次切换页面的时候url没有更新,也就是这个ajax的参数没有添加到url后面去,当刷新以后再更新url的话,mobilebone就会根据url的变化自动生成一个新的page了(或者说根据url的变化去重新请求一个ajax了)。

dancinglone commented 9 years ago

我倒是没有遇到过url不变的问题。不达页面不能刷新是个问题。

woaixiangbao commented 9 years ago

为了解决这个问题,我暂时把绑定事件的方法变为data-callback,替换原来的data-onfirstpageinto方法,不过我担心这样一来很容易给一个元素多次绑定同一事件。特别是当重复切换page的时候。

zhangxinxu commented 9 years ago

你好,可否告知下手机设备?其他手机有没有类似问题?

woaixiangbao commented 9 years ago

我觉得不是手机设备的问题,而是不知道哪里出了问题,因为我们用好几个手机测,不同型号不同品牌的手机都测了,结果都是这样的

woaixiangbao commented 9 years ago

对了,我发了一封邮件给你的zhangxinxu@zhangxinxu.com邮箱

woaixiangbao commented 9 years ago

对了,还要补充一点,第一次切换page 地址url没有更新的问题,在电脑浏览器里是无法复现的,必须在手机里才行,可以用手机的任意浏览器,或者自带webview的app也可以

zhangxinxu commented 9 years ago

使用data-reload或者data-reload=true, 你这个Ajax请求页面不能缓存。Mobilebone提供缓存管理机制,专门针对你这种实际开发需求。

woaixiangbao commented 9 years ago

此问题不能用在连接处加上data-reload的方法解决。

再详细说下复现流程吧,此复现不能在电脑浏览器上复现,只能在手机浏览器下复现: 1,有个“个人管理”页面(页面url是http://www.xxx.com/i/index),这个页面中有个“管理地址”的按钮,这个按钮的hred属性是"http://www.xxx.com/address/index",并且添加了data-reload="true"。然后点击这个按钮。 2,页面发生转场,展现出来的是“地址管理(或者称为地址列表)页面”,此时查看代码会发现,页面中新增了一个div,我将这个div的属性写下来:“< div class="page in slide" data-root="address" data-onpagefirstinto="indexEvent" style="display: block;" >”,这个div绑定了一个address对象,并且在onpagefiresinto的时候执行了address对象的indexEvent方法。这个indexEvent的方法了其实是执行了两个函数,一个是点击某条地址的时候执行一个“设置为默认地址”的方法,一个是点击“删除”按钮执行一个删除此条地址的方法,并且当你删除的是一条“默认地址”的时候,删除完成后页面会强制刷新一次。 3,ok,进入“地址管理”页面以后,我删除一条“默认地址”,一般情况下“默认地址”就是第一条地址,于是按照需求逻辑,当默认地址被删除的时候,页面强制刷新了一下。这时,这个页面(依然停留在地址管理页面)的删除按钮和设置默认地址两个方法都失效了。 4,我猜想这个绑定事件失效并不是因为页面缓存引起的,因为在电脑浏览器里无法复现这个问题,无论如何删除默认地址,刷新后的页面依然可以使用所有功能,只有在手机里才可以复现此问题。我通过某些软件(chrome的about:inspect)发现,在发生2的时候,页面的url地址没有变化,也就是第一次发生转场的时候,本来url应该是"http://www.xxx.com/i/index#&http://www.xxx.com/address/index"这样才对的,但是实际并非如此,转场以后的url依然是http://www.xxx.com/i/index,当删除了一条默认地址以后,由于js执行了强制刷新,刷新页面以后的地址才变成“http://www.xxx.com/i/index#&http://www.xxx.com/address/index",此时我发现,页面中又再次出现了一个< div class="page in slide" data-root="address" data-onpagefirstinto="indexEvent" style="display: block;" >,也就是说,页面有两个相同的”地址管理“page了,第二个里面没有成功绑定相关事件导致失效。 5,这基本就是我的分析,所以我想应该有两个解决此问题的办法,一个是让第一次发生转场的时候让url正常改变。二是即使有新增的一样的page出现,也能绑定事件。第一个解决方案,我估计要作者张鑫旭在查看一下原因了,第二个方案我的解决方案是把onpagefirestinto修改为callbakc,这样就是每次进入的时候都绑定一次事件,这暂时的解决了这个刷新页面后事件失效的问题,但是,这样修改以后又会出现新的问题。那就是,当地址管理页面再次发生转场的话,那么地址管理页面就会绑定两次事件了!

6,结论,还是请张鑫旭好好看看这个问题吧,我的第二中方案一点都不好。

dancinglone commented 9 years ago

我也遇到类似和事件绑定顺序问题。ajax加载页面,似乎iscroll(第三方js库)的绑定只能利用onpagefirstinto来绑定,用各种回调的方式都会有重复绑定的问题或者不知道如何选取最新滑进的页面的问题。一时想不到比较好的解决方案。ajax加载页面遇到了不少难题还好在逐渐解决。如何作者能给出比较完整的ajax加载实现demo就好了。

dancinglone commented 9 years ago

能不能让 data-success在onpagefirstinto之前执行呢,那就可以断续用onpagefirstinto绑定isroll了。如果把data-success要执行的函数放在onpagefirstinto内原本要执行的函数前应该可以吧,但是这样代码就太乱了,毕竟onpagefirstinto是所有页面都共用的,而data-success是一个页面的js,放在一起就太乱了。

woaixiangbao commented 9 years ago

我突然又想到了第三种解决问题的方案,那就是事件委托,我把删除动作委托给document或者body,但是此时又会有别的问题出现,比如,ios设置下只有默认有click事件的元素才能在document或者body上委托,比如只有a链接,否则事件委托会失效。google后发现可以用$("body > *).on("click",".delete",function(){ // ...})解决,但是总是觉得怪怪的。。。

dancinglone commented 9 years ago

(从博客复制) 张 鑫旭 说: 2014年12月5日于10:11 @蒋三 你好,事件绑定请使用Mobilebone提供的事件回调API. 你这种情况适合使用onpagefirstinto()回调方法。祝你好运~

回复 dcl 说: 2015年01月12日于14:29 使用onpagefirstinto()回调方法绑定iScroll会在ajax请求的动态数据加载之前就执行了,因为数据还没加载,页面是没有高度的,这样的话,页面的iscroll就有问题了不能滚动。这应该怎么解决啊,求指教。

求指教

woaixiangbao commented 9 years ago

哈哈,终于找到了比较好的复现方法:

修改你的test/ajax-html/index.html文件,在最后面加上下面的代码:

< script src = "http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.min.js" >< / script > < script > var address; address={ init:function(){ $(".delete").on("click",function(){ alert("delete"); }) } } < /script >

然后修改同一个目录下得ajax-page.html文件:body里的内容修改为:

< div class="page out" data-callback="optionsTest" data-root="address" data-onpagefirstinto="init" > < a href="#pageHome" data-rel="back" >返回< /a> < span class="delete" > delete < /span > < /div >

复现步骤,手机浏览器打开下面这个页面: image

然后点击“点击加载(每次都请求, 返回含page结构)”,这时候会转场到新的page,然后你会看到有个“delete"跟在”返回"按钮后面,假如你点击"delete"的话,会看到一个alert,然后你刷新下页面呢,在点击delete试试,哈哈,失效了吧。而且,你发现没有,你刷新页面的时候,又发生了一次转场,其实也就是又新增了一个page页面呢!

zhangxinxu commented 9 years ago

你好,PC上也是这样吗?我自己机子测试,并没有此问题。

woaixiangbao commented 9 years ago

pc上不会有问题,只有手机上才会。

woaixiangbao commented 9 years ago

我上传了一个demo:http://www.mashangju.com/kd100/mobilebone/test/ajax-html/index.html#&pageHome

woaixiangbao commented 9 years ago

进入http://www.mashangju.com/kd100/mobilebone/test/ajax-html/index.html#&pageHome 然后点击第二项,然后就会进入第二项的页面了,如果你点击"delete"会有一个弹窗,然后,你刷新一下页面,然后再点击“delete”,就不会有弹窗了。而且,当你第一次刷新这个页面的时候,你实际上能发现又多了一次转场,这个转场实际上是有生产了一个page。

zhangxinxu commented 9 years ago

好的,感谢反馈,刚提交了修复后的mobilebone.js~ 烧香保佑一切顺利~

woaixiangbao commented 9 years ago

已经验证,问题解决了,不过又导致另外一个问题出现,我另外开一个issue吧

woaixiangbao commented 9 years ago

好了,我知道我的另外那个问题是我自己写错了,没事了。^_^