组件开发--自定义左选择右查看select选项框

90 阅读1分钟

需求

满足左侧点击,右侧查看,滚动条左右自行滑动

样式

image.png

<!--
 * @Author: SunnyYang
 * @Date: 2024-01-19 14:47:28
 * @LastEditors: SunnyYang
 * @LastEditTime: 2024-03-23 14:35:56
 * @Description: 
-->
<template>
  <el-select
    :model-value="defaultValue"
    :placeholder="placeholder"
    popper-class="flow-custom-select"
    :style="{ ...style, minWidth: 'none' }"
    :fit-input-width="true"
    clearable
    @clear="handleClear"
  >
    <div class="options-left">
      <p class="options-title">默认交易流程</p>
      <el-option v-for="item in optionList" :key="item[keyValue]" :label="item[keyName]" :value="item[keyValue]">
        <span class="option-label" @click.stop="() => handleClickOptions(item[keyValue])">{{ item[keyName] }}</span>
      </el-option>
    </div>

    <div class="options-right">
      <p class="options-title">流程步骤</p>

      <template v-if="selectedItem?.[childrenKey]?.length > 0">
        <div class="options-steps" v-for="(stems, index) in selectedItem[childrenKey]" :key="stems[childrenKeyValue]">
          <span v-if="childrenKeyIndex">{{ index + 1 }}.</span>
          <span class="name">{{ stems[childrenKeyName] }}</span>
          <span class="tips" v-if="stems[childrenKeyTips]">{{ stems[childrenKeyTips] }}</span>
        </div>
      </template>
    </div>
  </el-select>
</template>

<script setup name="CustomSelect">
import { ref, onMounted } from 'vue'

const props = defineProps({
  defaultValue: {
    type: String,
    default: '',
  },
  onSelect: {
    type: Function,
    default: () => {},
  },
  optionList: {
    type: Array,
    default: () => [
      // {
      //   dataCode: '1',
      //   dataValue: '1',
      //   children: [{ dataCode: 'children1', dataValue: 'children1' }],
      // },
    ],
  },
  keyName: {
    type: String,
    default: 'dataValue',
  },
  keyValue: {
    type: String,
    default: 'dataCode',
  },
  childrenKey: {
    type: String,
    default: 'children',
  },
  childrenKeyName: {
    type: String,
    default: 'dataValue',
  },
  childrenKeyValue: {
    type: String,
    default: 'dataCode',
  },
  childrenKeyTips: {
    type: String,
    default: 'dataTips',
  },
  childrenKeyIndex: {
    type: Boolean,
    default: false,
  },
  placeholder: {
    type: String,
    default: '请选择',
  },
  style: {
    type: Object,
    default: {
      width: '100%',
      minWidth: 'none',
    },
  },
})

const { keyName, keyValue, childrenKey, childrenKeyName, childrenKeyValue } = props
const selectedItem = ref({})

onMounted(() => {
  if (props.defaultValue) {
    selectedItem.value = props.optionList.find((val) => val[keyValue] === props.defaultValue)
  }
})
function handleClickOptions(value) {
  const option = props.optionList.find((val) => val[keyValue] === value)
  selectedItem.value = { ...option }
  props.onSelect(value, option)
}

function handleClear() {
  props.onSelect('')
}
</script>

<style lang="scss">
.flow-custom-select {
  .el-scrollbar__wrap {
    overflow: initial;
  }
  .el-select-dropdown__list {
    width: 100%;
    display: flex;
  }
  .options-left {
    width: 50%;
    border-right: 1px solid #ccc;
  }

  .options-right {
    width: 50%;
  }

  .options-left,
  .options-right {
    max-height: 274px;
    overflow: auto;
    position: relative;
  }

  .options-steps {
    color: var(--el-text-color-regular);
    padding: 4px 10px 2px 20px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;

    .tips {
      color: #666;
    }
  }
  .options-title {
    padding: 0 32px 0 20px;
    word-break: keep-all;
    color: #999;
  }

  .options-steps,
  .options-title {
    position: sticky;
    top: 0;
    left: 0;
    background: #fff;
    z-index: 99;
  }
  .option-label {
    line-height: 34px;
    display: block;
    width: 100%;
    height: 100%;
    text-overflow: ellipsis;
    overflow: hidden;
    word-break: break-all;
    white-space: nowrap;
  }
}
</style>