模块实战:经典选项卡
总结:
1、HTML DOM结构:写栏目组和内容组
2、获取栏目组和内容组的元素
3、调用模块生成栏目组和内容组的内容
4、在父级绑定点击事件,利用事件冒泡原理调用事件委托,调用 设置当前按钮高亮模块方法和显示对应内容区的模块方法。
HTML示范:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>实战1:经典选项卡</title>
<style>
/* 隐藏 */
.hidden {
display: none;
}
/* 显示 */
.active {
display: block;
}
.type > *.active,
.content {
background-color: lightgreen;
}
</style>
</head>
<body>
<div class="box">
<!-- 栏目组 -->
<div class="type" style="display: flex;"></div>
<!-- 内容组 -->
<div class="content"></div>
</div>
<script type="module">
//导入模块
import * as tabs from "./modules/tabs.js";
// 1. 获取栏目,内容容器元素
const type = document.querySelector('.type');
const content = document.querySelector('.content');
//console.log(type,content);
// 2. 页面加载完成时,创建栏目栏目和对应的内容
window.onload = () => {
// console.log('页面加载完成')
//自动生成栏目和内容数据
tabs.createTab(type,content);
}
// 3.点击栏目时,设置按钮的状态,与按钮对应的内容的状态
// 事件委托(事件冒泡)
type.onclick = (ev) => {
//因为存在事件委托,所以就需要区分不同的事件主体
//使用ev来传递触发主体
//触发主体:ev.target
//绑定主体:ev.currentTarget,是触发主体的父级
// 1. 当前按钮高亮
tabs.setBtnStatus(ev);
// 2. 与按钮对应的内容显示出来
// ev.target:当前按钮
tabs.setContentStatus(ev,ev.target)
}
</script>
</body>
</html>
JS示范:
// todo 选项卡的数据及方法
// * 栏目数据
const cates = [
{ cid: 1, cname: '国际新闻' },
{ cid: 2, cname: '国内新闻' },
{ cid: 3, cname: '省内新闻' },
];
// * 列表数据
// 列表数据,必须与指定栏目,一一对应
const details = [
{
key: 1,
cid: 1,
content: [
{
title: '江泽民伟大光辉的一生',
url: 'https://news.ifeng.com/c/8LPwtTX7hsA'
},
{
title: '江泽民伟大光辉的一生',
url: 'https://news.ifeng.com/c/8LPwtTX7hsA'
},
{
title: '江泽民伟大光辉的一生',
url: 'https://news.ifeng.com/c/8LPwtTX7hsA'
},
],
},
{
key: 2,
cid: 2,
content: [
{
title: '北京:做好方舱医院治愈患者出院服务保障',
url: 'https://news.ifeng.com/c/8LSoYLjqyFZ'
},
{
title: '北京:做好方舱医院治愈患者出院服务保障',
url: 'https://news.ifeng.com/c/8LSoYLjqyFZ'
},
{
title: '北京:做好方舱医院治愈患者出院服务保障',
url: 'https://news.ifeng.com/c/8LSoYLjqyFZ'
},
],
},
{
key: 3,
cid: 3,
content: [
{
title: '从爱丽舍宫晚宴到白宫国宴,欧洲看透了美国',
url: 'https://news.ifeng.com/c/8LSyYMJBv1e'
},
{
title: '从爱丽舍宫晚宴到白宫国宴,欧洲看透了美国',
url: 'https://news.ifeng.com/c/8LSyYMJBv1e'
},
{
title: '从爱丽舍宫晚宴到白宫国宴,欧洲看透了美国',
url: 'https://news.ifeng.com/c/8LSyYMJBv1e'
},
],
},
];
//创建函数:生成栏目和内容区
function createTab(type, content) {
// 1.生成栏目
for (let i = 0; i < cates.length; i++) {
// 1.1 创建一个按钮
const btn = document.createElement('button');
// 1.2 设置按钮的文本
btn.textContent = cates[i].cname;
// 1.3 给按钮加一个自定义 data-key,主要是为了与内容ID绑定
btn.dataset.key = cates[i].cid;
// 1.4 默认高亮显示第1个,所以第一个加了class='active'
if (i === 0) btn.classList.add('active');
// 1.5 将新按钮,添加到栏目容器元素中 type
type.append(btn);
}
// 2.生成内容
for (let i = 0; i < details.length; i++) {
//2.1 创建列表<ul>
const ul = document.createElement('ul');
//2.2 添加列表索引<ul data-key>
ul.dataset.key = details[i].cid;
//2.3 默认显示第1个,其他隐藏
ul.classList.add(i === 0 ? 'active' : 'hidden');
//2.4 生成子元素<li><a>,用于显示第一条数据
//进入二次循环
for (let k = 0; k < details[i].content.length; k++) {
//生成一个 <li>
const li = document.createElement('li');
//生成一个 <a>
const a = document.createElement('a');
//a.href属性
a.href = details[i].content[k].url;
//a.textContent
a.textContent = details[i].content[k].title;
//将<a>添加到<li>
li.append(a);
//将<li>添加到<ul>
ul.append(li);
//将<ul>添加以.content容器中
content.append(ul);
}
}
}
function setBtnStatus(ev) {
//1.拿到当前按钮
const currentBtn = ev.target;
//2.去掉所有按钮的active,遍历
//ev.currentTarget:事件绑定主体,父元素,转为真数组
// console.log([...ev.currentTarget.children]);
[...ev.currentTarget.children].forEach(btn => btn.classList.remove('active'));
//设置当前按钮高亮
currentBtn.classList.add('active');
}
function setContentStatus(ev,currentBtn){
//1.获取所有列表
const lists = document.querySelectorAll('.content > ul');
//2.去掉所有列表的active,换成hidden
lists.forEach(list => list.classList.replace('active','hidden'));
//3.找到与栏目key对应的列表
//lists:Nodelist对象,不是数组
const currentList =[...lists].find(list => list.dataset.key == currentBtn.dataset.key);
//4.将当前列表高亮
currentList.classList.replace('hidden','active');
}
export { createTab, setBtnStatus, setContentStatus };