1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
| // 为滑动手势添加按钮控制
class AccessibleSlider {
constructor(slider) {
this.slider = slider
this.slides = slider.querySelectorAll('.slide')
this.currentIndex = 0
this.createControls()
this.initKeyboardSupport()
this.initTouchSupport()
}
createControls() {
const controls = document.createElement('div')
controls.className = 'slider-controls'
controls.setAttribute('role', 'group')
controls.setAttribute('aria-label', '幻灯片控制')
const prevButton = document.createElement('button')
prevButton.textContent = '上一张'
prevButton.setAttribute('aria-label', '查看上一张幻灯片')
prevButton.addEventListener('click', () => this.prev())
const nextButton = document.createElement('button')
nextButton.textContent = '下一张'
nextButton.setAttribute('aria-label', '查看下一张幻灯片')
nextButton.addEventListener('click', () => this.next())
const indicators = document.createElement('div')
indicators.className = 'slide-indicators'
indicators.setAttribute('role', 'tablist')
this.slides.forEach((slide, index) => {
const indicator = document.createElement('button')
indicator.setAttribute('role', 'tab')
indicator.setAttribute('aria-label', `幻灯片 ${index + 1}`)
indicator.setAttribute('aria-selected', index === 0 ? 'true' : 'false')
indicator.addEventListener('click', () => this.goTo(index))
if (index === 0) {
indicator.classList.add('active')
}
indicators.appendChild(indicator)
})
controls.appendChild(prevButton)
controls.appendChild(indicators)
controls.appendChild(nextButton)
this.slider.parentNode.insertBefore(controls, this.slider)
this.controls = { prevButton, nextButton, indicators }
}
initKeyboardSupport() {
this.slider.setAttribute('tabindex', '0')
this.slider.addEventListener('keydown', (e) => {
switch (e.key) {
case 'ArrowLeft':
e.preventDefault()
this.prev()
break
case 'ArrowRight':
e.preventDefault()
this.next()
break
case 'Home':
e.preventDefault()
this.goTo(0)
break
case 'End':
e.preventDefault()
this.goTo(this.slides.length - 1)
break
}
})
}
initTouchSupport() {
let startX = 0
let currentX = 0
this.slider.addEventListener('touchstart', (e) => {
startX = e.touches[0].clientX
})
this.slider.addEventListener('touchmove', (e) => {
currentX = e.touches[0].clientX
})
this.slider.addEventListener('touchend', () => {
const diff = startX - currentX
if (Math.abs(diff) > 50) {
if (diff > 0) {
this.next()
} else {
this.prev()
}
}
})
}
updateIndicators() {
const indicators = this.controls.indicators.querySelectorAll('[role="tab"]')
indicators.forEach((indicator, index) => {
indicator.setAttribute('aria-selected', index === this.currentIndex ? 'true' : 'false')
indicator.classList.toggle('active', index === this.currentIndex)
})
}
goTo(index) {
this.currentIndex = index
this.updateSlider()
this.updateIndicators()
}
next() {
this.currentIndex = (this.currentIndex + 1) % this.slides.length
this.updateSlider()
this.updateIndicators()
}
prev() {
this.currentIndex = (this.currentIndex - 1 + this.slides.length) % this.slides.length
this.updateSlider()
this.updateIndicators()
}
updateSlider() {
const offset = -this.currentIndex * 100
this.slider.style.transform = `translateX(${offset}%)`
// 更新ARIA标签
this.slider.setAttribute('aria-label', `当前显示第 ${this.currentIndex + 1} 张幻灯片`)
}
}
|