Commit 2b59b62e7f203fc10b69b92bea786a5e2f492844

Authored by 刘汉宸
1 parent c5c854dc

feat: 优化SchemaSelect组件

examples/views/docs/component/schema-select.md
... ... @@ -4,13 +4,13 @@
4 4  
5 5 ## 基础用法
6 6  
7   -`schema`设置配置项
  7 +一个展示内容更多的表格形式的下拉选择器,基本配置项与`z-schema-page`中`schema`相同
8 8  
9   -::: snippet `schema`设置配置项
  9 +::: snippet 设置`options`配置选择器数据源,`label-key`设置显示值字段,`value-key`设置绑定值字段。
10 10  
11 11 ```html
12 12 <template>
13   - <z-schema-select v-model="model" size="small" :schema="schema" :api-search="searchAPI" label-key="name" value-key="id"></z-schema-select>
  13 + <z-schema-select v-model="model" :options="options" :schema="schema" label-key="name" value-key="id" @change="onChange"></z-schema-select>
14 14 </template>
15 15  
16 16 <script>
... ... @@ -18,6 +18,10 @@ export default {
18 18 data() {
19 19 return {
20 20 model: '',
  21 + options: [
  22 + { id: '0', name: '李饼', age: 32, address: '地址0', status: '正常' },
  23 + { id: '1', name: '陈拾', age: 20, address: '地址1', status: '正常' },
  24 + ],
21 25 schema: {
22 26 table: {
23 27 props: {
... ... @@ -26,9 +30,175 @@ export default {
26 30 items: [
27 31 { label: '姓名', prop: 'name', minWidth: 120 },
28 32 { label: '年龄', prop: 'age', minWidth: 120 },
  33 + { label: '地址', prop: 'address', minWidth: 120 },
29 34 ]
30 35 }
31   - }
  36 + },
  37 + }
  38 + },
  39 + methods: {
  40 + onChange(row) {
  41 + console.log(row);
  42 + }
  43 + }
  44 +}
  45 +</script>
  46 +```
  47 +
  48 +:::
  49 +
  50 +## 远程搜索
  51 +
  52 +配置一个接口查询远程数据。
  53 +
  54 +::: snippet `api-search`设置远程搜索方法。
  55 +
  56 +```html
  57 +<template>
  58 + <div>
  59 + <z-schema-select v-model="model" :schema="schema" :api-search="searchAPI" label-key="name" value-key="id"></z-schema-select>
  60 + <span>{{ model }}</span>
  61 + </div>
  62 +</template>
  63 +
  64 +<script>
  65 +export default {
  66 + data() {
  67 + return {
  68 + model: '',
  69 + schema: {
  70 + table: {
  71 + props: {
  72 + border: false
  73 + },
  74 + items: [
  75 + { label: '姓名', prop: 'name', minWidth: 120 },
  76 + { label: '年龄', prop: 'age', minWidth: 120 },
  77 + { label: '地址', prop: 'address', minWidth: 120 },
  78 + ]
  79 + }
  80 + },
  81 + }
  82 + },
  83 + methods: {
  84 + searchAPI(params) {
  85 + console.log('search', params);
  86 + return new Promise(resolve => {
  87 + setTimeout(() => {
  88 + const list = [
  89 + { id: '0', name: '李饼', age: 32, address: '地址0', status: '正常' },
  90 + { id: '1', name: '陈拾', age: 20, address: '地址1', status: '正常' },
  91 + { id: '3', name: '王七', age: 26, address: '地址3', status: '正常' },
  92 + { id: '4', name: '崔倍', age: 27, address: '地址4', status: '正常' },
  93 + { id: '5', name: '孙豹', age: 38, address: '地址5', status: '正常' },
  94 + ];
  95 + resolve([list, 37]);
  96 + }, 500);
  97 + });
  98 + },
  99 + }
  100 +}
  101 +</script>
  102 +```
  103 +
  104 +:::
  105 +
  106 +## 设置默认文本
  107 +
  108 +通常情况下,编辑表单时,若未加载搜索接口,则需要给定一个对应当前值的默认显示的文本
  109 +
  110 +::: snippet 组件提供了一个`setLabel`可设置当前文本
  111 +
  112 +```html
  113 +<template>
  114 + <div>
  115 + <z-schema-select ref="select" v-model="model" size="small" :schema="schema" :api-search="searchAPI" label-key="name" value-key="id"></z-schema-select>
  116 + <span>{{ model }}</span>
  117 + </div>
  118 +</template>
  119 +
  120 +<script>
  121 +export default {
  122 + data() {
  123 + return {
  124 + model: '6',
  125 + schema: {
  126 + table: {
  127 + props: {
  128 + border: false
  129 + },
  130 + items: [
  131 + { label: '姓名', prop: 'name', minWidth: 120 },
  132 + { label: '年龄', prop: 'age', minWidth: 120 },
  133 + { label: '地址', prop: 'address', minWidth: 120 },
  134 + ]
  135 + }
  136 + },
  137 + options: [
  138 + { id: '6', name: '张三', age: 18, address: '上海市青浦区华新镇纪鹤公路1988号', status: '禁用' },
  139 + ]
  140 + }
  141 + },
  142 + mounted() {
  143 + setTimeout(() => {
  144 + this.$refs.select.setLabel('李四');
  145 + }, 3000);
  146 + },
  147 + methods: {
  148 + searchAPI(params) {
  149 + console.log('search', params);
  150 + return new Promise(resolve => {
  151 + setTimeout(() => {
  152 + const list = [
  153 + { id: '0', name: '李饼', age: 32, address: '地址0', status: '正常' },
  154 + { id: '1', name: '陈拾', age: 20, address: '地址1', status: '正常' },
  155 + { id: '3', name: '王七', age: 26, address: '地址3', status: '正常' },
  156 + { id: '4', name: '崔倍', age: 27, address: '地址4', status: '正常' },
  157 + { id: '5', name: '孙豹', age: 38, address: '地址5', status: '正常' },
  158 + ];
  159 + resolve([list, 37]);
  160 + }, 500);
  161 + });
  162 + },
  163 + }
  164 +}
  165 +</script>
  166 +```
  167 +
  168 +:::
  169 +
  170 +也可以通过设置修正数据源来修正当前显示内容
  171 +
  172 +::: snippet 开启`api-search`远程搜索时,设置`options`,则作为修正数据源使用。注:修正数据源不会出现在搜索数据列表中。
  173 +
  174 +```html
  175 +<template>
  176 + <div>
  177 + <z-schema-select ref="select" v-model="model" size="small" :schema="schema" :options="options" :api-search="searchAPI" label-key="name" value-key="id"></z-schema-select>
  178 + <span>{{ model }}</span>
  179 + </div>
  180 +</template>
  181 +
  182 +<script>
  183 +export default {
  184 + data() {
  185 + return {
  186 + model: '6',
  187 + schema: {
  188 + table: {
  189 + props: {
  190 + border: false
  191 + },
  192 + items: [
  193 + { label: '姓名', prop: 'name', minWidth: 120 },
  194 + { label: '年龄', prop: 'age', minWidth: 120 },
  195 + { label: '地址', prop: 'address', minWidth: 120 },
  196 + ]
  197 + }
  198 + },
  199 + options: [
  200 + { id: '6', name: '张三', age: 18, address: '上海市青浦区华新镇纪鹤公路1988号', status: '禁用' },
  201 + ]
32 202 }
33 203 },
34 204 methods: {
... ...
packages/schema-select/index.vue
1 1 <style lang="scss">
2 2 .z-schema-select {
3   - display: inline-block;
  3 + display: inline-flex;
4 4 }
5 5 .z-schema-select__popper {
6 6 padding: 0 !important;
7 7 }
8 8 .z-schema-select__popper-content {
9 9 padding: 4px;
  10 + user-select: none;
10 11 }
11 12 </style>
12 13  
... ... @@ -14,7 +15,6 @@
14 15 <el-popover class="z-schema-select" popper-class="z-schema-select__popper" v-model="visible" trigger="click" placement="bottom-start" transition="el-zoom-in-top">
15 16 <template #reference>
16 17 <el-input
17   - class="el-select__input"
18 18 v-model="model"
19 19 :size="selectSize"
20 20 :disabled="selectDisabled"
... ... @@ -34,11 +34,13 @@
34 34 </template>
35 35 <div class="z-schema-select__popper-content" v-clickoutside="onClickoutside">
36 36 <z-schema-page
  37 + v-if="apiSearch"
37 38 ref="schema"
38 39 :value-table.sync="tableData"
39 40 :value-filter="valueFilter"
40 41 @update:value-filter="e => $emit('update:value-filter', e)"
41 42 :schema="selectSchema"
  43 + :size="selectSize"
42 44 :auto="auto"
43 45 :api-search="apiSearch"
44 46 >
... ... @@ -47,6 +49,12 @@
47 49 <template v-else>{{ value }}</template>
48 50 </template>
49 51 </z-schema-page>
  52 + <z-schema-table v-else ref="table" :value="options" :schema="selectTableSchema" :size="selectSize">
  53 + <template v-for="(item, index) in tableColumns" #[`cell-${item.prop}`]="{ value }">
  54 + <cell-highlight v-if="highlight" :value="value" :keyword="query" :key="index"></cell-highlight>
  55 + <template v-else>{{ value }}</template>
  56 + </template>
  57 + </z-schema-table>
50 58 </div>
51 59 </el-popover>
52 60 </template>
... ... @@ -54,6 +62,7 @@
54 62 <script>
55 63 import debounce from 'throttle-debounce/debounce';
56 64 import Clickoutside from 'element-ui/src/utils/clickoutside';
  65 +import { get } from '../utils';
57 66  
58 67 export default {
59 68 name: 'SchemaSelect',
... ... @@ -80,16 +89,18 @@ export default {
80 89 return {};
81 90 },
82 91 },
  92 + options: {
  93 + type: Array,
  94 + default: () => [],
  95 + },
83 96 auto: {
84 97 type: Boolean,
85 98 default: true,
86 99 },
87   - // clearable: Boolean,
88 100 clearable: {
89 101 type: Boolean,
90 102 default: true,
91 103 },
92   - // highlight: Boolean,
93 104 highlight: {
94 105 type: Boolean,
95 106 default: true,
... ... @@ -123,7 +134,8 @@ export default {
123 134 },
124 135 data() {
125 136 return {
126   - model: '',
  137 + model: this.value || '',
  138 + currentLabel: '',
127 139 query: '',
128 140 visible: false,
129 141 inputHovering: false,
... ... @@ -134,6 +146,7 @@ export default {
134 146 this.debouncedOnInput = debounce(300, () => {
135 147 this.onInput();
136 148 });
  149 + this.model = this.selectedLabel;
137 150 },
138 151 computed: {
139 152 _elFormItemSize() {
... ... @@ -150,8 +163,8 @@ export default {
150 163 },
151 164 selectedLabel() {
152 165 if (this.value) {
153   - const item = this.tableData.find(item => item[this.valueKey] === this.value) || {};
154   - return item[this.labelKey];
  166 + const item = [...this.tableData, ...this.options].find(item => item[this.valueKey] === this.value) || {};
  167 + return item[this.labelKey] || this.currentLabel || this.value;
155 168 }
156 169 return '';
157 170 },
... ... @@ -171,23 +184,55 @@ export default {
171 184 },
172 185 };
173 186 },
  187 + selectTableSchema() {
  188 + if (!this.schema) {
  189 + return {};
  190 + }
  191 + return {
  192 + on: {
  193 + 'row-click': this.onTableRowClick,
  194 + },
  195 + props: {
  196 + size: 'small',
  197 + 'highlight-current-row': true,
  198 + ...(get(this.schema, 'table.props') || {}),
  199 + },
  200 + items: [...(get(this.schema, 'table.items') || [])],
  201 + };
  202 + },
174 203 showClose() {
175 204 let hasValue = this.value !== undefined && this.value !== null && this.value !== '';
176 205 let criteria = this.clearable && !this.selectDisabled && this.inputHovering && hasValue;
177 206 return criteria;
178 207 },
179 208 tableColumns() {
180   - if (this.schema) {
181   - return this.schema.items;
  209 + const tableSchema = this.schema.table;
  210 + if (tableSchema) {
  211 + return tableSchema.items;
182 212 }
183 213 return [];
184 214 },
185 215 },
  216 + watch: {
  217 + value(val) {
  218 + this.model = this.selectedLabel;
  219 + },
  220 + options() {
  221 + this.model = this.selectedLabel;
  222 + },
  223 + },
186 224 methods: {
  225 + // 手动设置当前value对应的label
  226 + setLabel(val) {
  227 + this.currentLabel = val;
  228 + this.model = this.selectedLabel;
  229 + },
187 230 // 输入查询
188 231 onInput() {
189 232 this.query = this.model;
190   - this.$refs.schema.search();
  233 + if (this.$refs.schema) {
  234 + this.$refs.schema.search();
  235 + }
191 236 },
192 237 onInputFocus() {
193 238 this.model = '';
... ... @@ -200,12 +245,13 @@ export default {
200 245 onClickoutside() {
201 246 if (this.visible) {
202 247 this.model = this.selectedLabel;
  248 + this.query = '';
203 249 }
204 250 },
205 251 // 点击表格行
206 252 onTableRowClick(row) {
207 253 this.query = '';
208   - this.model = row.name;
  254 + this.model = this.selectedLabel;
209 255 this.visible = false;
210 256 this.$emit('input', row[this.valueKey]);
211 257 this.$emit('change', row);
... ...