Vue はタブ ラベルを実装します (ラベルが自動スクロールを超える)

Vue はタブ ラベルを実装します (ラベルが自動スクロールを超える)

作成されたタブラベルがページの表示領域を超えると、タブラベルの距離だけ自動的にスクロールされます。また、クリックするとタブラベルを手動でスクロールできます。効果については GIF 画像を参照してください。

エフェクトプレビューGIF

<テンプレート>
    <div class="main-box">
        <button @click="add">追加</button>
        <div class="main-box-tab">
            <i @click="前へ"><<</i>
            <i @click="次へ">>></i>
            <div class="main-box-tab-content" ref="タブ">
                <div class="main-box-tab-roll">
                    <div v-for="(item,index) タブ内" :key="index"
                         :class="{'タブ項目アクション':アクション名 === 項目名 ,'タブ項目':アクション名 !== 項目名}"
                         @click.stop="clickTab(item.name,index)">
                        <span>{{item.meta.title}}</span>
                        <i class="el-icon-close" @click.stop="close(item.name)"></i>
                    </div>
                </div>
            </div>
        </div>
        <div class="メインボックスコンテンツ">
            <div>{{アクション名}}</div>
        </div>
    </div>
</テンプレート>
<スクリプト>
    エクスポートデフォルト{
        名前: "インデックス",
        データ() {
            戻る {
                タブ: [],
                移動X: 0,
                カウント: 1,
                空き: 0,
                タブ数: 0,
                アクション名: 'test1'
            }
        },
        時計:
            アクション名(val) {
                len = this.tabs.lengthとします
                // 重複データがある場合は、後続の関数の実行を終了します for (let i = 0; i < len; i++) {
                    if (this.tabs[i].name === val) {
                        this.$nextTick(() => {
                            this.translateX((i + 1 - this.tabsCount) * this.width - this.unoccupied)
                        })
                        戻る
                    }
                }

                this.tabs.push({
                    名前: `test${this.count}`,
                    メタ: {
                        タイトル: `test${this.count}`
                    }
                })
                this.$nextTick(() => {
                  // (合計でいくつのタブがあるか - オフセットされていないときに表示される要素の数) * 単一のタブ ラベル要素の長さ - 隠れたタブ要素の表示部分の幅 this.translateX((this.tabs.length - this.tabsCount) * this.width - this.unoccupied)
                })
            }
        },
        マウント() {
            this.tabs.push({
                名前: `test${this.count}`,
                メタ: {
                    タイトル: `test${this.count}`
                }
            })
            this.$nextTick(() => {
                tabs = this.$refs.tabs とします。
                getStyle = getComputedStyle(tabs.children[0].children[0], null) とします。
                marginLeft = parseFloat(getStyle.marginLeft.substr(0, getStyle.marginLeft.length - 2)) とします。
                marginRight = parseFloat(getStyle.marginRight.substr(0, getStyle.marginRight.length - 2)) とします。
                // 要素の実際の幅 = 要素の幅 + 余白 this.width = marginLeft + marginRight + tabs.children[0].children[0].offsetWidth

                /**
                 * 実装ロジックを理解するために、次のコメント計算方法が使用されます**/
                // // 表示領域に配置できる要素の数 = 表示領域の幅 / サブ要素の実際の幅 // let num = tabs.offsetWidth / this.width

                // // 隠されたタブ要素の表示部分の幅 = 表示領域の幅 - (子要素の実際の幅 * 整数に変換された数値)
                // this.unoccupied = tabs.offsetWidth - (this.width * parseInt(num))

                //最後に余りに簡略化されます(結果は上記の計算と同じになります)
                this.unoccupied = tabs.offsetWidth % this.width
                // 整数に変換 this.tabsCount = parseInt(tabs.offsetWidth / this.width)
            })
        },
        メソッド: {
            追加() {
                this.count++
                this.actionName = `test${this.count}`
            },

            /**
             * タブページを切り替える**/
            クリックタブ(名前) {
                if (this.actionName !== 名前) {
                    this.actionName = 名前
                }
            },

            /**
             * タブページを閉じる**/
            閉じる(名前) {
                len = this.tabs.lengthとします
                ジャンプ名をnullにする
                長さが1より大きい場合
                    (i = 0; i < len; i++) の場合 {
                        if (this.tabs[i].name === name) {
                            this.tabs.splice(i, 1)

                            ジャンプ名 = this.tabs[i ? i - 1 : 0].name
                            if (this.actionName !== ジャンプ名 && name === this.actionName) {
                                this.actionName = ジャンプ名
                            }

                            this.$nextTick(() => {
                                this.previous()
                            })
                            戻る
                        }
                    }
                }
            },

            /**
             * 右にシフト**/
            次() {
                // scrollWidth は正確ではありません // this.width * this.tabs.length を使用して合計の長さを計算します let totalWidth = this.width * this.tabs.length

                this.$nextTick(() => {
                    dom = this.$refs.tabs とします。
                    // 表示領域 < スクロール領域 (スクロール領域は表示領域より大きい場合にのみ移動できます)
                    // 移動距離 + 表示領域 = スクロール領域の幅(最後の幅、クリック時の実際の幅)< スクロール領域if (dom.clientWidth < totalWidth && this.moveX + dom.clientWidth < totalWidth) {
                        // this.moveX は 0 から未使用スペースの幅を引いた値です。this.moveX += this.moveX ? this.width : this.width - this.unoccupied
                        this.translateX(this.moveX)
                    }
                })
            },

            /**
             * 左オフセット**/
            前の() {
                (this.moveX > 0)の場合{
                    this.moveX -= this.width
                    this.translateX(this.moveX)
                }
            },

            /**
             * domの移動を開始する
             **/
            翻訳X(x) {
                this.moveX = x < 0 ? 0 : x
                this.$refs.tabs.children[0].style.transform = `translateX(-${this.moveX}px)`
            }
        }
    }
