九宫格, 里面有九张图片, 用鼠标拖动其中 1 张图片置于另 1 张图片之上时并松开鼠标后, 它俩的位置交换.
html 代码
- <!doctype html>
- <html>
- <head>
- <meta charset="utf-8">
- <title > 九宫格 -- 位置交换 </title>
- <style type="text/css">
- * {
- padding: 0;
- margin: 0;
- list-style: none;
- }
- ul {
- width: 480px;
- height: 480px;
- padding: 5px;
- background: #CFC;
- position: relative;
- margin: 100px auto;
- }
- li {
- width: 150px;
- height: 150px;
- margin: 5px;
- cursor: move;
- -webkit-user-select: none;
- background: #FF9;
- overflow: hidden;
- float: left;
- }
- img {
- width: 100%;
- height: 100%;
- border: none;
- }
- </style>
- </head>
- <body>
- <ul>
- <li><img src="http://www.qdfuns.com/misc.php?mod=attach&genre=editor&aid=46ac759c68ba5e51fc613502729240cf"></li>
- <li><img src="http://www.qdfuns.com/misc.php?mod=attach&genre=editor&aid=46ac759c68ba5e51fc613502729240cf"></li>
- <li><img src="http://www.qdfuns.com/misc.php?mod=attach&genre=editor&aid=46ac759c68ba5e51fc613502729240cf"></li>
- <li><img src="http://www.qdfuns.com/misc.php?mod=attach&genre=editor&aid=46ac759c68ba5e51fc613502729240cf"></li>
- <li><img src="http://www.qdfuns.com/misc.php?mod=attach&genre=editor&aid=46ac759c68ba5e51fc613502729240cf"></li>
- <li><img src="http://www.qdfuns.com/misc.php?mod=attach&genre=editor&aid=46ac759c68ba5e51fc613502729240cf"></li>
- <li><img src="http://www.qdfuns.com/misc.php?mod=attach&genre=editor&aid=46ac759c68ba5e51fc613502729240cf"></li>
- <li><img src="http://www.qdfuns.com/misc.php?mod=attach&genre=editor&aid=46ac759c68ba5e51fc613502729240cf"></li>
- <li><img src="http://www.qdfuns.com/misc.php?mod=attach&genre=editor&aid=46ac759c68ba5e51fc613502729240cf"></li>
- </ul>
- </body>
- </html>
- <script>
- /* 第一步: 准备方法 */
- function on(ele, type, fn) {
- if (ele.addEventListener) {
- ele.addEventListener(type, fn, false);
- } else {
- if (!ele["onEvent" + type]) {
- ele["onEvent" + type] = [];
- ele.attachEvent("on" + type, function () {
- run.call(ele)
- });
- }
- var a = ele["onEvent" + type];
- for (var i = 0; i <a.length; i++) {
- if (a[i] == fn)return;
- }
- a.push(fn);
- }
- }
- function run() {
- var e = window.event;
- var type = e.type;
- e.target = e.srcElement;
- e.pageX = (document.documentElement.scrollLeft || document.body.scrollLeft) + e.clientX;
- e.pageY = (document.documentElement.scrollTop || document.body.scrollTop) + e.clientY;
- e.preventDefault = function () {
- e.returnValue = false;
- };
- e.stopPropagation = function () {
- e.cancelBubble = true;
- };
- var a = this["onEvent" + type];
- if (a && a.length) {
- for (var i = 0; i < a.length; i++) {
- if (typeof a[i] == "function") {
- a[i].call(this, e);
- } else {
- a.splice(i, 1);
- i--;
- }
- }
- }
- }
- function off(ele, type, fn) {
- if (ele.removeEventListener) {
- ele.removeEventListener(type, fn, false);
- } else {
- var a = ele["onEvent" + type];
- if (a && a.length) {
- for (var i = 0; i < a.length; i++) {
- if (a[i] == fn) {
- a[i] = null;
- return;
- }
- }
- }
- }
- }
- function processThis(fn, context) {
- return function (e) {
- fn.call(context, e);
- };
- }
- function EventEmitter() {
- }
- EventEmitter.prototype.on = function (type, fn) {
- if (!this["emitter" + type]) {
- this["emitter" + type] = [];
- }
- var a = this["emitter" + type];
- for (var i = 0; i < a.length; i++) {
- if (a[i] == fn)return this;
- }
- a.push(fn);
- return this;
- };
- EventEmitter.prototype.run = function (type, e) {
- var a = this["emitter" + type];
- if (a && a.length) {
- for (var i = 0; i < a.length; i++) {
- if (typeof a[i] == "function") {
- a[i].call(this, e);
- } else {
- a.splice(i, 1);
- i--;
- }
- }
- }
- };
- EventEmitter.prototype.off = function (type, fn) {
- var a = this["emitter" + type];
- if (a && a.length) {
- for (var i = 0; i < a.length; i++) {
- if (a[i] == fn) {
- a[i] = null;
- break;
- }
- }
- }
- return this;
- };
- function Drag(ele) {
- this.x = null;
- this.y = null;
- this.mx = null;
- this.my = null;
- this.ele = ele;
- this.obj = ele;
- this.DOWN = processThis(this.down, this);
- this.MOVE = processThis(this.move, this);
- this.UP = processThis(this.up, this);
- on(this.ele, "mousedown", this.DOWN);// 对于这个 on 来说, 我们只是使用者
- //this.on; 对于这个 on 来说, 我们是开发者,
- }
- Drag.prototype.__proto__ = EventEmitter.prototype;
- // 这是更安全的继承方法, 一般在 Node 里都是采用这种方式实现继承. IE 不支持
- Drag.prototype = new EventEmitter;// 相对这种方式来说, 上边的写法更安全
- Drag.prototype.down = function (e) {
- this.x = this.ele.offsetLeft;
- this.y = this.ele.offsetTop;
- this.mx = e.pageX;
- this.my = e.pageY;
- if (this.ele.setCapture) {
- this.ele.setCapture();
- on(this.ele, "mousemove", this.MOVE);
- on(this.ele, "mouseup", this.UP);
- } else {
- on(document, "mousemove", this.MOVE);
- on(document, "mouseup", this.UP);
- }
- e.preventDefault();
- this.run("abcde1", e);
- };
- Drag.prototype.move = function (e) {
- this.ele.style.left = this.x + (e.pageX - this.mx) + "px";
- this.ele.style.top = this.y + (e.pageY - this.my) + "px";
- this.run("abcde2", e);
- };
- Drag.prototype.up = function (e) {
- if (this.ele.releaseCapture) {
- this.ele.releaseCapture();
- off(this.ele, "mousemove", this.MOVE);
- off(this.ele, "mouseup", this.UP);
- } else {
- off(document, "mousemove", this.MOVE);
- off(document, "mouseup", this.UP);
- }
- this.run("abcde3", e);
- };
- var oRange = {l: 0, r: 600, t: 0, b: 300};
- // 相当于重新写了一个计算元素拖拽位置的方法, 用这个方法, 把原来的 Drag.prototype.move 覆盖掉
- Drag.prototype.addRange = function (obj) {
- this.oRange = obj;
- this.on("abcde2", this.range);
- };
- Drag.prototype.range = function range(e) {
- var oRange = this.oRange;
- var l = oRange.l, r = oRange.r, t = oRange.t, b = oRange.b;
- var currentL = this.x + (e.pageX - this.mx);
- var currentT = this.y + (e.pageY - this.my);
- if (currentL>= r) {
- this.ele.style.left = r + "px";
- } else if (currentL <= l) {
- this.ele.style.left = l + "px";
- } else {
- this.ele.style.left = currentL + "px";
- }
- if (currentT>= b) {
- this.ele.style.top = b + "px";
- } else if (currentT <= t) {
- this.ele.style.top = t + "px";
- } else {
- this.ele.style.top = currentT + "px";
- }
- };
- Drag.prototype.border = function (width, color, style) {
- // 允许不传参数, 如果参数没有传, 则这里给它指定默认的值
- if (!width)width = "2";
- if (!color)color = "#666";
- if (!style)style = "dashed";
- this.borderStyle = {width: width, color: color, style: style};
- this.on("abcde1", this.addBorder);
- this.on("abcde3", this.removeBorder);
- };
- Drag.prototype.addBorder = function () {
- var bs = this.borderStyle;
- this.ele.style.border = bs.width + "px" + bs.color + " " + bs.style;
- };
- Drag.prototype.removeBorder = function () {
- this.ele.style.border = "none";
- };
- function Linear(t, b, c, d) {
- return c * t / d + b;
- }
- function animate(ele, obj, duration, effect, callback) {
- var oBegin = {};// 用来保存多个方向 begin;
- var oChange = {};// 用来保存多个方向的 change;
- var flag = 0;// 用来记录各个方向的距离是否有效
- for (var attr in obj) {
- var target = obj[attr]
- var begin = animate.getCss(ele, attr);
- var change = target - begin;
- if (change) {// 判断一下此方向的运动距离有效, 不为 0
- oBegin[attr] = begin;
- oChange[attr] = change;
- flag++;
- }
- }
- if (!flag)return;// 如果各个方向的运动距离都是 0, 则结束动画的执行
- var interval = 15;
- var times = 0;
- clearInterval(ele.timer);
- function step() {
- times += interval;
- if (times <duration) {
- for (var attr in oChange) {
- var change = oChange[attr];
- var begin = oBegin[attr];
- //var val=times/duration*change+begin;
- var val = Linear(times, begin, change, duration);
- animate.setCss(ele, attr, val);
- }
- } else {
- for (var attr in oChange) {
- var target = obj[attr];
- animate.setCss(ele, attr, target);
- }
- clearInterval(ele.timer);
- ele.timer = null;
- if (typeof callback == "function") {
- callback.call(ele);
- }
- }
- }
- ele.timer = setInterval(step, interval);
- }
- animate.getCss = function (ele, attr) {
- if (window.getComputedStyle) {
- return parseFloat(window.getComputedStyle(ele, null)[attr]);
- } else {
- if (attr == "opacity") {
- var val = ele.currentStyle.filter;
- //"alpha(opacity=50)";// 匹配到这样的一个字符串, 然后把这个字符串中的数字部分拿到
- var reg = /alpha\(opacity=(\d+(?:\.\d+)?)\)/;
- if (reg.test(val)) {
- return RegExp.$1 / 100;
- } else {
- // 如果没有给 IE 中的不透明度赋值, 则上边的正则为 false
- return 1;// 如果没有给不透明度赋值, 则应该把默认值 1 返回
- }
- // 方法没有返回值, 则此方法执行结束后留下一个 undefined. 即: 没有返回值的方法返回的是 undefined
- } else {
- return parseFloat(ele.currentStyle[attr]);
- }
- }
- };
- animate.setCss = function (ele, attr, val) {
- if (attr == "opacity") {
- ele.style.opacity = val;
- ele.style.filter = "alpha(opacity=" + val * 100 + ")";
- } else {
- ele.style[attr] = val + "px";
- }
- };
- /* 第二步: 碰撞检测 */
- var oLis = document.getElementsByTagName("li");
- // 如下代码, 循环倒着做就可以, 这是为什么呢? 一定要搞清楚
- for (var i = oLis.length - 1; i>= 0; i--) {
- var oLi = oLis.item(i);
- oLi.style.left = (oLi.l = oLi.offsetLeft) + "px";
- oLi.style.top = (oLi.t = oLi.offsetTop) + "px";
- oLi.style.position = "absolute";
- oLi.style.margin = 0;
- new Drag(oLi).on("abcde1", increaseIndex).on("abcde3", changePosition).on("abcde2", test);
- }
- var index = 0;
- function increaseIndex() {
- this.ele.style.zIndex = ++index;
- }
- function goHome() {
- animate(this.ele, {left: this.ele.l, top: this.ele.t}, 700);
- }
- // 如果两个元素撞上了, 则返回 true; 没有撞上, 则返回 false
- function isHited(b, r) {
- if (b.offsetLeft + b.offsetWidth <r.offsetLeft || b.offsetTop
- + b.offsetHeight < r.offsetTop || b.offsetLeft> r.offsetLeft
- + r.offsetWidth || b.offsetTop> r.offsetTop + r.offsetHeight)
- {
- return false;
- } else {
- return true;
- }
- }
- function test() {
- this.aHited = [];
- for (var i = 0; i <oLis.length; i++) {
- var oLi = oLis.item(i);
- if (oLi == this.ele)continue;
- if (isHited(this.ele, oLi)) {
- this.aHited.push(oLi);
- oLi.style.backgroundColor = "red";
- } else {
- oLi.style.backgroundColor = "";
- }
- }
- }
- function changePosition() {
- var a = this.aHited;
- if (a && a.length) {
- for (var i = 0; i < a.length; i++) {
- var oLi = a[i];
- // 计算被拖拽的元素和撞上的元素之间的距离, 并且把距离保存到 distance 属性上
- oLi.distance = Math.sqrt(Math.pow(this.ele.offsetLeft - oLi.offsetLeft, 2)
- + Math.pow(this.ele.offsetTop - oLi.offsetTop, 2));
- oLi.style.backgroundColor = "";
- }
- // 排序, 找出和被拖拽元素最短的那个元素
- a.sort(function (a, b) {
- return a.distance - b.distance
- });
- var shortest = a[0];
- shortest.style.backgroundColor = "orange";
- this.ele.style.backgroundColor = "orange";
- // 交换位置
- animate(shortest, {left: this.ele.l, top: this.ele.t}, 700);
- animate(this.ele, {left: shortest.l, top: shortest.t}, 700);
- var l = this.ele.l, t = this.ele.t;
- this.ele.l = shortest.l;
- this.ele.t = shortest.t;
- shortest.l = l;
- shortest.t = t;
- } else {// 如果没有撞上的元素, 则返回原始位置
- animate(this.ele, {left: this.ele.l, top: this.ele.t}, 700);
- }
- }
- </script>
来源: http://www.qdfuns.com/article/40901/97c8d0a2de3da29e7be49f6b138763cb.html