jobsys-mpower
Version:
Enhanced component based on Taro & NutUI
147 lines (129 loc) • 4.17 kB
JSX
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>
)
},
})