Tuesday, September 9, 2014

JQueryMobile performance

JQueryMobile defaults are extraordinarily bad and causing bad performance. But with few tweaks you can get to an almost-native performance, as long as you are ok with reduced visual beautiy.



See this blog for some ideas/details/hacks.

Bad transitions performance on Android

On Android, on page-change there is a bad effect of "jitter" once before moving to the page. It is not seen of chrome pc.
few approaches (see stackoverflow)
1 .Simplest : change transition to none.  Fastest on Android. data-transition="none". It also make the wierd temporary scroll bar go away
$.mobile.defaultPageTransition  = 'none';
$.mobile.defaultDialogTransition = 'none';
$.mobile.buttonMarkup.hoverDelay = 0;
Note some places say u need user-scalalbe=no on phono gap even with none data-transition


2. using this: <meta name="viewport" content="width=device-width, user-scalable=no" /> fade works fine without flicker, but it is still slow.


Slider/Range widgets are very slow on Android

known issue planned to be solved on 1.5
iOS performance was ok, on the one sample iPhone I tried.


Click delay?

http://stackoverflow.com/questions/10028782/replace-all-click-events-with-tap-in-jquery-mobile-to-
speed-up


1. One common internet opinition is to use https://github.com/ftlabs/fastclick . Didn`t help me much... 2.   On JQueryMobile I believe there is another issue. When you click on a button, the blue highlight starts, and the actual action/page-transition occurs considrable time afterwards (half-a-second...) You can remove this, by adding the fastclick class to relevant elements, and declare it as below, but note that it can cause problems with paenl buttons and that the highlight disappears...
$( document ).one( "pageshow", function() {
       $(".fastclick").on("vclick",function(e){
               $(this).trigger("click");
               e.preventDefault();
               return false;
           }); 
});

TODO; an actual better solution will be to first trigger an async-action (like page change), then show the blue-highlight. It appears it work the other way around now.
wierdly checkbox widget work better.


How to choose multi-panel or single?:

Approach 1 -  copy the header,panel each time.

It is better to have two separate pages (.html), one which each page in it.

<div data-role="page" id="profile">

    <div data-role="header" data-position="fixed" data-tap-toggle="false" data-id="persist1" data-theme="a">
      <span class="ui-title">Edit Profile</span>
        <div class="ui-btn-right">
            <a id="myButton1" class="headerButton" href="index.html" data-role="button">profile</a>            <a id="myButton2" class="headerButton" href="index2.html" data-role="button">index2</a>

        </div>
        <a href="#myPanel" class="ui-btn ui-btn-left ui-icon-bars ui-btn-icon-notext">not-visible</a>

    </div>
   <div data-role="panel" id="myPanel">
        <h2>Panel Header</h2>
        <p>panel2.</p>
     </div>
      <div data-role="main" class="ui-content" id="main-profile">
         profile page
      </div>

</div> <!--of page-->

in this case, there are three issues:
1. Ugly code which is the same for each page.
2. On transition, the header slightly change, unless you add it data-theme='a' (the default is bad)
3. If you are using multiple pages in the same .html file, after you move to another page, the panel fails to work, probably as we have multiple panels with the same-id.


Approach 2 -  external header and panel

In this case, you have to add a script above ,otherwise the external panel/header will not shown at all.

<script>
  $( document ).on( "pagecreate", function() {
  $( "body > [data-role='panel']" ).panel();
  $( "body > [data-role='panel'] [data-role='listview']" ).listview();
  });

  $( document ).one( "pageshow", function() {
   $( "body > [data-role='header']" ).toolbar();
   $( "body > [data-role='header'] [data-role='navbar']" ).navbar();
  });

 </script>

</head>

<body>

<div data-role="header" data-id="my-header" data-position="fixed" data-tap-toggle="false" data-theme="b">
    <h1>First</h1>
     <a href="#myPanel" class="ui-btn ui-btn-left ui-icon-bars ui-btn-icon-notext">not-visible</a>
    <div class="ui-btn-right">
            <a id="myButton1" class="headerButton" href="#first" data-prefetch="true" data-transition="fade" data-role="button">profile</a>
            <a id="myButton2" class="headerButton" href="#second" data-prefetch="true" data-transition="fade" data-role="button">home</a>
        </div>
</div><!-- /header -->

<div data-role="panel" id="myPanel">
        <h2>Panel Header</h2>
        <p>You can close the panel by clicking outside the panel, pressing the Esc key or by swiping.</p>
</div>

<div data-role="page" id="first">
    <div data-role="content"> 
        <p>The content</p>     
        <p>View internal page called <a href="#second">second</a></p> 
    </div><!-- /content -->
</div>

<div data-role="page" id="second">
    <div data-role="content"> 
        <p>I'm the second content 2nd</p>     
        <p><a href="#first">Back to first</a></p> 
    </div><!-- /content -->
</div>


</body>


Issues with this approach
1. You will have to change pragmatically the title, active-button of the header once you move to another page
2. still need the data-theme="a" to have any theme to your page.


Let`s discuss the events in this scenario.  If you programtically modify the content of the page and not loading a different page, the beforecreate,create and init event will be called the first time you move to that page, but not afterwards.  Also remember you have to manually call the page enhance, if your change require widget change.
(Navigate from A to B)
page B---pagebeforecreate   (ONCE)
page B---pagecreate            (ONCE)
page B---pageinit                 (ONCE)
page A---pagebeforehide
page B---pagebeforeshow
page A---pageremove
page A---pagehide
page B---pageshow 

            activepage =  $.mobile.pageContainer.pagecontainer("getActivePage");

            console.log( activepage[0].id);
You can put it on the pagebeforeshow event , as example.




Panels

For Android -like drawer:
 <div data-role="panel" id="myPanel"  data-display="overlay" data-position-fixed="true" data-theme="a">
data-position-fixed="true"  - you content will always jump up when you open.
data-display="overlay"  for Android style, use "push"/"reveal" for iOS style.







No comments: