使用jQuery将列表项移动到无序列表的顶部

时间:2022-12-02 18:14:04

Lets say i have the following unordered list

假设我有下面的无序列表

<ul>
 <li><a>Hank</a></li>
 <li><a>Alice</a></li>
 <li><a>Tom</a></li>
 <li><a>Ashlee</a></li>
</ul>

What im looking for is when i click on Tom, that it moves (animated and without dragging) to the top of the list (index 0).

我要找的是当我点击Tom时,它会移动到列表的顶部(索引0)。

Ive considered jquery sortable, but i cant find a way to activate the moving part programmatically.

我考虑过jquery可排序,但我无法找到一种方法以编程方式激活移动部分。

5 个解决方案

#1


17  

I came up with a solution that seems to work pretty well. It's a proof of concept, so you'll probably have to modify it a bit to work better for your specific case. Also, I only tested it in Firefox, but I don't see any reason why this wouldn't work in all the browsers. Anyway, here it is:

我想出了一个似乎很有效的解决方案。这是概念的证明,所以您可能需要对它进行一些修改,以更好地适应您的具体情况。此外,我只在Firefox中测试过它,但我不认为这在所有浏览器中都适用。无论如何,这里是:

<script type="text/javascript">
  $(document).ready(function() {
    $('li').click(function() {
      // the clicked LI
      var clicked = $(this);

      // all the LIs above the clicked one
      var previousAll = clicked.prevAll();

      // only proceed if it's not already on top (no previous siblings)
      if(previousAll.length > 0) {
        // top LI
        var top = $(previousAll[previousAll.length - 1]);

        // immediately previous LI
        var previous = $(previousAll[0]);

        // how far up do we need to move the clicked LI?
        var moveUp = clicked.attr('offsetTop') - top.attr('offsetTop');

        // how far down do we need to move the previous siblings?
        var moveDown = (clicked.offset().top + clicked.outerHeight()) - (previous.offset().top + previous.outerHeight());

        // let's move stuff
        clicked.css('position', 'relative');
        previousAll.css('position', 'relative');
        clicked.animate({'top': -moveUp});
        previousAll.animate({'top': moveDown}, {complete: function() {
          // rearrange the DOM and restore positioning when we're done moving
          clicked.parent().prepend(clicked);
          clicked.css({'position': 'static', 'top': 0});
          previousAll.css({'position': 'static', 'top': 0}); 
        }});
      }
    });
  });
</script>

<ul>
 <li><a>Hank</a></li>
 <li><a>Alice</a></li>
 <li><a>Tom</a></li>
 <li><a>Ashlee</a></li>
</ul>

It calculates the difference in offsets between the clicked LI and first LI and moves the clicked one up to the top by setting its position to relative and animating the top property. Similarly, it calculates how much space was left behind by the clicked LI and moves all the previous ones down accordingly. When it's done with the animations, it rearranges the DOM to match the new order and restores the positioning styles.

它计算被单击的LI和第一个LI之间的偏移量,并通过将其位置设置为相对的并对顶部属性进行动画化,将被单击的LI移动到顶部。同样,它计算被点击的LI留下了多少空间,并相应地将之前的所有空间向下移动。当动画完成后,它重新安排DOM以匹配新的订单并恢复定位样式。

Hope that helps!

希望会有帮助!

#2


47  

Found this even neater:

发现这更简洁:

$('li').on('click', function() {
    $(this).parent().prepend(this);
});​

Live example

生活的例子

#3


10  

Assuming:

假设:

<ul id="list">
 <li><a>Hank</a></li>
 <li><a>Alice</a></li>
 <li><a>Tom</a></li>
 <li><a>Ashlee</a></li>
</ul>

then:

然后:

$("#list a").click(function() {
  $(this).parent().before("#list a:first");
  return false;
});

If you want to animate then it's a little harder. One option:

如果你想要动画,那就有点难了。一个选项:

$("#list a").click(function() {
  $(this).parent().slideUp(500).before("#list a:first").slideDown(500);
  return false;
});

Another option:

另一个选择:

$("#list a").click(function() {
  var item = $(this).parent();
  var prev = item.prev();
  while (prev.length > 0) {
    item.before(prev);
    prev = item.prev();
  }
  return false;
});

