ASP.NET MVC3 jQuery移动页面的Ajax代码绑定使用PageInit事件

我们正在使用ASP.NET MVC3 + JqueryMobile RC1编写JQueryMobile应用程序。 很少有页面有自己的Ajax方法,我们使用jQuery代码( $.getJSON() )方法调用它们。

要在Ajax调用中调用这些,我们会在jquery-mobile的“pageinit”事件中单击事件绑定,如此处所述( http://jquerymobile.com/demos/1.0rc1/docs/api/events.html )。 但是,通过每次访问页面,调用绑定到pageinit的方法会增加+1。 例如,如果我使用后退按钮或任何其他链接再次访问我的页面,请再次访问它,调用两次pageinit方法,并且在pageinit内写入的任何代码执行两次…这些随着每次访问页面而不断增加。

我们应该使用哪个事件来绑定事件。 它应该只在页面加载时调用一次?

编辑: – 我们想要JQM的默认AJAX行为,并且我们将AjaxEnabled保持为true。

示例源代码(您可以通过创建新的MVC3 APP并使用给定代码替换以下三个.cshtml来重现此问题: –

我的_Layout.cshtml: –

          $(document).bind("mobileinit", function () { $.mobile.ajaxEnabled = true; });   @RenderSection("HeaderScripts", required: false)   

@ViewBag.Title

About Home
@RenderBody() @RenderSection("BodyScriptsSection", required: false)
@RenderSection("MobileFooter", required: false)

示例Index.cshtml

 @{ ViewBag.Title = "Home Page"; ViewBag.DivTitle = "HomeIndex"; } @section BodyScriptsSection {  $("#@ViewBag.DivTitle").live("pageshow", function () { alert ("PageShow Called - HomeIndex"); });  

示例AboutUS.cshtml

 @{ ViewBag.Title = "About Us"; ViewBag.DivTitle = "AboutUS"; } @section BodyScriptsSection {  $("#@ViewBag.DivTitle").live("pageshow", function () { alert("PageShow Called - AboutUS"); });  

为什么不在导航时杀死你的处理程序,如下所示:

 $("#@ViewBag.DivTitle").live("pagehide", function() { $("#@ViewBag.DivTitle").die("pageshow"); } 

使用jQuery Mobile框架,如果在

元素中放置 ,它将在每次显示页面时运行,如果您在代码中绑定事件处理程序,它们将被绑定每次查看页面时,DOM在整个站点导航过程中保持不变。

尝试将@RenderSection("BodyScriptsSection", required: false)语句移动到页面底部,就在结束标记之前。 这样,脚本将包含在每次完全刷新(如果用户按下刷新按钮),以及用户是否深入链接到您的站点; 但是每次jQuery Mobile的AJAX导航收集页面时都不会运行它。

您还可以通过缓存每个页面来解决此问题,以便在后续访问页面时不必通过AJAX导航收集它。 默认情况下,jQuery Mobile Beta 3及更高版本(此时为RC 1)在用户导航后从页面中删除页面(但不删除绑定的事件处理程序),此function有助于控制DOM的大小。 要缓存页面,请将data-dom-cache="true"

元素。

两种选择:

1.使用one()而不是bind()或live()
只要页面没有从DOM中删除,这应该会有所帮助。 看到这里 。

它说:“将一个处理程序附加到一个元素的事件。每个元素最多执行一次处理程序。”

Jquery Mobile也在JQM中使用它,可能是出于同样的原因。 所以,如果你喜欢这样:

$('button').one('click', function () { do something });

应该只开一次。

2.使用data()在触发事件后设置标志
另一个想法是使用data()将标志附加到页面元素,或者,可以从DOM中删除页面,更好地将其附加到HTML或BODY元素。 这些将留下……

我在页面上启动scrollview(希望一次)像这样:

 $('div[data-role="page"]').live('pagebeforeshow.scroll', function(event){ var $page = $(this); if ( $page.data('scrollable', 'Off') ) { $page.data('scrollable', 'On'); scrollMe( $page ); // init } }); 

这可能意味着将您的函数调用放在实际页面之外。

编辑:

这也适用于我使用attr

  // on pageinit - set global argument $('html').attr('fire-once', 'Off'); $( '#your page' ).live( 'pageshow',function(event){ if ( $('html').attr('fire-once') == 'Off' ) { $('html').attr('fire-once', 'On'); // your button.bind.behavior here } }); 

这样你就可以在HTML元素上设置“fire-once”,当你加载和输出页面时,它在JQM中总是保持不变。 只有当您转到data-rel =“external”的页面时,才会重置fire-once。

在您指定的页面上,您将侦听pageshow,触发该函数,首先将fire-once更改为“On”,然后添加按钮绑定。

由于fire-once现在变为“On”,即使使用多个绑定,if语句也会失败,并且您只会分配按钮行为一次。

我正在使用与JQM面板历史数组相同的设置,我只需要设置一次,并且只在changePage上添加一次条目。 以上工作对我来说很好,也应该符合你的目的。

如果您想查看实例,请给我发消息。

干杯,

频繁

您可以为每个页面保留一个变量IsPageInitialized = false ,仅在此变量为false时绑定事件,并在分配事件处理程序时将其设置为true。

您的示例代码使用’pageshow’而不是’pageinit’。 ‘Pageinit’应该可以正常工作。

听起来您可能需要将代码包装在IsPostBack检查中。 例如:

 void Page_Init(object sender, EventArgs e) { if (!IsPostBack) { RegisterScriptHere(); } } 

编辑

在第二次阅读时,您可能不会询问服务器端,如果您尝试在客户端执行此操作,请忽略我的答案。