効果を直接確認するために、リロード、左を閉じる、右を閉じる、その他の機能を閉じるなどの右クリック メニューが追加されました。 私の 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キーワード
目次意味構造例カスタムショートカットキー元に戻すとやり直し録音と再生マクロ要約する意味リクエストをオ...
01. コマンドの概要Linux には充実したヘルプ マニュアルが用意されています。コマンドのパラメ...
1. ワニスの概要1. ワニスの紹介Varnish は、新しいソフトウェア アーキテクチャを使用し、...
1. トランザクションとは何ですか?データベース トランザクション (略称: トランザクション) は...
最近、画像上に半透明の背景でテキストを表示する必要があるという要件に遭遇しました。その効果は次のよう...
以下のように表示されます。 SELECT prod_name,prod_price FROM pro...
訪問するたびにブラウザにCookieが生成されますが、 Cookieの存在はユーザーにとって良いこと...
XHTML 言語では、ul タグに li が含まれ、dl タグに dt と dd が含まれることは誰...
仮想マシン内のUbuntu 18.04がネットワークに接続できない問題の解決策は次のとおりですVMw...
/******************** * カーネルにおけるリンクリストの応用********...
ScreenCloud は、必要だとは思わなかった素晴らしい小さなアプリです。デスクトップ Lin...
序文セキュリティ上の理由から、会社が Linux サーバーへのすべてのログインにセキュリティ制限を課...
1. 概要ネットでいろいろ検索してみたところ、Linux システム向けではなく、現在の新しいバージ...
WeChat 関連サービスをデバッグする場合など、職場のサーバー環境でリモートデバッグを行う必要があ...
この半月、期末試験の準備にかなりのエネルギーを費やしました。今日はしっかり復習するべきだったのですが...