複雑なレイアウト構造の vue コンポーネント、ツリー コンポーネント統合テーブル コンポーネント、各ノードは行を表します

序文

この記事では、テーブル コンポーネントと統合されたツリー コンポーネントである、より複雑な組版方法を紹介します. ツリーの各ノードには構成の行があります.
比較商品ページは以下の通りです。

ここに画像の説明を挿入

需要分析

このページを見て最初に思いつくのは、ツリー コンポーネントとテーブル コンポーネントです。
右側を座るテーブル部品として使いたい場合は、よりコピーです。ツリー ノードの折り畳みを伴うため、対応する行も折り畳まれます。
したがって、最も簡単な方法は、右側のテーブルをシミュレートし、各行をツリー ノードに書き込むことです。このように、ノードが折りたたまれると、それに応じて対応する行も折りたたまれます。

コード

上部ヘッダーは、右にオフセットされた単一の div として実装されます。

<div class="top-header">
  <div class="col-item">
    Row count
  </div>
  <div class="col-item">
    Column count
  </div>
  <div class="col-item">
    Custom SQL
  </div>
  <div class="col-item">
    Freshness
  </div>
  <div class="col-item">
    Cardinality
  </div>
  <div class="col-item">
    Uniqueness
  </div>
  <div class="col-item">
    Nullness
  </div>
  <div class="col-item">
    Distribution
  </div>
</div>

左側のツリーは、element-plus のツリー コンポーネントを使用して表示されます。
各ノードはスロットを使用して作成する必要があります。これにより、レベルごとに異なるアイコンを使用するなど、多くのロジックを個別に処理できます。
各ノードのセル数は個別に設定できます。
セルの数は css クラスを使用して実装されます。クリックできないセルについては、背景色が透明に設定されるか、背景色と一致するように設定されます。
各セルを表示するかしないか、何色で表示するかは、ノードのデータとセルの種類に関係します。
したがって、セルの css クラスを取得するときは、セル タイプ 1 とノードの 2 つのパラメーターを使用します。次のように
<div :class="showCell(1, node)" class="node-rules-cell" />

特別な注意を払う必要があります:
ツリーにはさまざまなレベルがあり、各レベルの右側のくぼみの距離が異なります。後続のセルの組版に影響を与えずにブック ノードの幅を実現するため。
ツリー ノードの端を揃える必要があり、すべての異なるレベル ノードの幅は異なります。
このように書くことができます。

@levMargin: 16px;
.node-info {
    
    
  width: 340px;
  margin-right: 12px;
  &.node-lev2{
    
    
    width: calc(340px - @levMargin) ;
  }
  &.node-lev3{
    
    
    width: calc(340px - @levMargin * 2) ;
  }
  &.node-lev4{
    
    
    width: calc(340px - @levMargin * 3) ;
  }
}

第 1 レベル ノードの幅は 340px、第 2 レベル ノードの幅は 340-16、第 3 レベル ノードの幅は 340 - 16*2 です。等々。

いくつかの詳細な処理は、ノードのホバーとフォーカスの最適化を行う必要があることです。

.el-tree-node__content:hover .node-rules{
  background-color: #fff;
}
.el-tree-node:focus>.el-tree-node__content .node-rules{
  background-color: #fff;
}

実証効果

ここに画像の説明を挿入

完全なコード

<script lang="ts" setup>
interface Tree {
      
      
  id: string
  label: string
  children?: Tree[]
}

const props = {
      
      
  value: 'id',
  label: 'label',
  children: 'children',
}

const data = [
  {
      
      
    id: '1',
    label: 'sample_analytics',
    children: [
      {
      
      
        id: '1-1',
        label: 'core',
        children: [
          {
      
      
            id: '1-1-1',
            label: 'customers',
            children: [
              {
      
      
                id: '1-1-1-1',
                label: 'id',
              },
              {
      
      
                id: '1-1-1-2',
                label: 'name',
              },
              {
      
      
                id: '1-1-1-3',
                label: 'email',
              },
            ],
          },
          {
      
      
            id: '1-1-2',
            label: 'order_items',
            children: [
              {
      
      
                id: '1-1-2-1',
                label: 'item_value',
              },
              {
      
      
                id: '1-1-2-2',
                label: 'category',
              },
            ],
          },
          {
      
      
            id: '1-1-3',
            label: 'orders',
            children: [
              {
      
      
                id: '1-1-3-1',
                label: 'id',
              },
              {
      
      
                id: '1-1-3-2',
                label: 'order_value',
              },
              {
      
      
                id: '1-1-3-3',
                label: 'order_type',
              },
            ],
          },
          {
      
      
            id: '1-1-4',
            label: 'revenue',
            children: [
              {
      
      
                id: '1-1-4-1',
                label: 'sales_mtd',
              },
              {
      
      
                id: '1-1-4-2',
                label: 'sales_qtd',
              },
              {
      
      
                id: '1-1-4-3',
                label: 'sales_ytd',
              },
            ],
          },
          {
      
      
            id: '1-1-5',
            label: 'traffic',
            children: [
              {
      
      
                id: '1-1-5-1',
                label: 'visitors_daily',
              },
              {
      
      
                id: '1-1-5-2',
                label: 'visitors_wtd',
              },
              {
      
      
                id: '1-1-5-3',
                label: 'visitors_mtd',
              },
            ],
          },
        ],
      },
      {
      
      
        id: '1-2',
        label: 'hubspot',
      },
      {
      
      
        id: '1-3',
        label: 'jira',
      },

      {
      
      
        id: '1-4',
        label: 'salesforce',
      },
      {
      
      
        id: '1-5',
        label: 'segment',
      },
      {
      
      
        id: '1-6',
        label: 'stripe',
      },
      {
      
      
        id: '1-7',
        label: 'zendesk',
      },
    ],
  },
]