</スクリプト>

<style lang="scss" スコープ>
    .メインボックス{
        高さ: 500px;
        幅: 500ピクセル;
        パディング: 10px 20px 20px 20px;

        .メインボックスタブ{
            位置: 相対的;
            パディング: 10px 20px;
            オーバーフロー: 非表示;

            & > 私 {
                位置: 絶対;
                カーソル: ポインタ;
                下: 15px;

                &:n番目の子(1) {
                    左: 0;
                }

                &:n番目の子(2) {
                    右: 0;
                }
            }

            .メインボックスタブコンテンツ{
                オーバーフロー: 非表示;

                .メインボックスタブロール{
                    遷移: 変換 .5s;
                    ディスプレイ: フレックス;
                    アイテムの位置を中央揃えにします。

                    div {
                        フレックス収縮: 0;
                        カーソル: ポインタ;
                        幅: 130ピクセル;
                        高さ: 25px;
                        マージン: 0 5px;
                        ディスプレイ: フレックス;
                        アイテムの位置を中央揃えにします。
                        コンテンツの両端揃え: スペースの間;

                        スパン、i {
                            フォントサイズ: 12px;
                        }

                        スパン {
                            左マージン: 10px;
                            オーバーフロー: 非表示;
                            空白: ラップなし;
                            テキストオーバーフロー: 省略記号;
                        }

                        私 {
                            右マージン: 10px;
                        }
                    }
                }
            }

            .タブ項目{
                色: #cccccc;
                背景色: rgba(255, 255, 255, .5);
                境界線の半径: 0 1px 0 1px;
                境界線: 1px 実線 #052141;
            }

            .タブ項目アクション{
                色: #ffffff;
                背景: rgba(0, 180, 255, 0.8);
                境界線の半径: 0 1px 0 1px;
                境界線: 1px実線 #1E2088;
            }

        }

        .メインボックスコンテンツ{
            高さ: calc(100% - 70px);
            パディング: 10px;
            境界線: 1px サドルブラウン実線;
            背景サイズ: 100% 100%;
        }
    }
</スタイル>

Vue のタブタグの実装(タブが自動スクロールを超える)に関するこの記事はこれで終わりです。Vue タブタグの関連コンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き閲覧してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • vue-router がタブタグを切り替えて閉じるときに発生するキャッシュの問題を解決する
  • Vueはタブタグルーティング効果を実装し、Animate.cssを使用して遷移アニメーション効果を作成します。
  • タブページキャッシュ機能を実装するためのvuex + keep-alive
  • Vue2.0で実装したタブ切り替え効果の例(内容はカスタマイズ可能)
  • Vue2.0 タブとページ切り替えトランジションにスタイルを追加する方法
  • vue-router 実装タブページの詳細説明(単一ページ)

<<:  Linux の一般的なコマンド chmod を使用して、ファイルの権限 777 と 754 を変更します。

>>:  MySQL サーバー IO 100% 分析および最適化ソリューション

推薦する

優れたウェブフロントエンドデザインの指標

Web ページのアクセシビリティは、フロントエンドでのみ評価および実装できるもののようです。ユーザビ...

Nginx ベースの Mencached キャッシュ構成の詳細な説明

導入Memcached は分散キャッシュ システムです。Memcached には認証とセキュリティ制...

Linux コマンドにおける Ctrl+z、Ctrl+c、Ctrl+d の違いと使い方

Linux で Ctrl+c、Ctrl+d、Ctrl+z はどういう意味ですか? Ctrl+c と ...

VueプロジェクトにPWAを導入する手順

目次1. 依存関係をインストールする2. vue.config.js ファイルで pwa を設定しま...

MySql キャッシュ クエリの原理とキャッシュ監視およびインデックス監視の概要

クエリキャッシュ1. クエリキャッシュの動作原理クエリ ステートメントを実行する前に、MySQL は...

Nginx のステータス監視とログ分析の詳細な説明

1. Nginx ステータス監視Nginx には、Nginx の全体的なアクセス ステータスを監視す...

JavaScript で大きなファイルの並列ダウンロードを実装する方法

目次1. HTTP範囲リクエスト1.1 範囲構文2. 大きなファイルをダウンロードする方法2.1 補...

Dockerデータを完全にクリーンアップする方法

目次定期的に剪定するミラーエビクションコンテナのクリーンアップネットワークソート体積の蒸発完全にクリ...

MySQL 8.0.13 のインストールと設定方法のグラフィックチュートリアル (Win10 の場合)

MySQL 8.0.13 のインストールと設定方法を皆さんと共有したいと思います。お役に立てれば幸...

Linux で unzip コマンドを使用して複数のファイルを解凍する方法

Linuxにunzipコマンドがない問題の解決策unzipコマンドを使用して.zipファイルを解凍す...

MySQL 完全崩壊: クエリフィルタ条件の詳細な説明

概要実際のビジネス シナリオ アプリケーションでは、ビジネス条件に基づいて対象データを取得およびフィ...

クエリプロファイラを使用して MySQL ステートメントの実行時間を表示する方法

前回の記事では、MySQL ステートメントの実行時間をチェックする 2 つの方法を紹介しました。今日...

HTML テーブル マークアップ チュートリアル (9): セル間隔属性 CELLSPACING

テーブルがコンパクトになりすぎないように、テーブル内のセル間に一定の距離を設定できます。基本的な構文...

H5 WeChatパブリックアカウント認証を実装するための簡単な手順

序文昨日、h5 WeChat認証の実装が必要なプロジェクトがありました。したがって、この機能を完了す...