Files
aurora-admin/frameworks/slider.html
T

177 lines
6.0 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Aurora Admin · Slider (H5)</title>
<link rel="stylesheet" href="../.design_library/aurora-admin/colors_and_type.css">
<link rel="stylesheet" href="./Slider.css">
<style>
.demo { padding: 24px; background: #F5F7FA; font-family: var(--font-family); }
h1 { font-size: 20px; margin: 0 0 4px; color: #1F2329; }
.sub { color: #8C8C8C; margin: 0 0 24px; font-size: 12px; }
.demo-block { background: #fff; border-radius: 8px; padding: 20px 24px; margin-bottom: 20px; }
.demo-block > .hint { color: #8C8C8C; font-size: 12px; margin: 0 0 12px; }
.slider-row { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.slider-row .lab { width: 72px; font-size: 13px; color: #262626; }
</style>
</head>
<body>
<div class="demo">
<h1>Aurora Admin · Slider 组件(纯 H5)</h1>
<p class="sub">对齐 SliderInput 规范:单/双滑块、刻度、输入框联动</p>
<div class="demo-block">
<p class="hint">单滑块 + 数值联动</p>
<div class="slider-row">
<span class="lab">音量</span>
<div class="aa-slider" data-slider data-min="0" data-max="100" data-value="30" data-input></div>
</div>
</div>
<div class="demo-block">
<p class="hint">带刻度</p>
<div class="aa-slider" data-slider data-min="0" data-max="100" data-step="10" data-value="50" data-ticks></div>
</div>
<div class="demo-block">
<p class="hint">双滑块范围</p>
<div class="aa-slider" data-slider data-range data-min="0" data-max="100" data-value="20,60"></div>
</div>
<div class="demo-block">
<p class="hint">禁用</p>
<div class="aa-slider is-disabled" data-slider data-min="0" data-max="100" data-value="40"></div>
</div>
</div>
<script>
function initSlider(root) {
const min = +root.dataset.min || 0, max = +root.dataset.max || 100, step = +root.dataset.step || 1;
const range = root.hasAttribute('data-range');
const showTicks = root.hasAttribute('data-ticks');
const showInput = root.hasAttribute('data-input');
let value = range
? root.dataset.value.split(',').map(Number)
: (+root.dataset.value || 0);
const track = document.createElement('div');
track.className = 'aa-slider-track';
track.innerHTML = '<div class="aa-slider-rail"></div><div class="aa-slider-fill"></div><div class="aa-slider-ticks"></div>';
if (range) {
track.insertAdjacentHTML('beforeend', '<div class="aa-slider-handle" data-i="0"></div><div class="aa-slider-handle" data-i="1"></div>');
} else {
track.insertAdjacentHTML('beforeend', '<div class="aa-slider-handle" data-i="0"></div>');
}
root.appendChild(track);
const valueWrap = document.createElement('div');
valueWrap.className = 'aa-slider-value';
if (showInput) {
if (range) {
valueWrap.innerHTML = '<input type="number"><span>—</span><input type="number">';
} else {
valueWrap.innerHTML = '<input type="number">';
}
root.appendChild(valueWrap);
valueWrap.querySelectorAll('input').forEach(inp => {
inp.addEventListener('change', () => {
if (range) {
const a = +valueWrap.querySelectorAll('input')[0].value;
const b = +valueWrap.querySelectorAll('input')[1].value;
value = [Math.min(a, b), Math.max(a, b)];
} else {
value = +inp.value;
}
paint();
});
});
}
const rail = track.querySelector('.aa-slider-rail');
const fill = track.querySelector('.aa-slider-fill');
const ticks = track.querySelector('.aa-slider-ticks');
const handles = [...track.querySelectorAll('.aa-slider-handle')];
if (showTicks) {
const n = Math.floor((max - min) / step);
for (let i = 0; i <= n; i++) {
const v = min + i * step;
const t = document.createElement('div');
t.className = 'aa-slider-tick';
t.style.left = ((v - min) / (max - min) * 100) + '%';
ticks.appendChild(t);
}
}
function clamp(v) { v = Math.round((v - min) / step) * step + min; return Math.max(min, Math.min(max, v)); }
function pct(v) { return (v - min) / (max - min) * 100; }
function fromClientX(x) {
const rect = track.getBoundingClientRect();
return clamp(min + (x - rect.left) / rect.width * (max - min));
}
function paint() {
if (range) {
const [lo, hi] = value;
fill.style.left = pct(lo) + '%';
fill.style.width = (pct(hi) - pct(lo)) + '%';
handles[0].style.left = pct(lo) + '%';
handles[1].style.left = pct(hi) + '%';
if (showInput) {
valueWrap.querySelectorAll('input')[0].value = lo;
valueWrap.querySelectorAll('input')[1].value = hi;
}
} else {
fill.style.left = '0%';
fill.style.width = pct(value) + '%';
handles[0].style.left = pct(value) + '%';
if (showInput) valueWrap.querySelector('input').value = value;
}
}
function startDrag(i, e) {
e.preventDefault();
const move = (ev) => {
const x = (ev.touches ? ev.touches[0].clientX : ev.clientX);
const nv = fromClientX(x);
if (range) {
value[i] = nv;
value.sort((a, b) => a - b); // 保持顺序
} else {
value = nv;
}
paint();
};
const up = () => {
document.removeEventListener('pointermove', move);
document.removeEventListener('pointerup', up);
};
document.addEventListener('pointermove', move);
document.addEventListener('pointerup', up);
}
handles.forEach((h, i) => {
h.addEventListener('pointerdown', (e) => startDrag(i, e));
});
// 点击轨道定位最近的手柄
track.addEventListener('pointerdown', (e) => {
if (e.target.classList.contains('aa-slider-handle')) return;
const nv = fromClientX(e.clientX);
if (range) {
const i = Math.abs(nv - value[0]) <= Math.abs(nv - value[1]) ? 0 : 1;
value[i] = nv; value.sort((a, b) => a - b);
} else {
value = nv;
}
paint();
});
paint();
}
document.querySelectorAll('[data-slider]').forEach(initSlider);
</script>
</body>
</html>