使用JavaScript通过鼠标拖动订购图形列表 [英] Ordering a graphical list via mouse dragging using JavaScript

查看:99
本文介绍了使用JavaScript通过鼠标拖动订购图形列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:以下CSS的问题的确切描述。示例代码可以在 小提示,您可以点击(并按住)任何一个子元素,并在其中上下移动父div。



$ b

问题: $ b

如何检测所选元素是否已被拖到另一个元素的上方?我不仅想知道他们是否重叠,而是想把一个范围。像... ...

  if(当前孩子的中心超过另一个孩子的设置范围){
do stuff ...
}

我现在想做什么概念验证)是让底层孩子的背景颜色变化 WHILE 所选孩子的垂直中心在底部孩子高度的0.4-0.6范围内。



我尝试过以下类似的操作:

  $('。category')mouseover(function(){
if(dragging){
...执行代码...
}
});

但是,如果我将一个元素拖到另一个元素上,底部元素看不到鼠标



I' ve尝试了几种不同的方法来保持光标作为指针拖动时,但无论它切换到文本光标拖动时。



对于指针,我尝试了 $(this).css('cursor' ,和鼠标移动函数中的可用。



提前感谢!

解决方案

这里 是我提出的解决方案,纯粹使用JS和JQuery,不需要外部库,也不需要使用JQueryUI Sortables。



HTML

 < div class =list_container > 
< div class =list_item>一个< / div>
< div class =list_item>两个< / div>
< div class =list_item> Three< / div>
< div class =list_item>四< / div>
< div class =list_item> Five< / div>
< div class =list_item>六< / div>
< / div>

其中 list_container $ c> list_item 元素。它是后两者,可以移动创建您的排序列表。你可以在 list_item 中加入任何你想要的东西,它仍然可以正常工作。



CSS:

  .list_container {
position:
}
.list_item {
position:absolute;
z-index:0;
left:0px;
}
.list_item.selected {
z-index:1000;
}

请访问这篇文章提供了CSS规则的完整列表(只有必要的CSS规则如上所示)。



JavaScript



我将逐一介绍,然后在底部显示完整代码。



首先,我定义了一个数组,以匹配索引号与它们的书面对应

  var classes = new Array(one,two,three,...); 

这是用于动态创建类(在加载页面时)。这些类用于排序列表。您只需要填充与您在列表中将有的项目一样多的数组。这是我写的代码的一个垮台,我不确定如何克服这个问题(将是非常繁琐的输入元素列表的数百项,或更多!)



接下来是一些其他变量:

  var margin = 2; //每个列表项之间所需的空间
var $ el; //用于保存所选元素的ID
var oldPos = 0; //所选元素在动画之前的位置
var newPos = 0; //所选元素的位置AFTER动画(也是当前位置)
var dragging = false; //是否正在移动项目

var numElements = $('。list_container> div')。

// selectionHeight是每个列表元素的高度(假定所有高度相同)
//它包括div高度,顶部和底部边框的高度以及所需的margin

var selectionHeight = $('。list_container .list_item')。height()+ parseInt($('。list_container .list_item')。css(border-bottom-width))+ parseInt $('。list_container .list_item')。css(border-top-width))+ margin;

var classInfo =''; // classInfo将填充用于在页面加载时动态创建类的信息

加载,遍历每个 list_item 并根据它在列表中的初始位置为它分配一个类。还要添加到 classInfo 列表项顶部的位置。

  $('。list_container .list_item')。each(function(index){
$(this).addClass(classes [index]);
classInfo + ='。'+ classes [index] +'{top:'+ index * selectionHeight +'px;} \\\
';
});

现在,使用上面创建的 classInfo ,动态地将类写入页面。

  var style = document.createElement('style'); 
style.type ='text / css';
style.innerHTML = classInfo;
document.getElementsByTagName('head')[0] .appendChild(style);

上面的代码将把所需的类写入页面的HTML。如果您查看页面的来源,您可以在页面的头部看到类。



现在查找排序部分。首先, mousedown

  $('。list_item')。mousedown function(ev){
$ el = $(this);
oldPos = $ el.index()+ 1;
newPos = oldPos;
dragging = true;
startY = ev.clientY; //获取当前鼠标位置
startT = parseInt($ el.css('top')); //获取项目的TOP的当前位置
$ el.addClass('selected'); //添加类将它带到顶部(z-index)并改变列表项的颜色
});

