Vue+Element UI 樹形控件整合下拉功能菜單(tree + dropdown +input)


這篇博客主要介紹樹形控件的兩個小小的功能:

  • 下拉菜單
  • 輸入過濾框

以CSS樣式為主,也會涉及到Vue組件和element組件的使用。

對於沒有層級的數據,我們可以使用表格或卡片來展示。要展示或建立層級關系,就一定會用到樹形組件了。
使用Vue + Element UI,構建出最基本的樹如下圖所示:
最簡單的樹結構
現在我們就要在這個基礎上進行改造,使頁面更加符合我們的交互場景。

一、下拉菜單

將下拉菜單嵌到樹節點中,使操作更加簡便、緊湊。

效果演示

效果如圖:

  • 圖示1:懸浮在樹節點狀態
    懸浮在樹節點狀態

  • 圖示2:點擊三個點圖標狀態
    點擊三個點圖標狀態

  • 圖示3: 選中並選擇菜單
    下拉菜單效果

如上,當鼠標懸浮在樹節點上時,出現豎着的三個小點,點擊時彈出下拉菜單,顯示可以對樹節點進行的操作。

實現步驟

1、使用插槽(slot) + 子組件

  • 父組件(含有樹形控件)模板代碼
 <el-tree :data="resourceTree" :ref="tree" node-key="id"  size="small"
                :highlight-current="true" :check-on-click-node="true" >
                <span class="custom-tree-node" slot-scope="{ node, data }">
                    <div class="custom-tree-node-wrapper">
                        <span class="custom-tree-node-label">
                            {{ node.label }}
                        </span>
                        <span class="operate-btns">                
                            <dot-dropdown  :events="dropMenuEvents" :data="{node,data}" @addNode="addNode" />
                        </span>
                    </div>
                </span>
            </el-tree>

2、 DotDropdown 下拉框代碼

很多樹形結構都會使用該下拉框,所以定義組件,方便復用。

<template>
    <el-dropdown trigger="click" class="custom-tree-menu" size="small">
        <i class="el-icon-more rotate " />
        <el-dropdown-menu slot="dropdown">
            <el-dropdown-item v-for='(item,index) in events' :key="index" :divided="index >0" @click.native="clickMenu(item)">
                {{item.label}}
            </el-dropdown-item>
        </el-dropdown-menu>
    </el-dropdown>
</template>
<script>
export default {
  props: {
    events: {
      type: Array,
      default: function() {
        return [
          {
            label: '新建同級',
            funcName: 'addNode'
          },
          {
            label: '編輯',
            funcName: 'editNode'
          },
          {
            label: '刪除',
            funcName: 'deleteNode'
          }
        ]
      }
    },
    // 注入數據
    data: {
      type: Object
    }
  },
  methods: {
    clickMenu(item) {
      this.$emit(item.funcName, this.data)
    }
  }
}

模板代碼很簡單,是一個點擊觸發的下拉菜單組件(trigger="click"),菜單循環props中傳入的events屬性,data為從父組件拿到的數據,定義了菜單和菜單的事件(方法名稱),當點擊菜單(@click.native)時,觸發:

this.$emit(item.funcName, this.data)

容易看出,數據和實現方法都是父組件的,該子組件只做了轉發。

3、 父組件使用子組件

引入和注冊子組件,並定義好對應的方法即可。下面給出使用示例:

<span class="operate-btns">
          <dot-dropdown v-if="data.type === 1" :events="dropMenuEvents" :data="{node,data}"/>
          <dot-dropdown v-if="data.type === 2" :events="sysDropMenuEvents" :data="{node,data}" @addNode="addResource" />
 </span>

根據數據節點的類型,注入不同的events屬性,顯示不同的下拉框菜單。(常用場景:根節點不可刪除、不可編輯,只能新增子級,葉子節點可以新增同級和子級)。
在父組件中的data中定義:

sysDropMenuEvents: [{ label: '新增資源', funcName: 'addNode' }],

dropMenuEvents: [
      { label: '新建同級', funcName: 'addPeerNode' },
      { label: '新建子級', funcName: 'addNode' },
      { label: '分配操作', funcName: 'distributeAction' },
      { label: '編輯', funcName: 'editNode' },
      { label: '刪除', funcName: 'removeNode' }
 ]

父組件編寫實際功能方法:

// 打開新增資源彈窗
    addResource({ node, data }) {
      ...
    }

父組件注入data時,將樹節點插槽中的node和data都注入了進去(:data="{node,data}"),在使用時也可以用過同樣的大括號+屬性名的方式拿到對應的屬性,這里體現了ES6解構賦值的特性。

4、父組件樣式

父組件中,樹節點的樣式:

 .el-tree-node__content {
      position: relative;
      .operate-btns {
          position: absolute;
          right: 2px;
          display: none;
      }
      // 鼠標懸停時,展示
      &:hover,
      :focus-within {
          .operate-btns {
              display: inline;
          }
      }
  }
 }
  • 子絕對,父相對,使操作按鈕靠貼邊顯示
  • 無狀態時不顯示,hover或內部元素被激活時顯示(:hover :focus-within

5、子組件樣式

最終效果

  • 旋轉圖標
    原本的圖標使用的是element UI提供的 <i class="el-icon-more" />,是橫着的點點點↓
    原本的圖標

圖標有點小,顏色也不喜歡。改下字體讓它變大一點。這里注意需要修改的是元素的before偽類:

 .el-icon-more:before {
      content: "\E794";
      color: #c0c4cc;
      font-size: 20px;
}

加一個transform將它旋轉90°,懸停時鼠標樣式為pointer:

.rotate {
      cursor: pointer;
      margin-left: 5px;
      transform: rotate(90deg);
 }

點擊時,增加圓形半透明的灰色背景:

.rotate:focus {
      width: 20px;
      height: 20px;
      border-radius: 4em;
      background-color: rgba(130, 132, 138, 0.2);
}

至此,下拉全部完成。
除了用在樹節點中,也可以用在表格中。

輸入過濾框

el-tree提供了過濾方法,使用:filter-node-method="filterNode"屬性即可。這里主要分享樣式:
效果:
非激活狀態

激活輸入框狀態

模板代碼:

<div class="filter-input">
    <el-input placeholder="輸入資源名稱進行過濾" v-model="filterText" size="small" prefix-icon="el-icon-search">
       </el-input>
</div>
  • 去掉輸入框上、左右邊框和圓角,並兩側留出10px邊距
 .el-input__inner,.el-input-group__prepend{
      width: calc(100% - 20px);
      margin:0 10px;
      height: 40px;
      border-top:none;
      border-width: 0 0 1px;
      border-radius:0;
    }
  • 調整搜索圖標大小、顏色和粗細,並稍微調整位置:
    .el-input__prefix{
      .el-input__icon{
        margin-right: 15px;
        display: inline-block;
      }
      font-size:18px;
    }

此時點擊輸入框,只有下邊變藍色,希望圖標的樣式也隨之更改。
只有input被觸發了focus事件,icon感知不到,:focus偽類不滿足需求了。我們可以使用:focus-within偽類,加在iconinput共同的父類上。

.el-input:focus-within{
      .el-icon-search:before {
         color: #3c6eff;
         font-weight: bold;
      }
    }

至此完成。

總結

沒寫前端之前以為前端只是展示從后端拿到的數據,但現在覺得,前端作為面向用戶的直接門面,承擔了絕大部分交互體驗優化的任務。
合理的布局和樣式能避免用戶的無效操作,體驗的優化是一個漫長而細致的過程,可能需要仔細打磨,才能做出好用的產品。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM