vue后台管理系统常用的页面组件封装

5,003 阅读1分钟

table 表格组件封装

e-table-list

<template>
  <el-table
    ref="table"
    v-loading="loading"
    element-loading-text="Loading"
    :data="tableData"
    :row-key="rowKey"
    border
    fit
    highlight-current-row
    tooltip-effect="dark"
    style="width: 100%"
    @sort-change="handleSortChange"
    @selection-change="handleSelectionChange"
  >
    <!--多选列-->
      <el-table-column
              v-if="indexShow"
              type="index"
              align="center"
              width="50">
      </el-table-column>
    <el-table-column
      v-if="selectionShow"
      type="selection"
      width="50"
      align="center"
      highlight-current-row
      fixed
      :reserve-selection="true"
    ></el-table-column>
    <el-table-column
      v-for="(item, index) in tableLabel"
      :width="item.width ? item.width : ''"
      :fixed="item.fixed ? item.fixed : false"
      :type="item.type ? item.type : ''"
      :key="index"
      :align="item.align"
      :label="item.label"
      :prop="item.param"
      :sortable="item.sortable ? 'custom' : false"
      v-show="index==1"
    >
      <template slot-scope="scope">

        <slot v-if="item.slot" v-bind:scope="scope" :name="item.slot"></slot>
        <div v-html="item.render(scope.row)" v-else-if="item.render">
        </div>
        <span v-else>{{ scope.row[item.param] }} {{ item.type }}</span>
      </template>
    </el-table-column>

    <el-table-column
      v-if="tableOption.label"
      :width="tableOption.width"
      :label="tableOption.label"
      align="center"
      class-name="small-padding fixed-width"
      :fixed="tableOption.fixed ? tableOption.fixed : false"
    >
      <template slot-scope="scope">
        <el-button
          v-for="(item, index) in tableOption.options"
          :key="index"
          :type="item.type"
          :icon="item.icon"
          @click="handleButton(item.methods, scope.row, scope.row)"
          size="mini"
        >
          {{ item.label }}
        </el-button>
      </template>
    </el-table-column>
  </el-table>
</template>

<script>
export default {
  props: {
    loading: {
      type: Boolean,
      default: false,
    },
    tableData: {
      type: Array,
      default: () => {
        return [];
      },
    },
    tableLabel: {
      type: Array,
      default: () => {
        return [];
      },
    },
    tableOption: {
      type: Object,
      default: () => {
        return {};
      },
    },
    indexShow:{
        type: Boolean,
        default: false,
    },
    selectionShow:{
        type: Boolean,
        default: false,
    },
    radioShow:{
      type:Boolean,
      default: false
    },
    rowKey:{
      type:String,
      default:''
    }
  },
  components: {},
  methods: {
    handleButton(methods, row, index) {
      // 按钮事件
      this.$emit("handleButton", { methods: methods, row: row, index: index });
    },
    handleSortChange(val) {
      // 排序
      this.$emit("handleSortChange", val);
    },
    handleSelectionChange(val) {
      this.$emit("handleSelectionChange", val);
    }
  },
};
</script>

<style>
</style>

使用

image.png

image.png

image.png

search 表格组件分装

e-search

