UNPKG

jobsys-mpower

Version:

Enhanced component based on Taro & NutUI

147 lines (129 loc) 4.17 kB
import { computed, defineComponent, ref, watch } from "vue" import PickerWrapper, { pickerSlots } from "./PickerWrapper.jsx" import { Button, Picker } from "vant" import { defaultFieldProps, defaultOptionsProps } from "../utils" import { useFetch } from "../../hooks" import { find, isArray, isFunction, isString } from "lodash-es" /** * MpSelect 下拉选择 * @version 1.0.0 */ export default defineComponent({ name: "MpSelect", props: { ...defaultOptionsProps, ...defaultFieldProps, modelValue: { type: [Array, String, Number], default: "" }, /** * 标题 */ title: { type: String, default: "" }, /** * 是否显示清除按钮 */ clearable: { type: Boolean, default: false }, }, emits: ["update:modelValue", "change"], setup(props, { emit, slots, expose }) { const defaultValue = isArray(props.modelValue) ? props.modelValue : [props.modelValue] const componentValue = ref(defaultValue) const options = ref([]) let columns = 1 //根据子项的数组数来确定 Picker 的列数,默认为1列 const pickerRef = ref() watch( () => props.modelValue, () => { componentValue.value = isArray(props.modelValue) ? props.modelValue : [props.modelValue] }, ) const displayText = computed(() => { let value = isArray(props.modelValue) ? props.modelValue : [props.modelValue] return value .map((value, index) => { if (columns === 1) { return find(options.value, { value })?.text } else { return find(options.value[index], { value })?.text } }) ?.join("/") }) const fetchData = () => new Promise((resolve) => { useFetch() .get(props.url) .then((items) => { if (props.afterFetched) { items = props.afterFetched(items) } resolve(items) }) }) const prepareOptions = async (options) => { options = isFunction(options) ? options() : options if (options && options.length) { columns = options.filter((option) => isArray(option)).length || 1 } else if (props.url) { options = await fetchData() } options = options.map((option) => { if (isArray(option)) { return option.map((op) => { return isString(op) ? { value: op, label: op, text: op } : { text: op.label, ...op } }) } return isString(option) ? { value: option, label: option, text: option } : { text: option.label, ...option } }) return options } prepareOptions(props.options).then((opts) => (options.value = opts)) watch( () => props.options, () => prepareOptions(props.options).then((opts) => (options.value = opts)), ) // @hack // 由于在 Picker 清除 model value 后再次打开 Picker 在不重新选择新选项的情况下无法选中之前的选项 // 所以这里手动重新赋一次值给 model value const onOpenWrapper = () => { if (columns === 1 && !componentValue.value?.[0]) { componentValue.value = [options.value[0].value] } } const onConfirm = ({ selectedValues }) => { const value = columns === 1 ? selectedValues[0] : selectedValues emit("change", value) emit("update:modelValue", value) pickerRef.value.close() } const onClear = () => { const value = columns === 1 ? null : [] emit("change", value) emit("update:modelValue", value) pickerRef.value.close() } expose({ displayText }) return () => ( <PickerWrapper ref={pickerRef} closeable={false} onOpen={onOpenWrapper} disabled={props.readonly || props.disabled}> {{ ...pickerSlots(slots, props), default: () => [ <Picker v-model={componentValue.value} columns={options.value} onConfirm={onConfirm} onCancel={() => pickerRef.value.close()} {...props.defaultProps} />, props.clearable ? ( <div class={"ex-field-popup__clear-btn"}> <Button block type={"primary"} plain={true} round={true} onClick={onClear}> 清除 </Button> </div> ) : null, ], }} </PickerWrapper> ) }, })