js 急速入门之六(classList,dataset对象,选项卡,一键换肤,图片懒加载,简易轮播图)
classList:设置元素的类样式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>classList</title>
<style>
.red {
color:red;
}
.bg {
background-color: yellow;
}
.green{
color:green;
}
</style>
</head>
<body>
<!-- <p class="red bg">欢迎</p> -->
<p>欢迎</p>
<script>
const p =document.querySelector("p");
// p.className='red';
// p.className='red bg';
// classList:用来动态的设置元素的类样式
//对象有属性和方法
// p.classList.add("red");
// p.classList.add("bg")
// p.classList.remove("bg");
// p.classList.add("green","bg");
// p.classList.replace("green","red");
//toggle()动态切换:如果样式表有red 就移除,没有就添加
p.classList.toggle("red");
</script>
</body>
</html>
dataset对象:自定义属性
<!-- id:预定义属性 -->
<!-- email:自定义属性 -->
<p id='aaa' data-email='a@php.cn' data-my-age='40' data-index="1">我的资料</p>
<script>
const p = document.querySelector("p");
//使用getAttribute()方法获取自定义属性
// const email = p.getAttribute("email");
// console.log(email);
// dataset:读写自定义属性,但是这个属性在HTML中必须使用 'data-' 为前缀
// js代码中data- 前缀必须省;之后还有连接线时,连接线必须省去,原连接线后的首字母必须大写
console.log(p.dataset.email);
console.log(p.dataset.myAge);
console.log(p.dataset.index);
</script>
案例
选项卡
知识点:
数组的遍历: forEach()
数组的筛选: filter()
classList属性:classList.remove()
,classList.add()
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>选项卡</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
a {
text-decoration: none;
color: #555;
}
a:hover {
text-decoration: underline;
color: red;
}
li {
list-style: none;
line-height: 1.6em;
}
li:hover{
cursor:default;
}
.tabs {
width: 300px;
height: 300px;
margin: 30px;
background-color: #e6e6e6;
display: flex;
flex-direction: column;
}
.tab {
height: 36px;
display: flex;
}
.tab li {
flex: auto;
text-align: center;
line-height: 36px;
background-color: #fff;
}
.tab li.active {
background-color: #e6e6e6;
}
.tab li:hover {
cursor: pointer;
}
.item{
padding: 20px;
display: none;
}
.item.active {
display: block;
}
</style>
</head>
<body>
<div class="tabs">
<!-- 导航 -->
<ul class="tab">
<li class="active" data-index="1">省内</li>
<li data-index="2">国内</li>
<li data-index="3">国际</li>
</ul>
<!-- details -->
<ul data-index="1" class="item active" >
<li><a href="">省内新闻</a></li>
<li><a href="">省内新闻省内新闻</a></li>
<li><a href="">省内新闻省内新闻省内新闻</a></li>
</ul>
<ul data-index="2" class="item">
<li><a href="">国内国内国内国内</a></li>
<li><a href="">国内国内国内国内国内</a></li>
<li><a href="">国内国内国内国内</a></li>
</ul>
<ul data-index="3" class="item">
<li><a href="">国际国际国际国际国际国际</a></li>
<li><a href="">国际国际国际国际国际</a></li>
<li><a href="">国际国际国际国际</a></li>
</ul>
</div>
<script>
const tab = document.querySelector(".tab");
const items = document.querySelectorAll(".item");
//1. 清空之前所有出于激活状态的选项卡,并将当前点击对象激活
tab.onclick = (ev) => {
// 事件绑定对象
// console.log(ev.currentTarget);
//事件触发对象
// console.log(ev.target);
[...tab.children].forEach((item) => item.classList.remove("active"));
ev.target.classList.add("active");
//2. 根据自定义属性data-index找到对应的列表并显示
//NodeList对象内置了forEach接口
items.forEach(item => item.classList.remove("active"));
console.log(ev.target);
[...items].filter(item => item.dataset.index === ev.target.dataset.index)[0].classList.add("active");
};
</script>
</body>
</html>
一键换肤
知识点:
动态修改 body.style.backgroundImage
值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>一键换肤</title>
<style>
.container {
width: 300px;
display: grid;
grid-template-columns: repeat(3,1fr);
column-gap:10px;
}
.container>img{
width: 100%;
border:3px solid #fff;
opacity: 0.6;
}
.container > img:active {
opacity: 1;
}
.container > img:hover {
opacity: 1;
cursor:pointer;
width: 105%;
}
body {
background-image: url("static/images/1.jpg");
background-repeat: no-repeat;
background-size: cover;
}
</style>
</head>
<body>
<div class="container">
<img src="static/images/1.jpg" alt="" />
<img src="static/images/2.jpg" alt="" />
<img src="static/images/3.jpg" alt="" />
</div>
<script>
//事件代理,不需要给每个图片的缩略图添加点击事件,只需要给父元素添加就可以了
// document.querySelector(".container").onclick = ev=>document.body.backgroundImage = "url("+ev.target.src+")";
const box = document.querySelector(".container");
box.onclick = function (ev) {
const body = document.body;
let imgUrl = "url("+ev.target.src+")";
body.style.backgroundImage = imgUrl;
}
</script>
</body>
</html>
图片懒加载
懒加载原理
先将图片的url地址存到自定义属性 data-src
中,当图片top值<视口+滚动高度时 用 data-src
替换 src
值img.offsetTop < clientHeight + document.documentElement.scrollTop
知识点:setTimeout()
,两个事件 scroll,load
//视口高度
let viewHeight = document.documentElement.clientHeight;
//滚动高度
document.onscroll = ev=>{
console.log(document.documentElement.scrollTop);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>图片懒加载</title>
<style>
.container {
width: 500px;
display: grid;
gap: 10px;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.container img {
width: 100%;
}
</style>
</head>
<body>
<div class="container">
<img src="images/temp.jpg" alt="" data-src="images/img-1.jpg" />
<img src="images/temp.jpg" alt="" data-src="images/img-2.jpg" />
<img src="images/temp.jpg" alt="" data-src="images/img-3.jpg" />
<img src="images/temp.jpg" alt="" data-src="images/img-4.jpg" />
<img src="images/temp.jpg" alt="" data-src="images/img-5.jpg" />
<img src="images/temp.jpg" alt="" data-src="images/img-6.jpg" />
<img src="images/temp.jpg" alt="" data-src="images/img-7.jpg" />
<img src="images/temp.jpg" alt="" data-src="images/img-8.jpg" />
<img src="images/temp.jpg" alt="" data-src="images/img-9.jpg" />
<img src="images/temp.jpg" alt="" data-src="images/img-10.jpg" />
</div>
<script>
// const imgs =document.images;
const images = document.querySelectorAll(".container img");
const clientHeight = document.documentElement.clientHeight;
window.addEventListener("scroll", layzyload);
window.addEventListener("load", layzyload);
function layzyload() {
images.forEach((img) => {
if (img.offsetTop < clientHeight + document.documentElement.scrollTop)
setTimeout(() => (img.src = img.dataset.src), 500);
});
}
// images
</script>
</body>
</html>
轮播图
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>轮播图</title>
<link rel="stylesheet" href="banner/style.css" />
</head>
<body>
<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">
<!-- 应该根据图片的数量自动生成 -->
<!-- <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>
<script>
// 所有图片
const imgs = document.querySelectorAll(".container > .imgs img");
//按钮组
const btnGroup = document.querySelector(".container > .btns");
// 翻页按钮
const skip = document.querySelectorAll(".container > .skip > a");
// 创建出一组与图片数量一致的小按钮
function autoCreateBtns(ele, imgCount) {
const frag = document.createDocumentFragment();
for (let i = 0; i < imgCount; i++) {
const a = document.createElement("a");
a.href = "#";
a.dataset.index = i + 1;
if (i === 0) a.classList.add("active");
frag.appendChild(a);
}
ele.appendChild(frag);
}
// 调用创建小按钮的函数
autoCreateBtns(btnGroup, imgs.length);
// 为刚刚生成的小按钮添加点击事件
const btns = document.querySelectorAll(".container > .btns > *");
// 写两个公共函数
// 1. 获取激活的元素
function getActiveEle(eles) {
let activities = [...eles].filter((img) =>
img.classList.contains("active")
);
return activities.shift();
}
// 2. 设置激活元素,根据按钮索引更新正在显示的图片
function setActiveEle(btnIndex) {
[imgs, btns].forEach((arr) => {
// 将之前的状态重置到初始化
getActiveEle(arr).classList.remove("active");
arr.forEach((item) => {
if (item.dataset.index === btnIndex) {
item.classList.add("active");
}
});
});
}
btns.forEach((btn) =>
btn.addEventListener("click", (ev) =>
setActiveEle(ev.target.dataset.index)
)
);
let iMax = imgs.length;
//上一张
let prevSkip = document.querySelector(".prev");
prevSkip.addEventListener("click", () => {
let iIndex = getActiveEle(imgs).dataset.index;
let iPrev = parseInt(iIndex) - 1;
iPrev < 1
? setActiveEle(iMax.toString())
: setActiveEle(iPrev.toString());
});
//下一张
let nextSkip = document.querySelector(".next");
nextSkip.addEventListener("click", () => {
let iIndex = getActiveEle(imgs).dataset.index;
let iNext = parseInt(iIndex) + 1;
iNext > iMax
? setActiveEle("1")
: setActiveEle(iNext.toString());
});
//事件派发
startInterval = function () {
const ev = new Event("click");
nextSkip.dispatchEvent(ev);
};
//使用间歇式定时器
let intervalID = setInterval(startInterval, 2000);
let container = document.querySelector(".container");
container.addEventListener("mouseover", () => clearInterval(intervalID));
container.addEventListener(
"mouseleave",
() => (intervalID = setInterval(startInterval, 2000))
);
</script>
</body>
</html>
小结:调试过程中因为没有将事件派发封装,直接使用 setInterval()
设置派发造成一直无法达到效果。
由于没有了解setInterval用法造成时间的浪费,吃一堑长一智吧。