Skip to content
On this page

【Vue项目总结】基于饿了么组件封装

vue项目中,组件是项目的基石,每个页面都是组件来组装起来,我司没有自己的组件库,选用的是ElementUI组件库,在它的基础上再次封装。

可编辑表格

由于是后台管理项目,各种单据漫天飞,而且单据列表要可编辑,可验证,基于业务所以封装了可编辑表格组件

业务需求:

  1. 每列可以编辑

  2. 每列输入的值需要被验证

每列可编辑,则需要每列的字段需要一个可编辑的属性edit来确定是否可以编辑,输入的值可以被验证,需要我们传入验证规则。

确认需要传入的props

props: {
  // 表格数据
  tableData: {
    type: Array,
    default: () => []
  },
  // 需要验证的列字段
  columns: {
    type: Array,
    default: () => []
  },
  // 是否可编辑
  defaultEdit: {
    type: Boolean,
    default: true
  },
  // 验证集合
  verifyRules: {
    type: Object,
    default: () => {}
  }
}

表格传入数据后,初始化可编辑状态

阅读el-table源码,可以看到,表格组件拥有自己的store,一些需要通信的状态都是它来维护的,我们也可创建一个自有的table-store.js来维护编辑状态

// 初始化数据
this.store = new TableStore({
  list: this.tableData,
  columns: this.columns,
  defaultEdit: this.defaultEdit
});

可编辑列edit-table-cell

利用slot插槽来传递编辑状态和验证规则

<slot v-else :cellState="cellState" :validateCell="validateCell"></slot>
...
computed: {
  isInput() {
    return this.slotName === 'input';
  },
  rowState() {
    const states = this.editTable.store.states;
    const rowState = states.get(this.row);
    return rowState;
  },
  cellState() {
    const cellState = this.rowState.get(this.prop);
    return cellState;
  }
},
methods: {
  // 验证
  validateCell(cb) {
    this.editTable
      .verifyTableCell(this.row, this.prop, this.cellState)
      .then(errMsg => {
        const valid = !errMsg;
        typeof cb === 'function' && cb(valid);
      });
  }
}

使用组件

// edit-table.vue

<page-edit-table
  ref="editTable"
  v-model="tableData"
  :columns="['categoryName', 'name', 'purchaseDate']"
  :default-edit="true"
  :verify-rules="verifyRules"
>
  <el-table
    ref="table"
    v-loading="loading"
    :data="tableData"
    tooltip-effect="dark"
    highlight-current-row
    border
    stripe
    style="width: 100%"
  >
    <el-table-column align="center" label="序号" width="50">
      <template slot-scope="scope">{{ scope.$index + 1 }}</template>
    </el-table-column>
    <el-table-column label="品目名称" prop="categoryName" show-overflow-tooltip>
      <template slot-scope="{ row }">
        <edit-table-cell :row="row" prop="categoryName">
          <template slot-scope="{ cellState, validateCell }">
            <el-select
              v-if="cellState.edit"
              v-model="row.categoryName"
              clearable
              placeholder="请选择品目"
              @change="validateCell"
            >
              <el-option label="你" value="1"></el-option>
              <el-option label="好" value="2"></el-option>
              <el-option label="呀" value="3"></el-option>
            </el-select>
            <span v-if="!cellState.edit">{{ row.categoryName }}</span>
          </template>
        </edit-table-cell>
      </template>
    </el-table-column>
....

效果如下

具体代码可查看组件

增删改的树组件

el-tree树形组件其实已经支持了自定义节点内容,但是我们要在它的基础上改变节点内容,这里主要是运用了Vue.set向响应式对象中添加一个属性。

// 部分代码
append(node, data) {
  const { label } = this.configProps;
  const newChild = {
    id: id++,
    [label]: `三级-${id}`,
    children: [],
    isEdit: false
  };
  if (!data.children) {
    this.$set(data, 'children', []);
  }
  data.children.push(newChild);
  this.$emit('addNode', node, data);
},
edit(node, data) {
  if (!node.isEdit) {
    this.$set(node, 'isEdit', true);
  }
  this.$nextTick(() => {
    this.$refs[`treeInput${node.id}`].focus();
  });
  this.$emit('editNode', node, data);
}

效果如下:

总结

组件是项目的积木条,公用组件的封装成功与否其实是对项目的开发效率有直接影响。具体代码可查看vue-template,基于vue-cli3.0搭建的后台模版。