<!-- 搜索组件 -->
<template>
  <div class="content">
    <template v-for="(item, index) in fieldList">
      <div
        v-show="icon === 'close' ? index < count : true"
        :key="index"
      >
        <div class="item-style">
          <span class="label-style" :style="{width: width.labelWidth + 'px'}">{{ item.label }}</span>
          <!-- 普通输入框 -->
          <el-input
            v-if="item.type === 'input'"
            v-model.trim="defaultData[item.value]"
            :size="size"
            :style="{width: width.itemWidth + 'px'}"
            :type="item.type"
            :disabled="item.disabled"
            :placeholder="getPlaceholder(item)"
            @keyup.enter.native="handleFilter"
            @blur="handleEvent($event, item.value)"
          />
          <!-- 日期/时间 -->
          <el-date-picker
            v-if="item.type === 'date'"
            v-model="defaultData[item.value]"
            :size="size"
            :style="{width: width.itemWidth + 'px'}"
            :type="item.dateType"
            :picker-options="item.TimePickerOptions"
            :clearable="item.clearable"
            :disabled="item.disabled"
            start-placeholder="开始时间"
            end-placeholder="结束时间"
            value-format="yyyy-MM-dd HH:MM:SS"
            :placeholder="getPlaceholder(item)"
            @change="handleEvent($event, item.value, 'change')"
          />
          <!-- 选择框 -->
          <el-select
            v-if="item.type === 'select'"
            v-model="defaultData[item.value]"
            :size="size"
            :style="{width: width.itemWidth + 'px'}"
            :disabled="item.disabled"
            :clearable="item.clearable"
            :filterable="item.filterable"
            :multiple="item.multiple"
            :placeholder="getPlaceholder(item)"
            @change="handleEvent($event, item.value, 'change')"
          >
            <el-option
              v-for="childItem in listTypeInfo[item.list]"
              :key="childItem.id"
              :label="childItem.name"
              :value="childItem.id"
              :disabled="childItem.disabled"
            />
          </el-select>
          <!-- 计数器 -->
          <el-input-number
            v-if="item.type === 'inputNumber'"
            v-model="defaultData[item.value]"
            :size="size"
            :style="{width: width.itemWidth + 'px'}"
            :min="item.min"
            :max="item.max"
            @change="handleEvent($event, item.value, 'change')"
          />
        </div>
      </div>
    </template>
      <div
        v-if="!btnHidden && fieldList.length !== 0"
        class="btn-style"
      >
        <el-button
          :type="btnStyle[0].type"
          :size="size"
          :plain="btnStyle[0].plain"
          :round="btnStyle[0].round"
          :icon="btnStyle[0].icon"
          :disabled="btnStyle[0].disabled"
          @click="handleFilter"
        >
          {{ btnStyle[0].text }}
        </el-button>
        <el-button
          :type="btnStyle[1].type"
          :size="size"
          :plain="btnStyle[1].plain"
          :round="btnStyle[1].round"
          :disabled="btnStyle[1].disabled"
          :icon="btnStyle[1].icon"
          @click="handleReset"
        >
          {{ btnStyle[1].text }}
        </el-button>
      </div>
      <el-button
        v-if="!btnHidden && fieldList.length > count"
        type="text"
        @click="icon === 'open' ? icon = 'close' : icon = 'open'"
        style="margin-left: 6px;"
      >{{ icon === 'open' ? '收起' : '展开' }}
        <i :class="icon === 'open' ? 'el-icon-caret-top' : 'el-icon-caret-bottom'" />
      </el-button>
  </div>
</template>
<script>

