以下是 无jQuery实现拖拽排序Sortable js代码 的示例演示效果:
部分效果截图1:
部分效果截图2:
HTML代码(index.html):
<!DOCTYPE html>
<html>
<head>
<meta charset="gb2312"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<title>��jQueryʵ����ק����Sortable</title>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="stylesheet" href="css/zzsc.css">
<!--<link href='http://fonts.googleapis.com/css?family=Roboto:300' rel='stylesheet' type='text/css'/>-->
<style>
</style>
</head>
<body>
<div class="container">
<div style="padding: 80px 150px 0; height: 160px;">
<a class="logo" href="#"><img src="images/logo.png"/></a>
<h1 data-force="40" data-force-y="2.5">The JavaScript library for modern browsers and touch devices. No jQuery.</h1>
</div>
</div>
<div class="container" style="height: 520px">
<div data-force="30" class="layer block" style="left: 14.5%; top: 0; width: 37%">
<div class="layer title">List A</div>
<ul id="foo" class="block__list block__list_words">
<li>�ҧ֧ԧ֧ާ��</li>
<li>�ܧ���</li>
<li>�ѧߧ���</li>
<li>��ѧݧ�</li>
<li>�ا֧ݧ֧٧���ѧݧ�</li>
<li>�ӧѧݧڧ�</li>
<li>�ܧ��ӧѧ��</li>
<li>�ܧ�ѧ�</li>
</ul>
</div>
<div data-force="18" class="layer block" style="left: 58%; top: 143px; width: 40%;">
<div class="layer title">List B</div>
<ul id="bar" class="block__list block__list_tags">
<li>�ܧѧ٧ߧڧ��</li>
<li>,</li>
<li>�ߧ֧ݧ�٧�</li>
<li>���ާڧݧ�ӧѧ��</li>
</ul>
</div>
</div>
<div class="container">
<div id="multi" style="margin-left: 30px">
<div><div data-force="5" class="layer title title_xl">Multi</div></div>
<div class="layer tile" data-force="30">
<div class="tile__name">Group A</div>
<div class="tile__list">
<img src="images/59436_1391411357920_1388516_s.jpg"/><!--
--><img src="images/941190_10151608397684663_1532692251_s.jpg"/><!--
--><img src="images/382696_10150378364701671_1792621129_a.jpg"/><!--
--><img src="images/552948_430685950285752_1435082176_a.jpg"/>
</div>
</div>
<div class="layer tile" data-force="25">
<div class="tile__name">Group B</div>
<div class="tile__list">
<img src="images/558916_4874661741992_448469446_s.jpg"/><!--
--><img src="images/68347_385372304875713_1358705380_a.jpg"/><!--
--><img src="images/424349_465457316812937_2106915541_s.jpg"/>
</div>
</div>
<div class="layer tile" data-force="20">
<div class="tile__name">Group C</div>
<div class="tile__list">
<img src="images/303317_320632284665935_15996162_a.jpg"/><!--
--><img src="images/484507_4207733265938_1693034881_s.jpg"/>
</div>
</div>
</div>
</div>
<div class="container" style="margin-top: 100px">
<p> </p>
<p> </p>
<p> </p>
</div>
<script src="js/Sortable.js"></script>
<script>
(function (){
var console = window.console;
if( !console.log ){
console.log = function (){
alert([].join.apply(arguments, ' '));
};
}
new Sortable(foo, {
group: "words",
onAdd: function (evt){ console.log('onAdd.foo:', evt.detail); },
onUpdate: function (evt){ console.log('onUpdate.foo:', evt.detail); },
onRemove: function (evt){ console.log('onRemove.foo:', evt.detail); }
});
new Sortable(bar, {
group: "words",
onAdd: function (evt){ console.log('onAdd.bar:', evt.detail); },
onUpdate: function (evt){ console.log('onUpdate.bar:', evt.detail); },
onRemove: function (evt){ console.log('onRemove.bar:', evt.detail); }
});
new Sortable(multi, {
draggable: '.tile',
handle: '.tile__name'
});
[].forEach.call(multi.getElementsByClassName('tile__list'), function (el){
new Sortable(el, { group: 'photo' });
});
})();
// Background
document.addEventListener( "DOMContentLoaded", function (){
function setNoiseBackground(el, width, height, opacity){
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;
for( var i = 0; i < width; i++ ){
for( var j = 0; j < height; j++ ){
var val = Math.floor(Math.random() * 255);
context.fillStyle = "rgba(" + val + "," + val + "," + val + "," + opacity + ")";
context.fillRect(i, j, 1, 1);
}
}
el.style.background = "url(" + canvas.toDataURL("image/png") + ")";
}
setNoiseBackground(document.getElementsByTagName('body')[0], 50, 50, 0.02);
}, false );
</script>
<!-- Parallax -->
<script>
(function (){
var x, y;
var items = [].slice.call(document.querySelectorAll('.layer')).map(function (el){
var rect = el.getBoundingClientRect();
el.x = rect.left;
el.y = rect.top;
el.w = rect.right - rect.left;
el.h = rect.bottom - rect.top;
el.fX = el.getAttribute('data-force-x') || el.getAttribute('data-force') || 10;
el.fY = el.getAttribute('data-force-y') || el.getAttribute('data-force') || 10;
return el;
});
document.addEventListener('dragover', function (evt){
x = evt.clientX;
y = evt.clientY;
}, false);
document.addEventListener('mousemove', function (evt){
x = evt.clientX;
y = evt.clientY;
}, false);
(function _loop(){
if( x && y ){
var winWidth = window.innerWidth;
var winHeight = window.innerHeight;
var halfWidth = winWidth / 2;
var halfHeight = winHeight / 2;
var rx = x - winWidth/2;
var ry = winHeight/2 - y;
items.forEach(function (el){
var dx = el.w/el.fX * (rx / -halfWidth);
var dy = el.h/el.fY * (ry / halfHeight);
el.style['transform'] =
el.style['-webkit-transform'] = 'translate('+dx+'px,'+dy+'px)';
});
}
requestAnimationFrame(_loop);
})();
})();
</script>
</body>
</html>
JS代码(Sortable.js):
/**! * Sortable * @authorRubaXa <trash@rubaxa.org> * @license MIT */
(function (factory){
"use strict";
if( typeof define === "function" && define.amd ){
define("Sortable",[],factory);
}
else{
window["Sortable"] = factory();
}
}
)(function (){
"use strict";
var dragEl,ghostEl,rootEl,nextEl,lastEl,lastCSS,activeGroup,tapEvt,touchEvt,expando = 'Sortable' + (new Date).getTime(),win = window,document = win.document,parseInt = win.parseInt,_silent = false,Event = (function (){
function CustomEvent(event,params){
var evt = document.createEvent('CustomEvent');
evt.initCustomEvent(event,params.bubbles,params.cancelable,params.detail);
returnevt;
}
CustomEvent.prototype = win.CustomEvent.prototype;
return CustomEvent;
}
)(),noop = function (){
}
,slice = [].slice,touchDragOverListeners = [];
/** * @class Sortable * @param{
HTMLElement}
el * @param{
Object}
[options] * @constructor */
function Sortable(el,options){
this.el = el;
// root elementthis.options = options = (options ||{
}
);
// Defaultsoptions.group = options.group || Math.random();
options.handle = options.handle || null;
options.draggable = options.draggable || el.children[0] && el.children[0].nodeName || 'li';
options.ghostClass = options.ghostClass || 'sortable-ghost';
options.onAdd = _bind(this,options.onAdd || noop);
options.onUpdate = _bind(this,options.onUpdate || noop);
options.onRemove = _bind(this,options.onRemove || noop);
el[expando] = options.group;
// Bind all prevate methodsfor( var fn in this ){
if( fn.charAt(0) === '_' ){
this[fn] = _bind(this,this[fn]);
}
}
// Bind events_on(el,'add',options.onAdd);
_on(el,'update',options.onUpdate);
_on(el,'remove',options.onRemove);
_on(el,'mousedown',this._onTapStart);
_on(el,'touchstart',this._onTapStart);
_on(el,'dragover',this._onDragOver);
_on(el,'dragenter',this._onDragOver);
touchDragOverListeners.push(this._onDragOver);
}
Sortable.prototype ={
constructor:Sortable,_applyEffects:function (){
_toggleClass(dragEl,this.options.ghostClass,true);
}
,_onTapStart:function (evt/**TouchEvent*/
){
var touch = evt.touches && evt.touches[0],target = (touch || evt).target,options = this.options;
if( options.handle ){
target = _closest(target,options.handle,this.el);
}
target = _closest(target,options.draggable,this.el);
if( target && !dragEl ){
tapEvt = evt;
target.draggable = true;
// Disable "draggable"_find(target,'a',_disableDraggable);
_find(target,'img',_disableDraggable);
if( touch ){
// Touch device supporttapEvt ={
target:target,clientX:touch.clientX,clientY:touch.clientY}
;
this._onDragStart(tapEvt,true);
evt.preventDefault();
}
_on(this.el,'dragstart',this._onDragStart);
_on(this.el,'dragend',this._onDrop);
_on(document,'dragover',_globalDragOver);
try{
if( document.selection ){
document.selection.empty();
}
else{
window.getSelection().removeAllRanges()}
}
catch (err){
}
}
}
,_emulateDragOver:function (){
if( touchEvt ){
_css(ghostEl,'display','none');
var target = document.elementFromPoint(touchEvt.clientX,touchEvt.clientY),parent = target,group = this.options.group,i = touchDragOverListeners.length;
do{
if( parent[expando] === group ){
while( i-- ){
touchDragOverListeners[i]({
clientX:touchEvt.clientX,clientY:touchEvt.clientY,target:target,rootEl:parent}
);
}
break;
}
}
while( parent = parent.parentNode );
_css(ghostEl,'display','');
}
}
,_onTouchMove:function (evt){
if( tapEvt ){
var touch = evt.touches[0],dx = touch.clientX - tapEvt.clientX,dy = touch.clientY - tapEvt.clientY;
touchEvt = touch;
_css(ghostEl,'webkitTransform','translate3d('+dx+'px,'+dy+'px,0)');
}
}
,_onDragStart:function (evt/**Event*/
,isTouch){
var target = evt.target,dataTransfer = evt.dataTransfer;
rootEl = this.el;
dragEl = target;
nextEl = target.nextSibling;
activeGroup = this.options.group;
if( isTouch ){
var rect = target.getBoundingClientRect(),css = _css(target);
ghostEl = target.cloneNode(true);
_css(ghostEl,'top',rect.top - parseInt(css.marginTop,10));
_css(ghostEl,'left',rect.left - parseInt(css.marginLeft,10));
_css(ghostEl,'width',rect.right - rect.left);
_css(ghostEl,'height',rect.bottom - rect.top);
_css(ghostEl,'opacity','0.8');
_css(ghostEl,'position','fixed');
_css(ghostEl,'zIndex','100000');
target.parentNode.insertBefore(ghostEl,target);
// Bind touch events_on(document,'touchmove',this._onTouchMove);
_on(document,'touchend',this._onDrop);
this._loopId = setInterval(this._emulateDragOver,200);
}
else{
dataTransfer.effectAllowed = 'move';
dataTransfer.setData('Text',target.textContent);
_on(document,'drop',this._onDrop);
}
setTimeout(this._applyEffects);
}
,_onDragOver:function (evt){
if( !_silent && activeGroup === this.options.group && (evt.rootEl === void 0 || evt.rootEl === this.el) ){
var el = this.el,target = _closest(evt.target,this.options.draggable,el);
if( el.children.length === 0 ){
el.appendChild(dragEl);
}
else if( target && (target !== dragEl) ){
if( lastEl !== target ){
lastEl = target;
lastCSS = _css(target)}
var rect = target.getBoundingClientRect(),width = rect.right - rect.left,height = rect.bottom - rect.top,floating = /left|right|inline/.test(lastCSS.cssFloat + lastCSS.display),skew = (floating ? (evt.clientX - rect.left)/width:(evt.clientY - rect.top)/height) > .5,isLong = (target.offsetHeight > dragEl.offsetHeight),isWide = (target.offsetWidth > dragEl.offsetWidth),nextSibling = target.nextSibling,after;
_silent = true;
setTimeout(_unsilent,30);
if( floating ){
after = (target.previousElementSibling === dragEl) && !isWide || (skew > .5) && isWide}
else{
after = (target.nextElementSibling !== dragEl) && !isLong || (skew > .5) && isLong;
}
if( after && !nextSibling ){
el.appendChild(dragEl);
}
else{
target.parentNode.insertBefore(dragEl,after ? nextSibling:target);
}
}
}
}
,_onDrop:function (evt/**Event*/
){
clearInterval(this._loopId);
// Unbind events_off(document,'drop',this._onDrop);
_off(document,'dragover',_globalDragOver);
_off(this.el,'dragend',this._onDrop);
_off(this.el,'dragstart',this._onDragStart);
_off(document,'touchmove',this._onTouchMove);
_off(document,'touchend',this._onDrop);
if( evt ){
evt.preventDefault();
if( ghostEl ){
ghostEl.parentNode.removeChild(ghostEl);
}
if( dragEl ){
var opts ={
bubbles:true,cancelable:true,detail:dragEl}
;
_toggleClass(dragEl,this.options.ghostClass,false);
if( !rootEl.contains(dragEl) ){
// Remove eventrootEl.dispatchEvent(new Event('remove',opts));
// Add eventdragEl.dispatchEvent(new Event('add',opts));
}
else if( dragEl.nextSibling !== nextEl ){
// Update eventdragEl.dispatchEvent(new Event('update',opts));
}
}
// Set NULLrootEl =dragEl =ghostEl =nextEl =tapEvt =touchEvt =lastEl =lastCSS =activeGroup = null;
}
}
,destroy:function (){
var el = this.el,options = this.options;
_off(el,'add',options.onAdd);
_off(el,'update',options.onUpdate);
_off(el,'remove',options.onRemove);
_off(el,'mousedown',this._onTapStart);
_off(el,'touchstart',this._onTapStart);
_off(el,'dragover',this._onDragOver);
_off(el,'dragenter',this._onDragOver);
touchDragOverListeners.splice(touchDragOverListeners.indexOf(this._onDragOver),1);
this._onDrop();
this.el = null;
}
}
;
function _bind(ctx,fn){
var args = slice.call(arguments,2);
returnfn.bind ? fn.bind.apply(fn,[ctx].concat(args)):function (){
return fn.apply(ctx,args.concat(slice.call(arguments)));
}
;
}
function _closest(el,selector,ctx){
if( el && ctx ){
ctx = ctx || document;
selector = selector.split('.');
var tag = selector.shift().toUpperCase(),re = new RegExp('\\b('+selector.join('|')+')\\b','g');
do{
if( (tag === '' || el.nodeName == tag)&& (!selector.length || ((el.className+'').match(re) || []).length == selector.length)){
returnel;
}
}
while( el !== ctx && (el = el.parentNode) );
}
returnnull;
}
function _globalDragOver(evt){
evt.dataTransfer.dropEffect = 'move';
evt.preventDefault();
}
function _on(el,event,fn){
el.addEventListener(event,fn,false);
}
function _off(el,event,fn){
el.removeEventListener(event,fn,false);
}
function _toggleClass(el,name,state){
if( el ){
if( el.classList ){
el.classList[state ? 'add':'remove'](name);
}
else{
var className = (' '+el.className+' ').replace(/\s+/g,' ').replace(' '+name+' ','');
el.className = className + (state ? ' '+name:'')}
}
}
function _css(el,prop,val){
if( el && el.style ){
if( val === void 0 ){
if( document.defaultView && document.defaultView.getComputedStyle ){
val = document.defaultView.getComputedStyle(el,'');
}
else if( el.currentStyle ){
val= el.currentStyle;
}
returnprop === void 0 ? val:val[prop];
}
else{
el.style[prop] = val + (typeof val === 'string' ? '':'px');
}
}
}
function _find(ctx,tagName,iterator){
if( ctx ){
var list = ctx.getElementsByTagName(tagName),i = 0,n = list.length;
if( iterator ){
for(;
i < n;
i++ ){
iterator(list[i],i);
}
}
returnlist;
}
return[];
}
function _disableDraggable(el){
return el.draggable = false;
}
function _unsilent(){
_silent = false;
}
// Export utilsSortable.utils ={
on:_on,off:_off,css:_css,find:_find,bind:_bind,closest:_closest,toggleClass:_toggleClass}
;
Sortable.version = '0.1.1';
// ExportreturnSortable;
}
);
CSS代码(zzsc.css):
html{background-image:-webkit-linear-gradient(bottom,#F4E2C9 20%,#F4D7C9 100%);background-image:-ms-linear-gradient(bottom,#F4E2C9 20%,#F4D7C9 100%);background-image:linear-gradient(to bottom,#F4E2C9 20%,#F4D7C9 100%);}
html,body{margin:0;padding:0;position:relative;color:#464637;min-height:100%;font-size:20px;font-family:'Roboto',sans-serif;font-weight:300;}
h1{color:#FF3F00;font-size:20px;font-family:'Roboto',sans-serif;font-weight:300;text-align:center;}
ul{margin:0;padding:0;list-style:none;}
.container{width:80%;margin:auto;min-width:1100px;max-width:1300px;position:relative;}
@media (min-width:750px) and (max-width:970px){.container{width:100%;min-width:750px;}
}
.sortable-ghost{opacity:.2;}
img{border:0;vertical-align:middle;}
.logo{top:55px;left:30px;position:absolute;}
.title{color:#fff;padding:3px 10px;display:inline-block;position:relative;background-color:#FF7373;z-index:1000;}
.title_xl{padding:3px 15px;font-size:40px;}
.tile{width:22%;min-width:240px;color:#FF7270;padding:10px 30px;text-align:center;margin-top:15px;margin-left:5px;margin-right:30px;background-color:#fff;display:inline-block;vertical-align:top;}
.tile__name{cursor:move;padding-bottom:10px;border-bottom:1px solid #FF7373;}
.tile__list{margin-top:10px;}
.tile__list:last-child{margin-right:0;min-height:80px;}
.tile__list img{cursor:move;margin:10px;border-radius:100%;}
.block{opacity:1;position:absolute;}
.block__list{padding:20px 0;max-width:360px;margin-top:-8px;margin-left:5px;background-color:#fff;}
.block__list li{cursor:move;}
.block__list_words li{background-color:#fff;padding:10px 40px;}
.block__list_words .sortable-ghost{opacity:0.4;background-color:#F4E2C9;}
.block__list_words li:first-letter{text-transform:uppercase;}
.block__list_tags{padding-left:30px;}
.block__list_tags:after{clear:both;content:'';display:block;}
.block__list_tags li{color:#fff;float:left;margin:8px 20px 10px 0;padding:5px 10px;min-width:10px;background-color:#5F9EDF;text-align:center;}
.block__list_tags li:first-child:first-letter{text-transform:uppercase;}