const defaultExpandedKeys = ['1', '1-1']

function showCell(cell: number, node: any) {
      
      
  if ([1, 2].includes(node.level)) {
      
      
    return 'not-select'
  }
  if (node.level === 3) {
      
      
    return [1, 2, 4].includes(cell) ? 'select' : 'not-select'
  }
  if (node.level === 4) {
      
      
    return [5, 7, 8].includes(cell) ? 'select' : 'not-select'
  }
  return 'select'
}
</script>

<template>
  <div class="rules-container">
    <div class="top-header">
      <div class="col-item">
        Row count
      </div>
      <div class="col-item">
        Column count
      </div>
      <div class="col-item">
        Custom SQL
      </div>
      <div class="col-item">
        Freshness
      </div>
      <div class="col-item">
        Cardinality
      </div>
      <div class="col-item">
        Uniqueness
      </div>
      <div class="col-item">
        Nullness
      </div>
      <div class="col-item">
        Distribution
      </div>
    </div>
    <el-tree-v2
      class="table-tree-container"
      :default-expanded-keys="defaultExpandedKeys"
      :data="data"
      :props="props"
      :height="500"
    >
      <template #default="{ node }">
        <div class="node-item-row">
          <div class="node-info" :class="`node-lev${node.level}`">
            <span class="prefix" :class="{ 'is-leaf': node.isLeaf }" />
            <span>{
   
   { node.label }}</span>
          </div>
          <div class="node-rules">
            <div :class="showCell(1, node)" class="node-rules-cell" />
            <div :class="showCell(2, node)" class="node-rules-cell warning" />
            <div :class="showCell(3, node)" class="node-rules-cell" />
            <div :class="showCell(4, node)" class="node-rules-cell" />
            <div :class="showCell(5, node)" class="node-rules-cell" />
            <div :class="showCell(6, node)" class="node-rules-cell" />
            <div :class="showCell(7, node)" class="node-rules-cell error" />
            <div :class="showCell(8, node)" class="node-rules-cell" />
          </div>
        </div>
      </template>
    </el-tree-v2>
  </div>
</template>

<style lang="less">
@levMargin: 16px;
.rules-container{
      
      
  padding: 20px;
  border: 1px solid #ddd;
  height: 100%;
  .node-item-row{
      
      
    width: 100%;
    display: flex;
    // justify-content: space-between;
    padding-right: 20px;
    height: 28px;
    line-height: 28px;
  }
  .node-rules {
      
      
    // display: flex;
    // justify-content: space-between;
    // width: 1000px;
  }
  .node-rules-cell{
      
      
    display: inline-block;
    width: 100px;
    height: 28px;
    background-color: #47b881;
    box-shadow: white 0px 0px 0px 1px inset;
    &.warning{
      
      
      background-color: #f5d60099;
    }
    &.error{
      
      
      background-color: #eb5757;
    }
    &.not-select{
      
      
      background-color: #fff;
    }
  }
  .el-tree-node__content{
      
      
    height: 28px;
  }
  .table-tree-container {
      
      
    border: 1px solid #ddd;
    height: 100%;
    // margin-top: 50px;
  }
  .node-info {
      
      
    width: 340px;
    margin-right: 12px;
    &.node-lev2{
      
      
      width: calc(340px - @levMargin) ;
    }
    &.node-lev3{
      
      
      width: calc(340px - @levMargin * 2) ;
    }
    &.node-lev4{
      
      
      width: calc(340px - @levMargin * 3) ;
    }
  }
  .el-tree-node__content:hover .node-rules{
      
      
    background-color: #fff;
  }
  .el-tree-node:focus>.el-tree-node__content .node-rules{
      
      
    background-color: #fff;
  }
  .top-header{
      
      
    margin-left: 380px;
    .col-item{
      
      
      display: inline-block;
      width: 100px;
      font-size: 13px;
      text-align: center;
    }
  }

}
</style>

おすすめ

転載: blog.csdn.net/github_35631540/article/details/129061623