export default {
    name: 'ESearch',
    props: {
      /**字段默认数据 */
      data: {
        type: Object,
        default: () => {},
        required: true
      },
      /**字段配置项 */
      fieldList: {
        type: Array,
        default: () => [],
        required: true
      },
      /**相关的列表 */
      listTypeInfo: {
        type: Object,
        default: () => {}
      },
      /**按钮区域是否隐藏 */
      btnHidden: {
        type: Boolean,
        default: false
      },
      /**组件尺寸 */
      size: {
        type: String,
        default: 'mini'
      },
      /**默认搜索数 */
      count: {
        type: Number,
        default: 4
      },
      /**组件及label宽度 */
      width: {
        type: Object,
        default: () => ({
          labelWidth: 110,
          itemWidth: 220
        })
      },
      /**按钮配置 */
      btnStyle: {
        type: Array,
        default: () => [
          { icon: null, text: '搜索', disabled: false, type: 'primary', plain: false, round: false },
          { icon: null, text: '重置', disabled: false, type: null, plain: false, round: false }
        ]
      }
    },
    data: () => ({
      defaultData: {},
      icon: 'close'
    }),
    mounted () {
      /**
       * 子组件无法直接修改父组件传递过来的值
       * 于是将父组件传递的值首先赋值给 defaultData
       * 在搜索条件中同样使用 defaultData
       * 永远保持 props 传递的 data 纯洁度
       */
      this.defaultData = {...this.data}
    },
    methods: {
        /**
         * @func 占位符显示
         * @param {Object} row
         * @desc 📝
         */
        getPlaceholder (row) {
          let placeholder
          if (row.type === 'input') {
            placeholder = '请输入' + row.label
          } else if (row.type === 'select' || row.type === 'time' || row.type === 'date') {
            placeholder = '请选择' + row.label
          } else {
            placeholder = row.label
          }
          return placeholder
        },
        /**
         * @func 事件处理
         * @desc 📝
         */
        handleEvent (event, val, change) {
          let obj = {
            value: change === 'change' ? event : event.target.value,
            label: val
          }
          this.$emit('handleEvent', obj)
        },
        /**
         * @func 搜索
         * @desc 📝
         */
        handleFilter () {
          this.$emit('handleFilter', this.defaultData)
        },
        /**
         * @func 重置
         * @desc 📝
         */
        handleReset () {
          this.defaultData = {...this.data}
          this.$emit('handleReset', this.defaultData)
        }
    }
}
</script>
<style lang="scss" scoped>
.content {
  display: flex;
  flex-wrap: wrap;
  position: relative;
}
.content .item-style {
  margin: 6px auto;
  line-height: 1;
}
.content .item-style .label-style {
  display: inline-block;
  justify-self: end;
  font-size: 13px;
  white-space: nowrap;
  overflow: hidden;
  -o-text-overflow: ellipsis;
  text-overflow: ellipsis;
  text-align: right;
  margin-right: 12px;
  color: #222222;
}
.btn-style {
  margin: 6px 0 6px auto;
}
</style>

使用

image.png image.png

image.png

image.png

image.png

dialog 弹框

<template>
  <div>
    <el-dialog
      class="comn_dialog"
      :title="dialogTitle"
      :visible.sync="visible"
      :width="popupWidth"
      :top="popupTop"
      @close="Cancel"
    >
      <slot>
        <p>弹窗内容自定义</p>
      </slot>
      <span slot="footer" class="dialog-footer">
        <el-button @click="Cancel">取 消</el-button>
        <el-button type="primary" @click="Save">确定</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
export default {
  props: {
    dialogTitle: {
      type: String,
      default: "标题"
    },
    centerDialogVisible: {
      type: Boolean,
      default() {
        return false;
      }
    },
    popupWidth: {
      type: String,
      default() {
        return "430px";
      }
    },
    popupTop: {
      type: String,
      default() {
        return "23vh";
      }
    }
  },
  computed: {
    visible: {
      get() {
        return this.centerDialogVisible;
      },
      set(val) { // 当visible改变的时候,触发父组件的 updateVisible方法,在该方法中更改传入子组件的 centerDialogVisible的值
        this.$emit("updateVisible", val);
      }
    }
  },
  methods: {
    Cancel() {
      this.$emit("resetPopupData");
    },
    Save() {
      this.$emit("submitPopupData");
    }
  }
};
</script>
<style lang="scss">
.comn_dialog {
  .el-dialog__header {
    padding: 8px 0px 3px 8px;
    border-bottom: 1px solid #e7e6e6;
    box-shadow: 0px 4px 4px -4px #d1d0d0;
  }
  .el-dialog__title {
    font-size: 16px;
    letter-spacing: 1px;
    color: #464646;
    font-weight: bolder;
  }
  .el-dialog__footer {
    padding: 0px 20px 20px 0px;
  }
  .el-dialog__headerbtn {
    position: static; // 兼容IE11 ,取消原有的position定位
  }
  .el-dialog__close {
    // color: $header_bg;
    font-size: 20px;
    font-weight: bolder;
    position: absolute;
    top: 8px;
    right: 8px;
    &::after {
      content: '';
    //   border: 2px solid $header_bg;
      width: 20px;
      height: 20px;
      border-radius: 25px;
      position: absolute;
      right: -2px;
      top: -3px;
    }
  }
  .el-dialog__body {
    padding: 20px;
  }

  .dialog-footer{
    display: flex;
    justify-content: center;
    align-items: center;
  }
}
</style>

使用

image.png

image.png

image.png

image.png