一:前置知识
1.事件代理:
事件绑定者:ev.currentTarget
事件触发者:ev.target
思维:给母元素添加事件,通过ev.target解发事件的元素
2.dataset对象:自定义属性
dataset对象专用于访问自定义的标签属性,在自定义属性前面加上data-,便可以用“dataset.自定义标签名”,进行访问,如果自定义的标签是两个单词组成且中间有加”-“,访问时要省略掉”-“,并把第二个单词首字母进行大写
二:JS实战选项卡
思维:定义3个dataset,分别放在对应的主题和内容区标签里,利用事件绑定给相同的dataset自定义属性的classList添加active
html部分:
<div class="box">
<ul class="nav">
<li data-index="1" class="active">财经</li>
<li data-index="2">股票</li>
<li data-index="3">理财</li>
</ul>
<ul data-index="1" class="content active">
<li><a href="">道歉变自夸 全棉时代忘了本</a></li>
<li><a href="">拉夏贝尔内斗激烈 一年五换总裁</a></li>
<li><a href="">深圳华强北6亿缉私震荡波</a></li>
</ul>
<ul data-index="2" class="content">
<li><a href="">[美股]小摩:价值股即将咸鱼翻身</a></li>
<li><a href="">[港股]百度回港上市AB面</a></li>
<li><a href="">猪肉价格浮沉启示 A股需坚守信仰</a></li>
</ul>
<ul data-index="3" class="content">
<li><a href="">极致行情虐惨量化对冲基金</a></li>
<li><a href="">数字人民币在上海扩大试点 已实现“双离线”支付</a></li>
<li><a href="">[黄金] 国债收益率上攻叠加美指反弹 黄金出现急跌</a></li>
</ul>
</div>
css部分:
*{
margin: 0;
padding: 0;
box-sizing: border-box;
list-style: none;
text-decoration: none;
}
.box{
margin: 30px;
}
a{
color: #666;
}
a:hover{
text-decoration: underline;
color: red;
}
.box{
width: 300px;
height: 300px;
margin: 30px;
border-color: #F7F7F7;
display: flex;
flex-direction: column;
}
.nav{
height: 36px;
display: flex;
border-left: 1px solid #DBDEE1;
border-top: 1px solid #DBDEE1;
border-right: 1px solid #DBDEE1;
}
.nav li{
flex: auto;
text-align: center;
line-height: 36px;
background-color: #F8F8F8;
border-bottom: 1px solid #DBDEE1;
border-left: 1px solid #DBDEE1;
}
.nav li:hover{
border-bottom: none;
background-color: white;
}
/* 默认所有选项卡只能显示active*/
.content{
padding: 20px;
display: none;
}
.content.active{
display: block;
}
js实现:
const nav = document.querySelector(".nav");
const content=document.querySelectorAll(".content");
nav.onmouseover = ev =>{
Array.from(nav.children).forEach(lis=>lis.classList.remove("active"));
ev.target.classList.add("active");
// 根据自定义属性data-index找到对应的content并显示
content.forEach(lis=>lis.classList.remove("active"));
//filter方法虽然只返回了一个结果,但还是数组,所以要加[0]:
let result = Array.from(content).filter(lis=>lis.dataset.index===ev.target.dataset.index)[0];
result.classList.add("active");
}
效果如下:
before:
onmouseover:
三.js事件代理实现轮播图,并实现自动播放,鼠标移入停止播放功能
html部分:
<div class="container">
<!-- 1. 图片组 -->
<nav class="imgs">
<a href="#"
><img src="banner/banner1.jpg" alt="" data-index="1" class="active"
/></a>
<a href="#"><img src="banner/banner2.jpg" alt="" data-index="2" /></a>
<a href="#"><img src="banner/banner3.jpg" alt="" data-index="3" /></a>
<a href="#"><img src="banner/banner4.jpg" alt="" data-index="4" /></a>
</nav>
<!-- 2. 与图片组对应的按钮组(一个个独立的,数量与图片数量是相同的) -->
<nav class="btns">
<!-- 这些小按钮应该是js根据图片数量动态来创建 -->
<!-- <a href="#" data-index="1" class="active"></a>
<a href="#" data-index="2"></a>
<a href="#" data-index="3"></a>
<a href="#" data-index="4"></a> -->
</nav>
<!-- 3. 翻页按钮(只有二个,分别在左右) -->
<nav class="skip">
<!-- <: 实体符号 -->
<a href="#" class="prev"><</a>
<a href="#" class="next">></a>
</nav>
</div>
基本js功能:
//图片
const imgs = document.querySelectorAll(".container > .imgs img");
//按钮
const btnList = document.querySelector(" .container > .btns");
//小耳朵
const skip = document.querySelector(".skip");
//----------------------------生成小圆点-------------------------------------
//生成和图片数量一致的小圆点:
function antoCreateSpot(position,img){
//使用文档片断:
const frag = document.createDocumentFragment();
for(let i=0;i<img.length;i++){
const a = document.createElement("a");
a.href="#";
a.dataset.index = i+1;//data-index="i+1"
if(i===0)a.classList.add("active");//为第一个添加active
frag.appendChild(a);
}
position.appendChild(frag);
};
antoCreateSpot(btnList,imgs);//调用函数并实现生成小圆点
// 获取一下生成的小圆点的所有元素:
const spot=document.querySelectorAll(".container > .btns > *");
创建公共函数:
//----------------------------公共函数区-------------------------------------
//1.获取激活元素函数:
function getActivedElement(elements){
//contains():判断DOM元素的包含关系,返回布尔值
let actived = [...elements].filter(img=>img.classList.contains("active"));
return actived[0];//filter返回的是数组,所以要加[0]
};
//2.设置激活的元素:
function setActiveElement(btnIndex){
//同时遍历所有图片和按钮
[imgs,spot].forEach(arr => {
// 取消当前激活元素的状态:
getActivedElement(arr).classList.remove("active");
//根据当前用户点击的按钮的索引,重置应该激活的元素:
arr.forEach(item =>{
if(item.dataset.index === btnIndex){
item.classList.add("active");
}
})
});
};
给小圆点添加事件:
spot.forEach(btn=>
btn.addEventListener("click",ev=>setActiveElement(ev.target.dataset.index))
);
让两侧的小耳机变活:
skip.addEventListener("click",skipImg);
skip.children[1].addEventListener("click",skipImg);
function skipImg(ev){
// 获取当前被激活的图片:
let currentImg = getActivedElement(imgs);
//获取当前激活的图片包裹器的元素,因为图片包在a元素里面,所以要弄两次:
let parentEle = currentImg.parentElement.parentElement;
//获取当前激活元素的上一个兄弟节点:
let preEle = currentImg.parentElement.previousElementSibling;
//获取当前激活元素的下一个兄弟节点:
let nextEle = currentImg.parentElement.nextElementSibling;
//第一张图片:
let firstImg = parentEle.firstElementChild.firstElementChild;
//最后一张图片:
let lastImg = parentEle.lastElementChild.lastElementChild;
let activeImg = currentImg;
//向前:
if (ev.target.classList.contains("prev")){
//向前图片使用完毕,自动到最后一张
let activeImg=preEle !==null?preEle.firstElementChild:lastImg;
setActiveElement(activeImg.dataset.index);//同步更新
}
//向后:
if(ev.target.classList.contains("next")){
//向后结束后自动到第一张:
let activeImg=nextEle !==null?nextEle.firstElementChild:firstImg;
setActiveElement(activeImg.dataset.index);
}
}
让轮播图自动动起来:
let sk = null;
const clickEvent = new Event("click");
const box = document.querySelector(".container");
const autonext = document.querySelector(".skip .next");
box.addEventListener("mouseover",stop);
box.addEventListener("mouseout",start);
setTimeout(function (){
start()},1000);
function start(){
sk = setInterval(function (){
autonext.dispatchEvent(clickEvent)
},2000);
}
function stop(){
clearInterval(sk);
}