# ByCommonSelector 通用选择器组件

一个基于业务场景的通用选择器组件,支持多种选择模式和多样的交互效果。

注意:该组件通常在ByPageSearch组件中使用(可以单独使用),为了使选择器有一定间隙,务必给ByPageSearch中的formConfig.itemStyle设置间距:padding: '0px 20px 2px 0px'。

# 基础用法

# 下拉选择器

<template>
  <ByCommonSelector
    v-model="selectedValue"
    :options="options"
    type="select"
    placeholder="请选择用户"
    @change="handleChange"
  />
</template>

<script>
import ByCommonSelector from '@/components/common-selector/ByCommonSelector.vue'

export default {
  components: {
    ByCommonSelector
  },
  data() {
    return {
      selectedValue: '',
      options: [
        { id: 1, name: '何其灿', initial: 'H', status: 1 },
        { id: 2, name: '张三', initial: 'Z', status: 1 },
        { id: 3, name: '李四', initial: 'L', status: 1 },
        { id: 4, name: '王五', initial: 'W', status: 0 },
        { id: 5, name: '赵六', initial: 'Z', status: 1 },
        { id: 6, name: '孙七', initial: 'S', status: 1 },
        { id: 7, name: '周八', initial: 'Z', status: 1 },
        { id: 8, name: '吴九', initial: 'W', status: 1 },
        { id: 9, name: '郑十', initial: 'Z', status: 1 }
      ]
    }
  },
  methods: {
    handleChange(value) {
      console.log('选中值:', value)
    }
  }
}
</script>

# 异步加载数据

<template>
  <ByCommonSelector
    v-model="selectedValue"
    :loadOptions="fetchUserList"
    type="select"
    placeholder="请选择用户"
    @change="handleChange"
  />
</template>

<script>
import ByCommonSelector from '@/components/common-selector/ByCommonSelector.vue'

export default {
  components: {
    ByCommonSelector
  },
  data() {
    return {
      selectedValue: ''
    }
  },
  methods: {
    // 异步加载数据函数,返回Promise
    fetchUserList() {
      return new Promise(resolve => {
        // 模拟API请求
        setTimeout(() => {
          resolve([
            { id: 1, name: '何其灿', initial: 'H', status: 1 },
            { id: 2, name: '张三', initial: 'Z', status: 1 },
            { id: 3, name: '李四', initial: 'L', status: 1 },
            { id: 4, name: '王五', initial: 'W', status: 0 },
            { id: 5, name: '赵六', initial: 'Z', status: 1 },
            { id: 6, name: '孙七', initial: 'S', status: 1 },
            { id: 7, name: '周八', initial: 'Z', status: 1 },
            { id: 8, name: '吴九', initial: 'W', status: 1 },
            { id: 9, name: '郑十', initial: 'Z', status: 1 }
          ])
        }, 1000)
      })
    },
    handleChange(value) {
      console.log('选中值:', value)
    }
  }
}
</script>

# 展开式选择器

<template>
  <ByCommonSelector
    v-model="selectedValue"
    :options="options"
    type="checkbox"
    :multiple="true"
    placeholder="请选择多个用户"
    @change="handleChange"
  />
</template>

# Props 参数

参数 说明 类型 默认值 必填
value 绑定值 String/Number/Array -
options 选项数据 Array []
loadOptions 异步加载数据的函数 Function null
multiple 是否多选 Boolean false
type 选择器类型 String 'select'
placeholder 占位符文本 String '请选择'(enhancedSelect 类型默认为 '请输入用户名,手机号搜索')
size 组件尺寸 String 'default'
showSearchBar 是否显示搜索栏(A~Z+搜索框) Boolean false
pagination 是否启用分页 Boolean false
pageSize 每页显示数量 Number 50
needShowLoading 非select模式下是否显示加载状态 Boolean false
forceNoExpand 是否强制不展开 Boolean false
hiddenAllOptions 是否隐藏"全部"选项 Boolean false
showSuffixInput 是否显示后置输入框 Boolean false
suffixInputPlaceholder 后置输入框占位符 String '请输入'
suffixInputValue 后置输入框的值 String ''
suffixInputUnit 后置输入框的单位 String ''
suffixInputOptions 后置输入框的配置选项 Object {}
showSuffixBatchInput 是否显示后置批量输入按钮 Boolean false
suffixBatchInputPopoverTitle 后置批量输入弹窗的标题 String '批量输入'
suffixBatchInputPopoverWidth 后置批量输入弹窗宽度 String/Number '300'
enhancedAllOptions 增强下拉:所有选项数据(用于默认值回显与对象映射) Array [] 建议
enhancedTitleKey 增强下拉:标题字段名 String 'name'
enhancedDescriptionKey 增强下拉:描述字段名 String 'mobile'
enhancedDisabledKey 增强下拉:禁用标识字段名(0 置灰) String 'status'
enhancedDescriptionDisplay 增强下拉:是否显示描述 Boolean true
enhancedCollapseTags 增强下拉:多选是否折叠标签 Boolean false
enhancedDisabledCanSelect 增强下拉:禁用项是否可选 Boolean false

