序文
編集可能なテーブルとは何ですか? 簡単に言うと、テーブルに対してフォーム操作を行い、追加、削除、変更、クエリを実行することです。これは、一部のバックエンド管理システムで特に一般的です。
今日はvue2
+に基づいてelement-ui
フォームコンポーネントを設計します。(完全なコードは含まれていません。完全な関数を使用したい場合は、下部にあるリンクを参照してください)
設計を開始する
1. フォームコンポーネント
まず、テーブル内のフォーム要素をどのように実装するかを考えてみましょう。ユーザーがこれを使用するときは、ユーザーが指定された型を渡して、対応するフォーム コンポーネントと自動的に一致することを期待します。次に、すべての型を統合し、それぞれに型名を付ける必要があります。
element-ui
もちろん、既に実装されているプロパティとメソッドを最大限に保持するには、formEle
表示したいコンポーネント タイプを含むオブジェクトを受け取る必要があります。次をelement-ui
使用して、プロパティを元のプロパティ メソッドの一部$attrs
に直接バインドできます。 element-ui のフォームコンポーネント上。
このフォーム要素にコンポーネントという名前を付けformEle
、element-ui
実装されたプロパティとメソッドを可能な限り保持します。もちろん、クリア可能な属性をオンにしたり、プレースホルダーのデフォルト値を設定したりするなど、一般的に使用されるいくつかの属性のデフォルト値を変更することもできます。
以下はコードの一部です
<template>
<el-input
v-if="formType === 'input'"
v-model="localValue"
v-bind="$attrs"
v-on="$listeners"
:clearable="clearable"
:placeholder="placeholder"
>
<template v-for="(value, name) in $slots" #[name]>
<slot :name="name"> </slot>
</template>
</el-input>
<el-input-number
v-else-if="formType === 'inputNumber'"
v-model="localValue"
v-bind="$attrs"
v-on="$listeners"
:placeholder="placeholder"
>
<template v-for="(value, name) in $slots" #[name]>
<slot :name="name"> </slot>
</template>
</el-input-number>
<el-select
v-else-if="formType === 'select'"
v-model="localValue"
v-bind="$attrs"
v-on="$listeners"
:clearable="clearable"
:placeholder="placeholder"
>
<el-option
v-for="item in options"
v-bind="item"
:key="item.value"
></el-option>
</el-select>
<el-date-picker
v-else-if="formType === 'datePicker'"
v-model="localValue"
v-bind="$attrs"
v-on="$listeners"
:placeholder="placeholder"
:endPlaceholder="endPlaceholder"
:startPlaceholder="startPlaceholder"
>
</el-date-picker>
<el-time-select
v-else-if="formType === 'timeSelect'"
v-model="localValue"
v-bind="$attrs"
v-on="$listeners"
:placeholder="placeholder"
>
</el-time-select>
<el-time-picker
v-else-if="formType === 'timePicker'"
v-model="localValue"
v-bind="$attrs"
v-on="$listeners"
:placeholder="placeholder"
:endPlaceholder="endPlaceholder"
:startPlaceholder="startPlaceholder"
>
</el-time-picker>
<el-switch
v-else-if="formType === 'switch'"
v-model="localValue"
v-bind="$attrs"
:placeholder="placeholder"
>
</el-switch>
<el-cascader
v-else-if="formType === 'cascader'"
v-model="localValue"
:options="options"
ref="cascader"
v-bind="$attrs"
v-on="$listeners"
:placeholder="placeholder"
></el-cascader>
</template>
<script>
export default {
name: 'ClFormEle',
props: {
// 表单类型
formType: {
type: String,
default: 'input'
},
modelValue: null,
options: {
type: Array,
default: () => []
}
},
model: {
prop: 'modelValue',
event: 'editModelValue'
},
computed: {
localValue: {
get() {
return this.modelValue
},
set(val) {
this.$emit('editModelValue', val)
}
},
clearable() {
return this.$attrs.clearable === false ? false : true
},
placeholder() {
let text = '请选择'
if (this.formType === 'input') {
text = '请输入'
}
return this.$attrs.placeholder || text + (this.$attrs.label || '')
},
rangeSeparator() {
return this.$attrs.rangeSeparator || '至'
},
startPlaceholder() {
if (this.formType === 'datePicker') {
return this.$attrs.startPlaceholder || '开始日期'
} else {
return this.$attrs.startPlaceholder || '开始时间'
}
},
endPlaceholder() {
if (this.formType === 'datePicker') {
return this.$attrs.startPlaceholder || '结束日期'
} else {
return this.$attrs.startPlaceholder || '结束时间'
}
}
},
methods: {
// 获取级联组件的回显值
getCasLabelcader() {
this.$nextTick(() => {
return this.$refs.cascader?.inputValue
})
}
}
}
</script>
<style lang="less" scoped>
.el-input {
width: 100%;
height: 30px;
}
.el-select {
width: 100%;
}
.el-date-editor {
width: 100%;
}
</style>
element-ui
コンポーネントのスロット位置も予約する必要があることに注意してください。
2. テーブルのコンポーネントを考慮する
まず、フォームコンポーネントの検証機能などを利用する可能性があることを考慮し、el-form
テーブルコンポーネントを最外層でラップする必要があります。
2 つ目は、フォーム コンポーネント上のモデルのバインディング値の選択です。最終的にバインドするデータは配列形式でなければならないことが予想されます。なぜなら、テーブルにはデータが 1 つだけ存在するわけではないからです。ただし、配列をフォームのモデル属性にバインドすることはできないため、配列を配列オブジェクトの形式にカプセル化できます。
<!-- modelValueCom 为表格数据 -->
<el-form ref="formRef" :model="{ formData: modelValueCom }">
次に列データを処理します。列のデータも配列構造である必要があり、各列は 2 つのセクションに分割され、1 つはel-table-column
テーブルで使用される属性値、もう 1 つは内部フォーム コンテンツの属性値です。区別しやすくするために、いくつかのデータ形式を使用します。
[
{
prop: 'name',
label: '姓名',
minWidth: '200px',
formEle: {
formType: 'input'
}
}
]
上記の formEle オブジェクトは、将来フォーム コンポーネントで使用する必要がある属性値ですが、他の属性は直接それに適用されますel-table-column
。
<el-table-column
v-for="columItem in columList"
:key="columItem.prop"
v-bind="getColumnAttr(columItem)"
>
getColumnAttr メソッドの機能は、formEle 属性を削除することです。
次に、フォームコンポーネントの使用があります。フォーム検証メソッドが必要であるため、el-form-item
フォーム コンポーネントをラップするコンポーネントが必要であり、コンポーネントの最も重要なprop
プロパティは上記の列データから直接取得できます。データは配列であるため、添字を使用する必要があることに注意してください。データの特定の部分については、label
それを表示するためのテーブル ヘッダーがすでにあるため、属性を直接省略できます。
<el-form-item
v-if="row.isEdit"
:prop="'formData.' + $index + '.' + columItem.prop"
:rules="columItem.formEle?.rules"
>
テーブル ヘッダーについて言えば、必須チェック インジケーターを追加することを考える必要があるかもしれません。formEle に showRequiredIcon 属性を追加して、必須チェックを表示する必要があるかどうかを判断します。
<el-table-column
v-for="columItem in columList"
:key="columItem.prop"
v-bind="getColumnAttr(columItem)"
>
<template #default="{ row, $index }">
<el-form-item
v-if="row.isEdit"
:prop="'formData.' + $index + '.' + columItem.prop"
:rules="columItem.formEle?.rules"
>
<ClFormEle
v-model="row[columItem.prop]"
v-bind="columItem.formEle"
v-on="eventMap[columItem.prop]"
:label="columItem.label"
></ClFormEle>
</el-form-item>
<!-- getLabel方法用于回显,解析一些下拉,级联,时间等 -->
<span v-else>{
{
getLabel(
getFormType(columItem),
columItem,
row[columItem.prop],
$index
)
}}</span>
</template>
<template #header>
<span v-if="columItem.formEle?.showRequiredIcon" class="required_icon"
>*</span
>
{
{ columItem.label }}
</template>
</el-table-column>
最後に、行データの変更、保存、削除などを行うための操作ボタンの列も必要です。変更保存とは、テーブルデータのisEdit属性を変更してフォーム要素とスパン表示を切り替えることを指します。
<el-table-column v-bind="btnColCpd">
<template #default="{ row, $index: index, column }">
<slot name="endColumn" :data="{ row, index, column }">
<el-button
v-if="!row.isEdit"
type="text"
icon="el-icon-edit"
@click.native.stop="rowEdit(index)"
>修改</el-button
>
<el-button
v-else
type="text"
icon="el-icon-check"
@click.native.stop="saveRow(index)"
>保存</el-button
>
<el-popconfirm
v-if="isDelBtnTip"
:title="delBtnTip"
@confirm="delRow(index)"
>
<el-button
type="text"
icon="el-icon-delete"
class="del_btn_text"
slot="reference"
>删除</el-button
>
</el-popconfirm>
<el-button
v-else
type="text"
icon="el-icon-delete"
class="del_btn_text"
slot="reference"
@click.native.stop="delRow(index)"
>删除</el-button
>
</slot>
</template>
</el-table-column>
btnColCpd は最後の列に関するプロパティ設定オブジェクトで、element-ui の el-table-column コンポーネントのプロパティを使用して最後の列を制御できます。
この時点で、基本的には単純なフォームコンポーネント構造が実装されました。
もちろん、上記の設計には、フォーム コンポーネントのメソッドをバインドする方法、各フォーム コンポーネント スロットを破棄する方法、行を離れるときにフォーム検証をトリガーできるかどうかなど、まだ多くの欠陥があります。 formEle にそれが含まれていない場合の対処方法など。完全なフォームコンポーネントを実装したい場合は、これらを考慮する必要があります。比較的完全なフォーム コンポーネントをカプセル化しました。これはTableFormで確認できます。