Vue+elementUI コンポーネントは、折りたたみ可能な動的レンダリングのマルチレベル サイドバー ナビゲーションを再帰的に実装します。

Vue+elementUI コンポーネントは、折りたたみ可能な動的レンダリングのマルチレベル サイドバー ナビゲーションを再帰的に実装します。

かなり前に実装された機能ですが、クリックすると選択したメニュー項目の背景色が白くなることに気付きました。金曜日に注意深く観察したところ、スタイル調整の問題ではなく、オプションが選択されていないことが原因であることがわかりました。そこで、コンポーネントの再帰を注意深く研究し、考えをまとめて記録しました。

1. コンセプト

再帰: 簡単に言えば、再帰とは、入れ子人形のように自分自身を呼び出すことです。子供の頃、再帰原理を使った「ハノイの塔」というゲームをしました。

ここに画像の説明を挿入

関数の再帰: 関数は関数名を使用して独自のコンポーネントの再帰を呼び出します。したがって、コンポーネントの再帰は、vueコンポーネントのname属性を使用して実装されます。

2. 需要

マルチレベルサイドバーナビゲーションの折りたたみ可能な動的レンダリングを実装する

分析

ここに画像の説明を挿入

1. サイドバーのナビゲーションは一度に 1 レベルずつで、2 番目のレベルは最初のレベルの繰り返しに相当することに注意してください。 2. 一部のメニューには下位レベルがあり、一部には下位レベルがないという特徴があります。 3. 動的レンダリングとは、ツリー型データがバックグラウンド インターフェイスから取得され、動的にレンダリングされることを意味します。 4. コードの実装 1. まず、ドキュメント内のデモを実行して試してみましょう。

ドキュメント: 要素のドキュメント

2. 必要なスタイルに変更します。これは最初に書かれたときの様子です。

親コンポーネント サイドバー

<テンプレート>
  <el-menu class="menu-wrap" :default-active="メニューアクティブ名 || 'ホーム'" :active="メニューアクティブ名 || 'ホーム'"
           :collapse="サイドバーを折りたたむ" :collapseTransition="false" :unique-opened="true" @select="selectItem">
    <テンプレート>
      <el-menu-item @click="サイドバー折りたたみ = !サイドバー折りたたみ">
        <i v-show="!sidebarFold" class="el-icon-s-fold"></i>
        <i v-show="サイドバー折りたたみ" class="el-icon-s-unfold"></i>
        <span slot="title" class="sidebar-one">ナビゲーション リスト</span>
      </el-menu-item>
    </テンプレート>
<!-- <サイドバー項目 :list="メニューリスト"></サイドバー項目>-->
    <template v-for="(item,index) in menuList" class="menu">
      <!-- タイトル -->
      <テンプレート v-if="item.children.length">
        <el-submenu :key="index" :index="item.id" class="サブメニュー項目">
          <テンプレート:index="item.index" slot="title">
            <!-- <i :class="item.icon"></i>-->
            <i class="iconfont icon-danganjianying"></i>
            <span>{{アイテム名}}</span>
          </テンプレート>
          <el-menu-item-group class="メニュー項目グループ">
            <サイドバー項目:list="item.children"></サイドバー項目>
          </el-menu-item-group>
        </el-サブメニュー>
      </テンプレート>
      <!-- オプション -->
      <テンプレート v-else>
        <el-menu-item :key="index" :index="item.id" class="menu-item">
          <!-- <i :class="item.icon"></i>-->
          <i class="iconfont icon-danganjianying"></i>
          <span>{{アイテム名}}</span>
        </el-menu-item>
      </テンプレート>
    </テンプレート>
  </el-menu>
</テンプレート>

<スクリプト>

エクスポートデフォルト{
  名前: 'サイドバー',
  コンポーネント:
    サイドバーアイテム: () => import('@/components/common/SideBarItem')
  },
  データ () {
    戻る {

    }
  },
  マウントされた(){
  },
  メソッド: {
    selectItem(名前, パス){
      // アラート(名前)
      this.$router.push(パス)
      this.$store.commit('common/updateMenuActiveName', 名前)
    }
  },
  計算: {
    メニューリスト: {
      得る () {
        this.$store.state.common.menuList を返します
      },
      設定(値) {
        this.$store.commit('common/updateMenuList', val)
      }
    },
    メニューアクティブ名: {
      get() { this.$store.state.common.menuActiveName を返す },
      設定 (val) { this.$store.commit('common/updateMenuActiveName', val) }
    },
    サイドバー折りたたみ: {
      get() {this.$store.state.common.sidebarFold; を返します},
      設定(val) {this.$store.commit("common/updateSidebarFold", val);}
    },
  },
}
</スクリプト>
<style lang="less" スコープ>
.メニューラップ{
  幅: 200ピクセル;
  最小高さ: 1020px;
  背景: url('../../assets/img/sidebar_bg.png') 繰り返しなし;
  背景サイズ: 100% 100%;
}

/deep/ .el-menu{
  背景色: 透明 !重要;
  .アイコンフォント{
    フォントサイズ: 18px;
    垂直方向の位置合わせ: サブ;
    右マージン: 5px;
    表示: インラインブロック;
    幅: 20px;
    テキスト配置: 中央;
  }
}

/deep/ .el-メニュー項目、
/deep/ .el-submenu__title{
  色: #fff;

  .アイコンフォント{
    色: #fff;
  }
}

/deep/ .el-menu-item スパン、
/deep/ .el-submenu__title span{
  左パディング: 10px;
}

/deep/ .el-menu-item.is-active {
  -webkit-box-shadow: インセット 5px 100px 0px -2px #0064B6;
  ボックスシャドウ: インセット 5px 100px 0px -2px #0064B6;
}

/deep/ .el-submenu__title:hover、
/deep/ .el-menu-item:hover{
  背景: #0064B6;
}

/deep/ .el-menu-item-group__title{
  パディング: 0;
}

</スタイル>

サブコンポーネント SideBarItem

<テンプレート>
  <div class="メニュー">
    <template v-for="(item,index) in list">
      <!-- タイトル -->
      <テンプレート v-if="item.children.length">
        <el-submenu :key="index" :index="item.id" class="サブメニュー項目">
          <テンプレート:index="item.index" slot="title">
<!-- <i :class="item.icon"></i>-->
            <i class="iconfont icon-danganjianying"></i>
            <span>{{アイテム名}}</span>
          </テンプレート>
          <el-menu-item-group class="メニュー項目グループ">
            <サイドバー項目:list="item.children"></サイドバー項目>
          </el-menu-item-group>
        </el-サブメニュー>
      </テンプレート>
      <!-- オプション -->
      <テンプレート v-else>
        <el-menu-item :key="index" :index="item.id" class="menu-item" @click="selectItem(item.name, item.path)">
<!-- <i :class="item.icon"></i>-->
          <i class="iconfont icon-danganjianying"></i>
          <span>{{アイテム名}}</span>
        </el-menu-item>
      </テンプレート>
    </テンプレート>
  </div>
</テンプレート>
<スクリプト>

エクスポートデフォルト{
  名前: 'サイドバーアイテム',
  // プロパティ: ['リスト'],
  小道具: {
    リスト: {
      タイプ: 配列 || ''
    }
  },
  データ () {
    戻る {
      ツリーデータ: [{
        ラベル: '州'、
        子供たち: [{
          ラベル:「中国共産党省委員会」
          // 子供たち: [{
          // ラベル: 'レベル 3 1-1-1'
          // }]
        }, {
          ラベル: 「中国共産党省事務所」
        }, {
          ラベル:「中国共産党のある省の組織部」
        }
        ]
      }
      ]、
      isShow: 偽
      // メニューリスト: []
    }
  },
  マウントされた(){
    this.loadSysMenu()
  },
  メソッド: {
    システムメニューをロードする(){
      // console.log('menu', this.menuList)
    },
    // personManage (名前) {
    // if (name === '人事管理') {
    // this.isShow = !this.$store.state.common.rbflag
    // // アラート('111' + this.isShow)
    // this.$store.commit('common/updateShowRbox', this.isShow)
    // }
    // },
    selectItem(名前, パス){
      // アラート(名前)
      this.$router.push(パス)
      this.$store.commit('common/updateMenuActiveName', 名前)
    }
  },
}
</スクリプト>
<style lang="less" スコープ>
。メニュー{
  幅: 100%;

  .sub-menu-item /deep/ .el-submenu__title,
  .メニュー項目{
    高さ: 60px;
    行の高さ: 60px;
    テキスト配置: 左;
    //パディング左: 30px !重要;
    //border-bottom: 1px 実線 #000;
    //右境界線: 1px 実線 #000;
    色: #fff;
  }

  .サブメニュー項目 .elメニュー項目{
    右パディング: 0;
  }

 /deep/ .el-menu-item .is-active{
    背景色: #0087df;
  }

  .メニュー項目:ホバー、
  /deep/ .el-submenu__title:hover{
    背景色: #0087df;
  }

  .メニュー項目スパン、
  .sub-menu-item /deep/ .el-submenu__title>span{
    フォントの太さ: 700;
  }

  .menu-item-group /deep/ .el-menu-item-group__title{
    パディング: 0 !重要;
  }

  .メニュー項目グループ .メニュー項目{
    背景: url('../../assets/img/sidebar_bg.png') 繰り返しなし;
  }

  .el-メニュー項目グループ span{
    フォントの太さ: 標準;
  }

}

</スタイル>

後で、折りたたみが成功せず、選択した項目のスタイルが選択後に変更されないことがわかりました。後で、選択されていないことがわかりました。調査後、div の余分なレイヤーがネストされていたためであり、el-menu-item-group プロジェクトではこれが必要なかったため、改善は次のようになりました。

親コンポーネント サイドバー

<テンプレート>
  <el-menu class="menu-wrap" :default-active="menuActiveName" :collapse="sidebarFold" :collapseTransition="false" :unique-opened="true">
    <テンプレート>
      <el-menu-item @click="foldSideBar">
        <i v-show="!sidebarFold" class="el-icon-s-fold"></i>
        <i v-show="サイドバー折りたたみ" class="el-icon-s-unfold"></i>
        <span slot="title" class="sidebar-one">ナビゲーション リスト</span>
      </el-menu-item>
    </テンプレート>
    <side-bar-item v-for="menuList 内のメニュー" :key="menu.id" :menu="メニュー"></side-bar-item>
  </el-menu>
</テンプレート>

<スクリプト>

エクスポートデフォルト{
  名前: 'サイドバー',
  コンポーネント:
    サイドバーアイテム: () => import('@/components/common/SideBarItem')
  },
  データ () {
    戻る {
    }
  },
  マウントされた(){
  },
  メソッド: {
    折り畳みサイドバー(){
      this.sidebarFold = !this.sidebarFold
      this.menuActiveName = 'NAV'
    }
  },
  計算: {
    メニューリスト: {
      得る () {
        this.$store.state.common.menuList を返します
      },
      設定(値) {
        this.$store.commit('common/updateMenuList', val)
      }
    },
    メニューアクティブ名: {
      得る () {
        console.log(this.$store.state.common.menuActiveName)
        this.$store.state.common.menuActiveName を返します
      },
      設定(値) {
        this.$store.commit('common/updateMenuActiveName', val)
      }
    },
    サイドバー折りたたみ: {
      get() {this.$store.state.common.sidebarFold; を返します},
      設定(val) {this.$store.commit("common/updateSidebarFold", val);}
    },
  },
}
</スクリプト>
<style lang="less" スコープ>
.メニューラップ{
  幅: 200ピクセル;
  最小高さ: 1020px;
  背景: url('../../assets/img/sidebar_bg.png') 繰り返しなし;
  背景サイズ: 100% 100%;
}

/deep/ .el-menu{
  背景色: 透明 !重要;
  .アイコンフォント{
    フォントサイズ: 18px;
    垂直方向の位置合わせ: サブ;
    右マージン: 5px;
    表示: インラインブロック;
    幅: 20px;
    テキスト配置: 中央;
  }
}

/deep/ .el-メニュー項目、
/deep/ .el-submenu__title{
  色: #fff;

  .アイコンフォント{
    色: #fff;
  }
}

/deep/ .el-menu-item スパン、
/deep/ .el-submenu__title span{
  左パディング: 10px;
}

/deep/ .el-menu-item.is-active {
  -webkit-box-shadow: インセット 5px 100px 0px -2px #0064B6;
  ボックスシャドウ: インセット 5px 100px 0px -2px #0064B6;
}

/deep/ .el-submenu__title:hover、
/deep/ .el-menu-item:hover{
  背景: #0064B6;
}

</スタイル>

サブコンポーネント SideBarItem

<テンプレート>
    <!-- このメニューの下にサブメニューがあります-->
    <el-submenu v-if="menu.children.length" :index="menu.code" :popper-append-to-body=false>
        <テンプレートスロット="タイトル">
            <i class="iconfont icon-danganjianying"></i>
            <span>{{ メニュー名 }}</span>
        </テンプレート>
        <side-bar-item v-for="menu.children 内の項目" :key="item.id" :menu="項目"></side-bar-item>
    </el-サブメニュー>
    <!-- このメニューの下にはサブメニューはありません-->
    <el-menu-item v-else :index="menu.code" @click="selectItem(menu.code, menu.path)">
        <i class="iconfont icon-danganjianying"></i>
        <span>{{ メニュー名 }}</span>
    </el-menu-item>
</テンプレート>
<スクリプト>

