Open zhangxinxu opened 4 years ago
<div class="img-list" id="img-list">
<img class="img-thumb" src="https://images.pexels.com/photos/2387874/pexels-photo-2387874.jpeg?auto=compress&cs=tinysrgb&w=200" data-src="https://images.pexels.com/photos/2387874/pexels-photo-2387874.jpeg?auto=compress&cs=tinysrgb&w=1560">
<img class="img-thumb" src="https://images.pexels.com/photos/2524767/pexels-photo-2524767.jpeg?auto=compress&cs=tinysrgb&w=200" data-src="https://images.pexels.com/photos/2524767/pexels-photo-2524767.jpeg?auto=compress&cs=tinysrgb&w=940">
<img class="img-thumb" src="https://images.pexels.com/photos/2669181/pexels-photo-2669181.jpeg?auto=compress&cs=tinysrgb&w=200" data-src="https://images.pexels.com/photos/2669181/pexels-photo-2669181.jpeg?auto=compress&cs=tinysrgb&w=940">
<img class="img-thumb" src="https://images.pexels.com/photos/2865901/pexels-photo-2865901.jpeg?auto=compress&cs=tinysrgb&w=200" data-src="https://images.pexels.com/photos/2865901/pexels-photo-2865901.jpeg?auto=compress&cs=tinysrgb&w=1560">
<img class="img-thumb" src="https://images.pexels.com/photos/2159505/pexels-photo-2159505.jpeg?auto=compress&cs=tinysrgb&w=200" data-src="https://images.pexels.com/photos/2159505/pexels-photo-2159505.jpeg?auto=compress&cs=tinysrgb&w=1280">
<img class="img-thumb" src="https://images.pexels.com/photos/2847766/pexels-photo-2847766.jpeg?auto=compress&cs=tinysrgb&w=200" data-src="https://images.pexels.com/photos/2847766/pexels-photo-2847766.jpeg?auto=compress&cs=tinysrgb&w=940">
<img class="img-thumb" src="https://images.pexels.com/photos/2089799/pexels-photo-2089799.jpeg?auto=compress&cs=tinysrgb&w=200" data-src="https://images.pexels.com/photos/2089799/pexels-photo-2089799.jpeg?auto=compress&cs=tinysrgb&w=1560">
<img class="img-thumb" src="https://images.pexels.com/photos/1580173/pexels-photo-1580173.jpeg?auto=compress&cs=tinysrgb&w=200" data-src="https://images.pexels.com/photos/1580173/pexels-photo-1580173.jpeg?auto=compress&cs=tinysrgb&w=940">
</div>
<dialog id="dialog"><img class="img-preview" id="img-preview" draggable="false" src=""></dialog>
.img-list {
width: 420px;
height: 420px;
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
border: 10px solid #eee;
padding: 10px;
}
.img-thumb {
width: 100%;
height: 100%;
background: #eee;
object-fit: cover;
border: 0;
}
.img-thumb[dragging] {
box-shadow: 5px 5px 15px rgba(0, 0, 0, .2)
}
.img-preview {
max-width: 100%;
max-height: 100%;
transition: .3s;
visibility: hidden;
transform: scale(.5);
}
dialog {
display: flex;
box-sizing: border-box;
position: fixed;
justify-content: center;
align-items: center;
padding: 20px;
border: 0;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, .5);
font-size: 20px;
color: #fff;
transition: .3s;
}
dialog:not([open]) {
display: flex;
visibility: hidden;
opacity: 0;
}
dialog[open] {
visibility: visible;
opacity: 1;
}
dialog[open]:not([loading]) .img-preview {
visibility: visible;
transform: scale(1);
}
dialog[open][loading]::before {
position: absolute;
content: "loading...";
}
var imgList = document.getElementById('img-list');
var dialog = document.getElementById('dialog');
var imgPreview = document.getElementById('img-preview');
imgList.addEventListener('click', function(ev) {
if (ev.target.tagName === 'IMG') {
dialog.setAttribute('loading','');
dialog.show();
var img = new Image();
img.src = ev.target.dataset.src;
img.onload = function() {
dialog.removeAttribute('loading');
imgPreview.src = img.src;
}
}
})
dialog.addEventListener('click', function(ev) {
if (ev.target.tagName === 'DIALOG') {
this.close();
}
})
var currentDragItem = null;
imgList.querySelectorAll(':scope .img-thumb').forEach(function(el) {
el.addEventListener('dragstart', function(ev) {
currentDragItem = this;
})
el.addEventListener('dragend', function(ev) {
currentDragItem = null;
})
})
imgList.ondragover = function(ev) {
ev.preventDefault();
if (!currentDragItem) { return }
if (ev.target.tagName === 'IMG') {
if (currentDragItem.compareDocumentPosition(ev.target) == 2) {
ev.target.before(currentDragItem);
} else {
ev.target.after(currentDragItem);
}
}
}
//zxx: 还需要ondrop的默认行为阻止
//xboxyan: 看来和chrome的版本有很大关系,showModal在某个版本下不支持动画,最新的可以,ondrop的默认行为好像也和版本有关系。。另外,只有showModal才能默认用Esc关闭,show不行。
第二题使用原生拖拽实现,为了更好的效果,使用了最近刚刚写的一个美化polyfill
又把API熟悉了一遍... demo
//zxx: 点击弹框没出现,拖拽交互体验可以提高
// leslee: 尴尬... 类选择器忘记加点 导致点击事件没能添加成功... 因为想赶个第一没检查就发布...下次会留意, 质在量的前面.
<div class="domtest39">
<img draggable=" true" ondragenter="dragenter(event)" ondragover="return false" ondragend="dragend(event)"
src="http://i.ce.cn/newwap/fa/gd/201801/05/W020180105553424002522.jpg" alt="张国荣">
<img draggable="true" ondragenter="dragenter(event)" ondragover="return false" ondragend="dragend(event)"
src="http://i.ce.cn/newwap/fa/gd/201801/05/W020180105553424002522.jpg" alt="张国荣">
<img draggable="true" ondragenter="dragenter(event)" ondragover="return false" ondragend="dragend(event)"
src="http://i.ce.cn/newwap/fa/gd/201801/05/W020180105553424002522.jpg" alt="张国荣">
<img draggable="true" ondragend="dragend(event)" ondragover="return false" ondragenter="dragenter(event)"
src="http://n.sinaimg.cn/sinacn/w542h725/20180124/5208-fyqwiqk2138344.jpg" alt="张国荣">
</div>
body,
img {
padding: 0;
margin: 0;
}
.domtest39 {
width: 260px;
font-size: 0;
/* margin-left: -10px; */
}
.domtest39 img {
width: 80px;
height: 80px;
margin-left: 10px;
margin-bottom: 10px;
}
.domtest39 img:nth-child(3n-2) {
margin-left: 0;
}
document.querySelectorAll('.domtest39 img').forEach((item) => {
item.addEventListener('click', function (e) {
let dialog = document.createElement('dialog')
document.body.append(dialog)
let img = document.createElement('img')
img.width = window.innerWidth * 0.8
img.src = e.target.src
dialog.append(img)
dialog.showModal('gg')
})
})
document.addEventListener('click', e => e.target.close ? e.target.close() : '')
// 2
let enterTarget
function dragend(event) {
let parentNode = event.target.parentElement
let enterTempNode = enterTarget.cloneNode(true)
let targetTempNode = event.target.cloneNode(true)
parentNode.insertBefore(enterTempNode, event.target)
parentNode.removeChild(event.target)
parentNode.insertBefore(targetTempNode, enterTarget)
parentNode.removeChild(enterTarget)
}
function dragenter(event) {
enterTarget = event.target
}
//zxx: 没demo,永远移不到第3张素材的后面
<div>
<img src="https://dpic.tiankong.com/pc/xt/QJ6262880499.jpg?x-oss-process=style/794ws" />
<img src="https://dpic.tiankong.com/pu/be/QJ6266116275.jpg?x-oss-process=style/794ws" />
<img src="https://dpic.tiankong.com/pr/6x/QJ6292442803.jpg?x-oss-process=style/794ws" />
<img src="https://dpic.tiankong.com/p9/uj/QJ6267246227.jpg?x-oss-process=style/794ws" />
</div>
<dialog></dialog>
div {
width: 400px;
overflow: hidden;
}
div img {
float: left;
width: 120px;
margin-right: 20px;
margin-bottom: 10px;
height: 80px;
}
img:nth-child(3n) {
margin-right: 0;
}
// 1.
var div = document.querySelector('div')
var dialog = document.querySelector('dialog')
div.addEventListener('click', function (e) {
var target = e.target;
if (target.tagName === 'IMG') {
var newImg = target.cloneNode(true)
dialog.append(newImg)
dialog.showModal()
}
})
dialog.addEventListener('click', function () {
dialog.removeChild(dialog.firstElementChild)
dialog.close()
})
// 2.
div.addEventListener('dragover', function (e) {
e.preventDefault()
})
div.addEventListener('drop', function (e) {
e.preventDefault()
})
var imgs = document.querySelectorAll('img'),
dragElement = null;
for (var i = 0; i < imgs.length; i++) {
imgs[i].addEventListener('dragstart', function (ev) {
dragElement = this;
});
imgs[i].addEventListener('dragenter', function (ev) {
if (dragElement != this) {
if(this.parentNode.lastElementChild === this) {
this.parentNode.append(dragElement)
}else {
this.parentNode.insertBefore(dragElement, this);
}
}
})
};
let obj = null
let box = document.getElementById('box')
document.addEventListener('mouseup', function (e) {
const target = e.target
if (target.nodeName === 'IMG' && box.contains(target)) {
if (obj) {
obj.remove()
}
let newDialog = document.createElement('dialog')
// newDialog.setAttribute('open', '开启')
let imgBox = document.createElement('img')
imgBox.setAttribute('src', target.src.replace(/90$/, '180'))
newDialog.appendChild(imgBox)
newDialog.setAttribute('id', 'favDialog')
obj = newDialog
document.body.appendChild(newDialog)
var dialog = document.getElementById('favDialog')
dialog.showModal()
} else {
if (obj) {
obj.remove()
}
}
})
// 存储变量
var dragged;
document.addEventListener("dragstart", function (event) {
dragged = event.target;
}, false);
/* 放下目标节点时触发事件 */
document.addEventListener("dragover", function (event) {
// 阻止默认动作
event.preventDefault();
}, false);
document.addEventListener("dragenter", function (event) {
if (event.target.nodeName === 'IMG') {
var enterIndex = [].indexOf.call(box.childNodes, event.target);
var index = [].indexOf.call(box.childNodes, dragged);
if (index > enterIndex) {
dragged.parentNode.insertBefore(dragged, event.target);
} else {
dragged.parentNode.insertBefore(dragged, event.target.nextSibling);
}
}
}, false);
demo html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div class="img-group">
<img data-big_src="//bossaudioandcomic-1252317822.image.myqcloud.com/activity/document/7eaa8bd8fc72d4f536c17be887df8238.png" src="//bossaudioandcomic-1252317822.image.myqcloud.com/activity/document/7eaa8bd8fc72d4f536c17be887df8238.png"/>
<img data-big_src="https://img2.qidian.com/upload/gamesy/2019/10/22/20191022182743obsvqpbdqh.png" src="https://img2.qidian.com/upload/gamesy/2019/10/22/20191022182743obsvqpbdqh.png"/>
<img data-big_src="//qidian.qpic.cn/qidian_common/349573/bd326aea6e0a7ca656ed6a4011745b90/0" src="//qidian.qpic.cn/qidian_common/349573/bd326aea6e0a7ca656ed6a4011745b90/0"/>
<img data-big_src="https://img2.qidian.com/upload/gamesy/2019/09/29/20190929144145e9ir20e3dy.jpg" src="https://img2.qidian.com/upload/gamesy/2019/09/29/20190929144145e9ir20e3dy.jpg"/>
</div>
<dialog id="js-dalog">
<img src=""/>
</dialog>
</body>
</html>
css
#js-dalog img{
width: 360px;
}
js
let imgs = document.querySelectorAll('.img-group img');
let dalog = document.querySelector('#js-dalog');
let bigImg = document.querySelector('#js-dalog img');
imgs.forEach( item =>{
item.onclick = function(e){
let bigSrc = this.getAttribute('data-big_src');
bigImg.setAttribute('src',bigSrc);
dalog.showModal()
};
})
//点击任意位置隐藏
dalog.onclick = function(e){
dalog.close();
}
//2.
let nowImg;
document.querySelector('.img-group').ondragstart= function(e){
if(e.target.tagName === 'IMG'){
nowImg = e.target;
}
}
document.querySelector('.img-group').addEventListener("dragover",function(e){
if(e.target.tagName === 'IMG'){
let drag = e.target;
drag.parentNode.insertBefore(nowImg,drag.nextElementSibling);
}
},false);
//zxx: 移不到最后,交互上可以调整下
.img-thumb{
height:100px;
margin:0 10px 10px 0;
}
<div id="img-container">
<img class="img-thumb" draggable="true" src="https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=533762546,672570916&fm=26&gp=0.jpg" />
<img class="img-thumb" draggable="true" src="https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=537501145,2320471355&fm=26&gp=0.jpg" />
<img class="img-thumb" draggable="true" src="https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3082876337,1693663170&fm=26&gp=0.jpg" />
<img class="img-thumb" draggable="true" src="https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=423551398,1303118808&fm=26&gp=0.jpg" />
<img class="img-thumb" draggable="true" src="https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2595508360,28762262&fm=26&gp=0.jpg" />
</div>
<dialog id="dialog"><img id="img-preview"/></dialog>
var container = document.querySelector("#img-container");
var dialog =document.querySelector("#dialog");
container.addEventListener("click",function(e){
var target = e.target;
if(target.classList.contains('img-thumb')){
document.querySelector("#img-preview").src = target.src;
dialog.showModal();
}
})
dialog.addEventListener("click",function(){
this.close();
})
var dragImg;
container.addEventListener("dragstart", function( event ) {
dragImg = event.target;
}, false);
document.addEventListener("dragover", function( event ) {
event.preventDefault();
}, false);
container.addEventListener("drop", function( event ) {
event.preventDefault();
var target = event.target;
if(target.classList.contains("img-thumb")){
target.parentNode.insertBefore(dragImg,target);
}
}, false);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div class="container">
<img src="https://avatars2.githubusercontent.com/u/8694868" alt="avatars" crossorigin="anonymous" />
<img src="https://avatars0.githubusercontent.com/u/8696309" alt="avatars" crossorigin="anonymous" />
<img src="https://avatars3.githubusercontent.com/u/8697294" alt="avatars" crossorigin="anonymous" />
<img src="https://avatars1.githubusercontent.com/u/8669103" alt="avatars" crossorigin="anonymous" />
<img src="https://avatars1.githubusercontent.com/u/40731029" alt="avatars" crossorigin="anonymous" />
</div>
<dialog class="dialog-container">
<!-- zxx: 建议remove src属性 -->
<img src="" alt="dialog show img" />
</dialog>
<canvas></canvas>
</body>
</html>
// 1
var container = document.querySelector('.container');
var dialog = document.querySelector('.dialog-container');
var showImg = dialog.querySelector('img');
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
container.addEventListener('click', function(event) {
target = event.target;
if (target.tagName.toLowerCase() === 'img') {
// 显示图片,防止重复申请图片资源
var bodySize = document.body.getBoundingClientRect();
var width =
target.naturalWidth > bodySize.width - 30
? bodySize.width - 30
: target.naturalWidth;
var height = (width * target.naturalHeight) / target.naturalWidth;
canvas.width = width;
canvas.height = height;
ctx.drawImage(target, 0, 0, width, height);
// toDataURL 方法涉及到跨域,所以要在 img 添加属性 crossorigin="anonymous"
// var img = canvas.toDataURL();
// showImg.src = img;
// 使用异步 api toBlob
canvas.toBlob(function(blob) {
var url = URL.createObjectURL(blob);
showImg.src = url;
// dialog.showModal();
// 兼容 firefox 和 safari
dialog.setAttribute('open', '');
});
}
});
dialog.addEventListener('click', function(event) {
if (event.target.tagName.toLowerCase() === 'dialog') {
// 兼容 firefox 和 safari
event.target.removeAttribute('open')
}
});
document.addEventListener('keydown', function(event) {
console.log(event.key);
if (event.key === 'Escape' && dialog.hasAttribute('open')) {
// dialog.close();
// 兼容 firefox 和 safari
dialog.removeAttribute('open');
}
})
// 2
var dragElement, dragIndex, enterElement, enterIndex;
document.addEventListener(
'dragstart',
function(event) {
dragElement = event.target;
dragElement.style.opacity = 0.5;
document.querySelectorAll('img').forEach(function(img, index) {
if (img === dragElement) {
dragIndex = index;
}
});
// 图片过大拖拽会显示不出图片,选用 canvas 生成图片拖拽效果
var ctx = canvas.getContext('2d');
var width = dragElement.width;
var height = dragElement.height;
canvas.width = width;
canvas.height = height;
ctx.drawImage(dragElement, 0, 0, width, height);
var dt = event.dataTransfer;
dt.setDragImage(canvas, 25, 25);
},
false
);
document.addEventListener(
'dragend',
function(event) {
event.target.style.opacity = '';
},
false
);
document.addEventListener(
'dragover',
function(event) {
// 删除图片返回原始位置的效果
event.preventDefault();
},
false
);
document.addEventListener(
'dragenter',
function(event) {
enterElement = event.target;
if (
event.target.tagName.toLowerCase() !== 'img' ||
enterElement === dragElement
) {
return;
}
document.querySelectorAll('img').forEach(function(img, index) {
if (img === enterElement) {
enterIndex = index;
}
});
if (dragIndex < enterIndex) {
enterElement.after(dragElement);
[dragIndex, enterIndex] = [enterIndex, dragIndex];
} else if (dragIndex > enterIndex) {
enterElement.before(dragElement);
[dragIndex, enterIndex] = [enterIndex, dragIndex];
}
},
false
);
document.addEventListener('drop', function(event) {
// 禁止 firefox 打开窗口
event.preventDefault();
event.stopPropagation();
});
关于 svgo 工具的问题,我向官方提出了 issue,官方回复是在 v1.1.0 的版本以后已经修复了,所以只要升级就能解决问题 //zxx: 感谢
//zxx: 为何我拖了没效果出现
<div class="image-wrapper" id="imageWrapper">
<img src="https://bookcover.yuewen.com/qdbimg/349573/1016010400" alt="小说1">
<img src="https://bookcover.yuewen.com/qdbimg/349573/1015831596" alt="小说2">
<img src="https://bookcover.yuewen.com/qdbimg/349573/1014032643" alt="小说3">
<img src="https://bookcover.yuewen.com/qdbimg/349573/1015292101" alt="小说4">
</div>
<dialog id="dialogBox" class="dialog-box">
<img src="" alt="预览" id="previewImage">
</dialog>
let imageWrapper = document.getElementById('imageWrapper')
let dialogBox = document.getElementById('dialogBox')
let previewImage = document.getElementById('previewImage')
let dragEl = null
let dragElIndex = null
imageWrapper.addEventListener('click', e => {
const { nodeName, src } = e.target
if (nodeName === 'IMG' && src){
previewImage.src = src
dialogBox.showModal()
}
})
dialogBox.addEventListener('click', function () {
this.close()
})
imageWrapper.addEventListener('dragstart', e => {
// 记录拖拽元素
dragEl = e.target
dragElIndex = computeVmIndex(e.target)
})
imageWrapper.addEventListener('dragover', e => {
// 1. 阻止默认动作开启drop
e.preventDefault()
})
imageWrapper.addEventListener('drop', e => {
e.preventDefault()
// 2. 阻止Firefox打开新窗口
e.stopPropagation()
// 3. drop后判断是否为目标元素范围
if (e.target.nodeName === 'IMG') {
let crurrentElIndex = computeVmIndex(e.target)
e.target.parentNode.removeChild(dragEl)
// 4. 交换位置
if (dragElIndex > crurrentElIndex) {
// 相当于dragEl插入到e.target之前
e.target.parentNode.insertBefore(dragEl, e.target)
} else {
// 相当于dragEl插入到e.target之后
e.target.parentNode.insertBefore(dragEl, e.target.nextSibling)
}
}
})
imageWrapper.addEventListener('dragend', e => {
dragEl = null
dragElIndex = null
})
function computeVmIndex(element) {
return Array.from(element.parentNode.children).indexOf(element)
}
//zxx: 体验下来有些奇怪
* {
padding: 0;
margin: 0;
}
body {
display: flex;
height: 100vh;
justify-content: center;
align-items: center;
}
#img-list {
display: grid;
width: 600px;
height: 600px;
padding: 20px;
border-style: solid;
grid-template: repeat(3, 1fr) / repeat(3, 1fr);
grid-gap: 20px;
}
#img-list > img {
width: 100%;
height: 100%;
border: 1px solid #ccc;
cursor: pointer;
}
dialog:not([open]) {
opacity: 0;
}
dialog[open] {
display: flex;
width: 100%;
height: 100%;
border: none;
justify-content: center;
align-items: center;
opacity: 1;
}
<div id="img-list">
<img src="//bookcover.yuewen.com/qdbimg/349573/1010734492/150" alt="" draggable="true">
<img src="//bookcover.yuewen.com/qdbimg/349573/1010868264/150" alt="" draggable="true">
<img src="//bookcover.yuewen.com/qdbimg/349573/3602691/150" alt="" draggable="true">
<img src="//bookcover.yuewen.com/qdbimg/349573/1010400217/150" alt="" draggable="true">
<img src="//bookcover.yuewen.com/qdbimg/349573/1011449273/150" alt="" draggable="true">
<img src="//bookcover.yuewen.com/qdbimg/349573/1011705052/150" alt="" draggable="true">
<img src="//bookcover.yuewen.com/qdbimg/349573/1009480992/150" alt="" draggable="true">
<img src="//bookcover.yuewen.com/qdbimg/349573/1013432302/150" alt="" draggable="true">
<img src="//bookcover.yuewen.com/qdbimg/349573/1011058239/150" alt="" draggable="true">
</div>
<dialog>
<img src="//bookcover.yuewen.com/qdbimg/349573/1010734492/150" alt="" id="show-img">
</dialog>
{
let imgList = document.getElementById("img-list");
let aImg = imgList.querySelectorAll("img");
let showImg = document.getElementById("show-img");
let oDialog = document.querySelector("dialog");
let dragItem = null;
let type = 1; //0就放在目标元素之前吧,1就互换
imgList.addEventListener("click", (e) => {
if(e.target.tagName === "IMG"){
showImg.src = e.target.src;
oDialog.show();
}
});
oDialog.addEventListener("click", function(){
this.close();
});
aImg.forEach(item => {
item.addEventListener("dragstart", (e) => {
dragItem = item;
});
});
imgList.addEventListener("dragover", (e) => {
e.preventDefault();
});
imgList.addEventListener("drop", (e) => {
if(e.target != dragItem){
if(type === 0){
e.target.before(dragItem);
}else{
let [a, b] = [e.target.src, dragItem.src];
[a, b] = [b, a];
e.target.src = a;
dragItem.src = b;
}
}
})
}
<div class="imgs">
<img src="images/1.jpg">
<img src="images/2.jpg">
<img src="images/3.jpg">
<img src="images/4.jpg">
</div>
<dialog id="imgDialog">
<img src="">
</dialog>
.imgs img {
width: 100px;
height: 100px;
cursor: pointer;
margin-bottom: 10px;
}
.imgs {
width: 320px;
font-size: 0;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
#imgDialog {
position: absolute;
top: 0;
}
#imgDialog img{
width: 100%;
}
var imgDialog = document.getElementById('imgDialog')
var dragElement
var dragEvent
document.addEventListener('click', event => {
var src = event.target.src
var dialogImg = imgDialog.querySelector('img')
if (src && dialogImg.src !== src ) {
imgDialog.querySelector('img').src = src
imgDialog.showModal()
imgDialog.setAttribute('open', true)
} else {
imgDialog.close()
}
})
document.addEventListener('dragstart', event => {
dragEvent = event
dragElement = event.target
})
document.addEventListener('dragover', event => {
var imgNodes = [...document.querySelectorAll('.imgs img')]
if(imgNodes.includes(event.target)) {
var target = event.target
if (dragEvent.offsetX > event.offsetX) {
target.before(dragElement)
} else {
target.after(dragElement)
}
} else {
var firstNode = imgNodes[0]
var lastNode = imgNodes[imgNodes.length -1]
var lastNodeX = lastNode.offsetLeft + lastNode.offsetWidth
var lastNodeY = lastNode.offsetTop
if (event.offsetX > lastNodeX && event.offsetY > lastNodeY) {
document.querySelector('.imgs').appendChild(dragElement)
}
}
})
示例代码忘记加了,编辑一下 预览地址
#image-box {
width: 400px;
display: flex;
flex-wrap: wrap;
}
.image {
margin: 0 10px 10px 0;
display: block;
width: calc(100% / 3 - 10px);
}
dialog {
position: fixed;
top: 50px;
}
<div id="image-box">
<img class="image" src="https://bookcover.yuewen.com/qdbimg/349573/1015289424/150" alt="image"/>
<img class="image" src="https://bookcover.yuewen.com/qdbimg/349573/1015673983/150" alt="image">
<img class="image" src="https://bookcover.yuewen.com/qdbimg/349573/1015861294/150" alt="image">
<img class="image" src="https://bookcover.yuewen.com/qdbimg/349573/1015440199/150" alt="image">
</div>
var currentDrag = "";
var imageContainer = document.querySelector("#image-box");
var imageList = [].slice.call(document.querySelectorAll(".image"));
var dialog = document.createElement("dialog");
document.body.appendChild(dialog);
imageList.forEach(function (el) {
el.addEventListener("click", function (e) {
var src = e.target.src;
dialog.innerHTML = `<img src=${src} />`;
dialog.showModal();
});
el.addEventListener("dragstart", function (e) {
currentDrag = e.target;
});
el.addEventListener("dragover", function (e) {
e.preventDefault();
if (e.target.tagName === 'IMG' && e.target !== currentDrag) {
//使用2个元素交换法则
const temp = document.createElement("img");
imageContainer.replaceChild(temp, e.target);
imageContainer.replaceChild(e.target, currentDrag);
imageContainer.replaceChild(currentDrag, temp);
}
});
el.addEventListener('dragend', function () {
currentDrag = null;
});
});
dialog.addEventListener("click", function (e) {
console.log(e);
if (e.target.nodeName === "DIALOG") {
this.close();
}
});
2019-11-5:修正拖放时位置没有即时变化的问题;为被拖放的图片增加效果;
看来想要更好的拖拽体验,需要去好好的研究一下DataTransfer对象才行。
//zxx: 位置变化应该是即时的
#container {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
width: 375px;
}
#container>img {
width: 30%;
margin-bottom: 10px;
}
.dragging {
outline: 2px dashed #666;
}
<div id="container">
<img src="https://placekitten.com/200/200">
<img src="https://placekitten.com/240/240">
<img src="https://placekitten.com/280/280">
<img src="https://placekitten.com/320/320">
</div>
let container = document.getElementById('container')
let dialog = document.createElement('dialog')
document.body.appendChild(dialog)
// 第一题
container.addEventListener('click', e => {
if (e.target.tagName.toLowerCase() === 'img') {
dialog.innerHTML = ''
dialog.appendChild(e.target.cloneNode())
dialog.showModal()
}
})
dialog.addEventListener('click', e => {
dialog.close()
})
// 第二题
let dragImg = null
let dropImg = null
container.addEventListener('dragstart', e => {
if (e.target.tagName.toLowerCase() === 'img') {
dragImg = e.target
dragImg.classList.add('dragging') // 为拖动元素添加效果
}
})
container.addEventListener('dragenter', e => {
if (e.target.tagName.toLowerCase() === 'img') {
dropImg = e.target
}
})
container.addEventListener('dragover', e => {
e.preventDefault()
if (dropImg !== dragImg) {
let imgs = Array.from(container.querySelectorAll('img'))
let dragIdx = imgs.indexOf(dragImg) // 被拖的图片的索引
let dropIdx = imgs.indexOf(dropImg) // 将放入的图片的索引
if (dropIdx > dragIdx) { // 判断排序往前还是往后
dropImg.after(dragImg)
} else {
dropImg.before(dragImg)
}
}
})
container.addEventListener('dragend', e => {
dragImg.classList.remove('dragging')
})
//zxx: 位置变化应该是即时的
body {
position: relative;
margin: 0;
padding: 0;
}
.imgbox {
display: flex;
flex-wrap: wrap;
width: 510px;
margin: 30px auto;
}
.imgbox img {
width: 150px;
height: 150px;
margin: 10px 5px;
}
dialog {
width: 100vw;
height: 100vh;
padding: 0;
border: none;
background: transparent;
}
dialog img {
display: block;
max-width: 80vh;
max-height: 80vh;
margin: 10vh auto;
}
dialog::backdrop {
background: rgba(0, 0, 0, .6);
}
<div class="imgbox">
<img src="https://b-ssl.duitang.com/uploads/blog/201312/04/20131204184148_hhXUT.jpeg" data-id="1" alt="">
<img src="http://pic22.nipic.com/20120620/9644879_220135570113_2.jpg" data-id="2" alt="">
<img src="http://pic33.nipic.com/20131008/13661616_134400215000_2.jpg" data-id="3" alt="">
<img src="http://pic31.nipic.com/20130628/11809329_095205782183_2.jpg" data-id="4" alt="">
</div>
let dialog = document.createElement("dialog")
document.body.appendChild(dialog)
let bigimg = document.createElement("img")
dialog.appendChild(bigimg)
let imgbox = document.querySelector(".imgbox")
let img = document.querySelectorAll(".imgbox img")
let oversrc = null
let starsrc = null
let targetimg = null
img.forEach(item => {
item.addEventListener("click", function(e) {
bigimg.setAttribute("src", this.getAttribute("src"))
dialog.showModal()
e.stopPropagation()
})
item.addEventListener('dragstart', dragstar)
item.addEventListener("dragend", dragEnd)
item.addEventListener("dragover", function(e) {
oversrc = this.getAttribute("src")
targetimg = this
})
})
document.addEventListener("click", function(e) {
dialog.close()
})
function dragstar(e) {
starsrc = this.getAttribute("src")
}
function dragEnd(e) {
this.setAttribute("src", oversrc)
targetimg.setAttribute("src", starsrc)
}
//zxx: 图片释放会浏览器打开
HTML
<div class="container">
<img src="http://bookcover.yuewen.com/qdbimg/349573/1016171761/90" alt="">
<img src="//bookcover.yuewen.com/qdbimg/349573/1016457437/90" alt="">
<img src="//bookcover.yuewen.com/qdbimg/349573/1012394723/90" alt="">
<img src="//bookcover.yuewen.com/qdbimg/349573/1016350338/90" alt="">
</div>
<dialog id="imgDialog" class="imgDialog">
<img src="" alt="">
</dialog>
CSS
.container {
/* border: 1px solid saddlebrown; */
width: 310px;
font-size: 0px;
display: inline-block;
}
.container img {
width: 100px;
height: 100px;
object-fit: cover;
margin-left: 2px;
}
.container img:hover {
margin-left: 0px;
border-left: 2px solid #83D0F2 !important;
}
.imgDialog {
display: flex;
padding: 1em;
box-sizing: border-box;
position: fixed;
justify-content: center;
align-items: center;
right: 0;
border: 0;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, .6);
font-size: 20px;
color: #fff;
transition: .3s;
}
.imgDialog:not([open]) {
display: flex;
visibility: hidden;
opacity: 0;
}
.imgDialog:not([open]) img {
/* transition: .3s; */
transform: scale(.3);
}
.imgDialog[open] {
/* transition: .3s; */
visibility: visible;
opacity: 1;
}
.imgDialog[open] img {
transform: scale(1);
}
.imgDialog img {
transition: .3s;
height: 60%;
object-fit: contain;
}
JS
let imgDoalogEle = document.getElementById('imgDialog')
let imgDoalogImgEle = document.querySelector('.imgDialog img')
let container = document.querySelector('.container')
console.log(imgDoalogEle, 'dialog')
let containerImg = [].slice.call(document.querySelectorAll('.container img'))
console.log(containerImg)
containerImg.forEach(item => {
item.addEventListener('click', () => {
imgDoalogImgEle.src = item.src
imgDoalogEle.show()
})
});
imgDoalogEle.addEventListener('click', function (ev) {
if (ev.target.tagName === 'DIALOG') {
this.close();
}
})
// 第二题
let sedTarget
let sedTargetSite
let endTarget
let endTargetSite
function computeVmIndex(element) {
return Array.from(element.parentNode.children).indexOf(element)
}
// 当拖动元素或选中的文本到一个可释放目标时触发
container.addEventListener('dragstart', (ev) => {
if (ev.target.tagName === 'IMG') {
// console.log(computeVmIndex(ev.target))
sedTargetSite = computeVmIndex(ev.target)
sedTarget = ev.target;
ev.target.style.opacity = .5;
}
})
// 当拖拽操作结束时触发 (比如松开鼠标按键或敲“Esc”键).
container.addEventListener("dragend", function (ev) {
if (ev.target.tagName === 'IMG') {
// reset the transparency
ev.target.style.opacity = "";
}
}, false);
// 当元素或选中的文本被拖到一个可释放目标上时触发
/* events fired on the drop targets */
container.addEventListener("dragover", function (ev) {
if (ev.target.tagName === 'IMG') {
// console.log('当元素或选中的文本被拖到一个可释放目标上时触发', computeVmIndex(event.target))
ev.target.style.borderLeft = '2px solid #83D0F2'
// prevent default to allow drop
event.preventDefault();
}
}, false);
// 当拖动元素或选中的文本离开一个可释放目标时触发
container.addEventListener("dragleave", function (ev) {
if (ev.target.tagName === 'IMG') {
ev.target.style.border = 'none'
}
})
// 当元素或选中的文本在可释放目标上被释放时触发
container.addEventListener("drop", ev => {
if (ev.target.tagName === 'IMG') {
ev.target.style.border = 'none'
endTargetSite = computeVmIndex(ev.target) // 目标地址
console.log(computeVmIndex(ev.target))
if (sedTargetSite > endTargetSite) {
ev.target.parentNode.insertBefore(sedTarget, ev.target)
} else {
ev.target.parentNode.insertBefore(sedTarget, ev.target.nextSibling)
}
}
})
//zxx: 弹框效果有些奇怪。拖拽会有穷闪场景。
var $container = document.getElementById("container"),// 容器
$win_perview = document.getElementById("win_perview"),// 预览窗体
$t = {},// 被点击的图
$shadow,// 随鼠标移动的图
$boxs;//图
function clickHandler(e) {// 点击事件
if (e.target instanceof HTMLImageElement) {
$win_perview.style.setProperty("--src", `url(${e.target.src})`);
$win_perview.open = "open";
}
}
function draggerHandler(e) {
e.preventDefault();
e.stopPropagation();// 防止浏览器插件冲突
switch (e.type) {
case "mousedown":
if (e.target instanceof HTMLImageElement) {
var { top, left, width, height } = e.target.getBoundingClientRect();
$boxs = getGravityPoints($container.children);// 缓存所有元素中心
$t = {//缓存被点击的图
target: e.target,
top,left,height,width,
gX: top + height / 2,
gY: left + width / 2,
};
$shadow = $t.target.cloneNode();// 缓存随鼠标移动的图
[
["position", "fixed"],
["margin", "0"],
["left", $t.left + "px"],
["top", $t.top + "px"],
["pointerEvents", "none"],
["width", $t.width + "px"]
].forEach(([k, v]) => $shadow.style[k] = v);
document.body.append($shadow);
$t.target.style.opacity = 0.2;
$container.addEventListener("mousemove", draggerHandler);
document.addEventListener("mouseup", draggerHandler);
}
break;
case "mousemove":
if (!$t.moved) {$t.moved = true;}
var { left, top } = $shadow.style;
[left, top] = [parseInt(left) + e.movementX, parseInt(top) + e.movementY];
//将插入的位置 nextIdx; 之前的位置 prevIdx;
var nextIdx = getCloserIndex($boxs, left + $t.width / 2, top + $t.height / 2);
var prevIdx = getElementIndex($t.target);
// 换位
if (nextIdx + 1 === $container.children.length) {
$container.appendChild($t.target)
}
else if (prevIdx + 1 === nextIdx) {
$container.insertBefore($t.target, $container.children[nextIdx + 1]);
}
else if ($t.target !== $container.children[nextIdx]) {
$container.insertBefore($t.target, $container.children[nextIdx]);
}
$boxs = getGravityPoints($container.children);// 重新缓存
// 位移随鼠标移动的图
// $shadow.style.left = left + "px";
// $shadow.style.top = top + "px";
$shadow.style.left = e.clientX - $t.width / 2 + "px";
$shadow.style.top = e.clientY - $t.height / 2 + "px";
break;
case "mouseup":
!$t.moved && clickHandler(e); //没移动则触发点击
$t.target.style.opacity = 1;
$t = null;
$container.removeEventListener("mousemove", draggerHandler);
document.removeEventListener("mouseup", draggerHandler);
$shadow.parentNode.removeChild($shadow);
break;
}
}
function getElementIndex(ele) {// 获取元素索引
for (var i = 0; ele = ele.previousElementSibling; i++);
return i;
}
function getGravityPoints([...children]) {// 获取所有元素中心
return children.map(item => {
var { top, left, width, height } = item.getBoundingClientRect();
return {
gX: left + width / 2,
gY: top + height / 2
};
});
}
function getCloserIndex($boxs, X, Y) {// 判定放置点
var point = $boxs.map(({ gX, gY }) => parseInt(Math.hypot(X - gX, Y - gY)));
var i = point.reduce(
(acc, cur, idx) => {
return acc.v > cur ? { i: idx, v: cur } : acc;
},
{ i: 0, v: point[0] }
).i;
return i;
}
$win_perview.addEventListener("click", $win_perview.close);
$container.addEventListener("mousedown", draggerHandler);
Demo https://codepen.io/crazyboy/pen/xxxpbry
//zxx: 点击弹框位置隐藏;位置变化应即时
(function () {
let dialogEle = document.createElement('dialog');
dialogEle.style.cssText = 'box-shadow: 0 0 0 100vmax rgb(0,0,0,0.3); z-index: 1;'
let dialogImgEle = document.createElement('img');
dialogEle.appendChild(dialogImgEle);
document.body.appendChild(dialogEle);
document.body.onclick = function(e) {
if (e.target.nodeName === 'IMG' && e.target.parentNode.nodeName !== 'DIALOG') {
dialogImgEle.src = e.target.attributes.src.value;
dialogEle.setAttribute('open', 'open');
} else {
dialogEle.removeAttribute('open');
}
};
let registerDrag = function(ele) {
ele.setAttribute('draggable', 'true');
let parent = ele.parentNode;
ele.ondragend = function(e) {
let exchangeEle;
let sibling = e.target.nextElementSibling;
for (let i = 0; i < parent.children.length; i++) {
let child = parent.children[i];
if (child.offsetLeft <= e.pageX && e.pageX <= (child.offsetLeft + child.offsetWidth) && child.offsetTop <= e.pageY && e.pageY <= (child.offsetTop + child.offsetHeight)) {
exchangeEle = parent.children[i];
break;
}
}
if (!!exchangeEle && exchangeEle !== e.target) {
if (exchangeEle === sibling) {
parent.removeChild(exchangeEle);
parent.insertBefore(exchangeEle, e.target);
} else {
parent.removeChild(e.target);
parent.insertBefore(e.target, exchangeEle);
parent.removeChild(exchangeEle);
if (!!sibling) {
parent.insertBefore(exchangeEle, sibling);
} else {
parent.appendChild(exchangeEle);
}
}
}
}
};
document.querySelector('div').style.cssText = 'width: 300px;'
Array.from(document.querySelectorAll('div img')).forEach(v => {
v.style.cssText = 'float: left; width: 30%; padding: 0 1.5% 3% 1.5%;';
registerDrag(v);
});
})();
//zxx: 弹框实现不错,拖拽存在相邻无法互换问题
.imgs {
font-size: 0;
max-width: 312px;
}
.imgs img {
width: 100px;
height: 100px;
margin: 2px;
cursor: pointer;
transition: transform 300ms;
}
.imgs img._on{
outline: 2px dashed red;
opacity: 0.5;
}
.imgs img:hover {
transform: scale(1.1);
}
.imgs img:active {
transform: scale(0.98);
}
.img-dialog {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
border: none 0;
cursor: pointer;
}
.img-dialog[open] {
background: transparent url('data:image/gif;base64,R0lGODlhHwAfANUAAN3d3dXV1dPT09vb2+rq6vHx8efn5/Ly8uzs7P39/c3Nzejo6NHR0c7OztLS0uLi4tra2tTU1NjY2NfX197e3vb29tDQ0NnZ2eTk5Nzc3O/v7+np6dbW1t/f3/Dw8OHh4eDg4OXl5fz8/Ovr6+Pj4/T09O3t7fn5+fr6+ubm5vPz8/v7+/j4+O7u7vX19ff398/Pz////8zMzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowNzgwMTE3NDA3MjA2ODExOEMxNERCODM5NjcyODU1MiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpBNTI1OERFQkMyNDkxMUUwOTcyOEE4MDlGQzk4Njk1MiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpBNTI1OERFQUMyNDkxMUUwOTcyOEE4MDlGQzk4Njk1MiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJpdmVkRnJv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') 50% 50% no-repeat;
}
.img-detail {
position: fixed;
top: 16px;
right: 16px;
bottom: 16px;
left: 16px;
background-position: 50% 50%;
background-repeat: no-repeat;
background-size: contain;
transition: transform 200ms;
}
.img-detail:active {
transform: scale(0.98);
}
.img-dialog::backdrop {
background-color: rgba(0, 0, 0, 0.8);
}
<div class="imgs j_imgs" id="imgThumbs">
<img draggable="true" width="100" height="100" src="https://placem.at/people?txt=1&w=100&h=100&random=5"
data-src="https://placem.at/people?txt=1&w=500&h=500&random=5" alt="img" title="显示大图1">
<img draggable="true" width="100" height="100" src="https://placem.at/people?txt=2&w=100&h=100&random=2"
data-src="https://placem.at/people?txt=2&w=500&h=500&random=2" alt="img" title="显示大图2">
<img draggable="true" width="100" height="100" src="https://placem.at/people?txt=3&w=100&h=100&random=3"
data-src="https://placem.at/people?txt=3&w=500&h=500&random=3" alt="img" title="显示大图3">
<img draggable="true" width="100" height="100" src="https://placem.at/people?txt=4&w=100&h=100&random=4"
data-src="https://placem.at/people?txt=4&w=500&h=500&random=4" alt="img" title="显示大图4">
</div>
<dialog class="img-dialog" id="imgDialog" title="关闭">
<div class="img-detail" id="imgDetail"></div>
</dialog>
// 第一题
var eleImgDialog = document.getElementById('imgDialog');
var eleImgDetail = document.getElementById('imgDetail');
var eleThumbBox = document.getElementById('imgThumbs');
eleImgDialog.addEventListener('click', function (e) {
eleImgDialog.close();
eleImgDetail.style.backgroundImage = null;
});
eleThumbBox.addEventListener('click', function (e) {
e.preventDefault();
if (e.target && e.target.tagName === "IMG") {
var originSrc = e.target.dataset.src;
eleImgDetail.style.backgroundImage = 'url("' + originSrc + '")';
eleImgDialog.showModal();
}
});
// 第二题 drap 事件
var eleCurrentDrop=null;
eleThumbBox.addEventListener('dragover',function(e){
e.preventDefault();
});
eleThumbBox.addEventListener('dragenter',function(e){
var eleOn = eleThumbBox.querySelector('._on');
eleOn && eleOn.classList.remove("_on");
e.target.classList.add("_on");
});
eleThumbBox.addEventListener('dragend',function(e){
if(eleCurrentDrop){
eleThumbBox.insertBefore(e.target,eleCurrentDrop);
eleCurrentDrop=null;
}
var eleOn = eleThumbBox.querySelector('._on');
eleOn && eleOn.classList.remove("_on");
});
eleThumbBox.addEventListener('drop',function(e){
eleCurrentDrop = e.target;
});
//zxx: 拖拽会变成打开图片
.img-list {
width: 260px;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
.img-item {
width: 83px;
height: 83px;
display: block;
margin-bottom: 5px;
object-fit: cover;
cursor: move;
}
.img-preview {
max-width: 100%;
height: auto;
display: block;
margin-bottom: 10px;
}
dialog::backdrop {
background: rgba(0, 0, 0, .4);
}
<div class="img-list">
<img class="img-item" draggable="true" src="https://bookcover.yuewen.com/qdbimg/349573/1016562761" alt="">
<img class="img-item" draggable="true" src="http://bookcover.yuewen.com/qdbimg/349573/1016594554" alt="">
<img class="img-item" draggable="true" src="http://bookcover.yuewen.com/qdbimg/349573/1016706397" alt="">
<img class="img-item" draggable="true" src="http://bookcover.yuewen.com/qdbimg/349573/1016673054" alt="">
<img class="img-item" draggable="true" src="http://bookcover.yuewen.com/qdbimg/349573/1016446189" alt="">
<img class="img-item" draggable="true" src="http://bookcover.yuewen.com/qdbimg/349573/1016232348" alt="">
</div>
<dialog id="img-box">
<img class="img-preview" src="" alt="">
</dialog>
const dialog = document.getElementById('img-box')
const imgItems = document.querySelectorAll('.img-item')
const imgPreview = document.querySelector('.img-preview')
var dragEl = null
imgItems.forEach(item => {
const src = item.getAttribute('src')
item.onclick = function () {
imgPreview.setAttribute('src', src)
dialog.showModal()
}
item.addEventListener('dragstart', handleStart, false)
item.addEventListener('dragover', handleOver, false)
item.addEventListener('drop', handleDrop, false)
})
dialog.onclick = function () {
dialog.close()
}
function handleStart (e) {
dragEl = this
e.dataTransfer.effectAllowed = 'move'
e.dataTransfer.setData('Text', e.target.src)
}
function handleOver (e) {
if (e.preventDefault) {
e.preventDefault()
}
e.dataTransfer.dropEffect = 'move'
return false
}
function handleDrop(e) {
if (e.stopPropagation) {
e.stopPropagation()
}
if (dragEl != this) {
dragEl.src = this.src
this.src = e.dataTransfer.getData('Text')
}
return false
}
<div class="drag-container">
<img draggable data-src="https://bookcover.yuewen.com/qdbimg/349573/1010734492/300"
src="https://bookcover.yuewen.com/qdbimg/349573/1010734492/150">
<img draggable data-src="https://bookcover.yuewen.com/qdbimg/349573/1010868264/300"
src="https://bookcover.yuewen.com/qdbimg/349573/1010868264/150">
<img draggable data-src="https://bookcover.yuewen.com/qdbimg/349573/3602691/300"
src="https://bookcover.yuewen.com/qdbimg/349573/3602691/150">
<img draggable data-src="https://bookcover.yuewen.com/qdbimg/349573/1010400217/600"
src="https://bookcover.yuewen.com/qdbimg/349573/1010400217/150">
</div>
.drag-container {
width: 500px;
}
.drag-container img {
cursor: pointer;
width: 150px;
object-fit: cover;
transition: all 0.5s;
margin: 5px;
}
// 1.
function showDialog(dom) {
var dialog
if (document.querySelector('dialog[data-use=imgPreview]')) {
dialog = document.querySelector('dialog[data-use=imgPreview]')
dialog.innerHTML = ''
} else {
dialog = document.createElement('dialog')
dialog.dataset.use = "imgPreview"
dialog.style.position = "fixed"
dialog.style.left = 0
dialog.style.right = 0
dialog.style.bottom = 0
dialog.style.top = 0
document.body.appendChild(dialog)
dialog.addEventListener('click', (e) => {
dialog.close()
})
}
dialog.appendChild(dom)
dialog.showModal()
}
document.querySelector(".drag-container").addEventListener('click', (e) => {
let self = e.target
if (self.tagName === 'IMG') {
let img = document.createElement('img')
img.style.maxWidth = "80vw"
img.style.maxHeight = "80vh"
img.src = self.dataset.src
showDialog(img)
}
})
// 2.
function dragSort(dom) {
var dragged
dom.addEventListener("dragstart", function (e) {
dragged = e.target
// 使其透明
e.target.style.opacity = 0
}, false)
dom.addEventListener("dragend", function (e) {
// 重置透明度
e.target.style.opacity = ""
}, false)
dom.addEventListener("dragover", function (e) {
// 阻止默认动作
e.preventDefault()
if (e.target.tagName == "IMG") {
let parent = e.target.parentNode
let next = dragged.nextSibling
parent.insertBefore(dragged, e.target)
parent.insertBefore(e.target, next)
}
}, false)
}
dragSort(document.querySelector(".drag-container"))
感觉有少许bug demo
//zxx: 点击任意位置隐藏弹框;拖拽动画有些多余。
.img-list {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
width: 400px;
border: 1px solid #eeeeee;
margin: auto;
cursor: pointer;
}
.pad {
width: 30%;
}
.img-item {
width: 30%;
margin: 1.25% 0;
border: 1px solid #ececec;
box-sizing: border-box;
transition: width .2s linear;
}
dialog img {
width: 100%;
transition: all 2s linear;
cursor: pointer;
user-select: none;
}
dialog {
width: 40vw;
}
<div class="img-list">
<img class="img-item" src="http://b-ssl.duitang.com/uploads/item/201610/12/20161012010005_dHfu8.jpeg" alt="">
<img class="img-item"
src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1572541328333&di=68f44f6742fe3f5dc860b6de5be7b591&imgtype=0&src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F019a8058464281a8012060c822b94f.jpg"
alt="">
<img class="img-item"
src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1573223264&di=5608a4a1e45db8c28cd81330e6456495&imgtype=jpg&er=1&src=http%3A%2F%2Fi1.hdslb.com%2Fbfs%2Fface%2F476d919128aa86b46b6b192d1a0c33dde6a8db03.jpg"
alt="">
<img class="img-item"
src="https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=1540585939,4136794415&fm=26&gp=0.jpg" alt="">
<i class="pad"></i>
<i class="pad"></i>
<i class="pad"></i>
</div>
<dialog><img src="" alt=""></dialog>
const dialog = document.querySelector('dialog')
const imglist = document.querySelector('.img-list')
let dragTarget
document.querySelectorAll('.img-item').forEach(item => {
// 第二题
item.addEventListener('dragstart', dragstart)
item.addEventListener('dragend', dragend)
item.addEventListener('dragenter', dragenter)
// 第一题
item.addEventListener('click', (e) => {
dialog.querySelector(':root img').src = e.target.src
document.querySelector('dialog').showModal()
setTimeout(() => {
window.addEventListener('click', closeDialog)
})
})
})
document.querySelector('dialog img').addEventListener('click', e => {
e.stopPropagation()
})
function closeDialog() {
dialog.close()
window.removeEventListener('click', closeDialog)
}
function dragstart(event) {
dragTarget = event.target
event.target.style.opacity = '0'
}
function dragenter(e) {
const target = event.target
if (target !== dragTarget) {
dragTarget.style.width = '0'
console.log(target)
if (target.previousElementSibling === dragTarget) {
imglist.insertBefore(dragTarget, target.nextElementSibling)
} else {
imglist.insertBefore(dragTarget, target)
}
}
setTimeout(() => {
dragTarget.style.width = ''
})
}
function dragend(event) {
dragTarget.style.opacity = '1'
const last = imglist.querySelector('.img-item:last-of-type')
if (event.pageX > (last.offsetLeft + last.clientWidth), event.pageY > last.offsetTop) {
imglist.insertBefore(dragTarget, imglist.querySelector('.pad:first-of-type'))
}
}
//zxx: 拖不动,除了拖到最后
wingmeng: 多谢张老师,昨晚太困了 js 逻辑没写完 :cry: ,今早才补完的
.img-list {
display: flex;
flex-wrap: wrap;
width: 260px;
background: #fff;
border: 1px solid #ccc;
transition: all .2s;
}
.img-list.is-dragenter {
background: #ffd;
border-color: #333;
}
.img-list > img {
max-width: 33.3333%;
padding: 2px;
box-sizing: border-box;
cursor: move;
}
.img-preview img {
display: block;
max-width: 100%;
}
.img-preview::backdrop {background: rgba(0, 0, 0, .6);}
<div class="img-list" id="imgList">
<img src="https://cdn.pixabay.com/photo/2014/12/30/13/19/girls-583917_960_720.jpg" alt="海边女孩">
<img src="https://cdn.pixabay.com/photo/2019/10/21/10/33/garden-4565700_960_720.jpg" alt="花园">
<img src="https://cdn.pixabay.com/photo/2019/10/27/18/48/chinatown-4582511_960_720.jpg" alt="都市">
<img src="https://cdn.pixabay.com/photo/2016/12/03/14/20/woman-1879905_960_720.jpg" alt="金发女郎">
<img src="https://cdn.pixabay.com/photo/2019/10/08/18/13/matterhorn-4535693_960_720.jpg" alt="山峰">
<img src="https://cdn.pixabay.com/photo/2017/04/22/10/15/sport-2250970_960_720.jpg" alt="运动">
<img src="https://cdn.pixabay.com/photo/2013/06/10/09/23/morocco-123978_960_720.jpg" alt="沙漠">
</div>
const viewImgList = {
init(selector) {
this.el = document.querySelector(selector);
this.dialog = null;
this.bindClick();
this.bindDrag();
},
bindClick() {
// 图片点击事件
this.el.addEventListener('click', e => {
if (e.target.tagName.toLowerCase() === 'img') {
this.togglePreview(e.target.src);
}
});
// 任意位置点击
window.addEventListener('click', e => {
if (!this.el.contains(e.target)) {
this.togglePreview(false);
}
});
},
bindDrag() {
let imgElm = null;
const isInside = elm => elm === this.el || this.el.contains(elm);
// 拖动开始
this.el.addEventListener('dragstart', e => {
e.target.style.opacity = 0;
imgElm = e.target;
});
// 拖动结束
this.el.addEventListener('dragend', e => e.target.style.opacity = '');
// 放置目标
document.addEventListener('dragover', e => {
if (isInside(e.target)) {
e.preventDefault();
if (e.target === this.el) {
this.el.appendChild(imgElm);
} else {
const compareValue = imgElm.compareDocumentPosition(e.target);
if (compareValue === 2) { // 目标图片在前
e.target.before(imgElm); // 添加到目标图片前面
} else if (compareValue === 4) { // 目标对象在后
e.target.after(imgElm); // 添加到目标图片后面
}
}
}
});
// 进入目标区域
document.addEventListener('dragenter', e => {
this.el.classList[isInside(e.target) ? 'add' : 'remove']('is-dragenter');
});
// 允许放置
this.el.addEventListener('drop', e => {
e.preventDefault();
this.el.classList.remove('is-dragenter');
});
},
togglePreview(src) {
if (src) {
this.buildDialog(src);
this.dialog && !this.dialog.open && this.dialog.showModal();
} else {
this.dialog && this.dialog.close();
this.destoryDialog();
}
},
buildDialog(imgSrc) {
const dialog = document.createElement('dialog');
const img = new Image();
dialog.className = 'img-preview';
img.src = imgSrc;
this.dialog = dialog;
dialog.appendChild(img);
document.body.appendChild(dialog);
},
destoryDialog() {
this.dialog && document.body.removeChild(this.dialog);
this.dialog = null;
}
};
viewImgList.init('#imgList');
先打个卡,明天早起来做
<div class="img-list">
<img class="img-item" src="https://img.alicdn.com/imgextra/i4/3015214310/O1CN01OFcLG71hi1c3MRrLi_!!0-item_pic.jpg_60x60q90.jpg" data-big="https://img.alicdn.com/imgextra/i4/3015214310/O1CN01OFcLG71hi1c3MRrLi_!!0-item_pic.jpg_430x430q90.jpg">
<img class="img-item" src="https://img.alicdn.com/imgextra/i2/3015214310/O1CN01eZhuJs1hi1ay8z3ti_!!3015214310.jpg_60x60q90.jpg" data-big="https://img.alicdn.com/imgextra/i2/3015214310/O1CN01eZhuJs1hi1ay8z3ti_!!3015214310.jpg_430x430q90.jpg">
<img class="img-item" src="https://img.alicdn.com/imgextra/i2/3015214310/O1CN01wydRvC1hi1antaUhp_!!3015214310.jpg_60x60q90.jpg" data-big="https://img.alicdn.com/imgextra/i2/3015214310/O1CN01wydRvC1hi1antaUhp_!!3015214310.jpg_430x430q90.jpg">
<img class="img-item" src="https://img.alicdn.com/imgextra/i2/3015214310/O1CN013la2Oc1hi1awuC1Ha_!!3015214310.jpg_60x60q90.jpg" data-big="https://img.alicdn.com/imgextra/i2/3015214310/O1CN013la2Oc1hi1awuC1Ha_!!3015214310.jpg_430x430q90.jpg">
</div>
let imgDialog
let imgList = document.querySelector('.img-list')
let imgItems = document.querySelectorAll('.img-item')
let source,target
let sourceIndex,targetIndex
//1. 预览弹框-打开
imgItems.forEach(function(item){
(function(ele){
ele.addEventListener('click',function(e){
event.stopPropagation()
let bigImg = e.target.getAttribute('data-big')
openPreview(bigImg)
})
}(item))
})
function openPreview(url){
if(!imgDialog){
imgDialog = document.createElement('dialog')
imgDialog.className = 'img-dialog'
let bigImg = document.createElement('img')
imgDialog.appendChild(bigImg)
document.body.appendChild(imgDialog)
}
imgDialog.querySelector('img').setAttribute('src',url)
imgDialog.show()
}
//1. 预览弹框-关闭
document.addEventListener('click',function(e){
if(imgDialog&&imgDialog.open) {
if(!imgDialog.contains(e.target)){
imgDialog.close()
}
}
})
imgList.addEventListener('dragstart',startDrag,false)
imgList.addEventListener('dragover', function (e) {
e.preventDefault()
}, false)
imgList.addEventListener("dragenter", function (e) {
if (e.target.className === 'img-item') {
e.target.classList.add('enter');
}
target = e.target
targetIndex = [].slice.call(document.querySelectorAll('.img-item')).indexOf(e.target)
}, false);
imgList.addEventListener("dragleave", function (event) {
if (/enter/.test(event.target.classList)) {
event.target.classList.remove('enter')
}
}, false);
imgList.addEventListener('drop', exchangeEle, false)
function startDrag(e) {
source = e.target
sourceIndex = [].slice.call(document.querySelectorAll('.img-item')).indexOf(e.target)
}
//2. 拖拽小图改变顺序
function exchangeEle(e) {
e.preventDefault();
if(targetIndex < 0){
return
}
event.target.classList.remove('enter')
source.remove()
if(sourceIndex < targetIndex){
target.after(source)
}else{
target.before(source)
}
}
本期要点:
本期小测温习下dialog元素,以及常见的拖拽排序实现。
素材图大家自己随便找找,建议用大图,实在找不到可以使用 www.qidian.com 上的书封图。
积分:3+3
大家提交回答的时候,注意缩进距离,起始位置从左边缘开始;另外,github自带代码高亮,所以请使用下面示意的格式(缩进和代码高亮1积分)。
**心怀瑞雪,自己作答,不要参考别人回答**
其他 本周六11月2日上午10:00答疑,直播地址:https://live.bilibili.com/21193211
每位答题者会有至少2积分参与分,本次小测满分10积分。
首位答题者将会获得100%被翻牌的技能。