Commit 8657d1e91433c9104dd0fa5377c4c690c4a36978

Authored by 刘汉宸
1 parent cda4e04e

feat: 新增Table组件

examples/router/routes.js
... ... @@ -57,6 +57,17 @@ const _components = [
57 57 ],
58 58 },
59 59 {
  60 + group: '展示组件',
  61 + children: [
  62 + {
  63 + path: 'table',
  64 + name: 'table',
  65 + meta: { title: 'Table 表格' },
  66 + component: () => import('@/views/docs/component/table.md'),
  67 + },
  68 + ],
  69 + },
  70 + {
60 71 group: '方案组件',
61 72 children: [
62 73 {
... ...
examples/views/docs/component/form.md
... ... @@ -115,9 +115,9 @@ export default {
115 115 ```html
116 116 <template>
117 117 <z-form label-width="100px" size="mini" span="8">
118   - <z-form-item label="户主姓名" v-model="model.name" required></z-form-item>
119   - <z-form-item label="年龄" v-model="model.age"></z-form-item>
120   - <z-form-item label="性别" v-model="model.gender"></z-form-item>
  118 + <z-form-item label="户主姓名" :value="model.name" required></z-form-item>
  119 + <z-form-item label="年龄" :value="model.age"></z-form-item>
  120 + <z-form-item label="性别" :value="model.gender"></z-form-item>
121 121 <z-form-item label="详细地址" span="24">
122 122 <el-tag size="mini" type="info">{{ model.address }}</el-tag>
123 123 <template #label>
... ...
examples/views/docs/component/select.md
... ... @@ -144,6 +144,37 @@ export default {
144 144  
145 145 </div>
146 146  
  147 +## 绑定值参数名
  148 +
  149 +可以根据不同业务数据的需要,自定义下拉框的绑定值参数名。
  150 +
  151 +::: snippet `labelKey`设置下拉框显示的文本,默认**label**;`valueKey`设置下拉框选项对应的值,默认**value**。
  152 +
  153 +```html
  154 +<template>
  155 + <div>
  156 + <z-select v-model="model" :options="options" label-key="name" value-key="code"></z-select>
  157 + <span>{{ model }}</span>
  158 + </div>
  159 +</template>
  160 +
  161 +<script>
  162 +export default {
  163 + data() {
  164 + return {
  165 + model: '',
  166 + options: [
  167 + { name: '单车', code: 'VAN' },
  168 + { name: '牵引车', code: 'TRACTOR' }
  169 + ],
  170 + }
  171 + }
  172 +}
  173 +</script>
  174 +```
  175 +
  176 +:::
  177 +
147 178 ## 设置多选
148 179  
149 180 多选时支持字符串或数组类型的值
... ... @@ -242,7 +273,7 @@ export default {
242 273  
243 274 ## 远程加载
244 275  
245   -可以通过设置`queryApi`自定义查询接口,也可以设置`url`及`http`进行内置格式的查询,其中`http`可在组件库全局配置
  276 +可以通过设置`queryApi`自定义查询接口,必须是返回`Promise`的`Function`类型,Promise的返回值为`Array`类型,格式需要与`lebalKey`、`valueKey`项对应。
246 277  
247 278 <div class="code-snippet-box">
248 279  
... ... @@ -269,6 +300,9 @@ export default {
269 300 },
270 301 methods: {
271 302 queryAPI(val) {
  303 + // 正式项目使用时,可以返回axios的实例,如:
  304 + // return this.$axios({ url: 'xxx', params: { foo: 'bar' } }).then(response => ({ result: response.result }));
  305 + // 此处的Promise是模拟接口
272 306 return new Promise(resolve => {
273 307 setTimeout(() => {
274 308 resolve({
... ... @@ -375,6 +409,52 @@ export default {
375 409  
376 410 </div>
377 411  
  412 +## 搜索前校验
  413 +
  414 +可以通过设置`before-query`设置搜索之前的钩子,若为返回值为**false**则不执行搜索。
  415 +
  416 +::: snippet 一般用于搜索前的业务逻辑校验
  417 +
  418 +```html
  419 +<template>
  420 + <z-select v-model="model" :options="options" :queryApi="queryAPI" :before-query="beforeQuery"></z-select>
  421 +</template>
  422 +
  423 +<script>
  424 +export default {
  425 + data() {
  426 + return {
  427 + model: '',
  428 + options: [
  429 + { label: '王七', value: 'wq' },
  430 + { label: '陈拾', value: 'cs' },
  431 + ]
  432 + }
  433 + },
  434 + methods: {
  435 + beforeQuery(query) {
  436 + console.log(query.length);
  437 + return query.length > 2;
  438 + },
  439 + queryAPI(val) {
  440 + return new Promise(resolve => {
  441 + setTimeout(() => {
  442 + resolve({
  443 + result: [
  444 + { label: '王五', value: 'ww' },
  445 + { label: '赵六', value: 'zl' },
  446 + ]
  447 + });
  448 + }, 1000);
  449 + });
  450 + },
  451 + }
  452 +}
  453 +</script>
  454 +```
  455 +
  456 +:::
  457 +
378 458 ## API
379 459  
380 460 ## Attribute 属性
... ... @@ -384,8 +464,8 @@ export default {
384 464 value | 值 | String, Number, Boolean, Object, Array | - | -
385 465 placeholder | 占位符 | String | - | 请选择
386 466 options | 选项列表 | Array | - | []
387   -labelKey | 标签字段名 | String | - | name
388   -valueKey | 值字段名 | String | - | code
  467 +labelKey | 标签字段名 | String | - | label
  468 +valueKey | 值字段名 | String | - | value
389 469 searchKey | 搜索字段名 | String | - | query
390 470 size | 大小 | String | mini、small、large | mini
391 471 multiple | 多选 | Boolean | - | false
... ...
examples/views/docs/component/table.md 0 → 100644
... ... @@ -0,0 +1,79 @@
  1 +# Table 表格
  2 +
  3 +拓展ElementUI的`el-table`
  4 +
  5 +## 基础用法
  6 +
  7 +基本参数与ElementUI的`el-table`相同。
  8 +
  9 +::: snippet 支持`size`继承
  10 +
  11 +```html
  12 +<template>
  13 + <el-form size="mini">
  14 + <z-table :data="tableData" border>
  15 + <el-table-column prop="name" label="姓名"></el-table-column>
  16 + <el-table-column prop="age" label="年龄"></el-table-column>
  17 + <el-table-column prop="gender" label="性别"></el-table-column>
  18 + </z-table>
  19 + </el-form>
  20 +</template>
  21 +
  22 +<script>
  23 +export default {
  24 + data() {
  25 + return {
  26 + tableData: [
  27 + { name: '张三', age: '31', gender: '男' },
  28 + { name: '李四', age: '27', gender: '女' },
  29 + { name: '王五', age: '16', gender: '男' },
  30 + ],
  31 + };
  32 + },
  33 +}
  34 +</script>
  35 +```
  36 +
  37 +:::
  38 +
  39 +## 可编辑表格
  40 +
  41 +一般用于表格的静态数据编辑
  42 +
  43 +::: snippet 设置type为`editable`开启可编辑模式
  44 +
  45 +```html
  46 +<template>
  47 + <el-form size="mini">
  48 + <el-row>
  49 + <el-col :span="18">
  50 + <z-table :value="tableData" type="editable" border :columns="columns"></z-table>
  51 + </el-col>
  52 + <el-col :span="6" style="padding-left: 10px">
  53 + <pre class="demo-model">{{ tableData }}</pre>
  54 + </el-col>
  55 + </el-row>
  56 + </el-form>
  57 +</template>
  58 +
  59 +<script>
  60 +export default {
  61 + data() {
  62 + return {
  63 + tableData: [
  64 + { name: '张三', age: '31', gender: '男' },
  65 + { name: '李四', age: '27', gender: '女' },
  66 + { name: '王五', age: '16', gender: '男' },
  67 + ],
  68 + columns: [
  69 + { prop: 'name', label: '姓名' },
  70 + { type: 'el-input-number', prop: 'age', label: '年龄' },
  71 + { prop: 'gender', label: '性别' },
  72 + ]
  73 + };
  74 + },
  75 +}
  76 +</script>
  77 +```
  78 +
  79 +:::
0 80 \ No newline at end of file
... ...
packages/index.js
1 1 import Vue from 'vue';
  2 +import ZTable from './table/index';
  3 +import ZTableNormal from './table/normal';
  4 +import ZTableEditable from './table/editable';
2 5 import ElImageViewer from './upload/image-viewer';
3 6  
4 7 let components = {};
... ... @@ -11,6 +14,9 @@ componentsFiles.keys().forEach(path =&gt; {
11 14  
12 15 // 给组件库配置install方法
13 16 const install = function(Vue, opts = {}) {
  17 + components[ZTable.name] = ZTable;
  18 + components[ZTableNormal.name] = ZTableNormal;
  19 + components[ZTableEditable.name] = ZTableEditable;
14 20 Object.values(components).forEach(component => {
15 21 // 组件前缀
16 22 const prefix = opts.name || 'z';
... ...
packages/table/editable.vue 0 → 100644
... ... @@ -0,0 +1,106 @@
  1 +<template>
  2 + <el-table :data="tableData | tableDataFilter" :size="tableSize" v-bind="_props" @header-click="onHeaderClick" @cell-click="onCellClick" @cell-dblclick="onCellDblclick">
  3 + <template v-for="(item, index) in columns">
  4 + <el-table-column v-bind="item" :key="index">
  5 + <template #default="{ row, column }">
  6 + <table-column-cell
  7 + :editable="row.$editable || (tableEditCell.index === row.$index && tableEditCell.prop === item.prop)"
  8 + :type="item.type"
  9 + :value="row[column.property]"
  10 + @input="onCellInput"
  11 + ></table-column-cell>
  12 + </template>
  13 + </el-table-column>
  14 + </template>
  15 + </el-table>
  16 +</template>
  17 +
  18 +<script>
  19 +import TableNormal from './normal';
  20 +import tableProps from './props';
  21 +import { cloneDeep, get, set } from '../utils';
  22 +
  23 +export default {
  24 + name: 'TableEditable',
  25 + extends: TableNormal,
  26 + components: {
  27 + tableColumnCell: {
  28 + props: {
  29 + value: [String, Number, Array, Object],
  30 + type: { type: String, default: 'el-input' },
  31 + editable: Boolean,
  32 + },
  33 + watch: {
  34 + editable(val) {
  35 + if (val && this.type === 'el-input') {
  36 + this.$nextTick(() => {
  37 + this.$children[0].focus();
  38 + });
  39 + }
  40 + },
  41 + },
  42 + render(h) {
  43 + if (this.editable) {
  44 + return h(this.type, {
  45 + props: { value: this.value, size: 'mini' },
  46 + on: {
  47 + input: value => {
  48 + this.$emit('input', value);
  49 + },
  50 + },
  51 + });
  52 + }
  53 + return h('span', this.value);
  54 + },
  55 + },
  56 + },
  57 + props: {
  58 + value: {
  59 + type: Array,
  60 + default() {
  61 + return [];
  62 + },
  63 + },
  64 + columns: {
  65 + type: Array,
  66 + default() {
  67 + return [];
  68 + },
  69 + },
  70 + ...tableProps,
  71 + },
  72 + data() {
  73 + return {
  74 + tableData: this.value,
  75 + tableRowTemplate: { $editable: true }, // 行数据模板
  76 + tableEditCell: {}, // 正在编辑的单元格
  77 + tableSelection: [], // 表格已选中
  78 + };
  79 + },
  80 + filters: {
  81 + tableDataFilter(value) {
  82 + return value.map((item, index) => ({ ...item, $index: index }));
  83 + },
  84 + },
  85 + methods: {
  86 + onHeaderClick() {
  87 + this.tableEditCell = {};
  88 + },
  89 + onCellClick(row, column, cell, event) {
  90 + if (row.$index !== this.tableEditCell.index || column.property !== this.tableEditCell.prop) {
  91 + this.tableEditCell = {};
  92 + }
  93 + },
  94 + onCellDblclick(row, column, cell, event) {
  95 + this.tableEditCell = { index: row.$index, prop: column.property };
  96 + },
  97 + onCellInput(value) {
  98 + const tableData = cloneDeep(this.tableData);
  99 + const tableRow = tableData[this.tableEditCell.index];
  100 + set(tableRow, this.tableEditCell.prop, value);
  101 + tableData[this.tableEditCell.index] = tableRow;
  102 + this.$set(this.tableData, this.tableEditCell.index, tableRow);
  103 + },
  104 + },
  105 +};
  106 +</script>
... ...
packages/table/index.js 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +import tableProps from './props';
  2 +
  3 +export default {
  4 + name: 'Table',
  5 + props: {
  6 + type: {
  7 + type: String,
  8 + default: 'normal',
  9 + },
  10 + value: {
  11 + type: Array,
  12 + default() {
  13 + return [];
  14 + },
  15 + },
  16 + columns: {
  17 + type: Array,
  18 + default() {
  19 + return [];
  20 + },
  21 + },
  22 + ...tableProps,
  23 + },
  24 + render(h) {
  25 + const scopedSlots = this.$scopedSlots;
  26 + return h(`z-table-${this.type}`, { props: { ...this._props }, scopedSlots });
  27 + },
  28 +};
... ...
packages/table/normal.vue 0 → 100644
... ... @@ -0,0 +1,36 @@
  1 +<template>
  2 + <el-table :size="tableSize" v-bind="_props">
  3 + <slot></slot>
  4 + <slot name="append"></slot>
  5 + </el-table>
  6 +</template>
  7 +
  8 +<script>
  9 +import tableProps from './props';
  10 +
  11 +export default {
  12 + name: 'TableNormal',
  13 + inject: {
  14 + elForm: {
  15 + default: '',
  16 + },
  17 + elFormItem: {
  18 + default: '',
  19 + },
  20 + },
  21 + props: {
  22 + ...tableProps,
  23 + },
  24 + computed: {
  25 + _elFormItemSize() {
  26 + return (this.elFormItem || {}).elFormItemSize;
  27 + },
  28 + tableSize() {
  29 + return this.size || this._elFormItemSize || (this.elForm || {}).size || (this.$ELEMENT || {}).size;
  30 + },
  31 + },
  32 + mounted() {
  33 + // console.log(this);
  34 + },
  35 +};
  36 +</script>
... ...
packages/table/props.js 0 → 100644
... ... @@ -0,0 +1,62 @@
  1 +export default {
  2 + data: {
  3 + type: Array,
  4 + default: function() {
  5 + return [];
  6 + },
  7 + },
  8 + size: String,
  9 + width: [String, Number],
  10 + height: [String, Number],
  11 + maxHeight: [String, Number],
  12 + fit: {
  13 + type: Boolean,
  14 + default: true,
  15 + },
  16 + stripe: Boolean,
  17 + border: Boolean,
  18 + rowKey: [String, Function],
  19 + context: {},
  20 + showHeader: {
  21 + type: Boolean,
  22 + default: true,
  23 + },
  24 + showSummary: Boolean,
  25 + sumText: String,
  26 + summaryMethod: Function,
  27 + rowClassName: [String, Function],
  28 + rowStyle: [Object, Function],
  29 + cellClassName: [String, Function],
  30 + cellStyle: [Object, Function],
  31 + headerRowClassName: [String, Function],
  32 + headerRowStyle: [Object, Function],
  33 + headerCellClassName: [String, Function],
  34 + headerCellStyle: [Object, Function],
  35 + highlightCurrentRow: Boolean,
  36 + currentRowKey: [String, Number],
  37 + emptyText: String,
  38 + expandRowKeys: Array,
  39 + defaultExpandAll: Boolean,
  40 + defaultSort: Object,
  41 + tooltipEffect: String,
  42 + spanMethod: Function,
  43 + selectOnIndeterminate: {
  44 + type: Boolean,
  45 + default: true,
  46 + },
  47 + indent: {
  48 + type: Number,
  49 + default: 16,
  50 + },
  51 + treeProps: {
  52 + type: Object,
  53 + default() {
  54 + return {
  55 + hasChildren: 'hasChildren',
  56 + children: 'children',
  57 + };
  58 + },
  59 + },
  60 + lazy: Boolean,
  61 + load: Function,
  62 +};
... ...