JavaScript实现拖拽排序的方法详解

目录
  • 实现原理概述
  • 代码实现
  • 完整代码实现

可拖拽排序的菜单效果大家想必都很熟悉,本次我们通过一个可拖拽排序的九宫格案例来演示其实现原理。 先看一下完成效果:

实现原理概述

拖拽原理

  • 当鼠标在【可拖拽小方块】(以下简称砖头)身上按下时,开始监听鼠标移动事件
  • 鼠标事件移动到什么位置,砖头就跟到什么位置
  • 鼠标抬起时,取消鼠标移动事件的监听

排序原理

  • 提前定义好9大坑位的位置(相对外层盒子的left和top)
  • 将9大砖头丢入一个数组,以便后期通过splice方法随意安插和更改砖头的位置
  • 当拖动某块砖头时,先将其从数组中移除(剩余的砖头在逻辑上重新排序)
  • 拖动结束时,将该砖头重新插回数组的目标位置(此时实现数据上的重排)
  • 数组中的9块砖头根据新的序号,对号入座到9大坑位,完成重新渲染

代码实现

页面布局

9块砖头(li元素)相对于外层盒子(ul元素)做绝对定位

	<ul id="box">
	    <li style="background-color:black;top: 10px; left: 10px">1</li>
	    <li style="background-color:black;top: 10px; left: 220px">2</li>
	    <li style="background-color:black;top: 10px; left: 430px">3</li>
	    <li style="background-color:black;top: 220px; left: 10px">4</li>
	    <li style="background-color:black;top: 220px; left: 220px">5</li>
	    <li style="background-color:black;top: 220px; left: 430px">6</li>
	    <li style="background-color:black;top: 430px; left: 10px">7</li>
	    <li style="background-color:black;top: 430px; left: 220px">8</li>
	    <li style="background-color:black;top: 430px; left: 430px">9</li>
	</ul>

样式如下

	    * {
	        margin: 0;
	        padding: 0;
	    }

	    html,
	    body {
	        width: 100%;
	        height: 100%;
	    }

	    ul,
	    li {
	        list-style: none;
	    }

	    ul {
	        width: 640px;
	        height: 640px;
	        border: 10px solid pink;
	        border-radius: 10px;
	        margin: 50px auto;
	        position: relative;
	    }

	    li {
	        width: 200px;
	        height: 200px;
	        border-radius: 10px;
	        display: flex;
	        justify-content: center;
	        align-items: center;
	        color: white;
	        font-size: 100px;
	        position: absolute;
	    }

定义砖头的背景色和9大坑位位置

	// 定义9大li的预设背景色
	var colorArr = [
	    "red",
	    "orange",
	    "yellow",
	    "green",
	    "blue",
	    "cyan",
	    "purple",
	    "pink",
	    "gray",
	];

	/* 定义9大坑位 */
	const positions = [
	    [10, 10], [220, 10], [430, 10],
	    [10, 220], [220, 220], [430, 220],
	    [10, 430], [220, 430], [430, 430],
	]

找出砖头并丢入一个数组

	var ulBox = document.querySelector("#box")
	var lis = document.querySelectorAll("#box>li")
	/* 将lis转化为真数组 */
	lis = toArray(lis)

这里我使用了一个将NodeList伪数组转化为真数组的轮子:

	/* 伪数组转真数组 pseudo array */
	function toArray(pArr){
	    var arr = []
	    for(var i=0;i<pArr.length;i++){
	        arr.push(pArr[i])
	    }
	    return arr
	}

给所有砖头内置一个position属性

	/* 给每块砖内置一个position属性 */
	lis.forEach(
	    (item, index) => item.setAttribute("position", index)
	)

定义正在拖动的砖头

        /* 正在拖动的Li(砖头) */
        var draggingLi = null;

        // 正在拖动的砖头的zindex不断加加,保持在最上层
        var maxZindex = 9

在身上按下 谁就是【正在拖动的砖头】

        /* 在身上按下 谁就是【正在拖动的砖头】 */
        lis.forEach(
            function (li, index) {
                li.style.backgroundColor = colorArr[index]

                /* li中的文字不可选(禁止selectstart事件的默认行为) */
                li.addEventListener(
                    "selectstart",
                    function (e) {
                        // 阻止掉拖选文本的默认行为
                        e.preventDefault()
                    }
                )

                /* 在任意li身上按下鼠标=我想拖动它 */
                li.addEventListener(
                    "mousedown",
                    function (e) {
                        draggingLi = this
                        draggingLi.style.zIndex = maxZindex++
                    }
                )
            }
        )

在任意位置松开鼠标则停止拖拽

        /* 在页面的任意位置松开鼠标=不再拖拽任何对象 */
        document.addEventListener(
            "mouseup",
            function (e) {
                // 当前砖头自己进入位置躺好
                const p = draggingLi.getAttribute("position") * 1
                // draggingLi.style.left = positions[p][0] + "px"
                // draggingLi.style.top = positions[p][1] + "px"
                move(
                    draggingLi,
                    {
                        left:positions[p][0] + "px",
                        top:positions[p][1] + "px"
                    },
                    200
                    // callback
                )

                // 正在拖拽的砖头置空
                draggingLi = null;
            }
        )

当前砖头从鼠标事件位置回归其坑位时用到动画效果,以下是动画轮子

/**
 * 多属性动画
 * @param {Element} element 要做动画的元素
 * @param {Object} targetObj 属性目标值的对象 封装了所有要做动画的属性及其目标值
 * @param {number} timeCost 动画耗时,单位毫秒
 * @param {Function} callback 动画结束的回调函数
 */
const move = (element, targetObj, timeCost = 1000, callback) => {
    const frameTimeCost = 40;

    // 500.00px 提取单位的正则
    const regUnit = /[\d\.]+([a-z]*)/;

    // 计算动画总帧数
    const totalFrames = Math.round(timeCost / frameTimeCost);

    // 动态数一数当前动画到了第几帧
    let frameCount = 0;

    /* 查询特定属性的速度(汤鹏飞的辣鸡) */
    // const getAttrSpeed = (attr) => (parseFloat(targetObj[attr]) - parseFloat(getComputedStyle(element)[attr]))/totalFrames

    // 存储各个属性的初始值和动画速度
    const ssObj = {};

    /* 遍历targetObj的所有属性 */
    for (let attr in targetObj) {
        // 拿到元素属性的初始值
        const attrStart = parseFloat(getComputedStyle(element)[attr]);

        // 动画速度 = (目标值 - 当前值)/帧数
        const attrSpeed =
            (parseFloat(targetObj[attr]) - attrStart) / totalFrames;

        // 将【属性初始值】和【属性帧速度】存在obj中 以后obj[left]同时拿到这两个货
        // obj{ left:[0px初始值,50px每帧] }
        ssObj[attr] = [attrStart, attrSpeed];
    }

    /* 开始动画 */
    const timer = setInterval(
        () => {
            // element.style.left = parseFloat(getComputedStyle(element).left)+"px"
            // element.style.top = parseFloat(getComputedStyle(element).top)+"px"
            // element.style.opacity = getComputedStyle(element).opacity

            // 帧数+1
            frameCount++;

            /* 每个属性的值都+=动画速度 */
            for (let attr in targetObj) {
                // console.log(attr, ssObj[attr], totalFrames, frameCount);

                // 用正则分离出单位
                // console.log(regUnit.exec("500px"));
                // console.log(regUnit.exec(0));
                const unit = regUnit.exec(targetObj[attr])[1];

                // 计算出当前帧应该去到的属性值
                const thisFrameValue =
                    ssObj[attr][0] + frameCount * ssObj[attr][1];

                // 将元素的属性掰到当前帧应该去到的目标值
                element.style[attr] = thisFrameValue + unit;
            }

            /* 当前帧 多个属性动画完成 判断是否应该终止动画  */
            if (frameCount >= totalFrames) {
                // console.log(frameCount, totalFrames);
                clearInterval(timer);

                /* 强制矫正(反正用户又看不出来 V) */
                // for (let attr in targetObj) {
                //     element.style[attr] = targetObj[attr];
                //     console.log(attr, getComputedStyle(element)[attr]);
                // }

                // 如果有callback就调用callback
                // if(callback){
                //     callback()
                // }
                callback && callback();
            }
        },

        frameTimeCost
    );

    /* 动画结束后再过一帧 执行暴力校正 */
    setTimeout(() => {
        /* 强制矫正(反正用户又看不出来 V) */
        for (let attr in targetObj) {
            element.style[attr] = targetObj[attr];
            // console.log(attr, getComputedStyle(element)[attr]);
        }
    }, timeCost + frameTimeCost);

    // 返回正在运行的定时器
    return timer;
};

移动鼠标时 砖头跟随 所有砖头实时洗牌

        /* 在ul内移动鼠标 draggingLi跟随鼠标 */
        ulBox.addEventListener(
            "mousemove",
            function (e) {
                /* 如果draggingLi为空 什么也不做 直接返回 */
                if (draggingLi === null) {
                    return
                }

                // 拿到事件相对于ulBox的位置
                var offsetX = e.pageX - ulBox.offsetLeft - 100
                var offsetY = e.pageY - ulBox.offsetTop - 100

                /* 校正砖头的偏移量 */
                offsetX = offsetX < 10 ? 10 : offsetX
                offsetY = offsetY < 10 ? 10 : offsetY
                offsetX = offsetX > 430 ? 430 : offsetX
                offsetY = offsetY > 430 ? 430 : offsetY

                // 将该位置设置给draggingLi
                draggingLi.style.left = offsetX + "px"
                draggingLi.style.top = offsetY + "px"

                /* 实时检测实时【坑位】 */
                const newPosition = checkPosition([offsetX, offsetY]);

                // 如果当前砖头的position发生变化 则数据重排
                const oldPosition = draggingLi.getAttribute("position") * 1
                if (newPosition != -1 && newPosition != oldPosition) {
                    console.log(oldPosition, newPosition);

                    /* 数据重排 */
                    // 先将当前砖头拽出数组(剩余的砖头位置自动重排)
                    lis.splice(oldPosition, 1)
                    // 再将当前砖头插回newPosition
                    lis.splice(newPosition, 0, draggingLi)

                    // 打印新数据
                    // logArr(lis,"innerText")

                    // 砖头洗牌
                    shuffle()
                }

            }
        )

坑位检测方法

        /* 实时检测坑位:检测ep与9大坑位的距离是否小于100 */
        const checkPosition = (ep) => {
            for (let i = 0; i < positions.length; i++) {
                const [x, y] = positions[i]//[10,10]
                const [ex, ey] = ep//[offsetX,offsetY]

                const distance = Math.sqrt(Math.pow(x - ex, 2) + Math.pow(y - ey, 2))
                if (distance < 100) {
                    return i
                }
            }

            // 没有进入任何坑位
            return -1
        }

砖头洗牌方法

        /* 砖头洗牌:lis中的每块砖去到对应的位置 */
        const shuffle = () => {
            for (var i = 0; i < lis.length; i++) {
                lis[i].style.left = positions[i][0] + "px"
                lis[i].style.top = positions[i][1] + "px"

                // 更新自己的位置
                lis[i].setAttribute("position", i)
            }
        }

完整代码实现

主程序

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>九宫格拖拽排序</title>

    <style>
        * {
            margin: 0;
            padding: 0;
        }

        html,
        body {
            width: 100%;
            height: 100%;
        }

        ul,
        li {
            list-style: none;
        }

        ul {
            width: 640px;
            height: 640px;
            border: 10px solid pink;
            border-radius: 10px;
            margin: 50px auto;
            position: relative;
        }

        li {
            width: 200px;
            height: 200px;
            border-radius: 10px;
            display: flex;
            justify-content: center;
            align-items: center;
            color: white;
            font-size: 100px;
            position: absolute;
        }
    </style>
</head>

<body>
    <ul id="box">
        <li style="background-color:black;top: 10px; left: 10px">1</li>
        <li style="background-color:black;top: 10px; left: 220px">2</li>
        <li style="background-color:black;top: 10px; left: 430px">3</li>
        <li style="background-color:black;top: 220px; left: 10px">4</li>
        <li style="background-color:black;top: 220px; left: 220px">5</li>
        <li style="background-color:black;top: 220px; left: 430px">6</li>
        <li style="background-color:black;top: 430px; left: 10px">7</li>
        <li style="background-color:black;top: 430px; left: 220px">8</li>
        <li style="background-color:black;top: 430px; left: 430px">9</li>
    </ul>

    <!--
    position 位置
     -->
    <script src="../../../tools/arr_obj_tool.js"></script>
    <script src="../../../tools/animtool.js"></script>

    <script>
        // 定义9大li的预设背景色
        var colorArr = [
            "red",
            "orange",
            "yellow",
            "green",
            "blue",
            "cyan",
            "purple",
            "pink",
            "gray",
        ];

        /* 定义9大坑位 */
        const positions = [
            [10, 10], [220, 10], [430, 10],
            [10, 220], [220, 220], [430, 220],
            [10, 430], [220, 430], [430, 430],
        ]

        var ulBox = document.querySelector("#box")
        var lis = document.querySelectorAll("#box>li")
        /* 将lis转化为真数组 */
        lis = toArray(lis)

        /* 给每块砖内置一个position属性 */
        lis.forEach(
            (item, index) => item.setAttribute("position", index)
        )

        /* 正在拖动的Li(砖头) */
        var draggingLi = null;

        // 正在拖动的砖头的zindex不断加加,保持在最上层
        var maxZindex = 9

        /* 在身上按下 谁就是【正在拖动的砖头】 */
        lis.forEach(
            function (li, index) {
                li.style.backgroundColor = colorArr[index]

                /* li中的文字不可选(禁止selectstart事件的默认行为) */
                li.addEventListener(
                    "selectstart",
                    function (e) {
                        // 阻止掉拖选文本的默认行为
                        e.preventDefault()
                    }
                )

                /* 在任意li身上按下鼠标=我想拖动它 */
                li.addEventListener(
                    "mousedown",
                    function (e) {
                        draggingLi = this
                        draggingLi.style.zIndex = maxZindex++
                    }
                )
            }
        )

        /* 在页面的任意位置松开鼠标=不再拖拽任何对象 */
        document.addEventListener(
            "mouseup",
            function (e) {
                // 当前砖头自己进入位置躺好
                const p = draggingLi.getAttribute("position") * 1
                // draggingLi.style.left = positions[p][0] + "px"
                // draggingLi.style.top = positions[p][1] + "px"
                move(
                    draggingLi,
                    {
                        left: positions[p][0] + "px",
                        top: positions[p][1] + "px"
                    },
                    200
                    // callback
                )

                // 正在拖拽的砖头置空
                draggingLi = null;
            }
        )

        /* 在ul内移动鼠标 draggingLi跟随鼠标 */
        ulBox.addEventListener(
            "mousemove",
            function (e) {
                /* 如果draggingLi为空 什么也不做 直接返回 */
                if (draggingLi === null) {
                    return
                }

                // 拿到事件相对于ulBox的位置
                var offsetX = e.pageX - ulBox.offsetLeft - 100
                var offsetY = e.pageY - ulBox.offsetTop - 100

                /* 校正砖头的偏移量 */
                offsetX = offsetX < 10 ? 10 : offsetX
                offsetY = offsetY < 10 ? 10 : offsetY
                offsetX = offsetX > 430 ? 430 : offsetX
                offsetY = offsetY > 430 ? 430 : offsetY

                // 将该位置设置给draggingLi
                draggingLi.style.left = offsetX + "px"
                draggingLi.style.top = offsetY + "px"

                /* 实时检测实时【坑位】 */
                const newPosition = checkPosition([offsetX, offsetY]);

                // 如果当前砖头的position发生变化 则数据重排
                const oldPosition = draggingLi.getAttribute("position") * 1
                if (newPosition != -1 && newPosition != oldPosition) {
                    console.log(oldPosition, newPosition);

                    /* 数据重排 */
                    // 先将当前砖头拽出数组(剩余的砖头位置自动重排)
                    lis.splice(oldPosition, 1)
                    // 再将当前砖头插回newPosition
                    lis.splice(newPosition, 0, draggingLi)

                    // 打印新数据
                    // logArr(lis,"innerText")

                    // 砖头洗牌
                    shuffle()
                }

            }
        )

        /* 实时检测坑位:检测ep与9大坑位的距离是否小于100 */
        const checkPosition = (ep) => {
            for (let i = 0; i < positions.length; i++) {
                const [x, y] = positions[i]//[10,10]
                const [ex, ey] = ep//[offsetX,offsetY]

                const distance = Math.sqrt(Math.pow(x - ex, 2) + Math.pow(y - ey, 2))
                if (distance < 100) {
                    return i
                }
            }

            // 没有进入任何坑位
            return -1
        }

        /* 砖头洗牌:lis中的每块砖去到对应的位置 */
        const shuffle = () => {
            for (var i = 0; i < lis.length; i++) {
                lis[i].style.left = positions[i][0] + "px"
                lis[i].style.top = positions[i][1] + "px"

                // 更新自己的位置
                lis[i].setAttribute("position", i)
            }
        }

    </script>
</body>

</html>

动画轮子

function moveWithTransition(element, targetObj, duration) {
    element.style.transition = `all ${duration / 1000 + "s"} linear`;
    for (var attr in targetObj) {
        element.style[attr] = targetObj[attr];
    }
    setTimeout(() => {
        element.style.transition = "none";
    }, duration);
}

/**
 * 多属性动画
 * @param {Element} element 要做动画的元素
 * @param {Object} targetObj 属性目标值的对象 封装了所有要做动画的属性及其目标值
 * @param {number} timeCost 动画耗时,单位毫秒
 * @param {Function} callback 动画结束的回调函数
 */
const move = (element, targetObj, timeCost = 1000, callback) => {
    const frameTimeCost = 40;

    // 500.00px 提取单位的正则
    const regUnit = /[\d\.]+([a-z]*)/;

    // 计算动画总帧数
    const totalFrames = Math.round(timeCost / frameTimeCost);

    // 动态数一数当前动画到了第几帧
    let frameCount = 0;

    /* 查询特定属性的速度(汤鹏飞的辣鸡) */
    // const getAttrSpeed = (attr) => (parseFloat(targetObj[attr]) - parseFloat(getComputedStyle(element)[attr]))/totalFrames

    // 存储各个属性的初始值和动画速度
    const ssObj = {};

    /* 遍历targetObj的所有属性 */
    for (let attr in targetObj) {
        // 拿到元素属性的初始值
        const attrStart = parseFloat(getComputedStyle(element)[attr]);

        // 动画速度 = (目标值 - 当前值)/帧数
        const attrSpeed =
            (parseFloat(targetObj[attr]) - attrStart) / totalFrames;

        // 将【属性初始值】和【属性帧速度】存在obj中 以后obj[left]同时拿到这两个货
        // obj{ left:[0px初始值,50px每帧] }
        ssObj[attr] = [attrStart, attrSpeed];
    }

    /* 开始动画 */
    const timer = setInterval(
        () => {
            // element.style.left = parseFloat(getComputedStyle(element).left)+"px"
            // element.style.top = parseFloat(getComputedStyle(element).top)+"px"
            // element.style.opacity = getComputedStyle(element).opacity

            // 帧数+1
            frameCount++;

            /* 每个属性的值都+=动画速度 */
            for (let attr in targetObj) {
                // console.log(attr, ssObj[attr], totalFrames, frameCount);

                // 用正则分离出单位
                // console.log(regUnit.exec("500px"));
                // console.log(regUnit.exec(0));
                const unit = regUnit.exec(targetObj[attr])[1];

                // 计算出当前帧应该去到的属性值
                const thisFrameValue =
                    ssObj[attr][0] + frameCount * ssObj[attr][1];

                // 将元素的属性掰到当前帧应该去到的目标值
                element.style[attr] = thisFrameValue + unit;
            }

            /* 当前帧 多个属性动画完成 判断是否应该终止动画  */
            if (frameCount >= totalFrames) {
                // console.log(frameCount, totalFrames);
                clearInterval(timer);

                /* 强制矫正(反正用户又看不出来 V) */
                // for (let attr in targetObj) {
                //     element.style[attr] = targetObj[attr];
                //     console.log(attr, getComputedStyle(element)[attr]);
                // }

                // 如果有callback就调用callback
                // if(callback){
                //     callback()
                // }
                callback && callback();
            }
        },

        frameTimeCost
    );

    /* 动画结束后再过一帧 执行暴力校正 */
    setTimeout(() => {
        /* 强制矫正(反正用户又看不出来 V) */
        for (let attr in targetObj) {
            element.style[attr] = targetObj[attr];
            // console.log(attr, getComputedStyle(element)[attr]);
        }
    }, timeCost + frameTimeCost);

    // 返回正在运行的定时器
    return timer;
};

