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
我不是说 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?
在我的 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我不是说 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?