一、tab切换
1,效果预览
demo需求简介:
- js原生实现;
- tab切换,active样式切换;
- tab过多右侧出现箭头滚动;
2,代码实现
我们按照实现思路来实现:
(1)第一步:点击当前tab,添加active样式;
就需要给每个tab都绑定点击事件,当点击某一个tab时,需要给当前tab加上active的class名,并且去除掉其他tab兄弟们的active的class名,这样就唯我独秀啦。这其中涉及到的js语法可能会有:
添加class名:元素.classList.add("active");
去除class名:元素.classList.remove("active");
写法一:
先给每个tab-item绑定点击事件,因为item的个数不能定死,所以我们就可以循环去绑定,然后点击事件内先给每个item去掉一波active的class,然后给当前点击的这个item加上active的class不就可以了,就给他单独开小灶,你说气不气?话不多说,直接上代码:
<ul class="tabs">
<li class="tab-item active">tab1tab1tab1</li>
<li class="tab-item">tab2</li>
<li class="tab-item">tab3</li>
<li class="tab-item">tab4</li>
<li class="tab-item">tab5</li>
<li class="tab-item">tab6</li>
<li class="tab-item">tab7</li>
<li class="tab-item">tab8</li>
</ul>
var tabItem = document.getElementsByClassName("tab-item");
for (let ele = 0; ele < tabItem.length; ele++) {
tabItem[ele].onclick = function () {
//循环去除全部active的class
for (let i = 0; i < tabItem.length; i++) {
tabItem[i].classList.remove("active");
}
//给当前item添加active的class
tabItem[ele].classList.add("active");
};
}
写法二:
或许还有另一种思路,咱也是给每个item绑定事件,也是要给当前item添加active的class,但我们可不可以去掉其他兄弟们的active,这样咱就可以不给当前的去一波了,当前的本来就没active,你还去剥削一遍,咋这么缺德捏?
但是咋获取其他的兄弟元素呢???
咱咋知道他们是我的兄弟啊?你说是就是啊?那当然得去问你爸妈不是?你爸妈告诉你他们生了几个娃,这个是老大,老二,老三....走起,说干就干:
<ul class="tabs">
<li class="tab-item active">tab1tab1tab1</li>
<li class="tab-item">tab2</li>
<li class="tab-item">tab3</li>
<li class="tab-item">tab4</li>
<li class="tab-item">tab5</li>
<li class="tab-item">tab6</li>
<li class="tab-item">tab7</li>
<li class="tab-item">tab8</li>
</ul>
//获取兄弟节点
function siblings(value, className) {
let parent = value.parentNode;//获取父节点
let bro = parent.childNodes;//获取子节点
console.log("bro", bro); //打印试试
}
//循环绑定事件
for (let ele = 0; ele < tabItem.length; ele++) {
tabItem[ele].onclick = function () {
tabItem[ele].classList.add("active");
siblings(tabItem[ele], "active"); //获取兄弟节点+去除active的class
};
}
咋这么多玩意呀,咋还有一些text的节点呢?那是因为你问的太仔细了,七大姑八大姨都算进去了,啥表姊妹表兄弟都算上,是不是就麻烦了呢?仔细了解一下发现:
获取元素子节点的所有类型节点:元素.childNodes;(空格和换行符都会都会被默认成文本节点)
获取当前元素的子元素节点:元素.children;(不返回文本节点和属性节点)
既然如此,咱也不舍近求远了,怎么方便怎么来:
function siblings(value, className) {
let parent = value.parentNode;
let bro = parent.children;
let siblings = [];
for (let i = 0; i < bro.length - 1; i++) {
if (bro[i] != value) {
siblings.push(bro[i]);
for (const key in siblings) {
siblings[key].classList.remove(className);
}
}
}
}
for (let ele = 0; ele < tabItem.length; ele++) {
tabItem[ele].onclick = function () {
tabItem[ele].classList.add("active");
siblings(tabItem[ele], "active");
};
}
通过函数调用传参的方式,把节点,和class名传进去处理,这样如果后面有需要的话,也可以调用此函数,从而减少代码的耦合性。
当然childNodes返回的结果也是可以过滤的,也能达到想要的效果:
if (
!(
bro[i].nodeType == "3" &&
bro[i].nodeName == "#text" &&
!/\S/.test(bro[i].nodeValue)
)
) {
//正常代码
}
(2)第二步:点击当前tab,显示相对于的tab-content内容;
很简单,也可以按照上面的思路来实现,咱通过新增一个class样式来控制tab-content的显示和隐藏即可;
.show{
display:block;
}
.hidden{
display:hidden;
}
写法一:
和上面实现的思路一致,全部剥削一遍,然后单独开小灶呗,开整: