w-form-select.vue(自定义下拉框组件)

文章目录

  • [1、w-form-select.vue 组件中每个属性的含义](#1、w-form-select.vue 组件中每个属性的含义)
  • 2、实例
  • 3、源代码

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: 1v-model 直接绑定了 value
      • 如果 :multiple="true" value[1, 3, 5] 等数组, 对应后端可能也会是这样的数组结构,例如 "relatedIds":[1,3,5]
      • 如果 :multiple="false" value1, 对应后端字段值, 例如 userType: 1
    • optionValue: 指定 list 中哪个属性的值作为下拉选项的值传递给后端, 例如你的 list[{id: 1, label: '普通用户'}], 那么 optionValue="id" 表明,你选择了 普通用户 后, id1 的值,会被作为 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-selectvalue:

    • 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">&nbsp;&nbsp;&nbsp;&nbsp;</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>
相关推荐
yqcoder14 分钟前
Node.js 与 JavaScript 是什么关系
开发语言·javascript·node.js
贵州晓智信息科技1 小时前
Three.js实现动态水泡效果逐步解析GLSL着色器
开发语言·javascript·着色器
老K(郭云开)1 小时前
最新版Edge浏览器加载ActiveX控件技术——allWebPlugin中间件之awp_CreateActiveXObject接口用法
前端·javascript·chrome·中间件·edge
一点一木1 小时前
从零开始:使用 Brain.js 创建你的第一个神经网络(一)
前端·javascript·人工智能
小璇玑学前端1 小时前
微信小程序地图,定位,仿多多自提点
前端
我的div丢了肿么办1 小时前
vue3.5的更新保证你看的明明白白
前端·javascript·vue.js
愚z1 小时前
WorkboxWebpackPlugin 使用指南
前端
带多刺的玫瑰2 小时前
Leecode刷题C语言之统计打字方案数
javascript·数据结构·算法
m0_748248652 小时前
详细介绍Sd-WebUI提示词的语法规则
前端
南北极之间2 小时前
前端新手必看:10 大 UI 组件库全面解析,快速搭建高质量 Web 应用」 「从零开始:Vue 和 React 最受欢迎的 UI 组件库入门指南」 「超实用!PC 端和移动端 UI 组件库推荐与实战
前端·vue.js·ui·elementui·element·anti-design-vue·ui组件库