but I doubt you'll get smooth animation that way.

但我怀疑你不会得到平滑的动画。

#4


2  

i played around with the fiddle No Surprises has made, and extended the code for swapping two arbitrary sets of elements (the only restriction being they must directly follow each other).

我摆弄了一下小提琴,没有什么奇怪的,并扩展了交换任意两组元素的代码(唯一的限制是它们必须直接跟随彼此)。

see here: http://jsfiddle.net/ZXYZ3/139/

在这里看到的:http://jsfiddle.net/ZXYZ3/139/

#5


1  

I came up with this solution: http://jsfiddle.net/FabienDemangeat/TBYWw/

我想到了这个解决方案:http://jsfiddle.net/FabienDemangeat/TBYWw/

The idea is to choose the index of the Li element which will move and its destination. If the destination value is inferior to the index of the li element to move, the effect will be reversed.

其思想是选择将要移动的Li元素及其目的地的索引。如果目标值低于要移动的li元素的索引,则效果将被反转。

Some parts are not perfect but it can be a start point. I inspired myself from the snippet provided by "No Surprises"

有些部分并不完美,但可以作为起点。我从“无意外”提供的片段中获得灵感

The main function swapLiElements swaps two li elements and the callback function as parameters allows to do more than one swap easily (see fiddle).

swapLiElements的主函数交换了两个li元素,回调函数作为参数,可以轻松地进行多个交换(参见fiddle)。

function swapLiElements($northLi, $southLi, isPushingDown, duration, easing, callbackFunction) {

    var movement = $northLi.outerHeight();

    // Set position of the li elements to relative
    $northLi.css('position', 'relative');
    $southLi.css('position', 'relative');

    // Set the z-index of the moved item to 999 to it appears on top of the other elements
    if(isPushingDown)
        $northLi.css('z-index', '999');
    else        
        $southLi.css('z-index', '999');

    // Move down the first li
    $northLi.animate({'top': movement}, {
        duration: duration,
        queue: false,
        easing: easing,
        complete: function() {
            // Swap the li in the DOM
            if(isPushingDown)
                $northLi.insertAfter($southLi);
            else
                $southLi.insertBefore($northLi);

            resetLiCssPosition($northLi);
            resetLiCssPosition($southLi);

            callbackFunction();
        }
    });

    $southLi.animate({'top': -movement}, {
        duration: duration,
        queue: false,
        easing: easing,
    });

}

#1


17  

I came up with a solution that seems to work pretty well. It's a proof of concept, so you'll probably have to modify it a bit to work better for your specific case. Also, I only tested it in Firefox, but I don't see any reason why this wouldn't work in all the browsers. Anyway, here it is:

我想出了一个似乎很有效的解决方案。这是概念的证明,所以您可能需要对它进行一些修改,以更好地适应您的具体情况。此外,我只在Firefox中测试过它,但我不认为这在所有浏览器中都适用。无论如何,这里是:

<script type="text/javascript">
  $(document).ready(function() {
    $('li').click(function() {
      // the clicked LI
      var clicked = $(this);

      // all the LIs above the clicked one
      var previousAll = clicked.prevAll();

      // only proceed if it's not already on top (no previous siblings)
      if(previousAll.length > 0) {
        // top LI
        var top = $(previousAll[previousAll.length - 1]);

        // immediately previous LI
        var previous = $(previousAll[0]);

        // how far up do we need to move the clicked LI?
        var moveUp = clicked.attr('offsetTop') - top.attr('offsetTop');

        // how far down do we need to move the previous siblings?
        var moveDown = (clicked.offset().top + clicked.outerHeight()) - (previous.offset().top + previous.outerHeight());

        // let's move stuff
        clicked.css('position', 'relative');
        previousAll.css('position', 'relative');
        clicked.animate({'top': -moveUp});
        previousAll.animate({'top': moveDown}, {complete: function() {
          // rearrange the DOM and restore positioning when we're done moving
          clicked.parent().prepend(clicked);
          clicked.css({'position': 'static', 'top': 0});
          previousAll.css({'position': 'static', 'top': 0}); 
        }});
      }
    });
  });
</script>