# type 可选值

  • select: 下拉选择器
  • enhancedSelect: 增强下拉选择器(支持远程搜索、对象回传、默认值智能回显)
  • checkbox: 展开式选择器(无边框样式)
  • border: 带边框的展开式选择器

# size 可选值

  • mini: 迷你尺寸
  • small: 小尺寸
  • medium: 中等尺寸
  • default: 默认尺寸

# 选项数据格式

const options = [
  {
    id: 1, // 选项值(必填)
    name: '张三', // 显示文本(必填)
    initial: 'Z', // 首字母,用于快速筛选(可选,如果未提供会自动根据name生成)
    status: 1 // 状态,0表示禁用/离职等(可选)
  }
]

# Events 事件

事件名 说明 回调参数
change 选中值发生变化时触发 普通类型:(value: String/Number/Array);enhancedSelect:(obj: Object 或 Array<Object>)
input 绑定值发生变化时触发 (value: String/Number/Array)
suffix-input-change 后置输入框值变化时触发 (value: String)
suffix-batch-input 批量输入确定时触发 (value: String)
search enhancedSelect 远程搜索触发 (query: String)

# Slots 插槽

插槽名 说明
suffixSlot 后置插槽,在选择器和后置输入框后添加内容

# 使用示例

# 1. 基础单选

<ByCommonSelector v-model="selectedUser" :options="userList" type="select" placeholder="请选择用户" />

# 2. 多选下拉

<ByCommonSelector
  v-model="selectedUsers"
  :options="userList"
  type="select"
  :multiple="true"
  placeholder="请选择多个用户"
/>

# 3. 异步加载数据

<ByCommonSelector v-model="selectedUser" :loadOptions="fetchUserOptions" type="select" placeholder="请选择用户" />
methods: {
  fetchUserOptions() {
    return this.$api.getUserList().then(response => {
      return response.data.map(user => ({
        id: user.id,
        name: user.name,
        initial: user.pinyin.charAt(0).toUpperCase(),
        status: user.status
      }))
    })
  }
}

# 4. 展开式单选

<ByCommonSelector v-model="selectedUser" :options="userList" type="checkbox" placeholder="请选择用户" />

# 5. 展开式多选

<ByCommonSelector
  v-model="selectedUsers"
  :options="userList"
  type="checkbox"
  :multiple="true"
  placeholder="请选择多个用户"
/>

# 6. 带边框样式

<ByCommonSelector v-model="selectedUsers" :options="userList" type="border" :multiple="true" placeholder="请选择用户" />

# 7. 禁用搜索

<ByCommonSelector
  v-model="selectedUser"
  :options="userList"
  type="checkbox"
  :showSearchBar="false"
  placeholder="请选择用户"
/>

# 8. 带后置输入框

<ByCommonSelector
  v-model="selectedUser"
  :options="userList"
  type="checkbox"
  :showSuffixInput="true"
  suffixInputPlaceholder="请输入备注"
  suffixInputUnit=""
  v-model:suffixInputValue="remarkValue"
  @suffix-input-change="handleRemarkChange"
/>
data() {
  return {
    selectedUser: '',
    remarkValue: '',
    userList: [
      // ...用户列表
    ]
  }
},
methods: {
  handleRemarkChange(value) {
    console.log('备注值变化:', value)
  }
}

# 9. 使用后置插槽

<ByCommonSelector v-model="selectedUser" :options="userList" type="checkbox">
  <template #suffixSlot>
    <el-button size="small" type="primary" style="margin-left: 5px">确定</el-button>
  </template>
</ByCommonSelector>

# 10. 增强下拉选择器(enhancedSelect)

增强下拉用于本地搜索(模拟远程搜索交互),支持标题+描述展示,默认值智能回显,变更时向外抛出对象(或对象数组)。

单选示例:

<template>
  <ByCommonSelector
    v-model="selectedUserId"
    :options="enhancedSearchResults"
    :enhancedAllOptions="allUsers"
    type="enhancedSelect"
    enhancedTitleKey="name"
    enhancedDescriptionKey="mobile"
    :enhancedDescriptionDisplay="true"
    placeholder="请输入用户名,手机号搜索"
    @search="handleEnhancedSearch"
    @change="handleEnhancedChange"
  />
</template>

