使用JavaScript下载图片并保存到本地,超详细
将选中的图片下载到本地1.先获取到图片信息2.设置图片信息3.图片下载实现原理解释
·
将选中的图片下载到本地
1.先获取到图片信息
2.设置图片信息
3.图片下载实现原理解释
- 首先,创建一个新的 Image 对象,并将图片的 URL 赋值给它。
- 通过设置 crossOrigin 属性为 “Anonymous”,解决跨域访问的问题。
- 当图片加载完成后,创建一个新的 canvas 元素,并将图片绘制到 canvas 上。
- 创建一个新的 a元素作为下载链接,并设置下载的文件名为 imgName ,
a.download = filename || url.split('/').pop() || 'downloaded_image.jpg'
。 - 将 canvas 的数据转换为 Data URL,并将其赋值给下载链接的 href 属性。
- 最后,模拟用户点击下载链接,触发图片下载的操作。
js代码
async function downloadImage(url, filename) {
try {
// 创建img元素
const img = new Image();
img.crossOrigin = 'Anonymous'; // 设置跨域
// 加载图片
await new Promise((resolve, reject) => {
img.onload = resolve;
img.onerror = reject;
img.src = url + '?t=' + Date.now(); // 添加时间戳防止缓存
});
// 创建canvas并绘制图片
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
// 转换为Blob并下载
canvas.toBlob(blob => {
const blobUrl = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = blobUrl;
a.download = filename || url.split('/').pop() || 'downloaded_image.jpg';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(blobUrl);
}, 'image/jpeg');
} catch (error) {
console.error('下载失败:', error);
// alert('图片下载失败: ' + error.message);
}
}
function downloadSelectedImages() {
const selectedCheckboxes = document.querySelectorAll('.gallery-item input[type="checkbox"]:checked');
if (selectedCheckboxes.length === 0) {
alert('请先选择要下载的图片');
return;
}
selectedCheckboxes.forEach(checkbox => {
const img = checkbox.closest('.gallery-item').querySelector('img');
const imgUrl = img.src;
const filename = imgUrl.split('/').pop() || 'downloaded_image.jpg';
downloadImage(imgUrl, filename);
});
}
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Image_Gallery图片采集</title>
<style>
/* 全局样式 */
* {
padding: 0;
margin: 0;
}
body {
font-family: Arial, sans-serif;
}
.imgMain {
width: 99%;
min-height: 100%;
border: 1px solid #ccc;
margin: 10px;
}
/* 标题样式 */
.header {
font-size: 20px;
font-weight: bold;
padding: 10px 10px;
border-bottom: 1px solid #ccc;
}
/* 副标题样式 */
.sub-header {
width: 95%;
font-size: 18px;
font-weight: bold;
margin: 20px auto;
display: flex;
}
.sub-header-space {
width: 500px;
height: 2px;
margin-top: 11px;
border-bottom: 1px solid #ccc;
}
.sub-header-item {
color: #ccc;
}
.sub-header-item-selected {
color: #333;
}
/* 图片库样式 */
.gallery {
display: flex;
flex-wrap: wrap;
align-content: flex-start;
width: 95%;
height: 680px;
margin: 0 auto;
gap: 5px;
overflow: auto;
}
/*滚动条样式*/
.gallery::-webkit-scrollbar {
width: 8px;
}
.gallery::-webkit-scrollbar,
.gallery::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 5px rgba(63, 136, 219, 0.5);
background: rgba(10, 109, 238, 0.5);
}
.gallery::-webkit-scrollbar,
.gallery::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.5);
border-radius: 0;
background: rgba(0, 0, 0, 0.1);
}
.gallery-item {
position: relative;
width: 100px;
height: 100px;
margin: 5px;
}
.gallery-item img {
width: 100%;
height: 100%;
object-fit: cover;
cursor: pointer;
border: 2px solid #2e8cf0;
/* 添加默认边框线 */
box-sizing: border-box;
/* 确保边框不占用额外空间 */
}
.gallery-item img.selected {
border-color: blue;
/* 选中图片的边框颜色 */
}
.gallery-item input[type="checkbox"] {
position: absolute;
top: 5px;
left: 5px;
z-index: 1;
width: 26px;
height: 26px;
}
/* 模态框样式 */
.modal {
display: none;
position: fixed;
z-index: 1;
padding-top: 60px;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.9);
}
.modal-content {
margin: auto;
display: block;
max-width: 80%;
max-height: 80%;
}
.close {
position: absolute;
top: 20px;
right: 35px;
color: #fff;
font-size: 40px;
font-weight: bold;
transition: 0.3s;
cursor: pointer;
}
.close:hover {
color: #bbb;
}
.nextButtonBox {
width: 100%;
margin-top: 20px;
border-top: 1px solid #ccc;
height: 74px;
position: relative;
left: 0;
}
/* 下一步按钮样式 */
.next-button {
margin-top: 20px;
padding: 10px 20px;
background-color: #2d8cf0;
color: white;
border: none;
cursor: pointer;
position: absolute;
right: 20px;
}
.next-button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
/* 新增删除按钮样式 */
.delete-btn {
position: absolute;
top: 2px;
right: 2px;
width: 20px;
height: 20px;
background: rgba(255, 0, 0, 0.8);
border-radius: 50%;
color: white;
text-align: center;
line-height: 20px;
cursor: pointer;
display: none;
z-index: 2;
}
.delete-btn::after {
content: "×";
font-size: 18px;
}
.gallery-item:hover .delete-btn {
display: block;
}
/* 步骤容器 */
.step-container {
display: none;
padding: 10px;
}
.step-container.active {
display: block;
}
/*滚动条样式*/
.info-table::-webkit-scrollbar {
width: 8px;
}
.info-table::-webkit-scrollbar,
.info-table::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 5px rgba(63, 136, 219, 0.5);
background: rgba(10, 109, 238, 0.5);
}
.info-table::-webkit-scrollbar,
.info-table::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.5);
border-radius: 0;
background: rgba(0, 0, 0, 0.1);
}
/* 表格样式 */
.info-table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
/* 设置表头为块级元素,以便与tbody对齐 */
.info-table thead,
tbody tr {
display: table;
width: 100%;
table-layout: fixed;
}
/* 设置tbody为块级元素,并限制高度 */
.info-table tbody {
display: block;
min-height: 500px;
max-height: 580px;
/* 设置最大高度 */
overflow-y: auto;
/* 当内容超过高度时显示垂直滚动条 */
}
/* 设置表头的样式 */
.info-table thead {
width: calc(100% - 1em);
/* 减去滚动条的宽度 */
}
.info-table tbody td select {
width: 180px;
}
.info-table th,
.info-table td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
.info-table th {
background-color: #f2f2f2;
text-align: center;
}
.info-table input {
width: 100%;
padding: 5px;
box-sizing: border-box;
}
.info-table tbody tr {
min-height: 50px;
}
/* 操作按钮 */
.action-buttons {
display: flex;
gap: 10px;
position: relative;
left: 0;
min-width: 700px;
}
.error-msg {
display: none;
color: #515a6e;
margin-top: 10px;
position: absolute;
padding: 10px;
border-radius: 6px;
top: 0;
left: 50%;
width: 800px;
text-align: center;
margin-left: -400px;
background: #fff;
/* border: 1px solid #ccc; */
}
.msg-success {
border: 1px solid #8ce6b0;
background-color: #edfff3;
}
.msg-error {
border: 1px solid #ffb08f;
background-color: #ffefe6;
}
/* 表头设置样式 */
.header-setting {
/* display: flex; */
align-items: center;
gap: 5px;
}
.header-setting input {
width: 150px;
}
.header-setting button {
padding: 5px 10px;
background-color: #2d8cf0;
color: white;
border: none;
cursor: pointer;
}
a {
text-decoration: none;
color: #444;
transition: all .3s;
}
div,
img,
ul,
li,
em,
p,
span {
margin: 0;
padding: 0;
}
ul,
li {
list-style: none;
}
em,
p,
span,
i {
font-style: normal;
}
input,
select,
textarea,
button {
margin: 0;
padding: 0;
font-size: 14px;
font-family: 'Source Han Sans SC', 'PingFang SC', 'Microsoft YaHei', Helvetica, Arial, sans-serif;
}
/*分页*/
.mo-pagination {
min-width: 800px;
display: block;
overflow: hidden;
}
.mo-pagination-btn {
float: left;
height: 30px;
line-height: 28px;
box-sizing: border-box;
border: 1px solid #ddd;
background: #fff;
padding: 0 10px;
margin: 0 5px 5px 0;
display: block;
overflow: hidden;
cursor: pointer;
transition: all .3s;
border-radius: 6px;
}
.mo-pagination-btn:hover {
color: #068EFF;
border-color: #068EFF;
}
.mo-pagination-disabled {
pointer-events: none;
opacity: .5;
cursor: not-allowed;
}
.mo-pagination-select {
float: left;
display: block;
overflow: hidden;
line-height: 30px;
margin: 0 5px 5px 0;
}
.mo-pagination-select em {
float: left;
}
.mo-pagination-select select {
float: left;
height: 30px;
line-height: 28px;
border: 1px solid #ddd;
background: #fff;
padding: 0 10px;
margin: 0 5px;
display: block;
overflow: hidden;
transition: all .3s;
border-radius: 6px;
}
.mo-pagination-select select:hover {
border-color: #068EFF;
}
.mo-pagination-mark {
float: left;
height: 30px;
line-height: 30px;
padding: 0 10px;
margin: 0 5px 5px 0;
display: block;
overflow: hidden;
}
.mo-pagination-num {
float: left;
display: block;
overflow: hidden;
margin: 0 5px 5px 0;
}
.mo-pagination-num a {
float: left;
width: 30px;
text-align: center;
height: 30px;
line-height: 28px;
box-sizing: border-box;
border: 1px solid #ddd;
margin: 0 3px;
display: block;
overflow: hidden;
cursor: pointer;
border-radius: 50%;
}
.mo-pagination-num a.active {
color: #068EFF;
border-color: #068EFF;
}
.mo-pagination-enter {
float: left;
display: block;
overflow: hidden;
line-height: 30px;
}
.mo-pagination-enter em {
float: left;
}
.mo-pagination-enter input {
width: 50px;
height: 30px;
text-align: center;
line-height: 28px;
box-sizing: border-box;
border: 1px solid #ddd;
background: #fff;
float: left;
margin: 0 5px;
transition: all .3s;
border-radius: 6px;
}
.mo-pagination-enter input:hover {
color: #068EFF;
border-color: #068EFF;
}
.stepButtonBox {
width: 100%;
margin-top: 20px;
border-top: 1px solid #ccc;
height: 74px;
position: relative;
left: 0;
}
/* 下一步按钮样式 */
.step-button {
margin-top: 20px;
padding: 10px 20px;
background-color: #2d8cf0;
color: white;
border: none;
cursor: pointer;
position: absolute;
right: 20px;
}
</style>
</head>
<body>
<div class="imgMain">
<!-- 步骤1:选择图片 -->
<div id="step1" class="step-container active">
<!-- 原有图片选择界面 -->
<!-- 标题 -->
<div class="header">图片采集 <span style="color: #2d8cf0;">/ 添加至侵权图库</span></div>
<!-- 副标题:选择需保留的图片 -->
<div class="sub-header">
<div class="sub-header-item sub-header-item-selected">
1.选择需保留的图片
</div>
<div class="sub-header-space"></div>
<div class="sub-header-item">
2.填写图片信息
</div>
</div>
<!-- 图片库 -->
<div class="gallery" id="gallery">
<!-- Images will be dynamically inserted here -->
</div>
<!-- 模态框 -->
<div id="myModal" class="modal">
<span class="close">×</span>
<img class="modal-content" id="img01">
</div>
<!-- 下一步按钮 -->
<div class="nextButtonBox">
<button class="next-button" style="right: 210px;" onclick="downloadSelectedImages()">下载选中图片</button>
<button class="next-button" style="right: 120px;" onclick="toggleAll()">全选</button>
<button id="nextButton" class="next-button" disabled>下一步</button>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.0.0.min.js"></script>
<script>
const images = [
'https://cbu01.alicdn.com/img/ibank/O1CN01qSXOXm1jPpTzR7GUs_!!2215737524541-0-cib.jpg_b.jpg',
'http://10.100.1.200:8888/public/2023-09/22-20-08-37-666/6EE713438-DG.jpg',
'http://10.100.1.200:8888/public/2019-06/06-20-20-51-764/7HH401674.jpg',
'http://10.100.1.200:8888/public/2023-09/20-11-13-45-329/6EE713378-R.jpg',
'http://10.100.1.200:8888/public/2023-11/16-17-22-54-092/1AG202989-E-S.jpg',
'http://10.100.1.200:8888/public/2023-04/14-18-03-29-123/6EE107530-R.jpg',
'http://10.100.1.200:8888/public/2022-09/19-14-12-31-471/8YY204605.jpg'
];
const gallery = document.getElementById('gallery');
const modal = document.getElementById('myModal');
const modalImg = document.getElementById('img01');
const nextButton = document.getElementById('nextButton');
// 下载选中图片功能
// async function downloadImage(url, filename) {
// try {
// // 方案1:使用图片代理(推荐)
// const proxyUrl = `https://cors-anywhere.herokuapp.com/${url}`;
// const response = await fetch(proxyUrl, {
// headers: new Headers({
// 'Origin': window.location.origin,
// 'Cache-Control': 'no-cache'
// })
// });
// // const response = await fetch(url + '?t=' + Date.now(), { // 添加时间戳防止缓存
// // headers: new Headers({
// // 'Cache-Control': 'no-cache'
// // })
// // });
// if (!response.ok && response.type !== 'opaque') {
// throw new Error(`HTTP error! status: ${response.status}`);
// }
// const blob = await response.blob();
// const blobUrl = window.URL.createObjectURL(blob);
// const a = document.createElement('a');
// a.href = blobUrl;
// a.download = filename;
// document.body.appendChild(a);
// a.click();
// window.URL.revokeObjectURL(blobUrl);
// document.body.removeChild(a);
// } catch (error) {
// console.error('下载失败:', error);
// // alert('部分图片下载失败,请检查控制台日志');
// }
// }
async function downloadImage(url, filename) {
try {
// 创建img元素
const img = new Image();
img.crossOrigin = 'Anonymous'; // 设置跨域
// 加载图片
await new Promise((resolve, reject) => {
img.onload = resolve;
img.onerror = reject;
img.src = url + '?t=' + Date.now(); // 添加时间戳防止缓存
});
// 创建canvas并绘制图片
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
// 转换为Blob并下载
canvas.toBlob(blob => {
const blobUrl = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = blobUrl;
a.download = filename || url.split('/').pop() || 'downloaded_image.jpg';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(blobUrl);
}, 'image/jpeg');
} catch (error) {
console.error('下载失败:', error);
// alert('图片下载失败: ' + error.message);
}
}
function downloadSelectedImages() {
const selectedCheckboxes = document.querySelectorAll('.gallery-item input[type="checkbox"]:checked');
if (selectedCheckboxes.length === 0) {
alert('请先选择要下载的图片');
return;
}
selectedCheckboxes.forEach(checkbox => {
const img = checkbox.closest('.gallery-item').querySelector('img');
const imgUrl = img.src;
const filename = imgUrl.split('/').pop() || 'downloaded_image.jpg';
downloadImage(imgUrl, filename);
});
}
let isAllSelected = false; // 全局状态记录全选状态
function toggleAll() {
const checkboxes = document.querySelectorAll('.gallery-item input[type="checkbox"]');
isAllSelected = !isAllSelected; // 切换全选/反选状态
checkboxes.forEach(checkbox => {
checkbox.checked = isAllSelected;
});
updateNextButton(); // 更新下一步按钮状态
updateButtonText(); // 更新按钮文字
}
function updateButtonText() {
const btn = document.querySelector('.next-button[style*="right: 120px"]');
btn.textContent = isAllSelected ? '反选' : '全选';
}
// 初始化数据
var initialImages = [
// "http://10.100.1.200:8888/public/2024-08/15-18-57-39-747/13AC1304299.jpg",
// "http://10.100.1.200:8888/public/2024-08/28-10-16-59-448/2SS322764.jpg"
];
// Function to update the next button state
function updateNextButton() {
const selectedImages = document.querySelectorAll('.gallery-item input[type="checkbox"]:checked');
nextButton.disabled = selectedImages.length === 0;
}
// Function to handle the next step
function handleNextStep() {
const selectedImages = document.querySelectorAll('.gallery-item input[type="checkbox"]:checked');
const selectedImageUrls = Array.from(selectedImages).map(checkbox => {
return checkbox.closest('.gallery-item').querySelector('img').src;
});
console.log("img", selectedImageUrls);
initialImages = selectedImageUrls
// alert('Selected Images: ' + selectedImageUrls.join(', '));
}
// 修改图片创建逻辑,增加删除按钮
function createGalleryItems() {
images.forEach((src, index) => {
const galleryItem = document.createElement('div');
galleryItem.className = `gallery-item Image_${index + 1}`;
// 创建删除按钮
const deleteBtn = document.createElement('div');
deleteBtn.className = 'delete-btn';
// 删除按钮点击事件
deleteBtn.addEventListener('click', function (e) {
e.stopPropagation(); // 阻止事件冒泡
galleryItem.remove(); // 移除图片项
updateNextButton(); // 更新按钮状态
});
const img = document.createElement('img');
img.src = src;
img.alt = `Image ${index + 1}`;
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.addEventListener('change', updateNextButton);
img.addEventListener('click', function () {
// if (!checkbox.checked) {
modal.style.display = 'block';
modalImg.src = this.src;
// }
});
galleryItem.appendChild(deleteBtn); // 添加删除按钮
galleryItem.appendChild(checkbox);
galleryItem.appendChild(img);
gallery.appendChild(galleryItem);
});
}
// Close modal when clicking the close button
document.querySelector('.close').addEventListener('click', function () {
modal.style.display = 'none';
});
// Handle next button click
nextButton.addEventListener('click', handleNextStep);
// 延迟两秒钟执行图片创建逻辑
document.addEventListener('DOMContentLoaded', () => {
setTimeout(() => {
createGalleryItems();
}, 1000); // 延迟两秒钟
});
// 全局数据存储
let allData = [];
let currentStep = 1;
let currentPage = 1;
let pageSize = 10;
let totalImages = 0;
// 步骤切换
function goToStep(step) {
console.log('步骤切换', step);
document.querySelectorAll('.step-container').forEach(el => {
el.classList.remove('active');
});
document.getElementById(`step${step}`).classList.add('active');
// currentStep = step;
if (step === 2) {
initPagination();
generateTable(initialImages);
}
}
function goBack() {
goToStep(1);
}
// 初始化
document.addEventListener('DOMContentLoaded', () => {
// 从第一步的下一步按钮调用
document.getElementById('nextButton').addEventListener('click', () => {
goToStep(2);
});
});
</script>
</body>
</html>
更多推荐
所有评论(0)