文章目录
1、w-form-select.vue 组件中每个属性的含义
好的,我们来详细解释 w-form-select.vue
组件中每个属性的含义,并用表格列出它们是否与后端字段直接相关:
属性解释表格:
属性名 | 类型 | 默认值 | 含义 | 与后端字段直接相关性 |
---|---|---|---|---|
label |
string |
'' |
表单项的标签文本,显示在输入框左侧。 | 否 |
prop |
string |
'' |
表单验证的关键 。 对应后端数据模型中的一个字段名。 主要用于 el-form 的表单验证。 |
是 |
labelWidth |
string |
'160px' |
标签的宽度。 | 否 |
labelAlign |
string |
'right' |
标签文本的对齐方式。 | 否 |
tip |
string |
'' |
鼠标悬停在标签上的提示文本。 | 否 |
operateType |
string |
'' |
操作类型,用于判断组件的显示状态(如 'add' , 'edit' , 'view' )。 |
否 |
inputWidth |
string |
'100%' |
控制内部 el-select 组件的宽度。 可以是像素值、百分比或其他有效 CSS 宽度值。 |
否 |
value |
any |
'' |
组件的值 。这个值通常直接对应后端字段的值。 使用 v-model 双向绑定此值。 |
是 |
multiple |
boolean |
false |
是否允许多选。如果为 true ,则 value 为数组;否则 value 为单个值。 |
否 |
list |
any[] |
[] |
下拉选择框的数据源。通常是一个对象数组,其中每个对象表示一个选项。 | 间接相关 |
optionLabel |
string |
'' |
指定 list 中哪个属性的值作为下拉选项的标签文本显示。 |
否 |
optionValue |
string |
'value' |
指定 list 中哪个属性的值作为下拉选项的值。 |
是 |
placeholder |
string |
'' |
下拉选择框的占位符文本。 | 否 |
inputEnd |
string |
'' |
在输入框后附加的文本或元素。 | 否 |
allowCreate |
boolean |
false |
是否允许用户创建新的选项。 | 否 |
defaultFirstOption |
boolean |
false |
是否在输入框有值的时候,默认选择第一个匹配的选项。 | 否 |
详细解释:
-
与后端字段直接相关:
prop
: 这个属性的值通常与后端数据模型的字段名称对应, 用于表单验证, 例如你在后端有一个userType
的字段,那么你可以设置prop="userType"
。prop
的值不是直接传递给后端,而是用来匹配 rules, 用于表单校验。value
: 组件的值,例如用户选择了普通用户
,value
通常是1
, 最终会和表单其他数据一起提交给后端。value
的值直接对应后端字段的值,例如,如果后端有一个userType
字段, 你的表单提交数据中也需要userType: 1
。v-model
直接绑定了value
。- 如果
:multiple="true"
:value
为[1, 3, 5]
等数组, 对应后端可能也会是这样的数组结构,例如"relatedIds":[1,3,5]
。 - 如果
:multiple="false"
:value
为1
, 对应后端字段值, 例如userType: 1
。
- 如果
optionValue
: 指定list
中哪个属性的值作为下拉选项的值传递给后端, 例如你的list
为[{id: 1, label: '普通用户'}]
, 那么optionValue="id"
表明,你选择了普通用户
后,id
为1
的值,会被作为value
提交给后端。
-
与后端字段间接相关:
list
: 虽然list
本身不会直接提交给后端,但它的数据通常来源于后端接口返回的数据。例如,你通常会从后端接口获取一个 用户类型列表,作为你的list
的数据来源。
-
与后端字段无直接关系:
- 其他属性,如
label
,labelWidth
,tip
,operateType
,inputWidth
,optionLabel
,placeholder
,inputEnd
,allowCreate
,defaultFirstOption
, 等, 主要用于控制前端 UI 的展示,与后端字段没有直接的对应关系。
- 其他属性,如
总结:
这个表格清晰地展示了 w-form-select
组件中每个属性的作用,以及它们与后端字段的关系。 请记住, prop
用作表单验证, value
是与后端字段值直接对应的, 而 optionValue
指定了传递给后端的值。 其他属性主要用于组件的 UI 展示和交互。
2、实例
html
<w-form-select v-model="form.relatedIds" label="关联识别点" label-width="120px" :operate-type="operateType"
:list="identifies" option-label="description" option-value="id" :multiple="true" input-width="100%"
@visible-change="handleVisibleChange"
/>
在这个例子中,v-model="form.relatedIds"
这个属性对应着 w-form-select
组件的 value
。
详细解释:
-
v-model
的作用:v-model
是 Vue.js 中用于双向数据绑定的语法糖。 它实际上是v-bind:value
和@input
(或者@change
, 如果是<select>
组件) 的简写形式。 -
v-model="form.relatedIds"
的含义:- 读取值: 组件初始化时,会读取
form.relatedIds
变量的值,并显示在w-form-select
组件中。 - 更新值: 当用户在
w-form-select
组件中选择了新的选项时,组件的值会自动更新到form.relatedIds
变量。 - 双向绑定: 实现了
w-form-select
组件的value
属性和form.relatedIds
变量之间的双向绑定。
- 读取值: 组件初始化时,会读取
-
w-form-select
的value
:-
在
w-form-select
组件的代码中,我们看到了v-model="val"
, 并且在value
发生变化的时候, 将其更新到val
变量。html@Watch('value') watchValue(v: any) { this.val = v }
并且
el-select
组件使用了v-model="val"
:html<el-select v-model="val" ... />
-
当
w-form-select
组件的值发生变化的时候,会触发@input
事件,并且传递组件的值, 最终触发的是w-form-select
组件的@input
事件:html@input="value => $emit('input', value)"
-
-
所以
v-model="form.relatedIds"
实际上是以下代码的简写:html<w-form-select :value="form.relatedIds" @input="value => form.relatedIds = value" label="关联识别点" label-width="120px" :operate-type="operateType" :list="identifies" option-label="description" option-value="id" :multiple="true" input-width="100%" @visible-change="handleVisibleChange" />
-
form.relatedIds
的值:- 由于
:multiple="true"
, 所以form.relatedIds
的值是一个数组, 包含了用户选择的多个id
值, 例如[1, 3, 5]
。 如果:multiple="false"
, 则是一个单独的值, 例如1
。
- 由于
-
后端关系:
form.relatedIds
最终会传递到后端, 对应后端数据模型的字段。
总结:
在你的代码示例中, w-form-select
组件的 value
属性的值被 v-model="form.relatedIds"
所控制。 form.relatedIds
变量存储了组件的当前值,并且实现了双向数据绑定。
因此, 在你这个例子中 v-model="form.relatedIds"
就是对应 w-form-select
组件的 value
属性。
3、源代码
html
<!-- src/components/DialogForm/func/w-form-select.vue -->
<template>
<div class="wrap">
<div class="box">
<el-form-item :label="label" :prop="prop" :label-width="labelWidth">
<div slot="label" :style="`text-align: ${labelAlign};`">
<span>{{ label }}
<el-tooltip class="item" effect="dark" :content="tip || label || placeholder" placement="bottom-start">
<i class="el-icon-warning-outline" />
</el-tooltip>
</span>
</div>
<span v-if="operateType === 'view'">
<template v-if="multiple">
{{ list && list.length && list.filter(o => val.includes(o[optionValue])).map(o => o[optionLabel]).join(',')
}}
</template>
<template v-else>
<!-- {{ getSelectLabel(val) }} -->
{{ list && list.length && list.find(o => val === o[optionValue]) && list.find(o => val ===
o[optionValue])[optionLabel] }}
</template>
</span>
<div v-else class="input-container">
<!-- 这里有一个 v-else -->
<el-select v-model="val" :multiple="multiple" filterable clearable :placeholder="placeholder || label || tip"
:allow-create="allowCreate" :default-first-option="defaultFirstOption"
:style="inputWidth ? `width: ${inputWidth};` : `width: 100%;`" @input="value => $emit('input', value)"
@change="value => $emit('change', value)"
@visible-change="value => $emit('visible-change', value)"
>
<el-option v-if="list.length" :label="` `" :value="` `" />
<el-option v-for="(item, i) in list" :key="'' + item[optionLabel] + item[optionValue] + i"
:label="item[optionLabel]" :value="item[optionValue]"
/>
</el-select>
</div>
<div class="append-slot">
<!-- 添加一个容器包裹插槽 -->
<slot name="append"></slot> <!-- 插槽用于放置图片 -->
</div>
<template v-if="inputEnd"> </template>
{{ inputEnd }}
</el-form-item>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue, Prop, Emit, Watch } from 'vue-property-decorator'
import { AppModule } from '@/store/modules/app'
import { UserModule } from '@/store/modules/user'
@Component({
name: 'w-form-input',
components: {}
})
export default class extends Vue {
@Prop({ default: '' })
public label!: string
@Prop({ default: '' })
public prop!: string
@Prop({ default: '160px' })
public labelWidth: string
@Prop({ default: 'right' })
public labelAlign: string
@Prop({ default: '' })
public tip?: string
@Prop({ default: '' })
public operateType!: string
@Prop({ default: false })
@Prop({ default: '100%' })
public inputWidth?: string
@Prop({ default: '' })
public value?: any
@Prop({ default: false })
public multiple: boolean
@Prop({ default: () => [] })
public list!: any
@Prop({ default: '' })
public optionLabel: string
@Prop({ default: 'value' })
public optionValue: string
@Prop({ default: '' })
public placeholder?: string
@Prop({ default: '' })
public inputEnd?: string
@Prop({ default: false })
public allowCreate?: boolean
@Prop({ default: false })
public defaultFirstOption?: boolean
@Watch('list')
watchList(v: any) {
this.selList = v
}
@Watch('value')
watchValue(v: any) {
this.val = v
}
private multipleFlag: boolean = false
private selList: any = this.list
private val: any = this.value
}
</script>
<style scoped lang="scss">
.wrap {
width: 100%;
.box {
width: 100%;
position: relative;
overflow: visible;
}
.input-container {
position: relative; /* 确保下拉框的弹出层基于此容器定位 */
display: inline-block; /* 让下拉框和图片在同一行 */
}
.append-slot {
position: absolute; /* 将图片绝对定位 */
left: 15%; /* 图片放置在下拉框右侧 */
top: 53%; /* 垂直居中 */
transform: translateY(-50%); /* 确保垂直居中 */
margin-left: 10px; /* 图片与下拉框的间距 */
z-index: 1; /* 确保图片在下拉框之上 */
}
/* 确保 el-select 的下拉菜单不受干扰 */
.el-select {
width: 200px; /* 设置默认宽度 */
position: relative; /* 确保下拉框的弹出层基于此容器定位 */
}
.el-select-dropdown {
z-index: 9999 !important; /* 确保下拉菜单在最上层 */
}
}
</style>