<script>
export default {
  data() {
    return {
      selectedUserId: '',
      enhancedSearchResults: [], // 搜索结果(用于下拉展示)
      allUsers: [] // 全量数据(用于默认值回显与对象映射)
    }
  },
  methods: {
    async handleEnhancedSearch(query) {
      // 根据 query 远程查询,并设置 enhancedSearchResults
      const { data } = await this.$http.get('/api/users/search', { params: { q: query } })
      this.enhancedSearchResults = data.list
      // 建议在首次加载或独立接口中填充 allUsers(全量或足量数据以支持默认值回显)
    },
    handleEnhancedChange(userObj) {
      // userObj 形如:{ id, name, mobile }
      console.log('选中对象:', userObj)
    }
  }
}
</script>

多选示例:

<ByCommonSelector
  v-model="selectedUserIds"
  :options="enhancedSearchResults"
  :enhancedAllOptions="allUsers"
  type="enhancedSelect"
  :multiple="true"
  :enhancedCollapseTags="true"
  enhancedTitleKey="name"
  enhancedDescriptionKey="mobile"
  @search="handleEnhancedSearch"
  @change="handleEnhancedChangeMultiple"
/>

注意:

  • enhancedSelect 下 change 事件返回对象(多选返回对象数组),input 仍然是原始值(id 或 id 数组)。
  • 为保证默认值正确回显,需提供 enhancedAllOptions(至少包含已选中的项)。
  • enhancedDisabledKey 指定置灰字段,配合 enhancedDisabledCanSelect 决定置灰项是否可选。
  • enhancedDescriptionDisplay=true 时,选项以“标题 描述”形式展示。

# 注意事项

  1. 数据格式: 确保传入的 options 数据包含 idname 字段
  2. 首字母筛选: 如果需要使用首字母快速筛选功能,请确保数据包含 initial 字段或启用 showSearchBar。如果未提供initial字段,组件会自动根据name生成:
    • 对于中文,会提取拼音首字母并转为大写
    • 对于非中文,直接取首字母并转为大写
  3. 状态显示: 如果需要显示选项状态(如离职状态),请确保数据包含 status 字段,0表示禁用/离职
  4. 大量数据: 当选项数量超过pageSize时,会自动启用分页功能(如果pagination设为true)
  5. 样式定制: 组件样式已提取到 @/style/common-selector.scss 文件中,可根据需要进行定制
  6. 选中按钮: 展开式选择器(checkbox/border类型)通过CSS隐藏选中按钮,只通过边框和背景色表示选中状态
  7. 智能展开按钮: 组件会根据选项的实际渲染宽度自动判断是否需要显示展开/收起按钮,当内容不超过一行时不会显示展开按钮
  8. 响应式设计: 当浏览器窗口大小变化或页面缩放时,组件会自动重新计算是否需要显示展开按钮
  9. 后置输入框: 后置输入框仅在选择器展开时显示,可用于输入额外信息,如备注、说明等
  10. 批量输入功能: 批量输入功能仅在显示后置输入框时生效,支持多种分隔符,自动处理输入内容并双向回显

# 新增特性

# 1. 智能展开/收起按钮

组件会根据选项的实际渲染宽度自动判断是否需要显示展开/收起按钮:

  • 当选项内容不超过一行时,不会显示展开按钮
  • 当选项内容超过一行时,会显示展开按钮
  • 当浏览器窗口大小变化或页面缩放时,会自动重新计算是否需要显示展开按钮
  • 当开启分页功能且数据量超过pageSize时,会强制显示展开按钮

# 2. 自动生成首字母

# 3. 可控的加载状态显示

通过 needShowLoading 属性可以控制非select模式下是否显示加载状态:

<ByCommonSelector v-model="selectedValue" :loadOptions="fetchUserList" type="checkbox" :needShowLoading="true" />

needShowLoading 设置为 true 时,在异步加载数据过程中会显示"加载中..."的状态提示。

# 4. 后置输入框

组件支持在选择器后添加输入框,用于输入额外信息:

<ByCommonSelector
  v-model="selectedUser"
  :options="userList"
  type="checkbox"
  :showSuffixInput="true"
  suffixInputPlaceholder="请输入备注"
  suffixInputUnit=""
  v-model:suffixInputValue="remarkValue"
  @suffix-input-change="handleRemarkChange"
>
  <template #suffixSlot>
    <el-button size="small" type="primary" style="margin-left: 5px">确定</el-button>
  </template>
</ByCommonSelector>

后置输入框特性:

  • 通过 showSuffixInput 控制是否显示
  • 通过 suffixInputPlaceholder 设置占位符文本
  • 通过 v-model:suffixInputValue 双向绑定输入框的值
  • 通过 @suffix-input-change 监听输入框值变化
  • 通过 suffixInputOptions 传递其他el-input支持的属性
  • 通过 suffixInputUnit 设置后置输入框的单位
  • 通过 suffixSlot 插槽添加自定义内容

# 5. 批量输入功能

组件支持批量输入功能,方便用户一次性输入多个值:

<ByCommonSelector
  v-model="selectedUser"
  :options="userList"
  type="checkbox"
  :showSuffixInput="true"
  :showSuffixBatchInput="true"
  suffixInputPlaceholder="请输入用户ID"
  suffixBatchInputPopoverTitle="批量输入用户ID"
  suffixBatchInputPopoverWidth="400"
  v-model:suffixInputValue="userIds"
  @suffix-batch-input="handleBatchInput"
/>

批量输入功能特性:

  • 通过 showSuffixBatchInput 控制是否显示批量输入按钮
  • 通过 suffixBatchInputPopoverTitle 设置弹窗标题
  • 通过 suffixBatchInputPopoverWidth 设置弹窗宽度
  • 支持多种分隔符:换行、逗号、分号、空格
  • 自动过滤空项和去除首尾空格
  • 双向回显:打开弹窗时会回显后置输入框中的内容
  • 确定后会将处理后的内容用逗号分隔显示到后置输入框
  • 通过 @suffix-batch-input 监听批量输入确定事件

# 完整示例

<template>
  <div class="selector-demo">
    <h3>用户选择器</h3>

    <!-- 单选下拉 -->
    <div class="demo-item">
      <label>单选用户:</label>
      <ByCommonSelector
        v-model="singleUser"
        :options="userOptions"
        type="select"
        placeholder="请选择用户"
        @change="onSingleChange"
      />
      <span>选中: {{ singleUser }}</span>
    </div>

    <!-- 多选展开 -->
    <div class="demo-item">
      <label>多选用户:</label>
      <ByCommonSelector
        v-model="multipleUsers"
        :options="userOptions"
        type="checkbox"
        :multiple="true"
        placeholder="请选择多个用户"
        @change="onMultipleChange"
      />
      <span>选中: {{ multipleUsers }}</span>
    </div>

    <!-- 带后置输入框 -->
    <div class="demo-item">
      <label>带备注选择:</label>
      <ByCommonSelector
        v-model="selectedWithRemark"
        :options="userOptions"
        type="checkbox"
        :showSuffixInput="true"
        suffixInputPlaceholder="请输入备注"
        suffixInputUnit=""
        v-model:suffixInputValue="remarkValue"
        @suffix-input-change="onRemarkChange"
      >
        <template #suffixSlot>
          <el-button size="small" type="text" style="margin-left: 5px">确认</el-button>
        </template>
      </ByCommonSelector>
      <span>选中: {{ selectedWithRemark }}, 备注: {{ remarkValue }}</span>
    </div>

    <!-- 批量输入功能 -->
    <div class="demo-item">
      <label>批量输入:</label>
      <ByCommonSelector
        v-model="selectedWithBatch"
        :options="userOptions"
        type="checkbox"
        :showSuffixInput="true"
        :showSuffixBatchInput="true"
        suffixInputPlaceholder="请输入用户ID"
        suffixBatchInputPopoverTitle="批量输入用户ID"
        suffixBatchInputPopoverWidth="400"
        v-model:suffixInputValue="batchUserIds"
        @suffix-batch-input="onBatchInput"
      />
      <span>选中: {{ selectedWithBatch }}, 用户ID: {{ batchUserIds }}</span>
    </div>
  </div>
</template>

<script>
import ByCommonSelector from '@/components/common-selector/ByCommonSelector.vue'

export default {
  name: 'SelectorDemo',
  components: {
    ByCommonSelector
  },
  data() {
    return {
      singleUser: '',
      multipleUsers: [],
      selectedWithRemark: '',
      remarkValue: '',
      selectedWithBatch: '',
      batchUserIds: '',
      userOptions: [
        { id: 1, name: '张三', initial: 'Z', status: 1 },
        { id: 2, name: '李四', initial: 'L', status: 1 },
        { id: 3, name: '王五', initial: 'W', status: 0 },
        { id: 4, name: '赵六', initial: 'Z', status: 1 },
        { id: 5, name: '钱七', initial: 'Q', status: 1 }
      ]
    }
  },
  methods: {
    onSingleChange(value) {
      console.log('单选变化:', value)
    },
    onMultipleChange(value) {
      console.log('多选变化:', value)
    },
    onRemarkChange(value) {
      console.log('备注变化:', value)
    },
    onBatchInput(value) {
      console.log('批量输入内容:', value)
      // 这里可以处理批量输入的内容,比如解析用户ID等
    }
  }
}
</script>

<style lang="scss" scoped>
.selector-demo {
  padding: 20px;

  .demo-item {
    margin-bottom: 20px;

    label {
      display: inline-block;
      width: 100px;
      font-weight: bold;
    }

    span {
      margin-left: 10px;
      color: #666;
    }
  }
}
</style>
最后更新时间: 8/9/2025, 3:46:46 PM