<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">动态模糊 · 图片批量工具</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background: #0b0d15;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
padding: 20px;
}
.card {
max-width: 1000px;
width: 100%;
background: rgba(20, 24, 32, 0.8);
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
border-radius: 48px;
padding: 32px 28px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.6), inset 0 0 0 1px rgba(255, 255, 255, 0.04);
transition: box-shadow 0.2s;
}
h1 {
display: flex;
align-items: center;
gap: 12px;
font-weight: 500;
font-size: 1.8rem;
letter-spacing: -0.01em;
color: #eef2ff;
margin-bottom: 24px;
}
h1 span {
background: #2b324a;
padding: 4px 14px;
border-radius: 80px;
font-size: 0.9rem;
font-weight: 400;
color: #b3c2e2;
}
.toolbar {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 16px 20px;
margin-bottom: 28px;
background: #10131f;
padding: 16px 20px;
border-radius: 60px;
border: 1px solid #2a3147;
}
.btn {
background: #252d44;
border: none;
padding: 10px 20px;
border-radius: 40px;
font-weight: 450;
font-size: 0.95rem;
color: #d6e2ff;
display: inline-flex;
align-items: center;
gap: 8px;
cursor: pointer;
transition: 0.2s;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
border: 1px solid #3e4762;
flex-shrink: 0;
}
.btn-primary {
background: #4a5bcd;
border-color: #6e7ee0;
color: white;
box-shadow: 0 4px 10px rgba(74, 91, 205, 0.25);
}
.btn-primary:hover {
background: #5d6fdf;
transform: scale(1.02);
}
.btn-primary:active {
transform: scale(0.96);
}
.btn-outline {
background: transparent;
border: 1px solid #3f4a6b;
color: #b9c8f0;
}
.btn-outline:hover {
background: #1c233b;
border-color: #6574a8;
}
.btn:active {
transform: scale(0.96);
}
.blur-slider {
display: flex;
align-items: center;
gap: 14px;
flex: 1;
min-width: 160px;
}
.blur-slider label {
color: #b5c5f0;
font-size: 0.9rem;
white-space: nowrap;
}
input[type="range"] {
-webkit-appearance: none;
appearance: none;
background: #262f4a;
height: 6px;
border-radius: 6px;
flex: 1;
min-width: 80px;
outline: none;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 18px;
height: 18px;
border-radius: 20px;
background: #7f92f0;
border: 2px solid #b6c6ff;
cursor: pointer;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
transition: 0.1s;
}
input[type="range"]::-webkit-slider-thumb:hover {
transform: scale(1.12);
background: #95a6ff;
}
.blur-value {
min-width: 44px;
text-align: center;
font-weight: 500;
color: #dce6ff;
background: #1b2136;
padding: 4px 8px;
border-radius: 40px;
font-size: 0.9rem;
}
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 20px;
margin: 20px 0 10px;
}
.image-card {
background: #141b2b;
border-radius: 28px;
overflow: hidden;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.5);
transition: transform 0.2s, box-shadow 0.3s;
aspect-ratio: 1 / 1;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #2b344f;
position: relative;
}
.image-card img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
transition: filter 0.2s ease;
will-change: filter;
}
.image-card .remove-btn {
position: absolute;
top: 10px;
right: 10px;
background: #0f1322cc;
backdrop-filter: blur(8px);
border: none;
width: 32px;
height: 32px;
border-radius: 40px;
color: #f0f4ff;
font-size: 20px;
line-height: 26px;
text-align: center;
cursor: pointer;
transition: 0.15s;
opacity: 0;
border: 1px solid #ffffff30;
display: flex;
align-items: center;
justify-content: center;
}
.image-card:hover .remove-btn {
opacity: 1;
}
.image-card .remove-btn:hover {
background: #d2435ccc;
transform: scale(1.05);
}
.empty-state {
grid-column: 1 / -1;
text-align: center;
padding: 64px 20px;
color: #8596c9;
background: #101624;
border-radius: 40px;
border: 1px dashed #2f3c62;
font-size: 1rem;
display: flex;
flex-direction: column;
gap: 8px;
align-items: center;
}
.empty-state svg {
opacity: 0.6;
margin-bottom: 8px;
}
.footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 18px;
color: #6b7db0;
font-size: 0.85rem;
flex-wrap: wrap;
gap: 8px;
}
.footer .count {
background: #1b233b;
padding: 6px 16px;
border-radius: 40px;
border: 1px solid #2c365a;
}
.clear-btn {
background: transparent;
border: none;
color: #8899d4;
text-decoration: underline dotted #3c4a78;
padding: 6px 12px;
cursor: pointer;
border-radius: 30px;
transition: 0.15s;
}
.clear-btn:hover {
color: #bbc8ff;
background: #181f38;
}
@media (max-width: 600px) {
.card { padding: 20px 16px; }
.toolbar { flex-wrap: wrap; padding: 14px; border-radius: 40px; }
.btn { padding: 8px 16px; font-size: 0.85rem; }
.gallery { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 12px; }
h1 { font-size: 1.4rem; }
}
</style>
</head>
<body>
<div class="card">
<h1>
⚡ 模糊工坊
<span>动态效果</span>
</h1>
<div class="toolbar">
<button class="btn btn-primary" id="addImageBtn">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12v3a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h3"/><path d="M15 6h6v6"/><path d="M10 14 21 3"/></svg>
添加图片
</button>
<div class="blur-slider">
<label>🌫️ 模糊</label>
<input type="range" id="blurRange" min="0" max="20" step="0.2" value="4">
<span class="blur-value" id="blurDisplay">4.0</span>
</div>
<button class="btn-outline btn" id="resetBlurBtn">重置</button>
</div>
<div class="gallery" id="galleryContainer">
<div class="empty-state" id="emptyPlaceholder">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#6574a8" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
<span>点击「添加图片」导入照片</span>
<span style="font-size: 0.8rem; opacity: 0.7;">支持 JPG / PNG / WebP</span>
</div>
</div>
<div class="footer">
<span class="count" id="imageCount">0 张图片</span>
<div>
<button class="clear-btn" id="clearAllBtn">清空全部</button>
</div>
</div>
</div>
<script>
(function(){
// DOM 元素
const gallery = document.getElementById('galleryContainer');
const emptyState = document.getElementById('emptyPlaceholder');
const addBtn = document.getElementById('addImageBtn');
const blurRange = document.getElementById('blurRange');
const blurDisplay = document.getElementById('blurDisplay');
const resetBlurBtn = document.getElementById('resetBlurBtn');
const clearAllBtn = document.getElementById('clearAllBtn');
const imageCount = document.getElementById('imageCount');
// 状态管理
let imageList = []; // 存储图片数据: { id, src (dataUrl) }
let currentBlur = 4; // 默认模糊值
let idCounter = 0;
// 更新模糊值显示
function updateBlurValue(val) {
const v = parseFloat(val);
blurDisplay.textContent = v.toFixed(1);
currentBlur = v;
}
// 应用模糊到所有图片
function applyBlurToAll() {
const imgs = gallery.querySelectorAll('.image-card img');
const blurValue = currentBlur;
imgs.forEach(img => {
img.style.filter = `blur(${blurValue}px)`;
});
}
// 渲染画廊 (基于 imageList)
function renderGallery() {
// 清空 gallery 但保留 empty-placeholder 引用
const items = gallery.querySelectorAll('.image-card');
items.forEach(el => el.remove());
if (imageList.length === 0) {
emptyState.style.display = 'flex';
imageCount.textContent = `0 张图片`;
return;
}
emptyState.style.display = 'none';
// 重新填充卡片
imageList.forEach(item => {
const card = document.createElement('div');
card.className = 'image-card';
card.dataset.id = item.id;
const img = document.createElement('img');
img.src = item.src;
img.alt = '模糊图片';
img.draggable = false;
// 应用当前模糊
img.style.filter = `blur(${currentBlur}px)`;
img.style.transition = 'filter 0.15s ease';
const removeBtn = document.createElement('button');
removeBtn.className = 'remove-btn';
removeBtn.innerHTML = '✕';
removeBtn.setAttribute('aria-label', '移除图片');
removeBtn.addEventListener('click', function(e) {
e.stopPropagation();
const id = parseInt(card.dataset.id);
removeImageById(id);
});
card.appendChild(img);
card.appendChild(removeBtn);
gallery.appendChild(card);
});
imageCount.textContent = `${imageList.length} 张图片`;
}
// 根据 id 移除图片
function removeImageById(id) {
imageList = imageList.filter(item => item.id !== id);
renderGallery();
}
// 清空全部图片
function clearAllImages() {
if (imageList.length === 0) return;
imageList = [];
renderGallery();
}
// 添加新图片 (从 File 对象)
function addImageFromFile(file) {
if (!file || !file.type.startsWith('image/')) return;
const reader = new FileReader();
reader.onload = function(e) {
const src = e.target.result;
const newItem = {
id: ++idCounter,
src: src
};
imageList.push(newItem);
renderGallery();
};
reader.readAsDataURL(file);
}
// 打开文件选择器
function openFilePicker() {
const input = document.createElement('input');
input.type = 'file';
input.accept = 'image/*';
input.multiple = true;
input.style.display = 'none';
document.body.appendChild(input);
input.addEventListener('change', function(e) {
const files = Array.from(e.target.files);
if (files.length === 0) {
document.body.removeChild(input);
return;
}
files.forEach(file => addImageFromFile(file));
document.body.removeChild(input);
});
input.click();
}
// ------ 事件绑定 ------
// 添加图片按钮
addBtn.addEventListener('click', openFilePicker);
// 模糊滑块
blurRange.addEventListener('input', function(e) {
const val = e.target.value;
updateBlurValue(val);
applyBlurToAll();
});
// 重置模糊 (设为0)
resetBlurBtn.addEventListener('click', function() {
blurRange.value = 0;
updateBlurValue(0);
applyBlurToAll();
});
// 清空按钮
clearAllBtn.addEventListener('click', clearAllImages);
// 额外: 点击空状态触发添加 (方便)
emptyState.addEventListener('click', openFilePicker);
// 初始化模糊显示
blurRange.value = currentBlur;
updateBlurValue(currentBlur);
// 初始无图片,无需渲染
renderGallery();
// 演示:内置两张示例图片(动态效果展示)
function loadDemoImages() {
// 第一个示例 (SVG 矢量风格抽象图 1)
const svg1 = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Crect width='200' height='200' fill='%231b253a'/%3E%3Ccircle cx='100' cy='90' r='60' fill='%233f5ec9' opacity='0.9'/%3E%3Ccircle cx='70' cy='70' r='30' fill='%237992f0' opacity='0.7'/%3E%3Cpolygon points='100,140 140,100 60,100' fill='%23ffb347' opacity='0.7'/%3E%3Ctext x='80' y='170' font-size='22' fill='%23bcccf0' font-weight='500'%3E🌆%3C/text%3E%3C/svg%3E`;
const svg2 = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Crect width='200' height='200' fill='%23202b42'/%3E%3Crect x='30' y='30' width='140' height='140' rx='40' fill='%23344b92' opacity='0.8'/%3E%3Ccircle cx='110' cy='80' r='40' fill='%23f9d976' opacity='0.6'/%3E%3Cpath d='M40 170 L80 110 L120 140 L170 70' stroke='%237aa2ff' stroke-width='6' fill='none' stroke-linecap='round' /%3E%3Ctext x='60' y='180' font-size='24' fill='%23b0c8ff' %3E✨%3C/text%3E%3C/svg%3E`;
// 以文件添加方式模拟 (以便展示移除效果)
// 但直接用 item 推入更简洁
const demoItem1 = { id: ++idCounter, src: svg1 };
const demoItem2 = { id: ++idCounter, src: svg2 };
imageList.push(demoItem1, demoItem2);
renderGallery();
}
// 启动演示 (若用户无图片则显示示例)
// 但我们可以考虑只在画廊为空时加载演示,并延迟片刻让用户看到空状态也可。
setTimeout(() => {
if (imageList.length === 0) {
loadDemoImages();
}
}, 300);
})();
</script>
</body>
</html>
图片模糊工具使用说明
您可以通过简单的操作,为多张图片添加统一的动态模糊效果。

- 图片管理:点击 “添加图片” 按钮,可从本地选择多张图片进行批量导入,每张图片右上角都有一个 按钮,方便您单独移除。
- 模糊调节:通过拖动 “模糊”滑块,您可以实时调整所有图片的模糊程度,数值范围从0到20,点击 “重置” 按钮可将模糊值快速归零。
- 状态反馈:页面底部会显示当前图片总数,当没有图片时,会显示引导提示,点击该区域也可触发图片添加。
标签: 批量处理
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播