|
|
@@ -0,0 +1,219 @@ |
|
|
|
<!-- 下拉列表组件 zhao --> |
|
|
|
<template> |
|
|
|
<div> |
|
|
|
<slot/> |
|
|
|
<van-popup v-model="popupVisible" position="bottom"> |
|
|
|
<van-picker |
|
|
|
ref="picker" |
|
|
|
:title="label" |
|
|
|
show-toolbar |
|
|
|
:columns="options" |
|
|
|
:readonly="readonly" |
|
|
|
:value-key="labelKey" |
|
|
|
:loading="loading" |
|
|
|
@confirm="onConfirm" |
|
|
|
@cancel="onCancel" |
|
|
|
@change="onChanged" |
|
|
|
/> |
|
|
|
</van-popup> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
|
|
|
|
<script> |
|
|
|
import request from "@/utils/request"; |
|
|
|
|
|
|
|
export default { |
|
|
|
name: "Selector", |
|
|
|
props: { |
|
|
|
value: { |
|
|
|
default: null, |
|
|
|
}, |
|
|
|
readonly: { |
|
|
|
type: Boolean, |
|
|
|
default: false, |
|
|
|
}, |
|
|
|
label: { |
|
|
|
type: String, |
|
|
|
default: '', |
|
|
|
}, |
|
|
|
columns: { // 列表数据 Array |
|
|
|
type: Array, |
|
|
|
default: () => [], |
|
|
|
}, |
|
|
|
labelKey: { // 名称键名 String |
|
|
|
type: String, |
|
|
|
default: 'label', |
|
|
|
}, |
|
|
|
valueKey: { // 值键名 String |
|
|
|
type: String, |
|
|
|
default: 'value', |
|
|
|
}, |
|
|
|
remoteUrl: { // 远程列表加载地址 String, 函数, 或 Promise |
|
|
|
type: [String, Function, Object], |
|
|
|
default: null, |
|
|
|
}, |
|
|
|
onRemoteResponse: { // 远程获取到结果的处理回调 String|Function 如果是函数需返回数组, 如果是字符串支持.分割 |
|
|
|
type: [String, Function], |
|
|
|
default: null, |
|
|
|
}, |
|
|
|
clear: { // 点击取消时清空绑定值 |
|
|
|
type: Boolean, |
|
|
|
default: false, |
|
|
|
}, |
|
|
|
visible: { // 打开状态 |
|
|
|
type: Boolean, |
|
|
|
default: false, |
|
|
|
}, |
|
|
|
}, |
|
|
|
watch: { |
|
|
|
value: function (newVal, oldVal) { |
|
|
|
this.internalValue = newVal; |
|
|
|
this.visibleValue = newVal; |
|
|
|
this.syncIndex(); |
|
|
|
}, |
|
|
|
columns: function (newVal, oldVal) { |
|
|
|
this.syncIndex(); |
|
|
|
}, |
|
|
|
remoteUrl: function (newVal, oldVal) { |
|
|
|
this.requestRemote(); |
|
|
|
}, |
|
|
|
onRemoteResponse: function (newVal, oldVal) { |
|
|
|
this.parseRemote(); |
|
|
|
}, |
|
|
|
visible: function (newVal, oldVal) { |
|
|
|
if(newVal != this.popupVisible) |
|
|
|
this.popupVisible = newVal; |
|
|
|
}, |
|
|
|
popupVisible: function (newVal, oldVal) { |
|
|
|
if(newVal != this.visible) |
|
|
|
this.$emit('update:visible', newVal); |
|
|
|
} |
|
|
|
}, |
|
|
|
created() { |
|
|
|
if(this.remoteUrl) |
|
|
|
this.requestRemote(); |
|
|
|
}, |
|
|
|
data() { |
|
|
|
return { |
|
|
|
popupVisible: false, |
|
|
|
internalValue: this.value, |
|
|
|
visibleValue: '', |
|
|
|
defaultIndex: 0, |
|
|
|
remoteColumns: null, |
|
|
|
loading: false, |
|
|
|
remoteResponse: null, |
|
|
|
}; |
|
|
|
}, |
|
|
|
methods: { |
|
|
|
openPopup() { |
|
|
|
if(!this.readonly) |
|
|
|
{ |
|
|
|
this.popupVisible = true; |
|
|
|
this.$nextTick(() => { |
|
|
|
this.$refs.picker.setIndexes([this.defaultIndex]); |
|
|
|
}) |
|
|
|
} |
|
|
|
}, |
|
|
|
closePopup() { |
|
|
|
this.popupVisible = false; |
|
|
|
}, |
|
|
|
onChanged(data) { |
|
|
|
this.$emit('change', data); |
|
|
|
}, |
|
|
|
onConfirm(data) { |
|
|
|
this.syncValue(data); |
|
|
|
this.$emit('input', this.internalValue); |
|
|
|
this.$emit('confirm', this.internalValue); |
|
|
|
this.closePopup(); |
|
|
|
}, |
|
|
|
onCancel() { |
|
|
|
this.closePopup(); |
|
|
|
if(this.clear) |
|
|
|
{ |
|
|
|
this.visibleValue = ''; |
|
|
|
this.internalValue = null; |
|
|
|
this.$emit('input', this.internalValue); |
|
|
|
} |
|
|
|
this.$emit('cancel'); |
|
|
|
}, |
|
|
|
getValue(data) { |
|
|
|
return typeof(data) === 'object' && this.valueKey ? data[this.valueKey] : data; |
|
|
|
}, |
|
|
|
getLabel(data) { |
|
|
|
return typeof(data) === 'object' && this.labelKey ? data[this.labelKey] : data; |
|
|
|
}, |
|
|
|
syncValue(data) { |
|
|
|
this.internalValue = this.getValue(data); |
|
|
|
this.visibleValue = this.getLabel(data); |
|
|
|
}, |
|
|
|
syncIndex() { |
|
|
|
let columns = this.getColumns(); |
|
|
|
if(!columns) |
|
|
|
return -1; |
|
|
|
for(let i in columns) |
|
|
|
{ |
|
|
|
if(this.getValue(columns[i]) == this.internalValue) { |
|
|
|
this.defaultIndex = i; |
|
|
|
this.visibleValue = this.getLabel(columns[i]); |
|
|
|
this.onChanged(columns[i]); |
|
|
|
return i; |
|
|
|
} |
|
|
|
} |
|
|
|
if(1) // 不存在 |
|
|
|
{ |
|
|
|
this.defaultIndex = -1; |
|
|
|
this.visibleValue = this.internalValue; |
|
|
|
this.onChanged(null); |
|
|
|
} |
|
|
|
return -1; |
|
|
|
}, |
|
|
|
getColumns() { |
|
|
|
return this.columns ? this.columns : this.remoteColumns; |
|
|
|
}, |
|
|
|
requestRemote() { |
|
|
|
if(!this.remoteUrl) |
|
|
|
return; |
|
|
|
this.loading = true; |
|
|
|
this.remoteColumns = []; |
|
|
|
let promise = typeof(this.remoteUrl) === 'function' ? this.remoteUrl() : (this.remoteUrl instanceof Promise ? this.remoteUrl : request(this.remoteUrl)); |
|
|
|
promise.then((resp) => { |
|
|
|
this.remoteResponse = resp; |
|
|
|
this.parseRemote(); |
|
|
|
this.syncIndex(); |
|
|
|
}).catch((e) => { |
|
|
|
console.error(e); |
|
|
|
}).finally(() => { |
|
|
|
this.loading = false; |
|
|
|
}) |
|
|
|
}, |
|
|
|
parseRemote() { |
|
|
|
if(!this.remoteResponse) |
|
|
|
return; |
|
|
|
let type = typeof(this.onRemoteResponse); |
|
|
|
if(type === 'function') |
|
|
|
this.remoteColumns = this.onRemoteResponse(this.remoteResponse); |
|
|
|
else if(type === 'string') |
|
|
|
{ |
|
|
|
let arr = this.onRemoteResponse.split('.'); |
|
|
|
let ptr = this.remoteResponse; |
|
|
|
for(let i in arr) |
|
|
|
{ |
|
|
|
ptr = this.remoteResponse[arr[i]]; |
|
|
|
} |
|
|
|
this.remoteColumns = ptr; |
|
|
|
} |
|
|
|
else |
|
|
|
this.remoteColumns = this.remoteResponse; |
|
|
|
}, |
|
|
|
}, |
|
|
|
computed: { |
|
|
|
options() { |
|
|
|
return this.columns ? this.columns : (this.remoteColumns || []); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
</script> |
|
|
|
|
|
|
|
<style scoped> |
|
|
|
|
|
|
|
</style> |