伪数组转真数组轮子

/* 伪数组转真数组 pseudo array */
function toArray(pArr){
    var arr = []
    for(var i=0;i<pArr.length;i++){
        arr.push(pArr[i])
    }
    return arr
}

这里大家也可以简单地

const arr = [...pArr]

以上就是JavaScript实现拖拽排序的方法详解的详细内容,更多关于JavaScript拖拽排序的资料请关注我们其它相关文章!

(0)

相关推荐

  • javascript实现表格排序 编辑 拖拽 缩放

    简单表格排序 可以双击编辑 自定义编辑后的 规则 可拖动列进行列替换 可推动边框进行列宽度的缩放 复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xht

  • JS实现简易的图片拖拽排序实例代码

    由HTML5的拖放API,实现的简易图片拖放效果. 一.HTML5拖放API的知识点 首先我们得知道元素怎么才可以被拖放,需要设置它们的draggable属性,其中img和a标签的dragable属性默认是true,不需要我们手动设置. 拖放API的监听事件如下: dragstart: 源对象拖拽开始: drag: 源对象拖拽的过程中: dragend: 源对象拖拽结束: dragenter: 进入过程对象区域; dragover: 在过程对象区域内移动: dragleave: 离开过程对象区域

  • js 实现拖拽排序详情

    目录 1.前言 2.实现 3.为何不使用HTML拖放API实现? 4.总结 1.前言 拖拽排序对于小伙伴们来说应该不陌生,平时工作的时候,可能会选择使用类似Sortable.js这样的开源库来实现需求.但在完成需求后,大家有没有没想过拖拽排序是如何实现的呢?我花了点时间研究了一下,今天分享给大家. 2.实现 { margin: 0; padding: 0; box-sizing: border-box; } .grid { display: flex; flex-wrap: wrap; marg

  • js 表格排序(编辑+拖拽+缩放)

    Table body{ font-size:12px} #tab{ border-collapse: collapse;} .edit{ height:16px; width:98%; background-color:#EFF7FF; font-size:12px; border:0px;} #tab thead td{ background:url(/upload/201005/20100531233452190.bmp);color:#183C94} #tab tbody td{ over

  • 基于js实现的图片拖拽排序源码实例

    效果图: 直接上代码 <script> window.onload = function() { var oUl = document.getElementById("ul1"); var aLi = oUl.getElementsByTagName("li"); var disX = 0; var disY = 0; var minZindex = 1; var aPos = []; for (var i = 0; i < aLi.length;

  • JS+CSS制作DIV层可(最小化/拖拽/排序)功能实现代码

    复制代码 代码如下: <HTML> <HEAD> <TITLE>JS+CSS制作的DIV层最小化和随意拖拽排序功能</TITLE> <style type="text/css"> body { margin:10px; } #dragHelper { position:absolute;/*重要*/ border:2px dashed #000000; background-color:#FFFFFF; filter: alp

  • JavaScript实现拖拽排序的方法详解

    目录 实现原理概述 代码实现 完整代码实现 可拖拽排序的菜单效果大家想必都很熟悉,本次我们通过一个可拖拽排序的九宫格案例来演示其实现原理. 先看一下完成效果: 实现原理概述 拖拽原理 当鼠标在[可拖拽小方块](以下简称砖头)身上按下时,开始监听鼠标移动事件 鼠标事件移动到什么位置,砖头就跟到什么位置 鼠标抬起时,取消鼠标移动事件的监听 排序原理 提前定义好9大坑位的位置(相对外层盒子的left和top) 将9大砖头丢入一个数组,以便后期通过splice方法随意安插和更改砖头的位置 当拖动某块砖头

  • vue拖拽组件使用方法详解

    前言 pc端开发需要拖拽组件完成列表的顺序交换,一般移动端的UI组件会包含,但是我在用的iview并没有此功能的组件,于是手写一个,实现起来很简单.效果图如下: 可以拖拽完成新排序,点击某一项可以触发相关事件. 关于拖拽 drag & drop 拖放(Drag 和 drop)是 HTML5 标准的组成部分. 拖拽对象 dataTransfer对象,只能在拖放事件的事件处理程序中访问.重要属性: effectAllowed ( none | copy | copyLink | copyMove |

  • Javascript实现拖拽排序的代码

    运行环境:vue3.2以上,复制张贴运行即可看效果效果如下: <template> <div class="container"> <transition-group name="flip-list"> <div v-for="item in items" :key="item" draggable="true" class="items" @d

  • JavaScript 中有关数组对象的方法(详解)

    JS 处理数组多种方法 js 中的数据类型分为两大类:原始类型和对象类型. 原始类型包括:数值.字符串.布尔值.null.undefined 对象类型包括:对象即是属性的集合,当然这里又两个特殊的对象----函数(js中的一等对象).数组(键值的有序集合). 数组元素的添加 arrayObj.push([item1 [item2 [. . . [itemN ]]]]); 将一个或多个新元素添加到数组结尾,并返回数组新长度 arrayObj.unshift([item1 [item2 [. . .

  • 原生js实现拖拽功能基本思路详解

    如果要设置物体拖拽,那么必须使用三个事件,并且这三个事件的使用顺序不能颠倒. 1.onmousedown:鼠标按下事件 2.onmousemove:鼠标移动事件 3.onmouseup:鼠标抬起事件 拖拽的基本原理就是根据鼠标的移动来移动被拖拽的元素.鼠标的移动也就是x.y坐标的变化;元素的移动就是style.position的 top和left的改变.当然,并不是任何时候移动鼠标都要造成元素的移动,而应该判断鼠标左键的状态是否为按下状态,是否是在可拖拽的元素上按下的. 基本思路如下: 拖拽状态

  • JavaScript中数组随机排序的实现详解

    目录 一.原地算法 二.Array.property.sort() 1.方法一(不推荐) 2.方法一改良 三.洗牌算法实现随机排序 1.换牌 2.抽牌 一.原地算法 在谈sort之前,我们先了解一下原地算法,什么事原地算法呢?所谓原地算法就是说基于原有的数据结构进行一定的操作修改,而不借助额外的空间.使用原地算法时,其内存干净,空间复杂度是O(1),可以减少没必要的内存,避免造成内存浪费和冗余.当然,减小内存损耗会带来算法复杂度和时间消耗的增加,所以是一个Tradeoff.Tradeoff 是一

  • Javascript中的迭代、归并方法详解

    迭代方法 在Javascript中迭代方法个人觉得尤为重要,在很多时候都会有实际上的需求,javascript提供了5个迭代方法来供我们操作,它们分别为: every() 对数组中的每一个项运用给定的函数,如果每项都返回true,那么就会返回true filter() 对数组中的每一个项运用给定的函数,把返回true的项组成一个新数组并返回 forEach() 对数组中的每一项运用给定的函数,但是没有任何的返回值 map() 对数组中的每一个项运用给定的函数并返回每次函数调用的结果组成新的数组

  • JavaScript中Number对象的toFixed() 方法详解

    定义和用法 toFixed() 方法可把 Number 四舍五入为指定小数位数的数字. 语法 NumberObject.toFixed(num) 参数 描述 num 必需.规定小数的位数,是 0 ~ 20 之间的值,包括 0 和 20,有些实现可以支持更大的数值范围.如果省略了该参数,将用 0 代替. 返回值 返回 NumberObject 的字符串表示,不采用指数计数法,小数点后有固定的 num 位数字.如果必要,该数字会被舍入,也可以用 0 补足,以便它达到指定的长度.如果 num 大于 l

  • JavaScript中关键字 in 的使用方法详解

    for-in循环应该用在非数组对象的遍历上,使用for-in进行循环也被称为"枚举". 对于数组 ,迭代出来的是数组元素 但不推荐,因为不能保证顺序,而且如果在Array的原型上添加了属性,这个属性也会被遍历出来,所以 最好数组使用正常的for循环,对象使用for-in循环 对于对象 ,迭代出来的是对象的属性: var obj = { "key1":"value1", "key2":"value2", &q

  • 微信小程序移动拖拽视图-movable-view实例详解

    JS中的sender参数(sender是事件的传值)前提是只有一个touch移动的时候.多个touch需要在 changedTouches 数组中查找 redclcik:function(sender){ wx.showModal({ title: '点击红色', content: '', }) console.log(sender); }, redmove:function(sender){ console.log(sender); // console.log(sender.changedT

随机推荐