第17车厢-超实用!tab页签切换:data-*应用篇

本篇介绍常用的tab切换功能,使用js、jq、Vue3如何做到,以及说明若一个版面会出现一个以上需要切换时,该注意什麽?

还记的我们在<第15车厢-data-*的坑?data-*介绍篇>,已经介绍了抓去data-*的用法,接着我们就要透过data-*来实作时常用的tab切换功能罗!(画面阳春版喔)

▼ 完成图

HTML

注意 data-tablink="*"的内容是对应下方tab内容的id="*"

<div class="tab-demo">
  <!-- tab标签列 -->
  <ul class="tab-title">
    <li class="active">
      <a href="javascript:;" data-tablink="one">tab1</a>
    </li>
    <li>
      <a href="javascript:;" data-tablink="two">tab2</a>
    </li>
    <li>
      <a href="javascript:;" data-tablink="three">tab3</a>
    </li>
  </ul>
  <!-- tab内容 -->
  <div class="tab-inner-wrap">
    <div id="one" class="tab-inner">
      <!-- tab1的内容 -->
      内容1 内容1 内容1 内容1
    </div>
    <div id="two" class="tab-inner">
      <!-- tab2的内容 -->
       内容2
    </div>
    <div id="three" class="tab-inner">
      <!-- tab3的内容 -->
       内容3
    </div>
  </div>
</div>

...第二组

CSS

注意 li > a 原本是灰色li.active> a 则是加上蓝色

.tab-demo {
  padding: 20px;
}

.tab-title {
  display: flex; // 将li 排列再一起
}

.tab-title li {
  padding: 10px;
}

.tab-title li a {
  display: block;
  padding: 10px;
  color: #333;
  background-color: #ccc;
  text-decoration: none;
}

.tab-title li.active a {
  color: #fff;
  background-color: #0071bc;
}

.tab-inner {
  padding: 10px;
  border: 1px solid #ccc;
}

引入JQ

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

JQ(错误版)

目标:需做到按到哪个li就秀出对应的内容
siblings() 是返回被选元素的所有同级元素。

$(document).ready(function () {
  tabCutover1();
});

function tabCutover1() {
  //抓出li.active的data-tablink的内容;例如是"one"
  var tablink = $(".tab-title li.active").find("a").data("tablink");
  
  //将$("#one").显示,而其他兄弟们(叫做.tab-inner)都隐藏
  $('#'+ tablink).show().siblings(".tab-inner").hide();
  
  //当tab标题li被点到时,
  $(".tab-title li").click(function () {
      //抓出当下被点到的data-tablink的内容;例如是"Two",将$("#Two").显示,而其他兄弟们(叫做.tab-inner)都隐藏
    $('#'+$(this).find("a").data("tablink")).show().siblings(".tab-inner").hide();
    //抓出当下被点到的li要加上active(蓝色),其他li则要删除active(蓝色)
    $(this).addClass("active").siblings(".active").removeClass("active");
  });
}

▲好我们先停一下,看一下上方的code

看起来好像没问题?但是呢,发现第1个tab画面正常,第2个画面tab内容却都没隐藏了,这是为什麽呢?
https://ithelp.ithome.com.tw/upload/images/20211002/20142016TwwNZlvLf1.png
主要因为,

  • $(".tab-title li.active").find("a").data("tablink");只能叫出符合的第一个
  • $(".tab-title li.active")元素目前有2个才对
  • 所以我们要改为each使用回圈方式,这样两个选到的都能叫出来
    https://ithelp.ithome.com.tw/upload/images/20211002/20142016Low2jSsQXy.jpg
    所以呢,正如文章起头提到,如果要一个版面有很多切换区域,就可以写成下列写法

JQ (正确共用版)

/*tab 收合*/
function tabCutover() {

 $(".tab-title li.active").each(function () {
    var tablink = $(this).find("a").data("tablink");

    $('#'+tablink).show().siblings(".tab-inner").hide();
  });

 $(".tab-title li").click(function () {
    $('#'+$(this).find("a").data("tablink")).show().siblings(".tab-inner").hide();
    $(this).addClass("active").siblings(".active").removeClass("active");
  });
}

这样就解决啦!

JQ程序码

附上JQ版切换程序码

那...我们以上面逻辑用JS写写看(也太难写了吧!)

HTML及CSS同上喔

JS(献丑版)

我好像是第一次改写JS...JS找节点实在不是很熟
▼ 主要是因为JS没有siblings()找兄弟功能,要写可能要写很长,所以我只好写成先叫大家都清除,在叫点出来的串供!
JS