接下来, mousemove mouseup 函数绑在一起

  $(window).mousemove(function {//使用$(窗口)鼠标可以离开父div并仍然工作
if(dragging){
$ el.attr('class','list_item')//删除编号的类.one,.two等)
$ el.addClass('selected'); //添加这个类为美观

// -----计算新的顶部
var newTop = startT +(ev.clientY - startY);
$ el.css('cursor','pointer');
// ------

// ------留在父级
var maxTop = $ el.parent()。height() - $ el.height();
newTop = newTop< 0? 0:newTop> maxTop?maxTop:newTop;
$ el.css('top',newTop);
// ------

newPos = getPos (newTop,selectionHeight); //确定所选列表项的当前位置是

//如果列表项的位置已更改,请将位置的当前元素移出并重新分配oldPos to newPos
if(oldPos!= newPos){
moveThings(oldPos,newPos,selectionHeight);
oldPos = newPos;
}
}
})mouseup(function(){
dragging = false; //用户不再拖动
$ el.removeClass ); //不再选择元素
setNewClass($ el,newPos); //设置移动列表项的新类
$ el.css('top',(newPos - 1) * selectionHeight); //将移动的元素定位到它所属的位置,否则它会在你释放它的地方休息,而不是在它正确的位置
});

最后,三个函数 getPos code> moveThings 和 setNewClass 如下:

  function getPos(a,b){// a == newTop,b == selectionHeight 
return Math.round((a / b)+ 1);
}

getPos 找出所选元素当前在哪个区域。如果newTop小于.5b,则它在区域1中。如果在.5b和1.5b之间,则它是区域2.如果在1.5b和2.5b之间,则区域3.等等。在一张纸上写出几个案例,它会发生什么。

  function moveThings(a,b ,c){// a == oldPos,b == newPos,c == selectedHeight 
var first = classes [b-1]; //将要移动的项目的当前类是什么?
var $ newEl = $('。list_container。'+ first); //将被移动的元素的ID

if(a< b){// oldPos小于newPos
var second = classes [b-2] //移动的元素的新类将少一些
var newTop = parseInt($ newEl.css('top')) - c; //元素的顶部将向上移动
} else {// oldPos多于newPos
var second = classes [b]; //被移动的元素的新类将再一次
var newTop = parseInt($ newEl.css('top'))+ c; //元素的顶部将向下移动
}

//需要以下代码行,否则以下动画
//将从top = 0px动画到新位置(相对于从顶部= currentPosition)
//尝试取出它,看到
$ newEl.css('top',parseInt($ newEl.css('top')));
$ newEl.removeClass(first); //移除当前编号的元素类以移动
//移动元素并移除添加的样式标签(或未来的动画将获得bug)
$ newEl.animate({top:newTop},300, function(){
$ newEl.removeAttr('style');
});
$ newEl.addClass(s​​econd); //添加新的编号类

return false; //清理动画
}

上面的函数是实际动画部分和

  function setNewClass(e,a){// e == selected元素,a == newPos 
//删除'selected'类,然后添加'list_item'类和新编号的类
e.attr('class','list_item')addClass类[a-1]);
}

**所有JavaScript在一起:**

  var classes = new Array(one,two,three,four,five,six,seven 八,九,十,十一,十二,十三,十四,十五,十六,七十,十八 ,twentyone,twentytwo,twentythree,twentyfour); 

$(document).ready(function(){
var margin = 2;
var $ el;
var oldPos = 0;
var newPos = 0;
var dragging = false;

var selectionHeight = $('。list_container .list_item')height()+ parseInt($('。list_container .list_item')。 css(border-bottom-width))+ parseInt($('。list_container .list_item')。css(border-top-width))+ margin;

var classInfo = ';

$('。list_container .list_item')每个函数(索引){
$(this).addClass(classes [index]);
classInfo + ='。'+ classes [index] +'{top:'+ index * selectionHeight +'px;} \\\
';
});

var style = document.createElement ('style');
style.type ='text / css';
style.innerHTML = classInfo;
document.getElementsByTagName('head')[0] .appendChild ;

$('。list_item')。mousedown(function(ev){
$ el = $(this);
oldPos = $ el.index ;
newPos = oldPos;
dragging = true;
startY = ev.clientY;
startT = parseInt($ el.css('top'));
$ el.addClass('selected');
});

$(window).mousemove(function(ev){
if(dragging){
$ el.attr('class','list_item')
$ el.addClass('selected');

// ----- calculate new top
var newTop = startT +(ev.clientY - startY);
$ el.css('cursor','pointer');
// ------

// ------留在父级
var maxTop = $ el.parent()。height() - $ el.height();
newTop = newTop< 0?0:newTop> maxTop?maxTop:newTop;
$ el.css 'top',newTop);
// ------

newPos = getPos(newTop,selectionHeight);

if(oldPos!= newPos ){
moveThings(oldPos,newPos,selectionHeight);
oldPos = newPos;
}
}
})mouseup dragging = false;
$ el.removeClass('selected');
setNewClass($ el,newPos);
$ el.css('top',(newPos - 1)* selectionHeight);
});
});

function getPos(a,b){// a == topPos,b == selectionHeight
return Math.round((a / b)+1);
}

function moveThings(a,b,c){// a == oldPos,b == newPos,c == selectedHeight
var first = classes [b- 1];
var $ newEl = $('。list_container。'+ first);

if(a< b){// oldPos小于newPos
var second = classes [b-2]
var newTop = parseInt($ newEl.css('top')) - c;
} else {// oldPos多于newPos
var second = classes [b];
var newTop = parseInt($ newEl.css('top'))+ c;
}

$ newEl.css('top',parseInt($ newEl.css('top')));
$ newEl.removeClass(first);
$ newEl.animate({
top:newTop
},300,function(){
$ newEl.removeAttr('style');
}
$ newEl.addClass(s​​econd);

return false; //清除动画
}

function setNewClass(e,a){// e == selected element,a == newPos
e.attr('class' 'list_item')。addClass(classes [a - 1]);
}


NOTE: Exact description of question follows CSS below. Sample code can be seen in this fiddle.

I have a parent div with a list of child divs within it, that looks like the following:

HTML for said container and children is:

<div class="categories_container">
    <div class="category one">One</div>
    <div class="category two">Two</div>
    <div class="category three">Three</div>
    <div class="category four">Four</div>
    <div class="category five">Five</div>
    <div class="category six">Six</div>
</div>

Where the classes .one, .two, .three, etc... are their relative position in the list.

The children elements are positioned with absolute positioning, within their parent.

CSS as follows (some properties not shown for simplicity):

.categories_container {
    height: 324px;
    width: 100%;
    position: relative;
}
.category {
    height: 50px;
    width: 98%;
    position: absolute;
    left: 0px;
    z-index: 0;
}
.one {
    top: 0px;
}
.two {
    top: 54px;
}
.three {
    top: 108px;
}
.four {
    top: 162px;
}
.five {
    top: 216px;
}
.six {
    top: 270px;
}

As can be seen in this fiddle, you can click (and hold) on any one of the child elements and move it up and down within the parent div. When you release the mouse, the selected child snaps back to its original position.

Question:

How can I detect if the selected element has been dragged overtop of another? I don't only want to know if they are overlapping, but would like to put a range on it. Something like...

if(center of current child is overtop a set range within another child){
    do stuff...
}

What I'd like to do for now (as a proof of concept) is to have the underneath child's background color change WHILE the vertical center of the selected child is within the range 0.4-0.6 of the bottom child's height. If the selected child is dragged out of said region, the background should change back.

I've tried something like:

$('.category').mouseover(function(){
    if(dragging){
        ... execute code...
    }
});

But it seems that if I am dragging one element over the other, the bottom element cannot see the mouse, and so the function is never executed.

Also:

I've tried a few different methods to keep the cursor as a pointer while dragging, but no matter what it switches to the text cursor whilst dragging. So any help with that would also be appreciated.

For the pointer thing I've tried putting $(this).css('cursor', 'pointer'); in the mousedown and mouse move functions, but to no avail.

Thanks in advance! Sorry if any of this is confusing.

解决方案

Here is the solution I came up with, purely with JS and JQuery, with no external libraries required and without using JQueryUI Sortables.

HTML:

<div class="list_container">
    <div class="list_item">One</div>
    <div class="list_item">Two</div>
    <div class="list_item">Three</div>
    <div class="list_item">Four</div>
    <div class="list_item">Five</div>
    <div class="list_item">Six</div>
</div>

where list_container holds the individual list_item elements. Is it the latter of the two which can be moved around to create your sorted list. You can put just about anything you'd like within list_item and it'll still work just fine.

CSS:

.list_container {
    position: relative;
}
.list_item {
    position: absolute;
    z-index: 0;
    left: 0px;
}
.list_item.selected {
    z-index: 1000;
}

Please visit this fiddle for the full list of CSS rules (only necessary ones are shown above).

JavaScript:

I'll go through this bit-by-bit and then show the full code at the bottom.

First off, I defined an array that matches up index numbers with their written counterparts

var classes = new Array("one", "two", "three", ...);

This is used to create classes dynamically (upon page load). These classes are used to order the list. You are only required to populate this array with as many items as you will have in your list. This is the one downfall of the code I have written and am unsure of how to overcome this issue (would be VERY tedious to enter in the elements for a list of hundreds of items, or more!)

Next, a few other variables:

var margin = 2;       // Space desired between each list item
var $el;              // Used to hold the ID of the element that has been selected
var oldPos = 0;       // The position of the selected element BEFORE animation
var newPos = 0;       // The position of the selected element AFTER animation (also current position)
var dragging = false; // Whether or not an item is being moved

var numElements = $('.list_container > div').length;

// selectionHeight is the height of each list element (assuming all the same height)
// It includes the div height, the height of top and bottom borders, and the desired margin

var selectionHeight = $('.list_container .list_item').height() + parseInt($('.list_container .list_item').css("border-bottom-width")) + parseInt($('.list_container .list_item').css("border-top-width")) + margin;

var classInfo = '';  // classInfo will be populated with the information that is used to dynamically create classes upon page load

When page loads, go through each list_item and assign it a class according to its initial position in the list. Also add to classInfo the location of the TOP of the list item.

$('.list_container .list_item').each(function (index) {
    $(this).addClass(classes[index]);
    classInfo += '.' + classes[index] + ' {top: ' + index * selectionHeight + 'px;}\n';
});

Now, using classInfo that was created above, dynamically write the classes to the page.

var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = classInfo;
document.getElementsByTagName('head')[0].appendChild(style);

The above bit of code will write the required classes into the HTML of the page. If you view the source of the page, you can see the classes in the head of the page.

Now for the ordering part. First, mousedown

$('.list_item').mousedown(function (ev) {
    $el = $(this);
    oldPos = $el.index() + 1;
    newPos = oldPos;
    dragging = true;
    startY = ev.clientY;               // Gets the current mouse position
    startT = parseInt($el.css('top')); // Gets the current position of the TOP of the item
    $el.addClass('selected');          // Adding class brings it to top (z-index) and changes color of list item
});

Next, the mousemove and mouseup functions are tied together

$(window).mousemove(function (ev) {  // Use $(window) so mouse can leave parent div and still work
    if (dragging) {
        $el.attr('class', 'list_item')  // Remove the numbered class (.one, .two, etc)
        $el.addClass('selected');       // Add this class back for aesthetics

        // ----- calculate new top
        var newTop = startT + (ev.clientY - startY);
        $el.css('cursor', 'pointer');
        // ------

        //------ stay in parent
        var maxTop = $el.parent().height() - $el.height();
        newTop = newTop < 0 ? 0 : newTop > maxTop ? maxTop : newTop;
        $el.css('top', newTop);
        //------

        newPos = getPos(newTop, selectionHeight); // Determine what the current position of the selected list item is

        // If the position of the list item has changed, move the position's current element out of the way and reassign oldPos to newPos
        if (oldPos != newPos) {
            moveThings(oldPos, newPos, selectionHeight);
            oldPos = newPos;
        }
    }
}).mouseup(function () {
    dragging = false;            // User is no longer dragging
    $el.removeClass('selected'); // Element is no longer selected
    setNewClass($el, newPos);    // Set the new class of the moved list item
    $el.css('top', (newPos - 1) * selectionHeight);  // Position the moved element where it belongs. Otherwise it'll come to rest where you release it, not in its correct position.
});

Finally, the three functions getPos, moveThings and setNewClass are as follows:

function getPos(a, b) { // a == newTop, b == selectionHeight
return Math.round( (a/b) + 1 ); 
}

getPos works by finding out which region the selected element is currently in. If newTop is less than .5b, then it is in region 1. If between .5b and 1.5b, then it is region 2. If between 1.5b and 2.5b, then in region 3. And so on. Write out a few cases on a piece of paper and it'll make sense what is happening.

function moveThings(a, b, c) { // a == oldPos, b == newPos, c == selectedHeight
    var first = classes[b - 1];  // What is the current class of the item that will be moved
    var $newEl = $('.list_container .' + first);  // ID of element that will be moved

    if (a < b) { // oldPos less than newPos
        var second = classes[b - 2]; // The new class of the moved element will be one less
        var newTop = parseInt($newEl.css('top')) - c; // Top of element will move up
    } else { // oldPos more than newPos
        var second = classes[b]; // The new class of the moved element will be one more
        var newTop = parseInt($newEl.css('top')) + c; // Top of element will move down
    }

    // The following line of code is required, otherwise the following animation 
    // will animate of from top=0px to the new position (opposed to from top=currentPosition)
    // Try taking it out and seeing
    $newEl.css('top', parseInt($newEl.css('top')));
    $newEl.removeClass(first); // Remove the current numbered class of element to move
    // Move element and remove the added style tags (or future animations will get buggy)
    $newEl.animate({top: newTop}, 300, function () {
        $newEl.removeAttr('style');
    });
    $newEl.addClass(second); // Add the new numbered class

    return false; // Cleans up animations
}

The function above is what does the actual animation part and moves the list items around to accommodate the selected list item.

function setNewClass(e, a) { // e == selected element, a == newPos
    // Remove 'selected' class, then add back the 'list_item' class and the new numbered class
    e.attr('class', 'list_item').addClass(classes[a-1]);
}

** All JavaScript together: **

var classes = new Array("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeem", "eighteen", "nineteen", "twenty", "twentyone", "twentytwo", "twentythree", "twentyfour");

$(document).ready(function () {
    var margin = 2;
    var $el;
    var oldPos = 0;
    var newPos = 0;
    var dragging = false;

    var selectionHeight = $('.list_container .list_item').height() + parseInt($('.list_container .list_item').css("border-bottom-width")) + parseInt($('.list_container .list_item').css("border-top-width")) + margin;

    var classInfo = '';

    $('.list_container .list_item').each(function (index) {
        $(this).addClass(classes[index]);
        classInfo += '.' + classes[index] + ' {top: ' + index * selectionHeight + 'px;}\n';
    });

    var style = document.createElement('style');
    style.type = 'text/css';
    style.innerHTML = classInfo;
    document.getElementsByTagName('head')[0].appendChild(style);

    $('.list_item').mousedown(function (ev) {
        $el = $(this);
        oldPos = $el.index() + 1;
        newPos = oldPos;
        dragging = true;
        startY = ev.clientY;
        startT = parseInt($el.css('top'));
        $el.addClass('selected');
    });

    $(window).mousemove(function (ev) {
        if (dragging) {
            $el.attr('class', 'list_item')
            $el.addClass('selected');

            // ----- calculate new top
            var newTop = startT + (ev.clientY - startY);
            $el.css('cursor', 'pointer');
            // ------

            //------ stay in parent
            var maxTop = $el.parent().height() - $el.height();
            newTop = newTop < 0 ? 0 : newTop > maxTop ? maxTop : newTop;
            $el.css('top', newTop);
            //------

            newPos = getPos(newTop, selectionHeight);

            if (oldPos != newPos) {
                moveThings(oldPos, newPos, selectionHeight);
                oldPos = newPos;
            }
        }
    }).mouseup(function () {
        dragging = false;
        $el.removeClass('selected');
        setNewClass($el, newPos);
        $el.css('top', (newPos - 1) * selectionHeight);
    });
});

function getPos(a, b) { // a == topPos, b == selectionHeight
    return Math.round((a / b) + 1);
}

function moveThings(a, b, c) { // a == oldPos, b == newPos, c == selectedHeight
    var first = classes[b - 1];
    var $newEl = $('.list_container .' + first);

    if (a < b) { // oldPos less than newPos
        var second = classes[b - 2];
        var newTop = parseInt($newEl.css('top')) - c;
    } else { // oldPos more than newPos
        var second = classes[b];
        var newTop = parseInt($newEl.css('top')) + c;
    }

    $newEl.css('top', parseInt($newEl.css('top')));
    $newEl.removeClass(first);
    $newEl.animate({
        top: newTop
    }, 300, function () {
        $newEl.removeAttr('style');
    });
    $newEl.addClass(second);

    return false; // Cleans up animations
}

function setNewClass(e, a) { // e == selected element, a == newPos
    e.attr('class', 'list_item').addClass(classes[a - 1]);
}

这篇关于使用JavaScript通过鼠标拖动订购图形列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