<ul>
 <li><a>Hank</a></li>
 <li><a>Alice</a></li>
 <li><a>Tom</a></li>
 <li><a>Ashlee</a></li>
</ul>

It calculates the difference in offsets between the clicked LI and first LI and moves the clicked one up to the top by setting its position to relative and animating the top property. Similarly, it calculates how much space was left behind by the clicked LI and moves all the previous ones down accordingly. When it's done with the animations, it rearranges the DOM to match the new order and restores the positioning styles.

它计算被单击的LI和第一个LI之间的偏移量,并通过将其位置设置为相对的并对顶部属性进行动画化,将被单击的LI移动到顶部。同样,它计算被点击的LI留下了多少空间,并相应地将之前的所有空间向下移动。当动画完成后,它重新安排DOM以匹配新的订单并恢复定位样式。

Hope that helps!

希望会有帮助!

#2


47  

Found this even neater:

发现这更简洁:

$('li').on('click', function() {
    $(this).parent().prepend(this);
});​

Live example

生活的例子

#3


10  

Assuming:

假设:

<ul id="list">
 <li><a>Hank</a></li>
 <li><a>Alice</a></li>
 <li><a>Tom</a></li>
 <li><a>Ashlee</a></li>
</ul>

then:

然后:

$("#list a").click(function() {
  $(this).parent().before("#list a:first");
  return false;
});

If you want to animate then it's a little harder. One option:

如果你想要动画,那就有点难了。一个选项:

$("#list a").click(function() {
  $(this).parent().slideUp(500).before("#list a:first").slideDown(500);
  return false;
});

Another option:

另一个选择:

$("#list a").click(function() {
  var item = $(this).parent();
  var prev = item.prev();
  while (prev.length > 0) {
    item.before(prev);
    prev = item.prev();
  }
  return false;
});

but I doubt you'll get smooth animation that way.

但我怀疑你不会得到平滑的动画。

#4


2  

i played around with the fiddle No Surprises has made, and extended the code for swapping two arbitrary sets of elements (the only restriction being they must directly follow each other).

我摆弄了一下小提琴,没有什么奇怪的,并扩展了交换任意两组元素的代码(唯一的限制是它们必须直接跟随彼此)。

see here: http://jsfiddle.net/ZXYZ3/139/

在这里看到的:http://jsfiddle.net/ZXYZ3/139/

#5


1  

I came up with this solution: http://jsfiddle.net/FabienDemangeat/TBYWw/

我想到了这个解决方案:http://jsfiddle.net/FabienDemangeat/TBYWw/

The idea is to choose the index of the Li element which will move and its destination. If the destination value is inferior to the index of the li element to move, the effect will be reversed.

其思想是选择将要移动的Li元素及其目的地的索引。如果目标值低于要移动的li元素的索引,则效果将被反转。

Some parts are not perfect but it can be a start point. I inspired myself from the snippet provided by "No Surprises"

有些部分并不完美,但可以作为起点。我从“无意外”提供的片段中获得灵感

The main function swapLiElements swaps two li elements and the callback function as parameters allows to do more than one swap easily (see fiddle).

swapLiElements的主函数交换了两个li元素,回调函数作为参数,可以轻松地进行多个交换(参见fiddle)。

function swapLiElements($northLi, $southLi, isPushingDown, duration, easing, callbackFunction) {

    var movement = $northLi.outerHeight();

    // Set position of the li elements to relative
    $northLi.css('position', 'relative');
    $southLi.css('position', 'relative');

    // Set the z-index of the moved item to 999 to it appears on top of the other elements
    if(isPushingDown)
        $northLi.css('z-index', '999');
    else        
        $southLi.css('z-index', '999');

    // Move down the first li
    $northLi.animate({'top': movement}, {
        duration: duration,
        queue: false,
        easing: easing,
        complete: function() {
            // Swap the li in the DOM
            if(isPushingDown)
                $northLi.insertAfter($southLi);
            else
                $southLi.insertBefore($northLi);

            resetLiCssPosition($northLi);
            resetLiCssPosition($southLi);

            callbackFunction();
        }
    });

    $southLi.animate({'top': -movement}, {
        duration: duration,
        queue: false,
        easing: easing,
    });

}