一般的には、左側にメニューがあった後、ページの上部に履歴タブ メニューを追加する必要があります。 1. tagNavタグコンポーネントを書く 2. ルーティングファイル内の各ルーティングコンポーネントにメタ属性 3. ストアのmutation.jsファイルにタグの追加/削除メソッドを記述し、メソッド内のsessionStorageデータを更新する 4. メイン ページにコンポーネントを追加し、router-view の外側のレイヤーにキープアライブ コンポーネントを追加します。私の場合、main.vue はログイン後のメイン ページであり、他のメニュー ページはこのページのルーティングに基づいています。 5. ミックスイン ファイルを作成します: beforeRouteLeave コールバック。サブページのキャッシュ オブジェクトはこのコールバックでのみ見つかると思われるためです。このファイルを main.js にインポートし、 6. 左メニューにルート監視を追加し、ラベルメニューをクリックしたときに左メニューが対応するメニューオプションを見つけて選択できるようにします。 7. タグ メニューをクリックするとルート リダイレクト メニューになる場合は、リダイレクトをトリガーするルート ページの meta.title のルート属性を取得するルート リスナーを追加し、ページの作成コールバックでタグのストア配列をループして、meta.title を現在のリダイレクトのタグ名に設定する必要があります。 開始コードの説明tagNavコンポーネントを書く <style lang="less" スコープ> @import "./base.less"; .タグ-nav { ディスプレイ: フレックス; アイテムの位置を揃える: ストレッチ; 高さ: 40px; パディング: 2px 0; 背景色: @background-color; { 右マージン: 1px; 幅: 24px; } ホバー{ 色: @light-theme-color; } a:最初の型 { 右マージン: 4px; } 、 .ドロップダウンボタン{ 表示: インラインブロック; 幅:30px; 高さ: 36px; 色: @title-color; 背景色: @white; テキスト配置: 中央; 行の高さ: 36px; 位置: 相対的; zインデックス: 10; } .タグラッパー{ フレックス: 1 1 自動; 位置: 相対的; .tags-wrapper-scroll { 位置: 絶対; 上: 0px; 左: 0; zインデックス: 5; 高さ: 36px; オーバーフロー: 表示可能; 空白: ラップなし; 遷移: すべて .3 のイーズイン アウト。 .タグ { フレックス収縮: 0; カーソル: ポインタ; } } } } </スタイル> <テンプレート> <div class="tags-nav"> <a href="javascript:void(0)" rel="外部 nofollow" rel="外部 nofollow" rel="外部 nofollow" @click="handleScroll('left')"> <icon name="angle-left"></icon> </a> <div class="tags-wrapper" ref="tagsWrapper"> <div class="tags-wrapper-scroll" ref="tagsWrapperScroll" :style="{ left: leftOffset + 'px' }"> <トランジショングループ名="スライドフェード"> <elタグ class="タグスライドフェードアイテム" ref="タグページが開かれました" v-for="(タグ、インデックス) in pageOpenedList" :key="'タグ_' + インデックス" :type="tag.selected ? '': 'info'" :closable="タグ名!='basicDevice'" :id="タグ名" 効果="暗い" :text="タグ名" @close="closeTag(インデックス、$event、タグ名)" @click="タグ選択(インデックス)" >{{tag.title}}</el-tag> </トランジショングループ> </div> </div> <a href="javascript:void(0)" rel="外部 nofollow" rel="外部 nofollow" rel="外部 nofollow" @click="handleScroll('right')"> <icon name="angle-right"></icon> </a> <!-- <el-dropdown class="dropdown-btn" @command="タグを閉じる"> <span class="el-dropdown-link"> <icon name="角度を下向き"></icon> </span> <el-dropdown-menu slot="ドロップダウン"> <el-dropdown-item command="closeOthers">その他を閉じる</el-dropdown-item> <el-dropdown-item command="closeAll">すべて閉じる</el-dropdown-item> </el-dropdown-menu> </el-dropdown> --> <!-- <ドロップダウン配置="bottom-end" @on-click="closeTags"> <a href="javascript:void(0)" rel="外部nofollow" rel="外部nofollow" rel="外部nofollow" style="margin-right: 0;"> <icon name="角度を下向き"></icon> </a> <DropdownMenu スロット="リスト"> <DropdownItem name="closeOthers">その他を閉じる</DropdownItem> <DropdownItem name="closeAll">すべて閉じる</DropdownItem> </ドロップダウンメニュー> </ドロップダウン> --> </div> </テンプレート> <スクリプト> エクスポートデフォルト{ データ () { 戻る { 現在のページ名: this.$route.name, 左オフセット: 0 } }, 小道具: { ページオープンリスト: { タイプ: 配列 } }, メソッド: { closeTags (アクション) { this.$emit('closeTags', アクション) if (アクション === 'closeOthers') { this.leftOffset = 0 } }, closeTag (インデックス、イベント、名前) { // 単一のタグを削除します。ホームページのタグは削除できません if (index !== 0) { this.$emit('closeTags', インデックス, 名前) } if (this.currentPageName !== name) { this.leftOffset = Math.min(0, this.leftOffset + event.target.parentNode.offsetWidth) } }, タグ選択 (インデックス) { this.$emit('tagSelected', インデックス) }, checkTagIsVisible (タグ) { 可視 = { isVisible: 偽、 位置: '左' } const leftDiffValue = tag.offsetLeft + this.leftOffset 左差分値 < 0 の場合 戻る表示 } const rightDiffValue = this.$refs.tagsWrapper.offsetWidth - this.leftOffset - tag.offsetWidth - tag.offsetLeft 左差分値 >= 0 かつ右差分値 >= 0 の場合 { 可視.isVisible = true } それ以外 { 表示位置 = '右' } 戻る表示 }, ハンドルスクロール (方向) { // 表示領域内の重要なタグを取得します criticalTag = this.getCriticalTag(direaction) とします。 スイッチ(方向){ ケース「左」: this.leftOffset = Math.min(this.$refs.tagsWrapper.offsetWidth - criticalTag.$el.offsetLeft, 0) 壊す ケース 'right': 定数 diffValue1 = -(criticalTag.$el.offsetLeft + criticalTag.$el.clientWidth) const diffvalue2 = -(this.$refs.tagsWrapperScroll.offsetWidth - this.$refs.tagsWrapper.offsetWidth) this.leftOffset = Math.max(diffValue1, diffvalue2) 壊す デフォルト: 壊す } }, getCriticalTag (方向) { クリティカルタグ const refsTagList = this.$refs.tagsPageOpened for (let tag of refsTagList) { // タグが可視領域内にあるかどうかを確認します if (this.checkTagIsVisible(tag.$el).isVisible) { criticalTag = タグ if (方向 === '左') { 壊す } } } criticalTagを返す }, setTagsWrapperScrollPosition (タグ) { const 可視 = this.checkTagIsVisible(タグ) (!visible.isVisible && visible.position === 'left')の場合{ // ラベルは表示領域の左側に配置されます this.leftOffset = -tag.offsetLeft } それ以外 { // タグは可視領域または可視領域の右側にあります this.leftOffset = Math.min(0, -(tag.offsetWidth + tag.offsetLeft - this.$refs.tagsWrapper.offsetWidth + 4)) } } }, マウントされた(){ // 現在開いているページのタグ位置を初期化します const refsTag = this.$refs.tagsPageOpened タイムアウトを設定する(() => { for (refsTagのconstタグ) { if (tag.text === this.$route.name) { const tagNode = タグ.$el タグノードのスクロール位置を設定します。 壊す } } }, 1) }, 時計: $route (宛先) { this.currentPageName = to.name this.$nextTick(() => { const refsTag = this.$refs.tagsPageOpened for (refsTagのconstタグ) { if (tag.text === this.$route.name) { const tagNode = タグ.$el タグノードのスクロール位置を設定します。 壊す } } }) } } } </スクリプト> 同じディレクトリ内のファイルが少ないほど //色 @theme1-color: #515a6e; テーマカラー: #2d8cf0; @light-theme-color: #5cadff; @ダークテーマカラー: #2b85e4; @情報カラー: #2db7f5; @成功カラー: #19be6b; @警告色: #ff9900; @エラー色: #ed4014; @タイトルカラー: #17233d; コンテンツのカラー: #515a6e; @サブカラー: #808695; 無効な色: #c5c8ce; @境界線の色: #dcdee2; @区切り線の色: #e8eaec; @背景色: #f8f8f9; @white: 白; // 間隔 @padding: 16px; //デフォルトのスタイル* { ボックスのサイズ: 境界線ボックス; } { 色: @theme-color; } ホバー{ 色: @light-theme-color; } .dark-a { 色: @title-color; } // フロートをクリア .clear-float::after { 表示: ブロック; クリア: 両方; コンテンツ: ""; 可視性: 非表示; 高さ: 0; } // アニメーション.スライドフェードアイテム { 遷移: すべて 0.1 秒のイーズイン アウト。 表示: インラインブロック; } .slide-fade-enter、.slide-fade-leave-to /* バージョン 2.1.8 未満では .list-complete-leave-active */ { 不透明度: 0; 変換: translateX(-10px); } // スクロールバー style.menu-scrollbar::-webkit-scrollbar, .common-scrollbar::-webkit-scrollbar { /*全体的なスクロールバーのスタイル*/ 幅: 11px; /*高さと幅はそれぞれ水平スクロールバーと垂直スクロールバーのサイズに対応します*/ 高さ: 1px; } // スクロールバースタイル 1 .menu-scrollbar::-webkit-scrollbar-thumb { /*スクロールバー内の小さな四角*/ 境界線の半径: 2px; ボックスシャドウ: インセット 0 0 5px rgba(0, 0, 0, 0.2); 背景: @sub-color; } // スクロールバースタイル 2 .common-scrollbar::-webkit-scrollbar-thumb { /*スクロールバー内の小さな四角*/ 境界線の半径: 2px; ボックスシャドウ: インセット 0 0 5px rgba(0, 0, 0, 0.2); 背景: @border-color; } -----------注: すべてを閉じて他の関数を閉じると、tagNav タグがクリアされるだけでルートとは関係がないため、クリアされたページ ルートの離脱イベントは取得できません。そのため、最初にこの 2 つの関数を閉じることしかできません------------ route.js ファイル内の各ルートにメタ属性を追加します。 { パス: 'auditManage', 名前: 'auditManage', meta:{title:'監査管理'}, コンポーネント: 関数 (解決) { 必要(['../page/sysConfig/audit/auditManageMain.vue']、解決); }, リダイレクト: '/main/auditManage/trendStatistics', 子供たち: [{ パス: 'trendStatistics', 名前: 'trendStatistics', meta:{title:'トレンド監査'}, コンポーネント: 関数 (解決) { 必要(['../page/sysConfig/audit/auditTrendStatisticsList.vue']、解決); } }, { パス: '検索', 名前: '検索', meta:{title:'監査クエリ'}, コンポーネント: 関数 (解決) { 必要(['../page/sysConfig/audit/auditSearchList.vue']、解決); } }, ------説明: これは、メタ属性モードコンテンツセットとルーティングリダイレクトを含むルーティングフラグメントです-------- ストアのmutation.jsにタグの追加/削除とsessionStorageメソッドの更新を記述します。 [setPageOpenedList](状態、パラメータ = null){ // 設定する前にローカルに保存されたオープンリストデータを読み取ります state.pageOpenedList = sessionStorage.pageOpenedList ? JSON.parse(sessionStorage.pageOpenedList) : [{ タイトル: 「インフラストラクチャ」、 名前: 'basicDevice', 選択: true }] if (!パラメータ) { 戻る } (パラメータインデックス === -1)の場合{ // 新しいページを開く state.pageOpenedList.push({ タイトル: params.route.meta.title, 名前: params.route.name、 選択: 偽 }) パラメータ.インデックス = state.pageOpenedList.length - 1 } // 選択された値を更新します for (let i = 0; i < state.pageOpenedList.length; i++) { パラメータインデックスが i の場合 state.pageOpenedList[i].selected = true } それ以外 { state.pageOpenedList[i].selected = false } } // ローカルの新しいオープンページリストデータを更新します sessionStorage.pageOpenedList = JSON.stringify(state.pageOpenedList) }, // PageOpenedList を削除する [removePageOpenedList] (状態、パラメータ = null) { if (!パラメータ) { 戻る } if (typeof params.action === 'number') { state.pageOpenedList.splice(params.action, 1) } それ以外 { //ここに入力すると、すべてのタブが削除され、最初に選択されたタブが割り当てられます 状態.pageOpenedList = [{ タイトル: 「インフラストラクチャ」、 名前: 'basicDevice', 選択: true }] //他のものを削除する場合は、現在のルートの下にタブを追加します params.action === 'closeOthers' && params.route.name !== 'basicDevice' の場合 { state.pageOpenedList[0].selected = false state.pageOpenedList.push({ タイトル: params.route.meta.title, 名前: params.route.name、 選択: true }) } } // ローカルの新しいオープンページリストデータを更新します sessionStorage.pageOpenedList = JSON.stringify(state.pageOpenedList) }, ------注: プロジェクトによってはストアの書き込み方法が異なるため、ここでの メインページ main.vue にタグコンポーネント、キープアライブコンポーネント、コンポーネントの選択/削除メソッドを追加し、ルートの変更を監視し、保存されたタグリストを計算します。 <div class="a-tag"> <tag-nav :pageOpenedList="pageOpenedList" ref="tagNavRef" @closeTags="タグを閉じる" @tagSelected="タグ選択済み"></tag-nav> </div> <div class="a-product"> <div class="loading" style="height:100%"> <キープアライブ:max="5"> <ルータービュー></ルータービュー> </キープアライブ> </div> </div> // ナビゲーションタグメソッド closeTags (action,elId) { isRemoveSelected を実行します。 if (typeof action === 'number') { // 単一のアクションを削除します let elEvent = new Event('click'); document.getElementById(elId).dispatchEvent(elEvent); //現在のタグであるかどうかに関係なく、デフォルトで現在のタグを削除します for (let i = 0; i < this.$store.state.pageOpenedList.length; i++) { if (アクション === i) { this.$store.state.pageOpenedList[i].selected = true } それ以外 { this.$store.state.pageOpenedList[i].selected = false } } //そして、現在のタブはisRemoveSelected = this.$store.state.pageOpenedList[action].selectedです } this.$store.commit('removePageOpenedList', { ルート: this.$route, アクション }) if (isRemoveSelected) { // 1つのタグを削除し、最後のタグのページに移動します this.$router.push({ 名前: this.$store.state.pageOpenedList[this.$store.state.pageOpenedList.length - 1].name }) } それ以外の場合 (アクション === 'closeAll') { this.$router.push('/main/basicDevice'); } }, タグ選択 (インデックス) { if (this.$store.state.pageOpenedList[index].name !== this.$route.name) { this.$router.push({ 名前: this.$store.state.pageOpenedList[index].name }) } }, 計算: { ページオープンリスト() { これを返します。$store.getters.getPageOpenedList }, }, 時計: $route (宛先) { // ルート変更、PageOpenedList の更新 インデックスを this.$util.indexOfCurrentPageOpened(to.name, this.$store.state.pageOpenedList) とします。 this.$store.commit('setPageOpenedList', { ルート: to, インデックス }) }, } // pageOpenedList で新しく開いたページを検索します indexOfCurrentPageOpened(name, pageOpenedList) { for (let index = 0; index < pageOpenedList.length; index++) { if (pageOpenedList[index].name === name) { インデックスを返す } } -1を返す }, ------注: ここではコンポーネントのインポートは投稿しません。キャッシュの制限は最大 5 タグです。タグを開きすぎると、ブラウザーのメモリが爆発してフリーズする恐れがあるためです。 ------- ミックスインファイルを書く: コールバックをルーティングし、main.js でグローバルにミックスする /** * 履歴タブメニュー用 */ エクスポートデフォルト{ beforeRouteLeave(to, from, next) { console.log("mixins-beforeRouteLeave:",from); フラグを true にする this.$store.state.pageOpenedList.forEach(e => { // pageOpenedList は開かれたタブのコンポーネントルーティングを保存します if(from.name == e.name) { フラグ = 偽 } }) if(フラグ && this.$vnode.parent && this.$vnode.parent.componentInstance.cache) { // let key = this.$vnode.key // 現在閉じているコンポーネント名 var key = (this.$vnode.key == null || this.$vnode.key == undefined) ? this.$vnode.componentOptions.Ctor.cid + (this.$vnode.componentOptions.tag ? `::${this.$vnode.componentOptions.tag}` : '') : this.$vnode.key; let cache = this.$vnode.parent.componentInstance.cache // キャッシュされたコンポーネント let keys = this.$vnode.parent.componentInstance.keys // キャッシュされたコンポーネント名 if (cache[key] != null) { キャッシュ[キー]を削除 インデックス = keys.indexOf(キー) とします。 if(インデックス > -1) { キーを連結します(インデックス、1) } } } 次() } } // 混合メソッドを導入する import beforeLeave from './mixins/beforeLeave' Vue.mixin(beforeLeave) ------説明: ここでの主な目的は、各ルートページを離れるたびにこの終了メソッドをコールバックし、現在終了しているルートが別のタブメニューに切り替えるか、現在のメニュータブを閉じるかを判断することです。閉じている場合は、対応するキャッシュを削除します--------- 左メニューにもルートリスナーを追加して、タグメニューを切り替えるときに左メニューが正しくジャンプしてタグを選択できるようにする必要があります。 ハンドル選択(インデックス、インデックスパス){ this.active = インデックス; }, 時計:{ $route (宛先) { console.log("アコーディオン==============",to,to.path); //if ステートメントがアドレスがリダイレクトされていることを示している場合は、リダイレクト親メニュー パスを使用してジャンプし、親ページが自身をリダイレクトするようにします if (to.matched && to.matched[to.matched.length-1].parent.redirect != undefined) { this.handleSelect(to.matched[to.matched.length-1].parent.path,null); }それ以外 { this.handleSelect(to.path,null); } } }, -----説明: 最初のメソッドは、el-menuがメニューを選択したときにトリガーされ、ルートを監視して一致する属性値を取得して判断します------ 切り替えたラベルがリダイレクトされたルーティングメニューである場合、リダイレクトされたページが初期化されるときに、ラベル配列のラジオラベルに対応するタイトル設定を取得する必要があります(私のプロジェクトのリダイレクトページは基本的にラジオで切り替えられます)。切り替え後にキャッシュされている場合は、ルートからタイトルを取得する必要があります。 <div class="tabsBox"> <el-radio-group class="radioStyle" v-for="メニュー内の項目" :key="item.route" v-model="activeName" @change="checkItem(item.route)"> <el-radio-button :label="item.text" @blur.native="goPath(item.route)"></el-radio-button> </el-ラジオグループ> </div> データ(){ 戻る { activeName:'参加者', メニュー:[ {route:"partyManageReport",text:"参加者"}, {ルート:"staffManageReport",テキスト:"スタッフ"}, {route:"partyAccountManageReport",text:"メインアカウント"}, {route:"partyAccountGroupManageReport",text:"メインアカウントグループ"}, {route:"partySubAccountManageReport",text:"アカウントから (Web アセット)"}, {route:"partySubAccountManageD",text:"アカウントから (インフラストラクチャ)"} ] } }, 時計:{ $route (宛先) { this.activeName = to.meta.title; } }, 作成された(){ this.$store.state.pageOpenedList.forEach((item)=>{ if(項目が選択されている){ this.activeName = アイテムのタイトル; } }) } 概要: 終了タグメソッドにクリックイベントが追加されているため、他のタグを閉じるときに、現在のタグとして設定して閉じることで、終了したタグに対応するルートを取得し、終了コールバックを通じてキャッシュをクリアできるようになります。ただし、これにより、他のタブを閉じた後、現在選択されているタブが最後のタブにジャンプすることになります。要求がそれほど高くない場合は、これはかろうじて受け入れられる程度です。しかし、それはあまり良い気分ではありません。他のタブ オプションに移動せずに、現在選択されているタブの対応するキャッシュをクリアしながら他のタブを閉じる良い方法はありますか? 最適化のアイデアを探しています。 また、すべて閉じるときに閉じたタブのキャッシュをクリアする方法やその他のオプションがわかりません。前述のように、閉じるときにルートを離れるトリガーする方法は取得できず、単にタブ配列をリセットします。 最初のものは基本タグなので、閉じるボタンは削除されています。 vue+elementui+vuex+sessionStorage で履歴タブメニューを実装するサンプルコードに関するこの記事はこれで終わりです。vue 履歴タブメニューに関するより関連性の高いコンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。 以下もご興味があるかもしれません:
|
>>: HTMLベースの複数画像アップロードのプレビュー機能を実装
エラー メッセージ:ストアの更新、挿入、または削除ステートメントが予期しない行数 (0) に影響を与...
目次1. ブロックスコープとは何ですか? 2. ブロックスコープが必要なのはなぜですか? 3. 関数...
<br />読みやすさはウェブサイトにとって非常に重要な部分であり、ウェブサイトの核心と...
質問docker run コマンドを使用して、tomcat コンテナが正常に追加されました。ポートも...
MySQL のデータ ディクショナリは、データベースの重要なコンポーネントの 1 つです。INFOR...
現在の要件は、ファイルのアップロード ボタンがあることです。ボタンをクリックすると、アップロードする...
Xrdp は、グラフィカル インターフェイスを通じてリモート システムを制御できる Microsof...
少し前にTik Tokを見ていて、フォローするときのボタンアニメーションがとても美しいと思ったのと、...
背景あっという間に忙しい一年が終わり、毎年恒例のイベントの時期がやってきます。お祭り気分を演出するに...
展示する デザインパスワード強度分析パスワードは数字、文字、特殊記号で構成されていますパスワード: ...
この記事では、3Dカルーセル効果をjsで実装するための具体的なコードを参考までに共有します。具体的な...
mysql 行から列へ、列から行へ難しい文章ではないので、詳しく説明はしません。文章を読むときは、一...
ブラウザの非overflow:auto要素resize伸縮機能を利用して、JavaScript を使...
一般的に言えば、コンテナが起動した後、ポート マッピングを通じてコンテナが提供するサービスを使用...
<abbr>タグと<acronym>タグは、Web ページに表示される略語と...