index.vue 4.25 KB
<template>
  <el-select :size="size" v-model="model" :disabled="disabled" :remote="remote" :remote-method="remote ? remoteMethod : undefined" :placeholder="placeholder || i18n('eagle.select.select') || '请选择'" clearable :filterable="filterable" :multiple="multiple" :value-key="format == 'text' ? undefined : valueKey" @change="handleChange" @focus="handleFocus" :loading="loading">
    <el-option v-for="item in option" :key="format == 'text' ? item[valueProps.value] : item[valueKey]" :label="item[valueProps.label]" :value="format == 'text' ? item[valueProps.value] : item"></el-option>
  </el-select>
</template>
<script>
export default {
  name: 'Select',
  props: {
    // 组件值
    value: [Object, String, Number, Boolean, Array],
    // 选择框禁用状态
    disabled: {
      type: Boolean,
      default: false
    },
    // 选择框提示
    placeholder: {
      type: String,
    },
    // 选择框大小
    size: String,
    // 是否可搜索
    filterable: {
      type: Boolean,
      default: false
    },
    // 远程搜索
    remote: {
      type: Boolean,
      default: false,
    },
    // 数据源
    dataSource: {
      type: [Promise, Function, Array],
      required: true,
    },
    // 数据唯一标识
    valueKey: {
      type: String,
      default: 'value'
    },
    // 数据格式
    valueProps: {
      type: Object,
      default: () => {
        return { value: 'value', label: 'label' };
      }
    },
    // 格式化值类型 text object
    format: {
      type: String,
      default: 'text'
    },
    // 是否每次打开下拉框刷新数据
    uptodate: {
      type: Boolean,
      default: false
    },
    // 是否动态数据源
    dynamicSource: {
      type: Boolean,
      default: false
    },
    // 是否为多选
    multiple: {
      type: Boolean,
      default: false
    },
  },
  data () {
    return {
      // 绑定值(由于选择框直接绑定model后Vue会报错,因此不使用value直接绑定而使用model代替)
      model: this.multiple ? [] : undefined,
      // 下拉框数据
      option: [],
      // 加载状态
      loading: false,
    };
  },
  watch: {
    value(val) {
      if (this.multiple && !val) {
        this.model = [];
      } else {
        this.model = val;
        if (this.remote) {
          if (this.format === 'text') {
            this.remoteMethod(val, this.valueProps.value);
          } else {
            this.remoteMethod(val ? val[this.valueProps.label] : val);
          }
        }
      }
    },
    dataSource(val) {
      if (this.dynamicSource) {
        if (this.remote) {
          if (this.format === 'text') {
            this.remoteMethod(this.value, this.valueProps.value);
          } else {
            this.remoteMethod((this.value || {})[this.valueProps.label]);
          }
        } else {
          this.queryData();
        }
      }
    }
  },
  mounted() {
    this.model = !this.multiple ? this.value : this.value || [];
    if (this.remote) {
      if (this.format === 'text') {
        this.remoteMethod(this.value, this.valueProps.value);
      } else {
        this.remoteMethod((this.value || {})[this.valueProps.label]);
      }
    } else {
      this.queryData();
    }
  },
  methods: {
    // 查询数据
    async queryData() {
      this.loading = true;
      if (this.dataSource instanceof Array) {
        this.option = this.dataSource;
      } else {
        this.option = await this.dataSource();
      }
      this.loading = false;
    },
    // 远程数据方法
    async remoteMethod(query, value) {
      this.loading = true;
      const { label = 'name' } = this.valueProps || {};
      this.option = await this.dataSource({ [value || label]: query });
      this.loading = false;
    },
    // 聚焦选择框
    handleFocus() {
      if (this.remote) {
        if (this.format === 'text') {
          this.remoteMethod(this.value, this.valueProps.value);
        } else {
          this.remoteMethod((this.value || {})[this.valueProps.label]);
        }
      } else {
        if (this.uptodate || this.dataSource instanceof Array) {
          this.queryData();
        }
      }
    },
    // 选择
    handleChange(value) {
      this.model = this.value;
      this.$emit('input', value);
      this.$emit('change', value);
    },
  }
};
</script>