Vue + TypeScript + ElementUI 封裝表頭查詢組件

前段時間有朋友私信我 Vue + TypeScript 的問題,而後就打算寫一篇 Vue + TypeScript 封裝組件的文章css

正好公司項目中須要封裝一個表頭查詢組件,就拿出來分享一下~html

 

組件的總體思路是經過一個 config 數組生成列表的頭部表單:vue

PS:配合《Vue 爬坑之路(九)—— 用正確的姿式封裝組件》食用更佳數組

 

1、組件設計數據結構

這個組件由兩部分組成:輸入組件和按鈕flex

其中輸入組件能夠經過 v-for 循環渲染,並經過 v-if 來切換輸入框 input 和下拉框 selectthis

每一個輸入組件都有各自的 v-model,能夠在 config 傳入對應的 code 來綁定對應的參數spa

基於這些想法,組件的基本結構就出來了:設計

 

由此能夠設計出 config 的數據結構 data.ts:3d

/*
 * data.ts
 *
 * 數據類型 - table-header 組件
 */

export class SelectOptionItem {
  public value: String | Number;
  public label: String | Number;
}

export class HeaderConfigItem {
  public title: String;
  public code: String;
  public type?: 'select' | 'input';
  public options?: SelectOptionItem[]
}

 

 

2、內部邏輯

整個組件須要傳入兩個必選參數:config 和 data

data 是整個表頭的數據對象,config 就是整個組件的配置項,由此渲染出頭部結構

 

 而後還有「查詢」和「清空」兩個按鈕

這類公共組件不建議直接處理事件,因此經過 emit 將事件拋給父組件處理

這裏的 this._copy 是 data 的拷貝對象,在 mounted 的時候將 data 拷貝出來做爲初始值,清空的時候再將這個初始值傳回去

這裏會涉及到在子組件中對父組件傳入的參數直接修改,因此須要用 sync 修飾符

 

3、完整代碼

除了這些基本邏輯以外,我還添加了一個 size 用於控制總體的尺寸,而後基於自身的項目微調了樣式,因此這部分僅作參考

<template>
  <div class="table-header">
    <el-form :inline="true" :model="data" class="form--label-left" label-width="180px">
      <el-row :gutter="20">
        <el-col :span="8" v-for="item in config" :key="item.code">
          <el-form-item :label="item.title" class="table-header-item">
            <el-select v-if="item.type === 'select'" v-model="data[item.code]" :placeholder="`請輸入${item.title}`" :size="size" clearable>
              <el-option v-for="option in item.options" :key="option.value" :value="option.value" :label="option.label"></el-option>
            </el-select>
            <el-input v-else v-model="data[item.code]" :placeholder="`請輸入${item.title}`" :size="size"></el-input>
          </el-form-item>
        </el-col>
        <el-col :span="8" class="table-header_button">
          <el-button :size="size" type="text" @click="reset">清空</el-button>
          <el-button :size="size" type="primary" icon="el-icon-search" @click="search">查詢</el-button>
        </el-col>
      </el-row>
    </el-form>
  </div>
</template>

<script lang="ts">
  import { Component, Prop, Vue } from 'vue-property-decorator';
  import { HeaderConfigItem } from "./data.ts";

  @Component({})
  export default class TableHeader extends Vue {
    public _copy: Object = {}
    @Prop({ default: function () {
        return 'small'
      }})
    size: 'small' | 'mini' | 'medium'

    @Prop({})
    data: Object

    @Prop({default: []})
    config: HeaderConfigItem[]

    mounted() {
      this._copy = Object.assign({}, this.data)
    }
    // 查詢
    search() {
      this.$emit('search', this.data)
    }
    // 清空
    reset() {
      this.$emit('update:data', Object.assign({}, this._copy))
      this.search()
    }
  }
</script>

<style lang="scss">
.table-header {
  padding-top: 10px;
  .table-header_button {
    text-align: right;
    float: right;
    margin-bottom: 12px;
    line-height: 40px;
  }
  .table-header-item.el-form-item {
    width: 100%;
    display: flex;
    flex: auto;
    margin-bottom: 12px;
    .el-form-item__content, .el-select {
      width: 100%;
    }
  }
}

</style>

父組件調用:

相關文章
相關標籤/搜索