エクスポートデフォルト{
  名前: 'サイドバーアイテム',
  // プロパティ: ['menu'],
  小道具: {
      メニュー:
      タイプ: オブジェクト || {}
    }
  },
  データ () {
    戻る {

    }
  },
  マウントされた(){
  },
  メソッド: {
    selectItem(コード、パス){
      // アラート(名前)
      console.log(コード、パス)
      this.$router.push(パス)
      this.$store.commit('common/updateMenuActiveName', コード)
    }
  },
}
</スクリプト>
<style lang="less" スコープ>
。メニュー{
  幅: 100%;

  .メニュー項目{
    高さ: 60px;
    行の高さ: 60px;
    テキスト配置: 左;
    色: #fff;
  }

  .サブメニュー項目 .elメニュー項目{
    右パディング: 0;
  }

 /deep/ .el-menu-item .is-active{
    背景色: #0087df;
  }

  .menu-item:hover{
    背景色: #0087df;
  }

  .メニュー項目スパン{
    フォントの太さ: 700;
  }

}

</スタイル>

機能は基本的に実装されていますが、バグがあります。マウスが折り目をクリックすると、特定のイベントが周期的に呼び出され、スタックオーバーフローエラーが発生します。記事を表示するには、サブメニューの属性を設定するだけです:popper-append-to-body="false"。記事を参照してください:Element-ui NavMenuサブメニューは再帰生成を使用してエラーを使用します

最後に、簡単なテストデータを添付します。

テストデータ: [
            {"id":"34161C2E8-7348-4439-8899-9A8039AE6AE4","pid":"0","code":"HOME","name":"Home","path":"/home","type":null,"icon":null,"sysId":"2761C2E8-7348-4439-8899-9A8039AE6AE3","orderNo":0,"isCheck":null,"children":[]},
            {"id":"703DBEBD-F92C-4347-9203-F60A73153C3F","pid":"0","code":"WD","name":"温度","path":"/温度","type":null,"icon":null,"sysId":"2AB00274-73DF-459A-A02E-C79A4D8A8929","orderNo":0,"isCheck":null,"children":[]},
            {"id":"73660AB4-48D3-4BDB-86FD-C8397D4D54EC","pid":"0","code":"BJ","name":"アラーム","path":"/alarm","type":null,"icon":null,"sysId":"2AB00274-73DF-459A-A02E-C79A4D8A8929","orderNo":0,"isCheck":null,
              "子供たち":[
                {"id":"1C99333D-886F-4AD6-93C4-7C5244E48247","pid":"73660AB4-48D3-4BDB-86FD-C8397D4D54EC","code":"FD","name":"盗難防止","path":"/burg","type":null,"icon":null,"sysId":"3691C2E8-8848-4439-8899-9A8039AE6AB5","orderNo":0,"isCheck":null,"children":[]},
                {"id":"1DBDF678-F51F-444A-B995-61E5D9CCA5AF","pid":"73660AB4-48D3-4BDB-86FD-C8397D4D54EC","code":"JL","name":"アラームベル","path":"/bell","type":null,"icon":null,"sysId":"3691C2E8-8848-4439-8899-9A8039AE6AB5","orderNo":0,"isCheck":null,"children":[]},
                {"id":"BFC8C2E1-0E5B-4EEE-B91D-3DABC63FF481","pid":"73660AB4-48D3-4BDB-86FD-C8397D4D54EC","code":"JS","name":"immersion","path":"/immersion","type":null,"icon":null,"sysId":"3691C2E8-8848-4439-8899-9A8039AE6AB5","orderNo":0,"isCheck":null,"children":[]},
                {"id":"BFC8C2E1-0E5B-4EEE-B91D-3DABC63FF482","pid":"73660AB4-48D3-4BDB-86FD-C8397D4D54EC","code":"MJ","name":"アクセス制御","path":"/punch","type":null,"icon":null,"sysId":"3691C2E8-8848-4439-8899-9A8039AE6AB5","orderNo":0,"isCheck":null,"children":[]},
                {"id":"BFC8C2E1-0E5B-4EEE-B91D-3DABC63FF483","pid":"73660AB4-48D3-4BDB-86FD-C8397D4D54EC","code":"ZT","name":"State","path":"/state","type":null,"icon":null,"sysId":"3691C2E8-8848-4439-8899-9A8039AE6AB5","orderNo":0,"isCheck":null,"children":[]}
              ]
            },
            {"id":"34161C2E8-7348-4439-8899-9A8039AE6AE5","pid":"0","code":"GZ","name":"Work","path":"/work","type":null,"icon":null,"sysId":"3691C2E8-8848-4439-8899-9A8039AE6AB5","orderNo":0,"isCheck":null,
              "子供たち":[]
            },
            {"id":"0CD6B09A-AA43-4AE9-9AC7-29BC5AC83495","pid":"0","code":"SJ","name":"データ据","path":"/data","type":null,"icon":null,"sysId":"2AB00274-73DF-459A-A02E-C79A4D8A8929","orderNo":0,"isCheck":null,
              "子供たち":[]
            },
            {"id":"049C670D-A33E-4188-9206-B3F3B5DDE77B","pid":"0","code":"SP","name":"视频","path":"/video","type":null,"icon":null,"sysId":"3691C2E8-8848-4439-8899-9A8039AE6AB5","orderNo":0,"isCheck":null,"children":[]},
            {"id":"0A15DBB6-3241-4C7F-AAD4-5417E7BBECAA","pid":"0","code":"RZ","name":"Log","path":"/log","type":null,"icon":null,"sysId":"2AB00274-73DF-459A-A02E-C79A4D8A8929","orderNo":0,"isCheck":null,
              "子供たち":[]
            }
          ]

効果は以下のようになります。

ここに画像の説明を挿入

折りたたんだ後は、次のようになります。

ここに画像の説明を挿入

これで、vue+elementUI コンポーネントによる折りたたみ可能な動的レンダリング マルチレベル サイドバー ナビゲーションの再帰実装に関するこの記事は終了です。elementUI 折りたたみ可能な動的サイドバー ナビゲーションに関するその他の関連コンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • element-uiでナビゲーションバーを使用してルートにジャンプする方法の詳細な説明
  • ElementUI で vue-router を使用してナビゲーションを実装する例
  • element-uiサイドバーのルーター問題について話しましょう

<<:  VMware での Ubuntu と Windows 間のファイル共有

>>:  Windows で Mysql を起動したときに 1067 が表示される場合の解決策

推薦する

HTMLでのフォーム送信の実装

フォーム送信コード1. ソースコード分析 <!DOCTYPE html> <htm...

ウェブ画像形式としてPNG、JPG、GIFを選択して使用する方法

では、GIF、PNG、JPG のどの形式を候補形式として選択すればよいのでしょうか。また、どの画像形...

mysqlパラメータsql_safe_updatesを使用して更新/削除範囲を制限する方法の詳細な説明

序文皆さんご存知のとおり、MySQL の運用・保守において、更新/削除条件が誤っているためにデータが...

CSS3 で z-index が効かない問題の解決方法

最近、CSS3 と js の組み合わせを作成したのですが、z-index が有効にならないケースが多...

CSS3はグラフィックの落下アニメーション効果を実現します

まずは効果を確認実装コード <div class="box box1"&g...

ホワイトボードを踏まないようにするゲームを実装するための HTML+CSS+JS

目次背景1. 思考分析2. ページ構成2.1 HTML レイヤー2.2 CSS レイヤー2.3 JS...

HTMLは読み取り専用のテキストボックスを実装しており、コンテンツを変更することはできません。

さっそく、コードを直接投稿します。具体的なコードは次のとおりです。 <!--方法 1: onf...

Reactイベントスロットリング効果が失敗する理由と解決策

目次ここでの問題は次の通りです:解決策1:解決策2: コンストラクタで初期化を割り当てる採掘場の概要...

Docker で Redis クラスターを素早く構築する方法の例

Redis クラスターとはRedis クラスターは、R​​edis が提供する分散データベース ソリ...

Node.jsサービスDockerコンテナアプリケーション実践のまとめ

この記事では、Docker コマンドの使用とインストールについては説明しません。Docker を基礎...

CSS3 は 3D キューブの読み込み効果を作成します

簡単な説明これは CSS3 のクールな 3D キューブのプリロード効果です。この特殊効果は、シンプル...

nginx で第 3 レベルドメイン名を設定する方法の例

問題の説明nginx を設定することで、異なるポートを介して異なる Web アプリケーションにアクセ...

nginx で http でアクセスする Web サイトを https に変更する方法

目次1. 背景2. 前提条件https:証明書システム: 3. 操作プロセス3.1 証明書の生成3....

Vue diffアルゴリズムの完全な分析

目次序文Vue 更新ビューパッチ同じVノードパッチVノード更新子供序文Vue は仮想 DOM を使用...

テキストエリアのテキストをHTMLに変換する方法、つまり復帰改行について

説明: テキストエリアの値の改行を新しい行に変更しますコードをコピーコードは次のとおりです。 <...