整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          如何使用JavaScript實現父級tabs懸停顯示子級導航?問題示例分析

          何使用JavaScript代碼解決父級選項卡鼠標懸停時子級菜單無法操作的問題。解決方案包括在子級導航上添加一個類并使用JavaScript代碼監聽鼠標事件來顯示或隱藏子級菜單。如果無法解決問題,建議檢查CSS樣式是否正確應用、JavaScript代碼是否正確工作、HTML結構是否正確、瀏覽器兼容性是否良好等問題。

          這個問題可以通過添加一些JavaScript代碼來解決。以下是一種可能的解決方案:

          你需要為你的子級導航添加一個類,比如 "subnav"。

          你可以使用JavaScript代碼來監聽鼠標事件,當鼠標移入父級tabs時,添加一個類來顯示子級導航。當鼠標移出tabs元素時,移除這個類來隱藏子級導航。如下所示:

          HTML如下:

          <div class="tabs">

          <a href="#">Tab 1</a>

          <a href="#">Tab 2</a>

          <a href="#">Tab 3</a>

          <div class="subnav">

          <a href="#">Subnav 1</a>

          <a href="#">Subnav 2</a>

          <a href="#">Subnav 3</a>

          </div>

          </div>

          CSS如下:

          .tabs {

          position: relative;

          }

          .subnav {

          position: absolute;

          top: 100%;

          left: 0;

          display: none;

          }

          .tabs:hover .subnav {

          display: block;

          }

          JavaScript如下:

          var tabs = document.querySelector('.tabs');

          var subnav = document.querySelector('.subnav');

          tabs.addEventListener('mouseenter', function() {

          subnav.classList.add('show');

          });

          tabs.addEventListener('mouseleave', function() {

          subnav.classList.remove('show');

          });

          在這個代碼中,當鼠標移入父級tabs時,使用 "mouseenter" 事件來添加一個 "show" 類來顯示子級導航。當鼠標移出tabs元素時,使用 "mouseleave" 事件來移除這個類來隱藏子級導航。

          如果代碼已經和上述的示例代碼類似,并且仍然無法操作子級菜單,那么你可以嘗試以下幾個步驟來診斷問題:

          1、確認CSS樣式是否正確應用

          確保CSS樣式被正確地應用于您的HTML代碼中。檢查CSS選擇器是否正確,檢查樣式表中是否存在任何語法錯誤。

          2、確認JavaScript代碼是否正確工作

          檢查JavaScript代碼是否正確工作。可以在控制臺中打印一些調試信息,例如在 mouseenter 和 mouseleave 事件處理程序中添加 console.log 語句來查看它們是否被正確調用。

          3、檢查HTML結構

          確保您的HTML結構正確,所有必需的元素都存在。檢查類名和ID是否正確命名,并且沒有拼寫錯誤。

          4、檢查瀏覽器兼容性

          檢查瀏覽器兼容性。有些瀏覽器可能不支持某些CSS或JavaScript功能。您可以使用瀏覽器的開發者工具來檢查這些問題,并嘗試在其他瀏覽器中測試您的代碼。


          加圖片注釋,不超過 140 字(可選)

          【成品鎮樓圖】 基礎概念 Tabs組件是一種常見的用戶界面組件,用于在一個界面中展示多個內容區域,并允許用戶通過點擊不同的標簽來切換可見的內容。它的實現原理主要涉及HTML、CSS和JavaScript,以下是一個基本的實現步驟: 1. HTML結構 首先,需要定義一個基本的HTML結構,包括標簽(tabs)和內容(tab content)部分。每個標簽對應一個內容區域。

          <div class="tabs">
            <div class="tab" data-tab="1">Tab 1</div>
            <div class="tab" data-tab="2">Tab 2</div>
            <div class="tab" data-tab="3">Tab 3</div>
          </div>
          <div class="tab-content" data-tab="1">Content 1</div>
          <div class="tab-content" data-tab="2">Content 2</div>
          <div class="tab-content" data-tab="3">Content 3</div>

          2. CSS樣式

          接下來,使用CSS來定義標簽和內容區域的樣式,尤其是如何在不同的標簽被選中時顯示或隱藏內容。

          .tabs {
            display: flex;
          }
          
          .tab {
            padding: 10px;
            cursor: pointer;
            background-color: #f1f1f1;
            border: 1px solid #ccc;
            margin-right: 2px;
          }
          
          .tab.active {
            background-color: #ddd;
          }
          
          .tab-content {
            display: none;
            padding: 10px;
            border: 1px solid #ccc;
            margin-top: 10px;
          }
          
          .tab-content.active {
            display: block;
          }

          3. JavaScript交互

          最后,使用JavaScript來處理標簽的點擊事件,并根據點擊的標簽來顯示相應的內容區域。

          document.addEventListener('DOMContentLoaded', function() {
            const tabs = document.querySelectorAll('.tab');
            const contents = document.querySelectorAll('.tab-content');
          
            tabs.forEach(tab => {
              tab.addEventListener('click', function() {
                const tabId = this.getAttribute('data-tab');
          
                // 移除所有標簽和內容的active類
                tabs.forEach(t => t.classList.remove('active'));
                contents.forEach(c => c.classList.remove('active'));
          
                // 為當前選中的標簽和相應的內容添加active類
                this.classList.add('active');
                document.querySelector(`.tab-content[data-tab="${tabId}"]`).classList.add('active');
              });
            });
          });

          工作原理

          1. HTML結構:定義標簽和內容區域,使用data-tab屬性來關聯標簽和內容。
          2. CSS樣式:初始狀態下所有內容區域都是隱藏的(display: none),只有被選中的內容區域才會顯示(display: block)。
          3. JavaScript交互
          • 監聽每個標簽的點擊事件。
          • 當一個標簽被點擊時,移除所有標簽和內容區域的active類。
          • 為被點擊的標簽和相應的內容區域添加active類,從而顯示對應的內容。

          通過這種方式,Tabs組件能夠在用戶點擊不同的標簽時,動態地顯示和隱藏相應的內容區域,從而實現標簽切換的功能。 Vue3 在Vue 3中,可以使用組件化的方式來實現Tabs組件。以下是一個基本的實現步驟: 1. 創建Tabs組件 首先,創建一個Tabs組件,用于容納所有的標簽和內容。

          <!-- Tabs.vue -->
          <template>
            <div>
              <div class="tabs">
                <div
                  v-for="(tab, index) in tabs"
                  :key="index"
                  :class="['tab', { active: activeTab === index }]"
                  @click="selectTab(index)"
                >
                  {{ tab.label }}
                </div>
              </div>
              <div class="tab-content">
                <slot></slot>
              </div>
            </div>
          </template>
          
          <script>
          export default {
            data() {
              return {
                activeTab: 0,
                tabs: []
              };
            },
            methods: {
              selectTab(index) {
                this.activeTab = index;
              },
              addTab(tab) {
                this.tabs.push(tab);
              }
            },
            provide() {
              return {
                registerTab: this.addTab,
                activeTab: () => this.activeTab
              };
            }
          };
          </script>
          
          <style>
          .tabs {
            display: flex;
          }
          
          .tab {
            padding: 10px;
            cursor: pointer;
            background-color: #f1f1f1;
            border: 1px solid #ccc;
            margin-right: 2px;
          }
          
          .tab.active {
            background-color: #ddd;
          }
          
          .tab-content {
            padding: 10px;
            border: 1px solid #ccc;
            margin-top: 10px;
          }
          </style>
          
          

          2. 創建Tab組件

          接下來,創建一個Tab組件,用于定義每個標簽和其對應的內容。

          <!-- Tab.vue -->
          <template>
            <div v-show="isActive">
              <slot></slot>
            </div>
          </template>
          
          <script>
          export default {
            props: {
              label: {
                type: String,
                required: true
              }
            },
            inject: ['registerTab', 'activeTab'],
            computed: {
              isActive() {
                return this.activeTab() === this.index;
              }
            },
            data() {
              return {
                index: null
              };
            },
            mounted() {
              this.index = this.$parent.tabs.length;
              this.registerTab(this);
            }
          };
          </script>
          
          

          3. 使用Tabs和Tab組件

          最后,在你的主組件中使用TabsTab組件。

          <!-- App.vue -->
          <template>
            <Tabs>
              <Tab label="Tab 1">Content 1</Tab>
              <Tab label="Tab 2">Content 2</Tab>
              <Tab label="Tab 3">Content 3</Tab>
            </Tabs>
          </template>
          
          <script>
          import Tabs from './Tabs.vue';
          import Tab from './Tab.vue';
          
          export default {
            components: {
              Tabs,
              Tab
            }
          };
          </script>

          工作原理

          1. Tabs組件:管理標簽和內容的顯示。它包含一個tabs數組,用于存儲所有的標簽信息,以及一個activeTab變量,用于記錄當前選中的標簽索引。selectTab方法用于切換標簽,addTab方法用于添加標簽。
          2. Tab組件:定義每個標簽和其對應的內容。它通過props接收標簽的名稱,并在mounted生命周期鉤子中將自己添加到父組件的tabs數組中。isActive變量用于控制內容的顯示與隱藏。
          3. 主組件:使用TabsTab組件,通過slot機制將內容傳遞給Tabs組件,并根據activeTab動態顯示對應的內容。

          通過這種方式,可以在Vue 3中實現一個功能完整的Tabs組件。 ColorUI Nav組件源碼

          <template>
          	<view>
          		<cu-custom bgColor="bg-gradual-pink" :isBack="true"><block slot="backText">返回</block><block slot="content">導航欄</block></cu-custom>
          		<view v-for="(item,index) in 10" :key="index" v-if="index==TabCur" class="bg-grey padding margin text-center">
          			Tab{{index}}
          		</view>
          		<view class="cu-bar bg-white solid-bottom">
          			<view class="action">
          				<text class="cuIcon-title text-orange"></text> 默認
          			</view>
          		</view>
          		<scroll-view scroll-x class="bg-white nav" scroll-with-animation :scroll-left="scrollLeft">
          			<view class="cu-item" :class="index==TabCur?'text-green cur':''" v-for="(item,index) in 10" :key="index" @tap="tabSelect" :data-id="index">
          				Tab{{index}}
          			</view>
          		</scroll-view>
          
          		<view class="cu-bar bg-white margin-top solid-bottom">
          			<view class="action">
          				<text class="cuIcon-title text-orange"></text> 居中
          			</view>
          		</view>
          		<scroll-view scroll-x class="bg-white nav text-center">
          			<view class="cu-item" :class="index==TabCur?'text-blue cur':''" v-for="(item,index) in 3" :key="index" @tap="tabSelect" :data-id="index">
          				Tab{{index}}
          			</view>
          		</scroll-view>
          
          		<view class="cu-bar bg-white margin-top solid-bottom">
          			<view class="action">
          				<text class="cuIcon-title text-orange"></text> 平分
          			</view>
          		</view>
          		<scroll-view scroll-x class="bg-white nav">
          			<view class="flex text-center">
          				<view class="cu-item flex-sub" :class="index==TabCur?'text-orange cur':''" v-for="(item,index) in 4" :key="index" @tap="tabSelect" :data-id="index">
          					Tab{{index}}
          				</view>
          			</view>
          		</scroll-view>
          		<view class="cu-bar bg-white margin-top solid-bottom">
          			<view class="action">
          				<text class="cuIcon-title text-orange"></text> 背景
          			</view>
          		</view>
          		<scroll-view scroll-x class="bg-red nav text-center">
          			<view class="cu-item" :class="index==TabCur?'text-white cur':''" v-for="(item,index) in 3" :key="index" @tap="tabSelect" :data-id="index">
          				Tab{{index}}
          			</view>
          		</scroll-view>
          		<view class="cu-bar bg-white margin-top solid-bottom">
          			<view class="action">
          				<text class="cuIcon-title text-orange"></text> 圖標
          			</view>
          		</view>
          		<scroll-view scroll-x class="bg-green nav text-center">
          			<view class="cu-item" :class="0==TabCur?'text-white cur':''" @tap="tabSelect" data-id="0">
          				<text class="cuIcon-camerafill"></text> 數碼
          			</view>
          			<view class="cu-item" :class="1==TabCur?'text-white cur':''" @tap="tabSelect" data-id="1">
          				<text class="cuIcon-upstagefill"></text> 排行榜
          			</view>
          			<view class="cu-item" :class="2==TabCur?'text-white cur':''" @tap="tabSelect" data-id="2">
          				<text class="cuIcon-clothesfill"></text> 皮膚
          			</view>
          		</scroll-view>
          
          	</view>
          </template>
          
          <script>
          	export default {
          		data() {
          			return {
          				TabCur: 0,
          				scrollLeft: 0
          			};
          		},
          		methods: {
          			tabSelect(e) {
          				this.TabCur = e.currentTarget.dataset.id;
          				this.scrollLeft = (e.currentTarget.dataset.id - 1) * 60
          			}
          		}
          	}
          </script>

          vue3+ts改造

          首先我們先來看一下原作者大佬的組件設計

          添加圖片注釋,不超過 140 字(可選)

          需求整理

          從原組件改造整理了如下需求

          1. 支持不同的布局
          • 默認布局
          • 居中布局
          • 平分布局
          1. 支持不同的背景樣式
          • 默認背景
          • 自定義背景顏色
          1. 支持圖標和背景色的標簽項

          初步實現

          tabs組件

          
          <!-- Tabs.vue -->
          <template>
            <div :class="isCard !== false ? 'is-card' : ''">
              <div
                class="nav flex"
                :class="[, `bg-${bg}`, `text-${text}`]"
                :style="getFlex"
              >
                <div
                  class="cu-item"
                  v-for="(tab, index) in tabs"
                  :key="index"
                  @click="selectTab(index, tab)"
                  :class="[activeTab === index ? 'cur text-blue' : '']"
                >
                  <i
                    v-if="tab.icon"
                    :class="`cuIcon-${tab.icon} text-${
                      activeTab === index ? 'blue' : tab.iconColor
                    }`"
                  ></i>
                  {{ tab.label }}
                </div>
              </div>
              <div class="tab-content"><slot :tab="tabs[activeTab]"></slot>·</div>
            </div>
          </template>
          
          <script setup lang="ts">
          import { ref, provide, computed, defineEmits, watch } from "vue";
          
          interface TabItem {
            label: string;
            icon?: string;
            iconColor?: string;
            bgColor?: string;
          }
          
          const tabs = ref<TabItem[]>([]);
          const activeTab = ref(0);
          
          const emit = defineEmits(["update:modelValue", "select"]);
          
          const selectTab = (index: number, tab: TabItem) => {
            activeTab.value = index;
            emit("update:modelValue", index);
            emit("select", tab);
          };
          
          const addTab = (tab: TabItem) => {
            tabs.value.push(tab);
            return tabs.value.length - 1; // 返回新添加的tab的索引
          };
          
          provide("registerTab", addTab);
          provide("activeTab", activeTab);
          
          const props = withDefaults(
            defineProps<{
              modelValue: number;
              center?: boolean;
              bg?: string;
              text?: string;
              isCard?: boolean;
              mode?: "center" | "flex-start" | "space-between";
            }>(),
            {
              center: false,
              bg: "white",
              isCard: false,
              mode: "flex-start",
              modelValue: 0,
            }
          );
          
          const getFlex = computed(() => {
            if (props.center !== false) {
              return "justify-content:center;";
            }
            return `justify-content:${props.mode}`;
          });
          
          watch(
            () => props.modelValue,
            (newVal) => {
              activeTab.value = newVal;
            }
          );
          </script>
          
          <script lang="ts">
          export default {
            name: "TTabs",
          };
          </script>
          
          <style>
          .tab-content {
            padding: 10px 16px;
            background: #fff;
          }
          </style>
          
          
          

          解釋

          1. Tabs.vue
          • 添加了 centerbgtextmode 屬性,以支持不同的布局和背景樣式。
          • 使用 computed 屬性 getFlex 動態計算布局樣式。
          • 通過 provideinject 實現子組件與父組件之間的數據傳遞和狀態管理。
          1. Tab.vue
          • 定義了 labeliconiconColor 屬性,以支持圖標和顏色的自定義。
          • 使用 inject 獲取父組件提供的 registerTabactiveTab,并在組件掛載時進行注冊。

          通過這些改造,我們的組件能夠支持不同的布局和背景樣式,并且標簽項可以包含圖標和自定義背景色。這樣就滿足了原組件的所有需求。 思考 那是不是就滿足了我們日常的開發需求呢,我的回答是我的是基本上滿足了,但還應該增加幾個常用功能 雙向綁定的當前選中變量:組件聯動、動態內容切換、狀態同步; select 事件回調并且傳回的是 tab:日志記錄、業務處理、路由導航; 自定義插槽:自定義樣式、復雜內容、圖標和文本組合。 代碼改進 為了滿足上述需求,我們可以進一步改進組件,增加以下功能:

          1. 雙向綁定的當前選中變量:通過 v-model 實現。
          2. select 事件回調并且傳回的是 tab:在 selectTab 方法中觸發事件并傳遞當前選中的 tab 信息。
          3. 自定義插槽:允許用戶自定義標簽項的內容。

          改進后的 Tabs 組件

          <!-- Tabs.vue -->
          <template>
            <div :class="isCard !== false ? 'is-card' : ''">
              <div
                class="nav flex"
                :class="[, `bg-${bg}`, `text-${text}`]"
                :style="getFlex"
              >
                <div
                  class="cu-item"
                  v-for="(tab, index) in tabs"
                  :key="index"
                  @click="selectTab(index, tab)"
                  :class="[modelValue === index ? 'cur text-blue' : '']"
                >
                  <i
                    v-if="tab.icon"
                    :class="`cuIcon-${tab.icon} text-${
                      modelValue === index ? 'blue' : tab.iconColor
                    }`"
                  ></i>
                  {{ tab.label }}
                </div>
              </div>
              <div class="tab-content">
                <slot :tab="tabs[activeTab]"></slot>·
              </div>
            </div>
          </template>
          
          <script setup lang="ts">
          import { ref, provide, computed, defineEmits, watch } from "vue";
          
          interface TabItem {
            label: string;
            icon?: string;
            iconColor?: string;
            bgColor?: string;
          }
          
          const tabs = ref<TabItem[]>([]);
          const activeTab = ref(0);
          
          const emit = defineEmits(["update:modelValue", "select"]);
          
          const selectTab = (index: number, tab: TabItem) => {
            activeTab.value = index;
            emit("update:modelValue", index);
            emit("select", tab);
          };
          
          const addTab = (tab: TabItem) => {
            tabs.value.push(tab);
            return tabs.value.length - 1; // 返回新添加的tab的索引
          };
          
          provide("registerTab", addTab);
          provide("activeTab", activeTab);
          
          const props = withDefaults(
            defineProps<{
              modelValue: number;
              center?: boolean;
              bg?: string;
              text?: string;
              isCard?: boolean;
              mode?: "center" | "flex-start" | "space-between";
            }>(),
            {
              center: false,
              bg: "white",
              isCard: false,
              mode: "flex-start",
            }
          );
          
          const getFlex = computed(() => {
            if (props.center !== false) {
              return "justify-content:space-between;";
            }
            return `justify-content:${props.mode}`;
          });
          
          watch(
            () => props.modelValue,
            (newVal) => {
              activeTab.value = newVal;
            }
          );
          </script>
          
          <script lang="ts">
          export default {
            name: "TTabs",
          };
          </script>
          
          <style>
          .tab-content {
            padding: 10px 16px;
            background: #fff;
          }
          </style>

          改進后的 TabItem 組件

          <!-- Tab.vue -->
          <template>
            <div v-show="isActive">
              <slot></slot>
              <slot name="custom" :tab="tabData"></slot>
            </div>
          </template>
          
          <script setup lang="ts">
          import { inject, ref, computed, onMounted, Ref } from "vue";
          
          const props = withDefaults(
            defineProps<{
              label: string;
              icon?: string;
              iconColor?: string;
            }>(),
            {
              icon: "",
              iconColor: "black",
            }
          );
          
          const registerTab =
            inject<(tab: { label: string; icon?: string; iconColor?: string }) => number>(
              "registerTab"
            );
          const activeTab = inject<Ref<number>>("activeTab");
          
          const index = ref<number | null>(null);
          
          const isActive = computed(() => {
            return activeTab?.value === index.value;
          });
          
          const tabData = computed(() => ({
            label: props.label,
            icon: props.icon,
            iconColor: props.iconColor,
          }));
          
          onMounted(() => {
            if (registerTab) {
              index.value = registerTab({
                label: props.label,
                icon: props.icon,
                iconColor: props.iconColor,
              });
              console.log(`Tab ${props.label} registered with index ${index.value}`);
            }
          });
          </script>
          
          <script lang="ts">
          export default {
            name: "TTab",
          };
          </script>

          解釋一下 我們在創建一個 Tabs 組件系統,其中包括 TabsTab 兩個組件:

          1. Tabs 組件:負責管理多個 Tab 組件。它提供了一個導航欄,用戶可以點擊不同的標簽來切換內容。
          2. Tab 組件:表示單個標簽頁的內容。每個 Tab 組件通過 labelicon 等屬性來定義其顯示內容。

          通過 provideinject 機制,Tab 組件可以注冊到 Tabs 組件中,并且 Tabs 組件可以管理和控制哪些 Tab 組件是激活狀態。 provideinject provideinject 是 Vue 3 中用于跨組件通信的兩個 API,特別適用于祖孫組件之間的數據傳遞。

          • provide:在祖先組件中使用,提供數據或方法給后代組件。
          • inject:在后代組件中使用,接收祖先組件提供的數據或方法。

          在我們的例子中,Tabs 組件使用 provide 來提供 registerTabactiveTab,而 Tab 組件使用 inject 來接收這些數據。 自定義插槽 自定義插槽允許我們在組件中定義可插入的內容,并且可以傳遞數據給插槽內容。

          • 普通插槽:默認插槽,不需要命名。
          • 命名插槽:通過 name 屬性命名,可以在使用組件時指定不同的內容插入到不同的插槽中。
          • 作用域插槽:可以傳遞數據給插槽內容。

          跨組件自定義插槽傳值 跨組件自定義插槽傳值結合了 provide/inject 和作用域插槽的概念。通過 Tabs 組件提供的數據,Tab 組件可以在自定義插槽中使用這些數據。 使用示例 在使用時,確保你在自定義插槽中正確地接收傳遞的數據:

          <template>
            <div>
              <TTitle>綜合示例:雙向綁定、事件回調、自定義插槽</TTitle>
              <TTabs v-model="selectedTab" @select="handleSelect">
                <TTab label="Tab 1">
                  <p>Content for Tab 1</p>
                </TTab>
                <TTab label="Tab 2">
                  <p>Content for Tab 2</p>
                </TTab>
                <TTab label="Tab 3" icon="rank" icon-color="red">
                  <template #custom="{ tab }">
                    {{ tab.label }} 自定義插槽
                  </template>
                </TTab>
              </TTabs>
              <p>當前選中的標簽索引:{{ selectedTab }}</p>
              <p>選中的標簽信息:{{ selectedTabInfo }}</p>
            </div>
          </template>
          
          <script setup lang="ts">
          import { ref } from "vue";
          
          const selectedTab = ref(0);
          const selectedTabInfo = ref(null);
          
          const handleSelect = (tab) => {
            selectedTabInfo.value = tab;
          };
          </script>

          總結

          本文詳細介紹了如何實現和改造Tabs組件,涵蓋了從基礎的HTML、CSS和JavaScript實現,到在Vue 3中實現組件化,再到進一步的功能改造。通過逐步完善Tabs組件的功能,使其能夠滿足更多的開發需求。

          果展示

          選中樣式制作

          • 將每個 tab 設置固定寬度。
          • 每個tab 添加相對定位,居中,行高
          • 添加偽類,偽類設置絕對定位,在底部。
          • 設置偽類的寬度為 0%(偽類會繼承該元素的寬度)
          • 設置選中時候的偽類寬度為50%(視情況而定)
          • 給元素添加過渡樣式

          HTML代碼(wxml)

          			
          				{{item.name}}
          			

          CSS(less):

          		.nav-bar{
          			position: relative;
          			z-index: 10;
          			height: 90upx;
          			white-space: nowrap;
          			background-color: #fbfbfb;
          			
          			.nav-item{
          				display: inline-block;
          				width: 150upx;
          				height: 90upx;
          				text-align: center;
          				line-height: 90upx;
          				font-size: 30upx;
          				color: #a4a4a4;
          				position: relative;
          			}
          			
          			.current{
          				color: #3f3f3f;
          				font-weight: bold;
          			}
          		}

          實現效果大致為這樣的:

          拓展

          PS: 以上為純CSS實現部分,如果項目 tab數量 為通過接口動態獲取的,可以適當加入一些 js 計算。

          JS 思路:

          • 獲取當前選中的 tab 的寬度
          • 獲取當前選中 tab 以及它之前全部 tab 的寬度總和。
          • 獲取當前屏幕寬度
          • 判斷當前選中 tab 是否超過屏幕中心點(當前選中 tab 以及它之前全部 tab 的寬度總和 - 當前選中 tab 寬度/2
          • 移動當前 tabs 到屏幕的重心點位置

          大致為(以微信小程序為例):

          				let width = 0; // 當前選中選項卡及它之前的選項卡之和總寬度
          				let nowWidth = 0; // 當前選項卡的寬度
          				//獲取可滑動總寬度
          				for (let i = 0; i <= index; i++) {
          					let result = await this.getElSize('tab' + i);
          					width += result.width;
          					if(i === index){
          						nowWidth = result.width;
          					}
          				}
          				// console.log(width, nowWidth, windowWidth)
          				//等待swiper動畫結束再修改tabbar
          				this.$nextTick(() => {
          					if (width - nowWidth/2 > windowWidth / 2) {
          						//如果當前項越過中心點,將其放在屏幕中心
          						this.scrollLeft = width - nowWidth/2 - windowWidth / 2;
          						console.log(this.scrollLeft)
          					}else{
          						this.scrollLeft = 0;
          					}
          					if(typeof e === 'object'){
          						this.tabCurrentIndex = index; 
          					}
          					this.tabCurrentIndex = index; 
          				})

          ps: getElSize() 函數代碼為:

          			getElSize(id) { 
          				return new Promise((res, rej) => {
          					let el = uni.createSelectorQuery().select('#' + id);
          					el.fields({
          						size: true,
          						scrollOffset: true,
          						rect: true
          					}, (data) => {
          						res(data);
          					}).exec();
          				});
          			},

          這樣就可以實現動態 tab 切換了:


          主站蜘蛛池模板: 精品一区二区三区在线播放| 色综合视频一区二区三区| 亚洲AV无码片一区二区三区| 精品无码一区二区三区在线| 人妻无码一区二区三区AV | 老熟妇仑乱一区二区视頻| 亚洲AV无码一区二区乱孑伦AS| 日本一区精品久久久久影院| 国内精品一区二区三区最新| 国产成人精品一区在线| 国产肥熟女视频一区二区三区 | 国产精品无码一区二区三区免费| 精品日韩一区二区| 视频在线观看一区二区| 亚洲AV日韩综合一区| 国产丝袜一区二区三区在线观看 | 久久久国产一区二区三区| 丰满人妻一区二区三区视频53| 一区在线免费观看| 在线播放偷拍一区精品| 内射女校花一区二区三区| 久久99国产精一区二区三区| 亚洲AV成人一区二区三区AV| 日本大香伊一区二区三区| 波多野结衣久久一区二区| 夜色福利一区二区三区| 日韩精品一区二区三区中文字幕| 精品一区二区三区无码免费视频| 日韩三级一区二区三区| 天天综合色一区二区三区| 日韩精品一区二区三区中文 | 一区二区国产在线观看| 亚洲国产成人久久一区二区三区| 国产福利酱国产一区二区| 亚洲福利视频一区二区三区| 精品视频在线观看你懂的一区| 日韩精品无码久久一区二区三| 无码AV天堂一区二区三区| 精品国产一区二区三区久久蜜臀| 亚洲一区中文字幕在线电影网| 波多野结衣AV一区二区三区中文|