const tabTitle = document.querySelectorAll(".tab-title li");
const tabInner = document.querySelectorAll(".tab-inner");

//tab内容大家都清除
tabInner.forEach(function (item) {
  item.style.display = "none";
});

//所有tab区域是active 抓出他data-tablink後 例如是"one" 就可以指定document.getElementById("one")将tab内容显示
document.querySelectorAll(".tab-title li.active").forEach(function (item) {
  let tablink = item.querySelector("a").getAttribute("data-tablink");
  document.getElementById(tablink).style.display = "block";
});

//tab-title每个li做监听 当click时
tabTitle.forEach(function (item) {
  item.addEventListener("click", function () {
    //抓出click那个元素的a的tablink,例如是"two"
    let tablink = item.querySelector("a").getAttribute("data-tablink");

    //先找到该父层将所有子层li 移除active的classname(蓝色)
    item.parentNode.querySelectorAll("li").forEach(function (item) {
      item.classList.remove("active");
    });
    //在将click那个li加回active的classname(蓝色)
    item.classList.add("active");
    //将刚刚抓出来的,例如是"two" >document.getElementById("two")的父层 <div class="tab_inner_wrap">...底下的tab内容都隐藏
    document.getElementById(tablink).parentNode.querySelectorAll(".tab-inner").forEach(function (item) {
        item.style.display = "none";
      });
    //因为刚刚是做全部底下的tab内容都隐藏,所以要再将刚刚抓出来的,例如是"two" tab内容秀出来
    document.getElementById(tablink).style.display = "block";
  });
});

程序码JS

附上JS切换程序码

那...我们加码分享Vue3版本

Vue3(超超新手版)

最近刚好要练Vue,请看我超新手写法XD

引入

<script src="https://unpkg.com/vue@next"></script>

HTML

  • 动态绑定classname 所以写成:class 如果tabID是one的话就会有active这个class出现
  • li 发生click事件时 所以写成@click 并将id当参数传进去 去改变tabID
<div id="app">
  <div class="tab-demo">
    <!-- tab标签列 -->
    <ul class="tab-title">
      <li :class="{ 'active': tabID == 'one'}"  @click="changeTab('one')">
        <a href="javascript:;" data-tablink="one">tab1</a>
      </li>
      <li  :class="{ 'active': tabID == 'two'}"  @click="changeTab('two')">
        <a href="javascript:;" data-tablink="two">tab2</a>
      </li>
      <li  :class="{ 'active': tabID == 'three'}" @click="changeTab('three')">
        <a href="javascript:;" data-tablink="three">tab3</a>
      </li>
    </ul>
    <!-- tab内容 -->
    <div class="tab-inner-wrap">
      <div id="one" class="tab-inner" v-if="tabID == 'one'">
        <!-- tab1的内容 -->
        内容1 内容1 内容1 内容1
      </div>
      <div id="two" class="tab-inner" v-if="tabID == 'two'">
        <!-- tab2的内容 -->
        内容2
      </div>
      <div id="three" class="tab-inner" v-if="tabID == 'three'">
        <!-- tab3的内容 -->
        内容3
      </div>
    </div>
  </div>
</div>

CSS同上喔

程序

const app = Vue.createApp({
  data(){
    return{
      tabID:'one',
    }
  },
  methods:{
    changeTab(id){
      this.tabID = id;
    }
  }
}).mount('#app')

程序码Vue3

附上程序码

本篇参考文章:
https://www.webdesigns.com.tw/jquery_tab.asp


<<:  D17 - 吃一颗 Class 语法糖 (上)

>>:  Day 30-完赛心得

Day 21. Unity 介面与Unreal Engine介面比较

我Day 2有关於Unity介面的介绍,一般来说,学习顺序是Unity -> Unreal,因...

Day 14 | 魔术方块AR游戏开发Part3 - 面的旋转(上)

在上一篇我们完成了魔术方块的侦测,今天我们要来制作面的旋转。 目录 选择的面 面的旋转 选择的面 建...

Day7-Go回圈

前言 回圈基本上是每个程序语言必备的函式,藉以回圈来达成反覆或是循环的动作。而 Go 语言的回圈种类...

Day27 Redis架构实战-Redis丛集Slot分流机制

Redis丛集Slot分流机制 # Redis丛集配置 client | V -----------...

{CMoney战斗营} 的期末专题 # 前後端分离

令人崩溃的期末专题进行了两个礼拜,终於在茫然的浑沌中摸索出一些头绪,对规划工作和时辰安排有比较好的掌...