Commit 61296e41448f7fd3697f2645977d114fe6566dd1
1 parent
70f019f6
Exists in
master
and in
1 other branch
重构form组件
Showing
4 changed files
with
321 additions
and
277 deletions
Show diff stats
examples/views/index.vue
| ... | ... | @@ -36,7 +36,7 @@ |
| 36 | 36 | </div> |
| 37 | 37 | <div class="cpt-title">下拉选择 eagle-select</div> |
| 38 | 38 | <div class="cpt-content"> |
| 39 | - <eagle-select v-model="selectValue" :dataSource="[{ label: '选项A', value: 'A' }, { label: '选项B', value: 'B' }]"></eagle-select> | |
| 39 | + <!-- <eagle-select v-model="selectValue" :dataSource="[{ label: '选项A', value: 'A' }, { label: '选项B', value: 'B' }]"></eagle-select> --> | |
| 40 | 40 | </div> |
| 41 | 41 | <div class="cpt-title">状态指示点 eagle-status-indicator</div> |
| 42 | 42 | <div class="cpt-content"> |
| ... | ... | @@ -62,7 +62,21 @@ |
| 62 | 62 | </div> |
| 63 | 63 | <div class="cpt-title">表单生成器 eagle-form</div> |
| 64 | 64 | <div class="cpt-content"> |
| 65 | - <eagle-cform v-model="formValue" :list="formList"></eagle-cform> | |
| 65 | + {{ formValue }} | |
| 66 | + <eagle-form ref="form" v-model="formValue" :list="formList" :form-props="{ size: 'large', 'label-width': '80px' }" submit-pure> | |
| 67 | + <template #group-not-bad="{ label, list }"> | |
| 68 | + <div style="background: deepskyblue">哎哟 - {{ label }} - 标题 [{{ list.length }} 项]</div> | |
| 69 | + </template> | |
| 70 | + <template #group-default="{ label }"> | |
| 71 | + <div style="background: deeppink">{{ label }} - 默认标题</div> | |
| 72 | + </template> | |
| 73 | + <template #item-name="{ model, key }"> | |
| 74 | + <el-select v-model="model[key]"> | |
| 75 | + <el-option value="A">A</el-option> | |
| 76 | + <el-option value="B">B</el-option> | |
| 77 | + </el-select> | |
| 78 | + </template> | |
| 79 | + </eagle-form> | |
| 66 | 80 | </div> |
| 67 | 81 | </div> |
| 68 | 82 | </template> |
| ... | ... | @@ -79,19 +93,48 @@ export default { |
| 79 | 93 | { id: 0, label: '一级菜单', children: [{ id: 1, label: '二级菜单-1' }, { id: 2, label: '二级菜单-2', children: [{ id: 3, label: '三级菜单' }] }] } |
| 80 | 94 | ], |
| 81 | 95 | formValue: {}, |
| 96 | + // formList: [ | |
| 97 | + // { type: 'el-input', key: 'name', label: '名称', group: '基本信息', span: 12 }, | |
| 98 | + // { type: 'el-input', key: 'gender', label: '性别', group: '基本信息', span: 12 }, | |
| 99 | + // { type: 'el-input', key: 'address', label: '住址', group: '家庭住址' }, | |
| 100 | + // { type: 'el-input', key: 'postcode', label: '邮编', group: '家庭住址' }, | |
| 101 | + // { type: 'el-input', key: 'political', label: '政治面貌', group: { key: 'pol', label: '政治审查' } }, | |
| 102 | + // ] | |
| 82 | 103 | formList: [ |
| 83 | - { type: 'el-input' } | |
| 104 | + { type: 'el-input', key: 'name', label: '名称', group: '那啥' }, | |
| 105 | + { type: 'el-input', key: 'gender', label: '性别', group: { label: '不错哦', key: 'not-bad' }, tip: '周某人说的', props: { disabled: true } }, | |
| 106 | + { type: 'eagle-select', key: 'address', label: '住址', default: '123', props: { dataSource: [{ label: '第一个', value: 'No.1' }, { label: '第二个', value: 'No.2' }] } }, | |
| 107 | + { type: 'el-input', key: 'postcode', label: '邮编', tip: { content: '随便挑', placement: "left" } }, | |
| 108 | + { type: 'el-input', key: 'political', label: '政治面貌', visible: (model) => model.name === 'B' }, | |
| 84 | 109 | ] |
| 85 | 110 | } |
| 86 | 111 | }, |
| 112 | + mounted() { | |
| 113 | + setTimeout(() => { | |
| 114 | + this.formValue.name = "B" | |
| 115 | + this.formValue.name2 = "B" | |
| 116 | + this.formValue.name3 = "B" | |
| 117 | + this.formValue.name4 = "B" | |
| 118 | + this.formValue.name5 = "B" | |
| 119 | + this.formValue.name6 = "B" | |
| 120 | + this.formValue.political = "B11111111111111111111111" | |
| 121 | + }, 5000) | |
| 122 | + | |
| 123 | + // setTimeout(() => { | |
| 124 | + // this.$refs.form.reset() | |
| 125 | + // }, 8000) | |
| 126 | + }, | |
| 87 | 127 | methods: { |
| 128 | + handleText(val) { | |
| 129 | + console.log(val) | |
| 130 | + }, | |
| 88 | 131 | handleConfirm() { |
| 89 | 132 | alert('确认') |
| 90 | 133 | }, |
| 91 | 134 | handleCancel() { |
| 92 | 135 | alert('取消') |
| 93 | 136 | } |
| 94 | - } | |
| 137 | + }, | |
| 95 | 138 | } |
| 96 | 139 | </script> |
| 97 | 140 | ... | ... |
packages/cform/index.vue
| ... | ... | @@ -1,271 +0,0 @@ |
| 1 | -<style scoped> | |
| 2 | -.edit-form { | |
| 3 | - padding-right: 30px; | |
| 4 | -} | |
| 5 | -.group-title { | |
| 6 | - font-weight: bold; | |
| 7 | - padding: 15px 5px; | |
| 8 | - border-bottom: 1px solid #d9d9d9; | |
| 9 | - margin-bottom: 30px; | |
| 10 | - /* margin-top: 15px; | |
| 11 | - margin-bottom: 30px; */ | |
| 12 | -} | |
| 13 | -/* .group-title:first-child { | |
| 14 | - margin-top: 0px; | |
| 15 | -} */ | |
| 16 | - | |
| 17 | -.group-content { | |
| 18 | - margin: 15px 0px; | |
| 19 | -} | |
| 20 | -</style> | |
| 21 | - | |
| 22 | -<template> | |
| 23 | - <el-form class="edit-form" size="small" ref="form" :model="model" :label-width="labelWidth"> | |
| 24 | - <template v-if="groupList.group"> | |
| 25 | - <!-- 这里可以合为一个代码段判断 --> | |
| 26 | - <template v-for="(data, index) in groupList.data"> | |
| 27 | - <template v-if="data.list.length > 0"> | |
| 28 | - <!-- 这里可以判断是否满足分组条件决定显示title,另外下面content的class也可以判断,div可以换满span的col代替 --> | |
| 29 | - <!-- 加上选项tips提示判断,类似avue --> | |
| 30 | - <div class="group-title" :key="index + 'title'">{{ data.title }}</div> | |
| 31 | - <el-row class="group-content" :key="index + 'list'" :gutter="15"> | |
| 32 | - <template v-for="(item, index) in data.list"> | |
| 33 | - <el-col v-if="componentVisible(item.visible)" v-show="componentShow(item.show)" :key="index + 'data'" :span="!item.span ? 24 : item.span"> | |
| 34 | - <el-form-item :label="item.label" :label-width="item.label ? undefined : item.labelWidth || '0px'" :prop="item.key" :rules="item.rules"> | |
| 35 | - <component @input="(e) => handleComponentInput(e, item)" :is="item.type" @change="(e) => handleComponentChange(e, item)" v-on="handleComponentOn(item)" :style="componentStyle(item.style)" v-model="model[item.key]" v-bind="componentProps(item)"></component> | |
| 36 | - </el-form-item> | |
| 37 | - </el-col> | |
| 38 | - </template> | |
| 39 | - </el-row> | |
| 40 | - </template> | |
| 41 | - </template> | |
| 42 | - </template> | |
| 43 | - <template v-else> | |
| 44 | - <el-row :gutter="15"> | |
| 45 | - <template v-for="(item, index) in list"> | |
| 46 | - <el-col v-if="componentVisible(item.visible)" v-show="componentShow(item.show)" :key="index" :span="!item.span ? 24 : item.span"> | |
| 47 | - <el-form-item :label="item.label" :label-width="item.label ? undefined : item.labelWidth || '0px'" :prop="item.key" :rules="item.rules"> | |
| 48 | - <component @input="(e) => handleComponentInput(e, item)" :is="item.type" @change="(e) => handleComponentChange(e, item)" v-on="handleComponentOn(item)" :style="componentStyle(item.style)" v-model="model[item.key]" v-bind="componentProps(item)"></component> | |
| 49 | - </el-form-item> | |
| 50 | - </el-col> | |
| 51 | - </template> | |
| 52 | - </el-row> | |
| 53 | - </template> | |
| 54 | - <!-- 使用slot,不用slot时可定义对齐位置 --> | |
| 55 | - <div style="text-align: right"> | |
| 56 | - <el-button type="primary" size="small" :loading="submitLoading" @click="handleSubmit">确定</el-button> | |
| 57 | - <el-button plain size="small" @click="handleCancel" style="margin-left: 8px">取消</el-button> | |
| 58 | - </div> | |
| 59 | - </el-form> | |
| 60 | -</template> | |
| 61 | - | |
| 62 | -<script> | |
| 63 | -export default { // ------------------------------------ 解决外部的v-model绑定值失效问题 | |
| 64 | - name: 'Cform', | |
| 65 | - props: { | |
| 66 | - // 用于实例化本组件绑定v-model的值 | |
| 67 | - value: { | |
| 68 | - type: Object, | |
| 69 | - default: () => { | |
| 70 | - return {}; | |
| 71 | - } | |
| 72 | - }, | |
| 73 | - // 配置列表 --------------------------------------------可换成对象,传list的同时传其它参数?是否跟formProps重复??? | |
| 74 | - list: { | |
| 75 | - type: Array, | |
| 76 | - required: true | |
| 77 | - }, | |
| 78 | - // 提交加载状态 | |
| 79 | - submitLoading: Boolean, // --------------------------------- isLoading 或者loading,考虑骨架屏? | |
| 80 | - // 表单模式,一般结合外部模态框判断新增或修改使用 ------------------------------尽量去掉mode,在外部隐藏时销毁组件,避免历史值遗留问题 | |
| 81 | - mode: String, | |
| 82 | - // 标签宽度 ------------------------------- form的props可以用单独的字段如formProps表示,动态传入,使用v-bind绑定 | |
| 83 | - labelWidth: { | |
| 84 | - type: String, | |
| 85 | - default: '90px' | |
| 86 | - } | |
| 87 | - }, | |
| 88 | - data() { | |
| 89 | - return { | |
| 90 | - // 编辑器表单模型 | |
| 91 | - model: {} | |
| 92 | - }; | |
| 93 | - }, | |
| 94 | - watch: { | |
| 95 | - value: function(val) { | |
| 96 | - if (val) { | |
| 97 | - Object.keys(this.model).forEach(key => { | |
| 98 | - this.model[key] = val[key]; | |
| 99 | - }); | |
| 100 | - } | |
| 101 | - }, | |
| 102 | - // 配置列表又改动时初始化表单模型 | |
| 103 | - list: function(value) { | |
| 104 | - this.initModel(value); | |
| 105 | - const obj = {}; | |
| 106 | - this.list.forEach(data => { | |
| 107 | - if (data.group) { | |
| 108 | - obj[data.group] = true; | |
| 109 | - } | |
| 110 | - }); | |
| 111 | - } | |
| 112 | - }, | |
| 113 | - computed: { | |
| 114 | - groupList() { | |
| 115 | - const obj = {}; | |
| 116 | - this.list.forEach(data => { | |
| 117 | - if (data.group) { | |
| 118 | - if (!obj[data.group]) { | |
| 119 | - obj[data.group] = []; | |
| 120 | - } | |
| 121 | - obj[data.group].push(data); | |
| 122 | - } | |
| 123 | - }); | |
| 124 | - return { | |
| 125 | - group: Object.keys(obj).length > 0, | |
| 126 | - data: Object.keys(obj).map(key => { | |
| 127 | - return { title: key, list: obj[key] }; | |
| 128 | - }) | |
| 129 | - }; | |
| 130 | - } | |
| 131 | - }, | |
| 132 | - created() { | |
| 133 | - // 初始化表单模型 | |
| 134 | - this.initModel(this.list); | |
| 135 | - }, | |
| 136 | - methods: { | |
| 137 | - handleComponentInput(e, item) { | |
| 138 | - if (item.oninput) { | |
| 139 | - item.oninput(e, this.model, this.mode); | |
| 140 | - } | |
| 141 | - this.emitModel(); | |
| 142 | - }, | |
| 143 | - handleComponentChange(e, item) { | |
| 144 | - if (item.onchange) { | |
| 145 | - item.onchange(e, this.model, this.mode); | |
| 146 | - } | |
| 147 | - }, | |
| 148 | - handleComponentOn(item) { | |
| 149 | - if (item.on) { | |
| 150 | - if (typeof item.on === 'function') { | |
| 151 | - return item.on(this.model, this.mode); | |
| 152 | - } else { | |
| 153 | - return item.on | |
| 154 | - } | |
| 155 | - } else { | |
| 156 | - return undefined | |
| 157 | - } | |
| 158 | - }, | |
| 159 | - // 向上推送表单值到实例化的组件的v-model中 | |
| 160 | - emitModel() { | |
| 161 | - const result = {}; | |
| 162 | - Object.keys(this.model).forEach(key => { | |
| 163 | - if (this.componentIsVisible(key)) { | |
| 164 | - let value = this.model[key]; | |
| 165 | - if (this.model[key] === null) { | |
| 166 | - value = undefined; | |
| 167 | - } | |
| 168 | - result[key] = value; | |
| 169 | - } | |
| 170 | - }); | |
| 171 | - this.$emit("input", result); | |
| 172 | - }, | |
| 173 | - // 初始化表单模型 | |
| 174 | - initModel(list) { | |
| 175 | - const model = {}; | |
| 176 | - list.forEach(item => { | |
| 177 | - model[item.key] = item.default; | |
| 178 | - }); | |
| 179 | - this.model = model; | |
| 180 | - this.emitModel(); | |
| 181 | - }, | |
| 182 | - // 设置表单模型值 | |
| 183 | - setValue(value) { | |
| 184 | - this.reset(); | |
| 185 | - Object.keys(value).forEach(key => { | |
| 186 | - this.model[key] = value[key]; | |
| 187 | - }); | |
| 188 | - this.emitModel(); | |
| 189 | - }, | |
| 190 | - // 判断名称为key的组件v-if是否为true | |
| 191 | - componentIsVisible(key) { | |
| 192 | - let visible = true; | |
| 193 | - this.list.forEach((item) => { | |
| 194 | - if (item.key === key) { | |
| 195 | - if (typeof item.visible === 'function') { | |
| 196 | - visible = item.visible(this.model, this.mode); | |
| 197 | - } else { | |
| 198 | - visible = item.visible === undefined ? true : item.visible; | |
| 199 | - } | |
| 200 | - } | |
| 201 | - }); | |
| 202 | - return visible; | |
| 203 | - }, | |
| 204 | - // 判断组件v-if状态 | |
| 205 | - componentVisible(visible = true) { | |
| 206 | - let componentVisible = visible; | |
| 207 | - if (typeof visible === 'function') { | |
| 208 | - componentVisible = visible(this.model, this.mode); | |
| 209 | - } | |
| 210 | - return componentVisible; | |
| 211 | - }, | |
| 212 | - // 判断组件v-show状态 | |
| 213 | - componentShow(show = true) { | |
| 214 | - let componentShow = show; | |
| 215 | - if (typeof show === 'function') { | |
| 216 | - componentShow = show(this.model, this.mode); | |
| 217 | - } | |
| 218 | - return componentShow; | |
| 219 | - }, | |
| 220 | - // 判断组件参数 | |
| 221 | - componentProps(item) { | |
| 222 | - const { props = {}, propsEditor = {} } = item; | |
| 223 | - let connectedProps = { ...props, ...propsEditor }; | |
| 224 | - Object.keys(connectedProps).forEach(key => { | |
| 225 | - if (typeof connectedProps[key] === 'function') { | |
| 226 | - connectedProps[key] = connectedProps[key](this.model, this.mode); | |
| 227 | - } | |
| 228 | - }); | |
| 229 | - return connectedProps; | |
| 230 | - }, | |
| 231 | - // 判断组件样式 | |
| 232 | - componentStyle(style = {}) { | |
| 233 | - return { | |
| 234 | - width: "100%", | |
| 235 | - ...style | |
| 236 | - }; | |
| 237 | - }, | |
| 238 | - // 点击确定提交表单的操作 | |
| 239 | - handleSubmit(name) { | |
| 240 | - this.$refs.form.validate(valid => { | |
| 241 | - if (valid) { | |
| 242 | - const result = {}; | |
| 243 | - Object.keys(this.model).forEach(key => { | |
| 244 | - if (this.componentIsVisible(key)) { | |
| 245 | - let value = this.model[key]; | |
| 246 | - if (this.model[key] === null) { | |
| 247 | - value = undefined; | |
| 248 | - } | |
| 249 | - result[key] = value; | |
| 250 | - } | |
| 251 | - }); | |
| 252 | - this.$emit("submit", result); | |
| 253 | - } | |
| 254 | - }); | |
| 255 | - }, | |
| 256 | - // 重置表单 | |
| 257 | - reset() { | |
| 258 | - Object.keys(this.model).forEach(key => { | |
| 259 | - this.model[key] = (this.list.find(item => item.key === key) || {}).default; | |
| 260 | - }); | |
| 261 | - this.$nextTick(() => { | |
| 262 | - this.$refs.form.clearValidate(); | |
| 263 | - }); | |
| 264 | - }, | |
| 265 | - // 点击取消的操作 | |
| 266 | - handleCancel() { | |
| 267 | - this.$emit("cancel"); | |
| 268 | - } | |
| 269 | - } | |
| 270 | -}; | |
| 271 | -</script> | |
| 272 | 0 | \ No newline at end of file |
| ... | ... | @@ -0,0 +1,271 @@ |
| 1 | +<style scoped> | |
| 2 | +.eagle-form { | |
| 3 | + padding: 0px; | |
| 4 | +} | |
| 5 | +.eagle-form__group-title { | |
| 6 | + font-weight: bold; | |
| 7 | + padding: 15px 5px; | |
| 8 | + border-bottom: 1px solid #d9d9d9; | |
| 9 | + margin-bottom: 30px; | |
| 10 | +} | |
| 11 | +.eagle-form__group-content { | |
| 12 | + margin: 15px 0px; | |
| 13 | +} | |
| 14 | +</style> | |
| 15 | + | |
| 16 | +<template> | |
| 17 | + <el-form class="eagle-form" ref="form" :model="model" v-bind="formProps"> | |
| 18 | + <el-row :gutter="15"> | |
| 19 | + <!-- 这里可以合为一个代码段判断 --> | |
| 20 | + <template v-for="(data, index) in listOption.dataList"> | |
| 21 | + <!-- 这里可以判断是否满足分组条件决定显示title,另外下面content的class也可以判断,div可以换满span的col代替 --> | |
| 22 | + <!-- 加上选项tips提示判断,类似avue --> | |
| 23 | + <template v-if="listOption.isGroup"> | |
| 24 | + <slot v-if="$scopedSlots[data.key] || $slots[data.key]" :name="data.key" v-bind="{...data}"></slot> | |
| 25 | + <el-col v-else class="eagle-form__group-title" :key="data.key" :span="24">{{ data.label }}</el-col> | |
| 26 | + </template> | |
| 27 | + <el-row :class="{ 'eagle-form__group-content': listOption.isGroup }" :key="'group-content-' + index" :gutter="15"> | |
| 28 | + <template v-for="(item, index) in data.list"> | |
| 29 | + <el-col v-if="bindItemVisible(item.visible)" v-show="bindItemShow(item.show)" :key="index + 'data'" :span="!item.span ? 24 : item.span"> | |
| 30 | + <el-form-item :label="item.label" :label-width="item.label ? undefined : item.labelWidth || '0px'" :prop="item.key" :rules="item.rules"> | |
| 31 | + <el-tooltip :disabled="!item.tip" v-bind="bindItemTip(item.tip)"> | |
| 32 | + <slot v-if="$scopedSlots[`item-${item.key}`] || $slots[`item-${item.key}`]" :name="`item-${item.key}`" :model="model" v-bind="item"></slot> | |
| 33 | + <component v-else :is="item.type" v-model="model[item.key]" v-bind="bindItemProps(item)" v-on="bindItemEvent(item)" :style="bindItemStyle(item.style)"></component> | |
| 34 | + </el-tooltip> | |
| 35 | + </el-form-item> | |
| 36 | + </el-col> | |
| 37 | + </template> | |
| 38 | + </el-row> | |
| 39 | + </template> | |
| 40 | + </el-row> | |
| 41 | + <!-- 使用slot,不用slot时可定义对齐位置 --> | |
| 42 | + <div style="text-align: right"> | |
| 43 | + <el-button type="primary" size="small" :loading="submitting" @click="handleSubmit">确定</el-button> | |
| 44 | + <el-button plain size="small" @click="handleCancel" style="margin-left: 8px">取消</el-button> | |
| 45 | + </div> | |
| 46 | + </el-form> | |
| 47 | +</template> | |
| 48 | + | |
| 49 | +<script> | |
| 50 | +export default { | |
| 51 | + name: 'Form', | |
| 52 | + props: { | |
| 53 | + // 用于实例化本组件绑定v-model的值 | |
| 54 | + value: { | |
| 55 | + type: Object, | |
| 56 | + default: () => { | |
| 57 | + return {}; | |
| 58 | + } | |
| 59 | + }, | |
| 60 | + // 配置列表 | |
| 61 | + list: { | |
| 62 | + type: Array, | |
| 63 | + required: true | |
| 64 | + }, | |
| 65 | + // 提交加载状态 | |
| 66 | + submitting: Boolean, | |
| 67 | + // 表单参数 | |
| 68 | + formProps: { | |
| 69 | + type: Object, | |
| 70 | + default() { | |
| 71 | + return { | |
| 72 | + size: 'small', | |
| 73 | + 'label-width': '70px' | |
| 74 | + } | |
| 75 | + } | |
| 76 | + }, | |
| 77 | + // 纯净提交 | |
| 78 | + submitPure: { | |
| 79 | + type: Boolean, | |
| 80 | + default: false | |
| 81 | + } | |
| 82 | + }, | |
| 83 | + data() { | |
| 84 | + return { | |
| 85 | + // 编辑器表单模型 | |
| 86 | + model: {} | |
| 87 | + }; | |
| 88 | + }, | |
| 89 | + watch: { | |
| 90 | + // 组件外部v-model值更新后同步刷新model | |
| 91 | + value(val) { | |
| 92 | + Object.keys(this.model).forEach(key => { | |
| 93 | + this.model[key] = val ? val[key] : undefined; | |
| 94 | + }); | |
| 95 | + }, | |
| 96 | + // 配置列表又改动时初始化表单模型 | |
| 97 | + list(value) { | |
| 98 | + this.initModel(value); | |
| 99 | + }, | |
| 100 | + model: { | |
| 101 | + handler(val) { | |
| 102 | + this.$emit("input", val); | |
| 103 | + }, | |
| 104 | + deep: true | |
| 105 | + } | |
| 106 | + }, | |
| 107 | + computed: { | |
| 108 | + // 配置列表键值对形式 | |
| 109 | + listKeySet() { | |
| 110 | + let result = {}; | |
| 111 | + this.list.forEach(item => { | |
| 112 | + result[item.key] = item; | |
| 113 | + }); | |
| 114 | + return result; | |
| 115 | + }, | |
| 116 | + // 配置列表解析为渲染配置项 | |
| 117 | + listOption() { | |
| 118 | + let groupSet = {}; | |
| 119 | + this.list.forEach(data => { | |
| 120 | + if (data.group) { | |
| 121 | + if (typeof data.group === 'object') { | |
| 122 | + if (!groupSet[`group-${data.group.key}`]) { | |
| 123 | + groupSet[`group-${data.group.key}`] = { | |
| 124 | + label: data.group.label, | |
| 125 | + list: [] | |
| 126 | + }; | |
| 127 | + } | |
| 128 | + groupSet[`group-${data.group.key}`].list.push(data); | |
| 129 | + } else if (typeof data.group === 'string') { | |
| 130 | + if (!groupSet[data.group]) { | |
| 131 | + groupSet[data.group] = { | |
| 132 | + label: data.group, | |
| 133 | + list: [] | |
| 134 | + }; | |
| 135 | + } | |
| 136 | + groupSet[data.group].list.push(data); | |
| 137 | + } | |
| 138 | + } else { | |
| 139 | + if (!groupSet['group-default']) { | |
| 140 | + groupSet['group-default'] = { | |
| 141 | + label: '基本信息', | |
| 142 | + list: [] | |
| 143 | + }; | |
| 144 | + } | |
| 145 | + groupSet['group-default'].list.push(data); | |
| 146 | + } | |
| 147 | + }); | |
| 148 | + const isGroup = Object.keys(groupSet).length > 1; | |
| 149 | + const dataList = Object.keys(groupSet).map(key => { | |
| 150 | + return { key, ...groupSet[key] }; | |
| 151 | + }) | |
| 152 | + return { isGroup, dataList }; | |
| 153 | + } | |
| 154 | + }, | |
| 155 | + created() { | |
| 156 | + // 初始化表单模型 | |
| 157 | + this.initModel(this.list); | |
| 158 | + }, | |
| 159 | + methods: { | |
| 160 | + // 绑定提示组件参数 | |
| 161 | + bindItemTip(tip) { | |
| 162 | + if (typeof tip === 'string') { | |
| 163 | + return { content: tip, effect: 'light' }; | |
| 164 | + } else if (typeof tip === 'object') { | |
| 165 | + return tip; | |
| 166 | + } else { | |
| 167 | + return {}; | |
| 168 | + } | |
| 169 | + }, | |
| 170 | + // 绑定组件事件 | |
| 171 | + bindItemEvent(item) { | |
| 172 | + if (item.on) { | |
| 173 | + if (typeof item.on === 'function') { | |
| 174 | + return item.on(this.model); | |
| 175 | + } else { | |
| 176 | + return item.on | |
| 177 | + } | |
| 178 | + } else { | |
| 179 | + return undefined | |
| 180 | + } | |
| 181 | + }, | |
| 182 | + // 初始化表单模型 | |
| 183 | + initModel(list) { | |
| 184 | + list.forEach(item => { | |
| 185 | + this.$set(this.model, item.key, item.default || undefined) | |
| 186 | + }); | |
| 187 | + }, | |
| 188 | + // 判断列表项是否存在 | |
| 189 | + isItemVisible(key) { | |
| 190 | + let visible = true; | |
| 191 | + const item = this.listKeySet[key] || {}; | |
| 192 | + if (typeof item.visible === 'function') { | |
| 193 | + visible = item.visible({ ...this.model }); // 返回model的复制结果,判断类属性禁止改变model,防止循环导致内存溢出 | |
| 194 | + } else { | |
| 195 | + visible = item.visible === undefined ? true : item.visible; // 没有定义visible时返回true,否则返回visible定义的值。【注意:不可写成“ !item.visible ”】 | |
| 196 | + } | |
| 197 | + return visible; | |
| 198 | + }, | |
| 199 | + // 绑定组件v-if状态 | |
| 200 | + bindItemVisible(visible = true) { | |
| 201 | + let result = visible; | |
| 202 | + if (typeof visible === 'function') { | |
| 203 | + result = visible(this.model); | |
| 204 | + } | |
| 205 | + return result; | |
| 206 | + }, | |
| 207 | + // 绑定组件v-show状态 | |
| 208 | + bindItemShow(show = true) { | |
| 209 | + let result = show; | |
| 210 | + if (typeof show === 'function') { | |
| 211 | + result = show(this.model); | |
| 212 | + } | |
| 213 | + return result; | |
| 214 | + }, | |
| 215 | + // 绑定组件参数 | |
| 216 | + bindItemProps(item) { | |
| 217 | + const { props = {} } = item; | |
| 218 | + let result = { ...props }; | |
| 219 | + Object.keys(result).forEach(key => { | |
| 220 | + if (typeof result[key] === 'function') { | |
| 221 | + result[key] = result[key](this.model); | |
| 222 | + } | |
| 223 | + }); | |
| 224 | + return result; | |
| 225 | + }, | |
| 226 | + // 绑定组件样式 | |
| 227 | + bindItemStyle(style = {}) { | |
| 228 | + return { | |
| 229 | + width: "100%", | |
| 230 | + ...style | |
| 231 | + }; | |
| 232 | + }, | |
| 233 | + // 点击确定提交表单的操作 | |
| 234 | + handleSubmit(name) { | |
| 235 | + this.$refs.form.validate(valid => { | |
| 236 | + if (valid) { | |
| 237 | + const result = this.submitPure ? this.getPureModel() : JSON.parse(JSON.stringify(this.model)); | |
| 238 | + this.$emit("submit", result); | |
| 239 | + } | |
| 240 | + }); | |
| 241 | + }, | |
| 242 | + // 重置表单 | |
| 243 | + reset() { | |
| 244 | + Object.keys(this.model).forEach(key => { | |
| 245 | + this.model[key] = this.listKeySet[key] ? this.listKeySet[key].default : undefined; | |
| 246 | + }); | |
| 247 | + this.$nextTick(() => { | |
| 248 | + this.$refs.form.clearValidate(); | |
| 249 | + }); | |
| 250 | + }, | |
| 251 | + // 获取以初始list为准的纯净model值 | |
| 252 | + getPureModel() { | |
| 253 | + const result = {}; | |
| 254 | + Object.keys(this.listKeySet).forEach(key => { | |
| 255 | + if (this.isItemVisible(key)) { | |
| 256 | + let value = this.model[key]; | |
| 257 | + if (this.model[key] === null) { | |
| 258 | + value = undefined; | |
| 259 | + } | |
| 260 | + result[key] = value; | |
| 261 | + } | |
| 262 | + }); | |
| 263 | + return result; | |
| 264 | + }, | |
| 265 | + // 点击取消的操作 | |
| 266 | + handleCancel() { | |
| 267 | + this.$emit("cancel"); | |
| 268 | + } | |
| 269 | + } | |
| 270 | +}; | |
| 271 | +</script> | |
| 0 | 272 | \ No newline at end of file | ... | ... |
packages/index.js
| ... | ... | @@ -3,7 +3,7 @@ import Confirm from './confirm' |
| 3 | 3 | import DistPicker from './dist-picker' |
| 4 | 4 | import Editor from './editor' |
| 5 | 5 | import FileUpload from './file-upload' |
| 6 | -import Cform from './cform' | |
| 6 | +import Form from './form' | |
| 7 | 7 | import ImageUpload from './Image-upload' |
| 8 | 8 | import ImageUploadMultiple from './Image-upload/multiple' |
| 9 | 9 | import ImageView from './image-view' |
| ... | ... | @@ -14,12 +14,12 @@ import SwitchButton from './switch-button' |
| 14 | 14 | import TreeSelect from './tree-select' |
| 15 | 15 | |
| 16 | 16 | const components = { |
| 17 | - Cform, | |
| 18 | 17 | Code, |
| 19 | 18 | Confirm, |
| 20 | 19 | DistPicker, |
| 21 | 20 | Editor, |
| 22 | 21 | FileUpload, |
| 22 | + Form, | |
| 23 | 23 | ImageUpload, |
| 24 | 24 | ImageUploadMultiple, |
| 25 | 25 | ImageView, |
| ... | ... | @@ -37,6 +37,7 @@ const install = function (Vue, opts = {}) { |
| 37 | 37 | const prefix = opts.name || 'eagle' |
| 38 | 38 | // 配置组件名称 |
| 39 | 39 | const name = prefix + component.name |
| 40 | + component.name = name | |
| 40 | 41 | // 给每个子组件配置install方法 |
| 41 | 42 | component.install = function (Vue) { |
| 42 | 43 | Vue.component(name, component) | ... | ... |