注:只针对js进行详细解释。
监听事件: element.addEventListener(eventType, (event) => { }); --element :绑定事件的 HTML 元素。
--eventType : 事件类型,例如 "click", "mouseover", "keydown" 等。
--(event) => { } : 是事件触发后执行的回调函数。event 是事件对象,它包含触发事件的相关信息。
自定义事件:
const event = new CustomEvent(eventName, {
detail: dataObject, // 可选,用于传递数据
bubbles: true, // 可选,是否允许事件冒泡
cancelable: true // 可选,是否允许取消事件
});
element.dispatchEvent(event); // 在element元素上触发自定义事件
--eventName 是自定义事件的名称,例如 "customEventName".
--detail 是一个对象,用于携带需要传递的数据。
--bubbles 表示事件是否冒泡到父元素,默认为 false。
--cancelable 表示事件是否可以被取消,默认为 false。
默认事件:
许多 HTML 元素在触发特定事件时会执行默认行为。例如:
-- 在 <a> 标签上点击会跳转到链接地址。
-- 在 <form> 表单上提交会刷新页面并发送数据。
-- 在文本框上按回车键会提交表单。
阻止默认事件的原因:
-- 有时,我们希望自定义这些元素的行为,而不执行它们的默认操作。此时,可以使用 event.preventDefault() 阻止默认行为。
class Slider {
constructor(id, cycle = 3000) {
this.container = document.getElementById(id); // 根据容器的id获取容器 这里获取到的还是最外层的div元素
this.items = this.container.querySelectorAll( // 根据两个类名查询所有的图片元素,返回一个NodeList对象
".slider-list__item, .slider-list__item--selected",
);
this.cycle = cycle; // 取到实例化对象时传入的参数
const controller = this.container.querySelector(".slide-list__control"); // 根据类名取到按钮组
if (controller) {// 如果取到的话
const buttons = controller.querySelectorAll( // 根据按钮的class获取button元素
".slide-list__control-buttons, .slide-list__control-buttons--selected",
);
controller.addEventListener("mouseover", (evt) => { // 设置一个监听事件。监听事件的格式在下面会进行讲解。
const idx = Array.from(buttons).indexOf(evt.target); // 由于buttons也是一个NodeList对象,所以需要先转换成数组。然后取到指向的按钮的索引
if (idx >= 0) {
this.slideTo(idx); // 移动到这个索引对应的图片
this.stop(); // 暂停cycle毫秒一次的自动切换
}
});
controller.addEventListener("mouseout", (evt) => {// 设置另一个监听事件 用于鼠标挪走之后进行cycle毫秒一次的自动切换
this.start();
});
this.container.addEventListener("slide", (evt) => { // 设置一个监听事件,不过这个监听事件是通过new CustomEvent自定义的。
const idx = evt.detail.index; // detail是slide自定义事件的数据载体,这个载体里面放着小圆圈的索引
const selected = controller.querySelector( // controller时按钮组,在按钮组中找到选中的按钮 用selected来接收
".slide-list__control-buttons--selected",
);
if (selected) selected.className = "slide-list__control-buttons"; // 如果接收到了,那么就把该按钮的class设为未选中
buttons[idx].className = "slide-list__control-buttons--selected";// 然后把鼠标指向的按钮的class设为选中
});
}
const previous = this.container.querySelector(".slide-list__previous"); // 从容器中获取左箭头元素
if (previous) { // 如果获取到了
previous.addEventListener("click", (evt) => { // 设置一个监听事件,点击进行触发。
this.stop(); // 点击之后 停止自动切换
this.slidePrevious(); // 挪到前一张照片
this.start(); // 开始自动切换
evt.preventDefault(); // 阻止默认事件(例如页面滚动等)
});
}
const next = this.container.querySelector(".slide-list__next"); // 从容器中获取右箭头元素
if (next) {
next.addEventListener("click", (evt) => { // 设置一个监听事件,点击进行触发
this.stop(); // 点击之后 停止自动切换
this.slideNext(); // 挪到后一张照片
this.start(); // 开始自动切换
evt.preventDefault(); // 阻止默认事件
});
}
}
getSelectedItem() { // 定义一个函数,用于返回选中图片的元素
let selected = this.container.querySelector(".slider-list__item--selected");
return selected;
}
getSelectedItemIndex() { // 定义一个函数,用于返回选中图片的索引
return Array.from(this.items).indexOf(this.getSelectedItem());
}
slideTo(idx) { // 定义一个函数,用于指定切换对应图片
let selected = this.getSelectedItem();
if (selected) {
selected.className = "slider-list__item";
}
let item = this.items[idx];
if (item) {
item.className = "slider-list__item--selected";
}
const detail = { index: idx }; // 定义一个对象detail,里面包含一个属性 index,属性的值是idx,代表指定切换照片的索引
const event = new CustomEvent("slide", { bubbles: true, detail }); // 自定义一个slide事件 ,bubbles: true代表可以在DOM树上冒泡,父元素可以对此事件进行监听
// detail 是事件的数据载体,通过 { detail } 将包含当前索引的 detail 对象附加到事件上。
this.container.dispatchEvent(event); // 触发slide自定义事件。
// 它在 container 元素上触发 "slide" 事件,所有对该事件设置了监听的代码(如 controller.addEventListener("slide", ...))会被调用。
}
slideNext() { // 切换下一张图片
let currentIdx = this.getSelectedItemIndex();
let nextIdx = (currentIdx + 1) % this.items.length;
this.slideTo(nextIdx);
}
slidePrevious() { // 切换上一张图片
let currentIdx = this.getSelectedItemIndex();
let previousIdx = (this.items.length + currentIdx - 1) % this.items.length; // 这里先加一个图片的个数是因为怕索引是0的时候,减1出现负数的情况
this.slideTo(previousIdx);
}
start() { // 开始自动切换照片函数
this.stop(); // 先调用stop函数把计时器清零
this._timer = setInterval(() => this.slideNext(), this.cycle); // 设置计时器,cycle毫秒调用一次slideNext函数,往后切换一张图片
}
stop() { // 停止自动切换照片函数
clearInterval(this._timer); // 清楚计时器
}
}
const slider = new Slider("my-slider");
slider.start();