在VanillaJavaScript中从头开始实现选项卡组件
通过使用普通 JavaScript 和您镇定的机智重新创建众所周知的选项卡组件来提高您的开发技能!
从表面上看,标签可能看起来很无聊。 我们都知道他们每天在我们的网络浏览器中做什么并使用它们,而无需多加思考,然而,设计一个仅使用原生浏览器技术在移动设备上运行良好的现代、可重复使用的选项卡组件实际上可能非常具有挑战性,并且是构建一些“真实世界”代码的绝佳机会。
基本要求
我们的标签组件需要:
- 响应式
- 可重复使用的
- 可嵌套
- 可以设置默认选项卡
让我们开始吧! 首先,我将从代码开始,然后分解正在发生的事情:
标记
这是我们的标签组件的基本 HTML 标记:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Gator tabs</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<div class="gator-tabs-container">
<ul class="gator-tabs-header">
<li>The nest</li>
<li class="default-gator-tab">Hello world!</li>
<li>Rise of the gator</li>
</ul>
<ul class="gator-tabs">
<li class="gator-tabs-container">
<ul class="gator-tabs-header">
<li>Nested 1</li>
<li class="default-gator-tab">Nested 2</li>
</ul>
<ul class="gator-tabs">
<li class="gator-tab">Some eggs in nest one</li>
<li class="gator-tab">Some eggs in nest two</li>
</ul>
</li>
<li class="gator-tab">Hello world from tab one!</li>
<li class="gator-tab">Believe me I know tabs, I have the best tabs. Nobody does tabs like I do.</li>
<li class="gator-tab">For now the eggs lay dormant but soon the gators will rise from the swamps.</li>
</ul>
</div>
<script src="main.js"></script>
</body>
</html>
造型
还有一些 CSS 样式让它看起来不错:
/* minimal reset */
* {
margin:0;
border:0;
padding:0;
box-sizing:border-box;
list-style:none;
}
body{
background-color: #333;
/* because serifs are gross (IMO) */
font-family: sans-serif;
}
.gator-tabs-container{
display:flex;
flex-direction:column;
width:100%;
}
.gator-tabs-header {
background-color:#DFA612;
display:flex;
flex-wrap:wrap;
padding:.375rem;
}
.gator-tabs-header > li {
color:#fff;
cursor:pointer;
flex-grow:1;
padding:.375rem;
font-size:1.125rem;
}
.gator-tabs {
display:flex;
}
.gator-tab {
padding:1rem;
color:#fff;
}
JavaScript 代码
现在让我们用一些简单的 JavaScript 让魔法发生:
function tabify( element ){
const header = element.querySelector('.gator-tabs-header');
const content = element.querySelector('.gator-tabs');
const tab_headers = [...header.children];
const tab_contents = [...content.children];
tab_contents.forEach( x => x.style.display = 'none');
let current_tab_index = -1;
function setTab( index ){
if( current_tab_index > -1 ){
tab_headers[ current_tab_index ].style.fontWeight = 400;
tab_contents[ current_tab_index ].style.display = 'none';
}
tab_headers[ index ].style.fontWeight = 800;
tab_contents[ index ].style.display = 'flex';
current_tab_index = index;
}
default_tab_index = tab_headers.findIndex( x => {
return [...x.classList].indexOf('default-gator-tab') > -1;
});
default_tab_index = default_tab_index === -1 ? 0 : default_tab_index;
setTab( default_tab_index );
tab_headers.forEach((x,i) => x.onclick = event => setTab(i));
}
// this is where the magic happens!
[...document.querySelectorAll('.gator-tabs-container')]
.forEach(x => tabify(x));
这是该应用程序在手机上的屏幕截图:
回顾/细分
我们的第一个要求是构建响应式的东西,使用带有 flex-wrap 属性的 Flexbox 很容易解决这个问题,因此现在标签页眉在移动设备上将相互堆叠。
使代码可重用一开始可能看起来很棘手,但通过将我们的代码包装到一个名为 tabify 的函数中,我们可以将任何内容放入一个满足所需类/标记结构的选项卡中。 这也使我们的下一个需求,可嵌套,自动落到位。
最后一个要求是能够将选项卡设置为页面打开时选择的默认选项。 这是通过将 default-gator-tab 类添加到所需的选项卡标题来完成的,我们的脚本将使用该类找到第一个选项卡标题的索引并使用它来设置初始选项卡。
在之前的文章中,我们描述了使用 React 构建标签的 ,但老实说,在这种情况下,我很难找到 React 相对于普通 Javascript 的任何显着优势。 我们能够将任何配置传递给我们的脚本,例如使用类名(而不是 props)的默认选项卡,并且我们使用的代码量与 React 版本大致相同,而没有框架的开销!
如果我们愿意,我们可以轻松地扩展我们必须包含的动画或更复杂的功能,但我会留给你。