Jquery Mobile: document ready vs. page events
estou a usar o jQuery Mobile, e estou a ter dificuldade em compreender as diferenças entre os eventos clássicos do document ready e do jQuery Mobile page.
-
Qual é a verdadeira diferença?
porque é que
<!-- language: lang-js --> $(document).ready() { });
ser melhor que
$(document).on('pageinit') { });
Qual é a ordem dos eventos da página, quando você transita de uma página para outra?
Como posso enviar dados de uma página para outra e é possível acessar dados de anteriores page?
5 answers
JQuery Mobile 1.4 Update:
O meu artigo original destinava-se ao tratamento de páginas antigas, basicamente tudo antes da jQuery Mobile 1.4. A antiga maneira de lidar com isso está agora desactualizada e vai permanecer ativa até (incluindo) jQuery Mobile 1.5, então você ainda pode usar tudo o que foi mencionado abaixo, pelo menos até o próximo ano e jQuery Mobile 1.6.Eventos antigos, incluindo pageinit já não existem, são substituídos por pagecontainer widget. Pageinit é completamente apagado e você pode usar pagecreate em vez disso, esse evento permaneceu o mesmo e não vai ser alterado.
Se você está interessado em uma nova maneira de lidar com eventos de página dê uma olhada toma., em qualquer outro caso, sinta-se livre para continuar com este artigo. Você deve ler esta resposta mesmo se você estiver usando jQuery Mobile 1.4 +, ele vai além de eventos de página, então você provavelmente vai encontrar um monte de informações úteis.
Mais velho conteúdo:
Este artigo também pode ser encontrado como parte do meu blog toma..
$(document).on('pageinit')
vs $(document).ready()
A primeira coisa que se aprende em jQuery é chamar código dentro do $(document).ready()
função para que tudo seja executado assim que o DOM for carregado. No entanto, emjQuery Mobile , Ajax é usado para carregar o conteúdo de cada página no DOM à medida que você navega. Por causa disto.$(document).ready()
irá despoletar antes da sua primeira página é carregado e todos os códigos destinados à manipulação de páginas serão executados após uma actualização de páginas. Isto pode ser um insecto muito subtil. Em alguns sistemas pode parecer que funciona bem, mas em outros pode causar errática, difícil de repetir estranheza a ocorrer.
Sintaxe clássica do jQuery:
$(document).ready(function() {
});
Para resolver este problema (e acreditem que este é um problema) os programadores jQuery Mobile criaram eventos de página. Em poucas palavras eventos de página são eventos desencadeados em um ponto particular da página execucao. Um desses eventos de página é um evento pageinit e podemos usá - lo assim:
$(document).on('pageinit', function() {
});
Podemos ir ainda mais longe e usar um ID de página em vez do selector de documentos. Digamos que temos uma página móvel jQuery com um índice de id ([58]}:
<div data-role="page" id="index">
<div data-theme="a" data-role="header">
<h3>
First Page
</h3>
<a href="#second" class="ui-btn-right">Next</a>
</div>
<div data-role="content">
<a href="#" data-role="button" id="test-button">Test button</a>
</div>
<div data-theme="a" data-role="footer" data-position="fixed">
</div>
</div>
Para executar um código que só estará disponível na página de índice, poderíamos usar esta sintaxe:
$('#index').on('pageinit', function() {
});
O evento Pageinit será executado sempre que a página estiver prestes a ser carregada e apresentada pela primeira vez. Ele não irá despoletar novamente a menos que a página seja atualizada manualmente ou o carregamento de páginas Ajax esteja desligado. No caso de querer executar o código sempre que visita uma página, é melhor usar o evento pagebefore howow .
Aqui está um exemplo de trabalho: http://jsfiddle.net/Gajotres/Q3Usv para demonstrar este problema. Mais algumas notas sobre esta questão. Não importa se você está usando 1 html várias páginas ou múltiplos arquivos HTML paradigma é aconselhável separar todos os seus personalizados JavaScript page handling into a single separate JavaScript file. Esta nota tornará o seu código ainda melhor, mas você terá uma visão geral do Código muito melhor, especialmente ao criar uma aplicação jQuery Mobile.Há também outro evento especial jQuery Mobilee chama-se mobileinit. Quando jQuery Mobile começa, despoleta um mobileinit no objecto do documento. Para sobrepor as opções predefinidas, ligue-as a mobileinit . Um dos bons exemplos de mobileinit uso é desligar o carregamento de páginas Ajax,ou alterar o comportamento padrão do carregador Ajax.
$(document).on("mobileinit", function(){
//apply overrides here
});
([135]}página Eventos ordem de transição
Em primeiro lugar, todos os eventos podem ser encontrados aqui: http://api.jquerymobile.com/category/events/
Digamos que temos uma página a e uma página B, Isto é uma ordem de descarga / carga.
Página B-evento pagebeforecreate
Página B - evento pagecreate
Página B - evento pageinit
Página do evento pagebeforehide
Página do evento pageremove
Página do evento pagehide
Página B-evento pagebefore how
Página B - evento pageshow
Para uma melhor compreensão de eventos de página Leia isto:
-
pagebeforeload
,pageload
epageloadfailed
são disparados quando uma página externa é carregado -
pagebeforechange
,pagechange
epagechangefailed
são eventos de alteração. Estes eventos são disparados quando um usuário está navegando entre páginas em aplicacao. -
pagebeforeshow
,pagebeforehide
,pageshow
epagehide
são de transição de página eventos. Estes eventos são disparados antes, durante e depois de uma transição e são nomeados. -
pagebeforecreate
,pagecreate
epageinit
são para inicialização de páginas. -
pageremove
pode ser disparada e depois manuseada quando uma página é removida do DOM
Page loading jsFiddle example: http://jsfiddle.net/Gajotres/QGnft/
Se o AJAX não estiver activo, alguns acontecimentos podem não disparar.
Impedir a transição da página
Se, por alguma razão, a transição da página precisar de ser evitada, sob alguma condição, pode ser feita com este código:
$(document).on('pagebeforechange', function(e, data){
var to = data.toPage,
from = data.options.fromPage;
if (typeof to === 'string') {
var u = $.mobile.path.parseUrl(to);
to = u.hash || '#' + u.pathname.substring(1);
if (from) from = '#' + from.attr('id');
if (from === '#index' && to === '#second') {
alert('Can not transition from #index to #second!');
e.preventDefault();
e.stopPropagation();
// remove active status on a button, if transition was triggered with a button
$.mobile.activePage.find('.ui-btn-active').removeClass('ui-btn-active ui-focus ui-btn');;
}
}
});
Este exemplo vai funcionar em qualquer caso, porque ele vai desencadear uma mendicidade de cada transição de página e o que é mais importante ele vai impedir a mudança de página antes de a transição de página pode ocorrer.
Aqui está um exemplo de trabalho:Impedir a ligação/activação de eventos múltiplos
jQuery Mobile
funciona de uma forma diferente das aplicações web clássicas. Dependendo de como você conseguiu vincular seus eventos cada vez que você visita alguma página, ela irá vincular eventos vezes sem conta. Isto não é um erro, é simplesmente como jQuery Mobile
trata das suas páginas. Por exemplo, dê uma olhada neste excerto de código:
$(document).on('pagebeforeshow','#index' ,function(e,data){
$(document).on('click', '#test-button',function(e) {
alert('Button click');
});
});
A trabalhar no exemplo jsFiddle: http://jsfiddle.net/Gajotres/CCfL4/
Cada vez que visitar a Página #index o evento click irá estar ligado ao botão #test-button. Teste-O movendo-se da página 1 para a Página 2 e para trás várias vezes. Existem poucas maneiras de prevenir este problema:
Solução 1
A melhor solução seria usar pageinit
para ligar os acontecimentos. Se você der uma olhada em uma documentação oficial você vai descobrir que pageinit
só irá despoletar uma vez, tal como o documento está pronto, para que os acontecimentos não voltem a ser ligados. Esta é a melhor solução porque você não tem processamento acima como ao remover eventos com o método off.
Esta solução de trabalho é feita com base num exemplo problemático anterior.
Solução 2
Remover o evento antes de o ligar:
$(document).on('pagebeforeshow', '#index', function(){
$(document).off('click', '#test-button').on('click', '#test-button',function(e) {
alert('Button click');
});
});
A trabalhar no exemplo jsFiddle: http://jsfiddle.net/Gajotres/K8YmG/
Solução 3
Use um selector de filtro jQuery, como este:
$('#carousel div:Event(!click)').each(function(){
//If click is not bind to #carousel div do something
});
Como o filtro de eventos não faz parte da estrutura oficial do jQuery, pode ser encontrado aqui: http://www.codenothing.com/archives/2009/event-filter/
Em poucas palavras, se a velocidade é a sua principal preocupação então a solução 2 é muito melhor do que a solução 1.
Solução 4
Um novo, provavelmente o mais fácil deles. todo.$(document).on('pagebeforeshow', '#index', function(){
$(document).on('click', '#test-button',function(e) {
if(e.handled !== true) // This will prevent event triggering more than once
{
alert('Clicked');
e.handled = true;
}
});
});
Exemplo jsFiddle: http://jsfiddle.net/Gajotres/Yerv9/
Tnx para o sholsinger para esta solução: http://sholsinger.com/archive/2011/08/prevent-jquery-live-handlers-from-firing-multiple-times/
Pagechange event quirks-trigging twice
Às vezes o evento pagechange pode desencadear duas vezes e não tem nada a ver com o problema mencionado antes.
A razão o evento pagebeforechange ocorre duas vezes é devido à chamada recursiva em changePage quando toPage não é um objeto DOM aprimorado jQuery. Esta recursão é perigosa, já que o desenvolvedor pode alterar a topagem dentro do evento. Se o desenvolvedor configura consistentemente toPage para uma string, dentro do pagebeforechange event handler, independentemente de ser ou não um objeto um loop recursivo infinito irá resultar. O evento pageload passa a nova página como propriedade da página do objeto de dados (isto deve ser adicionado à documentação, não está listado atualmente). O evento pageload pode, portanto, ser usado para acessar a página carregada.
Em poucas palavras, Isto está acontecendo porque você está enviando parâmetros adicionais através de pageChange.Exemplo:
<a data-role="button" data-icon="arrow-r" data-iconpos="right" href="#care-plan-view?id=9e273f31-2672-47fd-9baa-6c35f093a800&name=Sat"><h3>Sat</h3></a>
Para corrigir este problema, use qualquer evento de página listado em ordem de transição de eventos de Página .
Tempos De Mudança De Página
Como mencionado, quando você muda de uma página móvel jQuery para outra, tipicamente, clicando em um link para outra página móvel jQuery que já existe no DOM, ou chamando manualmente $.movel.changePage, vários eventos e ações subsequentes ocorrem. A um nível elevado, ocorrem as seguintes acções:- inicia-se um processo de mudança de Página
- é carregada uma nova Página
- o conteúdo dessa página é "melhorado" (estilizado)
- uma transição (slide/pop/etc) da Página existente para a nova página ocorre
Esta é uma referência média de transição de páginas:
Carga e processamento de páginas: 3 ms
Page enhance: 45 ms
Transição: 604 ms
Tempo Total: 670 ms
* estes valores estão em milisegundos.
Como podem ver, um evento de transição consome quase 90% do tempo de execução.Manipulação de dados/Parâmetros entre as transições de páginas
É possível. para enviar um parâmetro/s de uma página para outra durante a transição da página. Pode ser feito de poucas maneiras.Referência: https://stackoverflow.com/a/13932240/1848600
Solução 1:
Pode passar valores com changePage:
$.mobile.changePage('page2.html', { dataUrl : "page2.html?paremeter=123", data : { 'paremeter' : '123' }, reloadPage : true, changeHash : true });
E lê-os como isto:
$(document).on('pagebeforeshow', "#index", function (event, data) {
var parameters = $(this).data("url").split("?")[1];;
parameter = parameters.replace("parameter=","");
alert(parameter);
});
Exemplo:
Índice.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="widdiv=device-widdiv, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<title>
</title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
<script src="http://www.dragan-gaic.info/js/jquery-1.8.2.min.js">
</script>
<script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>
<script>
$(document).on('pagebeforeshow', "#index",function () {
$(document).on('click', "#changePage",function () {
$.mobile.changePage('second.html', { dataUrl : "second.html?paremeter=123", data : { 'paremeter' : '123' }, reloadPage : false, changeHash : true });
});
});
$(document).on('pagebeforeshow', "#second",function () {
var parameters = $(this).data("url").split("?")[1];;
parameter = parameters.replace("parameter=","");
alert(parameter);
});
</script>
</head>
<body>
<!-- Home -->
<div data-role="page" id="index">
<div data-role="header">
<h3>
First Page
</h3>
</div>
<div data-role="content">
<a data-role="button" id="changePage">Test</a>
</div> <!--content-->
</div><!--page-->
</body>
</html>
Segundo.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="widdiv=device-widdiv, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<title>
</title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
<script src="http://www.dragan-gaic.info/js/jquery-1.8.2.min.js">
</script>
<script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>
</head>
<body>
<!-- Home -->
<div data-role="page" id="second">
<div data-role="header">
<h3>
Second Page
</h3>
</div>
<div data-role="content">
</div> <!--content-->
</div><!--page-->
</body>
</html>
Solução 2:
Ou você pode criar um objeto JavaScript persistente para um propósito de armazenamento. Enquanto o Ajax for usado para o carregamento de páginas (e a página não for recarregada de forma alguma) esse objeto permanecerá ativo.
var storeObject = {
firstname : '',
lastname : ''
}
Exemplo: http://jsfiddle.net/Gajotres/9KKbx/
Solução 3:
Você também pode acessar os dados da página anterior assim:
$(document).on('pagebeforeshow', '#index',function (e, data) {
alert(data.prevPage.attr('id'));
});
PrevPage o objecto contém uma página anterior completa.
Solução 4:
Como última solução, temos uma implementação Nifty HTML do localStorage. Ele só funciona com navegadores HTML5 (incluindo navegadores Android e iOS), mas todos os dados armazenados são persistentes através da página actualizar.
if(typeof(Storage)!=="undefined") {
localStorage.firstname="Dragan";
localStorage.lastname="Gaic";
}
Exemplo: http://jsfiddle.net/Gajotres/J9NTr/
Provavelmente a melhor solução, mas falhará em algumas versões do iOS 5.X. É um erro bem conhecido.
Não uses .live()
/ .bind()
/ .delegate()
Esqueci-me de mencionar (e tnx andleer para me lembrar) uso on/off para ligação de eventos/unbinding, live/die E bind/unbind são depreciados.
O .o método vivo de jQuery foi visto como uma dádiva de Deus quando foi introduzido a a API na versão 1.3. Em um app jQuery típico pode haver um monte de manipulação DOM e pode se tornar muito tedioso para gancho e desapertar à medida que os elementos vêm e vão. O método .live()
tornou possível ligar um evento para a vida útil da aplicação com base no seu selector. Óptimo, não é? Errado, o método é extremamente lento. O método .live()
realmente liga os seus eventos ao objecto do documento, o que significa que o evento deve fazer uma bolha a partir do elemento que gerou o evento até atingir o documento. Isto pode ser incrivelmente demorado.
.live()
do que com ele.
Em vez de .live()
deve utilizar .on()
. .on()
é cerca de 2-3x mais rápido que .live(). Dê uma olhada neste evento benchmark binding benchmark: http://jsperf.com/jquery-live-vs-delegate-vs-on/34 tudo ficará claro a partir daí.
alert
sistema de notificação (cada "página de alteração de" vai mostrar de dados interrompendo a aplicação) e alterando-a para console.log
função.
Basicamente, este programa irá registar todos os seus eventos de página e, se ler este artigo com cuidado (descrição dos eventos de página), irá saber quanto tempo o jQm passou com as melhorias de página, As transições de página ....
Notas finais
Sempre, e quero dizer sempre ler a documentação oficial jQuery Mobile. Ele geralmente irá fornecer-lhe informações necessárias, e ao contrário de alguma outra documentação este é bastante bom, com explicações suficientes e exemplos de código.
Alterações:
- 30.01.2013-acrescentou um novo método de prevenção de múltiplos eventos
- 31.01.2013-adicionou uma melhor clarificação para o capítulo manipulação de dados / Parâmetros entre as transições de páginas
- 03.02.2013-adicionou novos conteúdos / exemplos ao capítulo manipulação de dados / Parâmetros entre as transições de páginas
- 22.05.2013-adicionou uma solução para page transition / change prevention and added links to the official page events API documentation
- 18.05.2013-adicionou outra solução contra a ligação de eventos múltiplos
$(document).on('pagebeforecreate',function(){console.log('pagebeforecreate');});
$(document).on('pagecreate',function(){console.log('pagecreate');});
$(document).on('pageinit',function(){console.log('pageinit');});
$(document).on('pagebeforehide',function(){console.log('pagebeforehide');});
$(document).on('pagebeforeshow',function(){console.log('pagebeforeshow');});
$(document).on('pageremove',function(){console.log('pageremove');});
$(document).on('pageshow',function(){console.log('pageshow');});
$(document).on('pagehide',function(){console.log('pagehide');});
$(window).load(function () {console.log("window loaded");});
$(window).unload(function () {console.log("window unloaded");});
$(function () {console.log('document ready');});
Você não vai ver a descarga na consola, pois esta é disparada quando a página está sendo descarregada (quando você se afasta da página). Use-o assim:
$(window).unload(function () { debugger; console.log("window unloaded");});
E vais ver o que quero dizer.
Esta é a maneira correcta:
Para executar um código que só estará disponível na página de índice, poderíamos usar esta sintaxe:
$(document).on('pageinit', "#index", function() {
...
});
A diferença simples entre o evento document ready e page in jQuery-mobile é que:
-
O evento document ready é usado para toda a página HTML,
$(document).ready(function(e) { // Your code });
-
Quando existe um evento de Página, usar para lidar com um evento de página em particular:
<div data-role="page" id="second"> <div data-role="header"> <h3> Page header </h3> </div> <div data-role="content"> Page content </div> <!--content--> <div data-role="footer"> Page footer </div> <!--footer--> </div><!--page-->
Também pode usar o documento para lidar com o evento pageinit:
$(document).on('pageinit', "#mypage", function() {
});
Enquanto usa .on (), é basicamente uma consulta ao vivo que você está usando.
Por outro lado,pronto (como no seu caso) é uma consulta estática. Ao usá-lo, você pode atualizar dados dinamicamente e não tem que esperar pela página para carregar. Você pode simplesmente passar os valores em seu banco de dados (se necessário) quando um determinado valor é inserido.O uso de consultas ao vivo é comum em formulários onde introduzimos dados (conta ou posts ou mesmo Comentários).