1

我在 jquery mobile 中有一个列表。我已经添加了代码来根据我所处的最近状态来处理列表。出于某种原因,我的逻辑不起作用。任何想法为什么?滚动时列表也非常缓慢。

检查此链接并单击左上角的查找最近的位置按钮

http://www.jm.bugs3.com/gl/state.html

<script>
function findMe(){

    if (navigator.geolocation !=undefined){
        navigator.geolocation.watchPosition(onFound, handleError);
    }
}
function onFound(position){
    var userLat = position.coords.latitude;
    var userLong = position.coords.longitude;
    $('ul li').each(function (index){
        var locationLat = $(this).find('.lat').html();
        var locationLong = $(this).find('.long').html();
        var distance = getDistance(userLat, locationLat, userLong, locationLong);
        $(this).data("distance", distance);
    })

    reOrder();  
}



function handleError(error){
    alert ("Could not find location");
}

function reOrder(){
    $('ul li').sort(sortAlpha).appendTo('ul');  
}

function sortAlpha(a, b){
    return $(a).data('distance') > $(b).data('distance') ? 1 : -1;  //if True or false 1 or -1
};
//Calculate the shortest distance based on lat and long
function getDistance(lat1, lat2, lon1, lon2){
    var R = 6371; //KM
    var d = Math.acos(Math.sin(lat1) * Math.sin(lat2) +
            Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1)) * R
        return d    
};

// 这是带有纬度和经度坐标的列表的代码

<div data-role="content">   
        <ul data-role="listview" data-inset="true">
            <li>
                <a href="#page2" data-transition="slide" >Alabama</a>
                <div class="lat" style="visibility:hidden">31.375626</div>
                <div class="long" style="visibility:hidden">-86.299592</div>
            </li>
            <li>
                <a href="#page3" data-transition="slide">Alaska</a>
                <div class="lat" style="visibility:hidden">60.216736</div>
                <div class="long" style="visibility:hidden">-149.882995</div>
            </li>
            <li>
                <a href="#page4" data-transition="slide">Arizona</a>
                <div class="lat" style="visibility:hidden">32.447659</div>
                <div class="long" style="visibility:hidden">-112.134568</div>
            </li>
            <li>
                <a href="#page5" data-transition="slide" >Arkansas</a>
                <div class="lat" style="visibility:hidden">33.678252</div>
                <div class="long" style="visibility:hidden">-92.340846</div>
            </li>
            <li>
                <a href="#page6" data-transition="slide" >Boston</a>
                <div class="lat" style="visibility:hidden">41.358431</div>
                <div class="long" style="visibility:hidden">-71.059773</div>
            </li>
4

2 回答 2

1

JavaScript 的排序是 O(n) - 换句话说,它不止一次地触及每个元素。这意味着您在同一个 elem 上多次调用 .data( 并且您也多次移动它,每次都会触发浏览器重绘。

不要对元素进行排序,而是对其“距离”数组进行排序。

然后,从视图中移除整个 UL,遍历距离数组,将每个值映射回 LI,从原始 UL 中提取它,将其附加到新的 UL。用新的 UL 代替旧的 UL。

这样浏览器重绘只发生一次,并且您在排序函数中使用已经计算的值(而不是挖掘 elem attrs)。

此外,使用 data attr 比 .find('div with class') 拉 lat, lon 更快。

下面不隐藏/显示旧/新UL,这意味着您在移动每个LI后都会重新绘制,但后端计算量会大大减少。

var distance_to_li_map = {}
$('ul li').each(function (index){
    var $this = $(this)
    , locationLat = $this.data("latitude")
    , locationLong = $this.data('longitude')
    , distance = getDistance(userLat, locationLat, userLong, locationLong)

    // store LI elem pointers into map
    distance_to_li_map[distance] = this
})

var distances = Object.keys(distance_to_li_map)

distances.sort()

var newUL = $('<ul></ul>').insertBefore('ul' /*the old UL*/)[0]

for (var i = 0; i < distances.length; i++) {
    newUL.appendChild(distance_to_li_map[distances[i]])
};
于 2012-06-09T19:41:58.363 回答
0

好时,

“...基于我所处的最近的状态”有点难以解释,原因如下:

  • 简而言之,“我所处的最近状态”是“我所处的状态”
  • “一个州最近的地理中心”可能不是“我所在的州”(例如,如果我在佛罗里达泛汉德尔的西端,那么“最近的州”是阿拉巴马州,而不是佛罗里达州)
  • 我可能不在某个状态(例如,我在海上)。

尽管存在这种困难并且相信您自己的代码正确地反映了正确的含义,并且以@ddotsenko 的回答为起点,但仍可以进行以下改进:

  • 真正的排序操作可以通过将<li>引用加载到一个数组中来避免,而不是一个对象,由距离索引(四舍五入)。这将以正确的顺序给出一个稀疏数组。
  • <li>元素可以在其原始元素中重新排序,避免每次排序都<ul>需要新元素。<ul>

考虑到这些要点,ddotsenko 代码的修改版本如下:

function onFound(position) {
    var userLat = position.coords.latitude,
        userLong = position.coords.longitude,
        arr = [],
        $ul = $("ul");//a more specific selector would be good
    $ul.find('li').each(function (index) {
        var $this = $(this),
            lat = Number($this.data("latitude")),
            lng = Number($this.data('longitude')),
            dist = Math.round(getDistance(userLat, lat, userLong, lng));
        arr[dist] = this;
    });
    //At this point, arr is a sparse array of li elements indexed by distance, hence in distance order.
    for(var item in arr) {
        //Ref: "Iterating over sparse arrays", //http://hexmen.com/blog/2006/12/iterating-over-sparse-arrays/
        if (String(item >>> 0) == item && item >>> 0 != 0xffffffff) {
            $ul.append(item);
        }
    };
}

这应该会明显更快。

关于缓慢的滚动,在 DOM 中使用更少的元素可能会更好。ddotsenko 代码中的 javasctipt 表示<li>s以下格式:

<li data-latitude="31.375626" data-longitude="-86.299592">
    <a href="#page2" data-transition="slide" >Alabama</a>
</li>

这应该比隐藏的 div 更好地保存数据。

更好的是在 javascript 中硬编码所有纬度/经度对,从而避免从 DOM 中较慢的检索,例如:

var stateLocations = {
    "Alabama":  {lat: 31.375626, lng: -86.299592},
    "Alaska":   {lat: 60.216736, lng: -149.882995},
    "Arizona":  {lat: 32.447659, lng: -112.134568},
    "Arkansas": {lat: 33.678252, lng: -92.340846},
    ...
};

然后相应地查找。

顺便说一句,波士顿是一个城市,而不是一个州。美国没有一个以“B”开头

于 2012-06-10T02:38:53.773 回答