Jquery Mobile + Phonegap 提高列表视图性能

Jquery Mobile + Phonegap improve listview performance

在我的 JQM 1.4 + Phonegap 3.6 应用程序中,我正在使用 listview,如下面的代码所示。

HTML:

<div id="boardselection">           
  <ul id="modelsListview" data-role="listview"  data-icon="false">
  </ul>         
</div>

JS:

function resetModelsListView(prodata, firsttime, funfeatureOn, specificBrand, specificPro) {

console.log("on passe dans resetModelsListView");
//  funfeatureOn = 0;

//debug timer
var time = [];
var dummy;
var i;
var listviewdeferred = $.Deferred();
var optionspro = '';
var optionsbrand = '';
var optionsmodel = '';
var countpros = 0;
var countbrands = 0;
var countmodels = 0;
var chosenmodelListViewHandle = $('#modelsListview');
var chosenbrandSelect = $('#chosenbrand');
optionsmodel += '';
var alreadyusedbrands = [];
prodata.sort(SortByName);

// get previously selected model to reselect it later
//var previouslySelectedModelId =parseInt(chosenmodelSelect.find('li:selected').val());

if (!funfeatureOn) {
    prodata.sort(SortByModel);
} else {
    prodata.sort(SortByFUN);
}

//populate model list
//~ if (firsttime){
    //~ var perfIsChecked = true;
    //~ var smallwaveIsChecked = true;
    //~ var stepupIsChecked = true;
//~ }else {
    var perfIsChecked = $('#checkboxperf').is(":checked");
    var smallwaveIsChecked = $('#checkboxsmallwave').is(":checked");
    var stepupIsChecked = $('#checkboxstepup').is(":checked");
//~ }

console.log("perfIsChecked, smallwaveIsChecked, stepupIsChecked =");
console.log(perfIsChecked);
console.log(smallwaveIsChecked);
console.log(stepupIsChecked);

//if none checked then no filter
if (!perfIsChecked && !smallwaveIsChecked && !stepupIsChecked) {
    perfIsChecked = true;
    smallwaveIsChecked = true;
    stepupIsChecked = true;
}

for (i = 1; i < prodata.length; ++i) {
    if (specificBrand && prodata[i]['brand'] != specificBrand) {
    } else if (specificPro && prodata[i]['name'] != specificPro) {
    } else {
        if (prodata[i]['fun'] == 0 && perfIsChecked) {
            optionsmodel += '<li><a class="optionfuninit" href="#" data-proid="' + prodata[i]['id'] + '"><div class="listviewtexts"><span class="listviewtextsmodel">' + prodata[i]['model'] + '</span> - <span class="listviewtextspro">as surfed by ' + prodata[i]['name'] + '</span></div></a></li>';
        } else if (prodata[i]['fun'] == 1 && smallwaveIsChecked) {
            optionsmodel += '<li><a class="optionfuninit" href="#" data-proid="' + prodata[i]['id'] + '"><div class="listviewtexts"><span class="listviewtextsmodel">' + prodata[i]['model'] + '</span> - <span class="listviewtextspro">as surfed by ' + prodata[i]['name'] + '</span></div></a></li>';
        } else if (prodata[i]['fun'] == 2 && stepupIsChecked) {
            optionsmodel += '<li><a class="optionstepupinit" href="#" data-proid="' + prodata[i]['id'] + '"><div class="listviewtexts"><span class="listviewtextsmodel">' + prodata[i]['model'] + '</span> - <span class="listviewtextspro">as surfed by ' + prodata[i]['name'] + '</span></div></a></li>';
        } else if (prodata[i]['fun'] == 3 && smallwaveIsChecked) {
            optionsmodel += '<li><a class="optionkidsinit" href="#" data-proid="' + prodata[i]['id'] + '"><div class="listviewtexts"><span class="listviewtextsmodel">' + prodata[i]['model'] + '</span> - <span class="listviewtextspro">as surfed by ' + prodata[i]['name'] + '</span></div></a></li>';
        }
        if (prodata[i]['model'] !== prodata[i - 1]['model']) { //eliminate name duplicates if prodata sorted by model
            countmodels = countmodels + 1;
        }
    }
}
chosenmodelListViewHandle.html(optionsmodel);

if (chosenmodelListViewHandle.listview("option", "disabled")) {
    chosenmodelListViewHandle.listview("option", "disabled", false);
}
//~ if (resetModelsOnly) {
//~ if ( !isNaN(previouslySelectedModelId) ) {
//~ chosenmodelListViewHandle.find('li[href="' + previouslySelectedModelId + '"]').attr("selected", "selected").siblings('li').removeAttr('selected');
//~ }
//~ }

//~ highlightFunModels(funfeatureOn, 1);
//~ highlightStepupModels(funfeatureOn, 0);


chosenmodelListViewHandle.listview("refresh", true);
$("#chosenmodel-button").addClass("ui-icon-carat-d ui-btn-icon-right");

if (!funfeatureOn) {
} else {
    $('ul#chosenmodel-menu').find("a.ui-btn:contains(SMALL-WAVE)").addClass("optionfun");
    $('ul#chosenmodel-menu').find("a.ui-btn:contains(STEP-UP)").addClass("optionstepup");
}
prodata.sort(SortById); //we need this otherwise prodata is not usable by the $('#chosenpro').trigger

$("#chosenmodel-button span").attr({ 'data-i18n': 'select.3' });
$("#boardselection").i18n();
listviewdeferred.resolve();
return listviewdeferred;
}

