効果を直接確認するために、リロード、左を閉じる、右を閉じる、その他の機能を閉じるなどの右クリック メニューが追加されました。 私の github のコードもチェックしてみてください (このコンポーネントが役に立つと思ったら、忘れずにスターを付けてください) コード: https://github.com/Caijt/VuePageTab デモ: https://caijt.github.io/VuePageTab/ 私のマルチタブコンポーネントでキャッシュを削除する方法は、キープアライブコンポーネントの包含と除外の組み合わせを使用するのではなく、キャッシュを削除するブルートフォース方式を使用することです。これは以前のブログでも言及しました。この方法を使用すると、より完全なマルチタブ機能を実現できます。たとえば、同じルートで異なるパラメータに応じて同時に異なるタブを開くことができ、それらのルートの名前値を書く必要はありません。 まず、コンポーネントコードを直接見てみましょう(いくつかのelement-uiコンポーネントが使用されています。element-uiを使用しない場合は、それらを削除して自分で実装できます) <テンプレート> <div class="__common-layout-pageTabs"> <el-スクロールバー> <div class="__tabs"> <div クラス="__タブ項目" v-for="openedPageRouters 内の項目" :class="{ '__is-active': item.fullPath == $route.fullPath、 }" :key="item.fullPath" @click="onClick(アイテム)" @contextmenu.prevent="コンテキストメニューを表示する($event, item)" > {{ item.meta.title }} <span クラス="el-icon-close" @click.stop="onClose(item)" @contextmenu.prevent.stop="" :style="openedPageRouters.length <= 1 ? 'width:0;' : ''" </span> </div> </div> </el-スクロールバー> <div v-show="コンテキストメニューを表示"> <ul :style="{ 左: contextMenuLeft + 'px'、上: contextMenuTop + 'px' }" クラス="__コンテキストメニュー" > <li> <el-button type="text" @click="reload()" size="mini"> 再読み込み</el-button> </li> <li> <el-ボタン タイプ="テキスト" @click="その他の左を閉じる" :disabled="false" サイズ="ミニ" >左を閉じる</el-button > </li> <li> <el-ボタン タイプ="テキスト" @click="その他の右を閉じる" :disabled="false" サイズ="ミニ" >右を閉じる</el-button > </li> <li> <el-button type="text" @click="closeOther" size="mini" >その他を閉じる</el-button > </li> </ul> </div> </div> </テンプレート> <スクリプト> エクスポートデフォルト{ 小道具: { keepAliveComponentInstance: {}, //キープアライブ制御インスタンスオブジェクト blankRouteName: { タイプ: 文字列、 デフォルト: "空白", }, // ルート名の値(空白)}, データ() { 戻る { contextMenuVisible: false, // 右クリック メニューが表示されるかどうかcontextMenuLeft: 0, // 右クリック メニューの表示位置contextMenuTop: 0, // 右クリック メニューの表示位置contextMenuTargetPageRoute: null, // 右ボタンが指すメニュー ルートopenedPageRouters: [], // 開かれたルート ページ}; }, 時計: //ルートが変更されたら、ページを開くメソッドを実行します $route: { ハンドラ(v) { this.openPage(v); }, 即時: true、 }, }, マウント() { //右クリック メニューを閉じるためのクリックを追加します。window.addEventListener("click", this.closeContextMenu); }, 破壊された() { window.removeEventListener("click", this.closeContextMenu); }, メソッド: { //ページを開く openPage(route) { ルート名が this.blankRouteName の場合 戻る; } isExist = this.openedPageRouters.some( とする (アイテム) => item.fullPath == route.fullPath ); 存在する場合 開いたページルートを this.openedPageRouters.find( とする (アイテム) => item.path == route.path ); // ページが異なるパラメータを持つ複数のページをサポートしているかどうかを確認します。サポートしておらず、同じパス値を持つページルートがすでに存在する場合は、それを置き換えます if (!route.meta.canMultipleOpen && openedPageRoute != null) { this.delRouteCache(openedPageRoute.fullPath); this.openedPageRouters.splice( this.openedPageRouters.indexOf(openedPageRoute)、 1、 ルート ); } それ以外 { this.openedPageRouters.push(ルート); } } }, //ページタブをクリック onClick(route) { (route.fullPath !== this.$route.fullPath)の場合{ this.$router.push(route.fullPath); } }, //ページタブを閉じる onClose(route) { ルートのインデックスを this.openedPageRouters.indexOf(route); this.delPageRoute(ルート); ルートのfullPathがthis.$route.fullPathの場合{ //ページを削除した後、前のページにジャンプします this.$router.replace( this.openedPageRouters[インデックス == 0 ? 0 : インデックス - 1] ); } }, //右クリックしてメニューを表示しますshowContextMenu(e, route) { this.contextMenuTargetPageRoute = ルート; this.contextMenuLeft = e.layerX; this.contextMenuTop = e.layerY; this.contextMenuVisible = true; }, //右クリックメニューを非表示にする closeContextMenu() { this.contextMenuVisible = false; this.contextMenuTargetPageRoute = null; }, //ページをリロードする reload() { this.delRouteCache(this.contextMenuTargetPageRoute.fullPath); if (this.contextMenuTargetPageRoute.fullPath === this.$route.fullPath) { this.$router.replace({ name: this.blankRouteName }).then(() => { this.$router.replace(this.contextMenuTargetPageRoute); }); } }, //他のページを閉じる closeOther() { (i = 0 とします; i < this.openedPageRouters.length; i++) { r = this.openedPageRouters[i]とします。 if (r !== this.contextMenuTargetPageRoute) { this.delPageRoute(r); 私 - ; } } if (this.contextMenuTargetPageRoute.fullPath != this.$route.fullPath) { this.$router.replace(this.contextMenuTargetPageRoute); } }, //パスに基づいてインデックスを取得する getPageRouteIndex(fullPath) { (i = 0 とします; i < this.openedPageRouters.length; i++) { if (this.openedPageRouters[i].fullPath === fullPath) { i を返します。 } } }, //左ページを閉じる closeOtherLeft() { インデックスを this.openedPageRouters.indexOf( とする this.contextMenuTargetPageRoute ); currentIndex = this.getPageRouteIndex(this.$route.fullPath); とします。 if (インデックス > 現在のインデックス) { this.$router.replace(this.contextMenuTargetPageRoute); } (i = 0; i < インデックス; i++) の場合 { r = this.openedPageRouters[i]とします。 this.delPageRoute(r); 私 - ; 索引 - ; } }, //右ページを閉じる closeOtherRight() { インデックスを this.openedPageRouters.indexOf( とする this.contextMenuTargetPageRoute ); currentIndex = this.getPageRouteIndex(this.$route.fullPath); とします。 (i = index + 1 とします; i < this.openedPageRouters.length; i++) { r = this.openedPageRouters[i]とします。 this.delPageRoute(r); 私 - ; } if (インデックス < 現在のインデックス) { this.$router.replace(this.contextMenuTargetPageRoute); } }, //ページを削除する delPageRoute(route) { routeIndex = this.openedPageRouters.indexOf(route); とします。 ルートインデックス >= 0 の場合 this.openedPageRouters.splice(routeIndex, 1); } ルートキャッシュを削除します。 }, //ページキャッシュを削除する delRouteCache(key) { キャッシュを this.keepAliveComponentInstance.cache とします。 キーを this.keepAliveComponentInstance.keys とします。 (i = 0 とします; i < keys.length; i++) { if (keys[i] == key) { キーを連結します(i, 1); if (cache[key] != null) { キャッシュ[キー]を削除します。 } 壊す; } } }, }, }; </スクリプト> <スタイル lang="scss"> .__共通レイアウトページタブ { .__コンテキストメニュー{ // 幅: 100px; マージン: 0; 境界線: 1px 実線 #e4e7ed; 背景: #fff; zインデックス: 3000; 位置: 絶対; リストスタイルタイプ: なし; パディング: 5px 0; 境界線の半径: 4px; フォントサイズ: 14px; 色: #333; ボックスの影: 1px 1px 3px 0 rgba(0, 0, 0, 0.1); li { マージン: 0; パディング: 0px 15px; &:ホバー{ 背景: #f2f2f2; カーソル: ポインタ; } ボタン { 色: #2c3e50; } } } タブの境界線の色: #dcdfe6; 位置: 相対的; &::前に { コンテンツ: ""; 境界線下部: 1px 実線 $c-tab-border-color; 位置: 絶対; 左: 0; 右: 0; 下部: 0; 高さ: 100%; } .__タブ { ディスプレイ: フレックス; .__タブ項目{ 空白: ラップなし; パディング: 8px 6px 8px 18px; フォントサイズ: 12px; 境界線: 1px 実線 $c-tab-border-color; 左境界線: なし; 下境界線: 0px; 行の高さ: 14px; カーソル: ポインタ; 遷移: 色 0.3s 立方ベジェ(0.645, 0.045, 0.355, 1)、 パディング 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); &:最初の子 { 左境界線: 1px 実線 $c-tab-border-color; 左上の境界線の半径: 2px; 左マージン: 10px; } &:最後の子 { 右上の境界線の半径: 2px; 右マージン: 10px; } &:not(.__is-active):ホバー { 色: #409eff; .el-icon-close { 幅: 12px; 右マージン: 0px; } } &.__ はアクティブです { 右パディング: 12px; 下境界線: 1px 実線 #fff; 色: #409eff; .el-icon-close { 幅: 12px; 右マージン: 0px; 左マージン: 2px; } } .el-icon-close { 幅: 0px; 高さ: 12px; オーバーフロー: 非表示; 境界線の半径: 50%; フォントサイズ: 12px; 右マージン: 12px; 変換元: 100% 50%; 遷移: すべて 0.3 秒 cubic-bezier(0.645, 0.045, 0.355, 1); 垂直配置: テキスト上; &:ホバー{ 背景色: #c0c4cc; 色: #fff; } } } } } </スタイル> このコンポーネントには 2 つのプロパティが必要です。1 つは keepAliveComponentInstance (キープアライブ制御インスタンス オブジェクト)、もう 1 つは blankRouteName (空のルート名) です。なぜキープアライブ コントロール インスタンス オブジェクトが必要なのでしょうか。このオブジェクトには、キープアライブ キャッシュ データを格納するキャッシュとキーの 2 つのプロパティがあるためです。このオブジェクトを使用すると、タブが閉じられたときにキャッシュを手動で削除できます。このオブジェクトはどうやって取得するのでしょうか? 以下に示すように、keep-alive が配置されている親ページのマウントされたイベントで取得します (keep-alive とマルチページ タブ コンポーネントが同じ親ページにない場合は、vuex を使用して値を渡す必要がある場合があります) <テンプレート> <div id="アプリ"> <ページタブ:keep-alive-component-instance="keepAliveComponentInstance" /> <div ref="keepAliveContainer"> <キープアライブ> <ルータービュー:key="$route.fullPath" /> </キープアライブ> </div> </div> </テンプレート> <スクリプト> 「./components/pageTabs.vue」からpageTabsをインポートします。 エクスポートデフォルト{ 名前:「アプリ」、 コンポーネント: ページタブ、 }, マウント() { (this.$refs.keepAliveContainer) の場合 { this.keepAliveComponentInstance = this.$refs.keepAliveContainer.childNodes[0].__vue__; //キープアライブコントロールインスタンスオブジェクトを取得する} }, データ() { 戻る { keepAliveComponentInstance: null、 }; } }; </スクリプト> 空白ルートの名前は何ですか? 主に、現在のページを更新する機能を実現したいです。 vue では現在のページにジャンプできないことがわかっているので、最初に別のページにジャンプしてから、ページに戻って、更新効果を実現したいと思います。 (もちろん relpace を使用しているので、履歴レコードは生成されません) 注: この空白ルートはルート ルートに固定されていません。これは、マルチタブ コンポーネントの場所によって異なります。ルート ルーター ビューとレイアウト コンポーネントがあり、レイアウト コンポーネントにも子ルーター ビューがあり、マルチタブ コンポーネントがこのレイアウト コンポーネント内にある場合は、レイアウト コンポーネントに対応するルートの子に空白ルートを定義する必要があります。 このコンポーネントは、ルーティングオブジェクトのメタオブジェクトに応じて以下のように異なる構成になります。 ルータ = 新しいルータ({ ルート: [ //これは空白ページです。現在のページを再読み込みすると{ 名前: "空白", パス: "/空白", }, { パス: "/a", 成分: A、 メタ: { title: "ページ A", //ページ タイトル canMultipleOpen: true //異なるパラメータに基づいて複数のタブを開くことをサポートします。/a と /a?v=123 のそれぞれに 2 つのタブを開く必要がある場合は、true に設定してください。そうでない場合は、1 つのタブのみが表示され、後で開いたタブが前に開いたタブに置き換わります。} } } 以上がVueのマルチタブコンポーネントの実装の詳細です。Vueのマルチタブコンポーネントの実装の詳細については、123WORDPRESS.COMの他の関連記事に注目してください。 以下もご興味があるかもしれません:
|
<<: Vue で HTML 5 ドラッグ アンド ドロップ API を使用する方法
>>: JavaScriptの詳細な説明 thisキーワード
背景前景要素から特定の色を継承する影の効果を作成する方法を知りたいと思ったことはありませんか?方法に...
Linux に zip 解凍機能をインストールする通常、 zip コマンドは Linux サーバーに...
1. 背景多くのブログや記事を読みましたが、JVM のメモリ割り当て方法に関する包括的な記事は見つか...
MySQLテーブルの自動インクリメント列の初期値をリセットする方法1. 問題の説明MySQL データ...
目次1. Dockerをビルドする2. コンテナに入る3. 設定ファイルを変更する4. Kafkaを...
目次序文React Context の初見コンテキストの使い方コンテキストを直接取得できるいくつかの...
1. 親コンポーネントは props を使用して子コンポーネントにデータを渡すことができます。 2....
LinuxにGeoIPをインストールする yum で nginx-module-geoip をインス...
目次仕様a. ページファイルはVueの単一ファイルコンポーネント仕様に準拠しています。 b. コンポ...
1. 概要ユーザーは、アクセスする Web アプリケーションがインタラクティブでスムーズに実行される...
通常の説明%はどのクライアントでも接続できることを意味しますlocalhostはローカルコンピュータ...
mptemp は安全な方法で一時ファイルまたはディレクトリを作成します。このコマンドの適用範囲: R...
序文: MySQL データベースは、よく使用される集計関数、日付および文字列処理関数など、幅広い関数...
「Enter != Submit」問題を実装するには、通常、「ボタンの種類」と「入力ボックスの数」か...
目次1. Vue環境を構築する2. Vue スキャフォールディングツール3. プロジェクトを作成する...