这会动态显示一长串图像和文本,具体取决于是否选中了过滤器(复选框),而且生成的这个列表很长,而且在 iOS 中特别难以滚动... .性能差

你能帮我想出一个提高性能的方法吗?

简而言之,jQuery 移动速度很慢。

我的应用程序中有一个动态列表视图,并且在使用 jQuery 移动设备时也遇到了性能问题。我得出的结论是,问题出在渲染中,是由 jQuery 移动设备引起的。我实现了自己的样式,渲染时间从 170 毫秒减少到 25 毫秒。

这里有一些支持我的观点(3 篇文章):http://apachecordova.blogspot.fi/search/label/jQuery%20Mobile


编辑:
作为对您在评论中的问题的回答,我认为如果我在这里发布我的代码不会有帮助。重点是你只写你需要的代码。我的列表视图可能与你的完全不同。

为了证明我的观点(再次),我制作了两个列表视图。第一个是基本的 jQM 列表视图。另一个使用自定义 CSS 样式,它非常接近我在我的应用程序中使用的样式。两者都有一个按钮呈现列表视图。引擎盖下发生的事情是非常不同的:

jQM: 如您所见,有很多东西(您可能不需要)正在进行



自定义 CSS: 为所有元素附加一个事件侦听器,使比较更加公平

这些配置文件是使用 Chrome 开发人员工具记录的,差异很明显:173 毫秒对 12 毫秒。这个习惯 CSS 花了我大约 5 分钟的时间来写:

#custom-listview {
    list-style-type: none;
    padding: 0px;
    margin: 0px;
}
#custom-listview li {
    display: block;
    position: relative;
    overflow: visible;
}
#custom-listview a {
    display: block;
    position: relative;
    text-overflow: ellipsis;
    text-decoration: none;
    color: white;
    padding: .7em 1em;
    font-size: 16px;
    background-color: #333;
    border: solid 1px #1f1f1f;
    overflow: hidden;
    white-space: nowrap;
    font-family: sans-serif;
}

我必须在此处添加一些代码,因为如果没有:

,我将无法从 link 到 Fiddle
  1. jQM
  2. Custom CSS

我不是说 jQuery 手机很糟糕。这对很多事情都有好处。但是如果你有复杂的结构 and/or 大量数据,性能可能会成为一个问题,尤其是在 PhoneGap 应用程序中。这是我凭着一点经验得出的结论。

接受的答案不正确。 你的代码很慢,但不是因为 jQuery Mobile。 看看你的 jsFiddle 中的循环:jsfiddle。net/L3gr46s8/4

for (i = 0; i <= 50; i++) {
    $('ul[data-role="listview"]').append('<li><a href="#">' + 'list item ' + i + '</a></li>');
    $('ul[data-role="listview"]').listview('refresh');
}

这四行代码中有几个非常重要的问题。

首先,您的代码执行两次 DOM 遍历以定位页面上的 ul。您可以在循环之前执行 $('ul[data-role="listview"]') 并将结果存储在变量中:

var listView = $('ul[data-role="listview"]');

其次,您的代码将列表项直接插入 DOM 并指示 jQuery Mobile 立即使用 .listview('refresh'); 应用标记增强。 这非常昂贵! 尤其是在动力不足的移动设备上。根据浏览器和页面布局,这两行代码可能会在循环的每次迭代中触发整个页面的重新绘制。

您应该将内容呈现为 DocumentFragment(在内存中),一次操作将其全部插入 DOM 并告诉 JQM 最后一次增强标记。即使只是将 $('ul[data-role="listview"]').listview('refresh'); 移出循环也会是一个显着的改进。

这里有一些关于在将内容插入 DOM 之前首先在内存中呈现内容的重要性的补充阅读:

How expensive is it to dynamically insert DIVs using JavaScript?

John Resig - DOM DocumentFragments