| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- <template>
- <view class="l-picker" :style="[styles]">
- <view class="l-picker__toolbar" v-if="cancelBtn || title || confirmBtn">
- <text class="l-picker__cancel" :style="cancelStyle" v-if="cancelBtn" @click="onCancel">{{cancelBtn}}</text>
- <text class="l-picker__title" :style="titleStyle" v-if="title">{{title}}</text>
- <text class="l-picker__confirm" :style="confirmStyle" v-if="confirmBtn" @click="onConfirm">{{confirmBtn}}</text>
- </view>
- <slot name="header"></slot>
- <view class="l-picker__main" :style="[groupHeight ? { height: groupHeight}: {}]">
- <slot>
- <l-picker-item v-for="(options, i) in columns" :options="options" :key="i" :column="i" :value="pickerValue.length > i ? pickerValue[i]: null"></l-picker-item>
- </slot>
- <view class="l-picker__empty" v-if="isEmpty">
- <slot name="empty"></slot>
- </view>
- </view>
- <slot name="footer" />
- <view class="l-picker__loading" ref="loadingRef" v-if="loading" :style="[loadingMaskColor ? {background: loadingMaskColor}: {}]">
- <l-loading :size="loadingSize" :color="loadingColor"></l-loading>
- </view>
- </view>
- </template>
- <script lang="ts">
- // @ts-nocheck
- /**
- * Picker 选择器组件
- * @description 多列数据选择器,支持级联数据展示和自定义样式配置
- * @tutorial https://ext.dcloud.net.cn/plugin?name=lime-picker
- *
- * @property {string} cancelBtn 取消按钮文字
- * @property {string | UTSJSONObject} cancelStyle 取消按钮样式
- * @property {string} confirmBtn 确定按钮文字
- * @property {string | UTSJSONObject} confirmStyle 确定按钮样式
- * @property {string} title 标题文字
- * @property {string | UTSJSONObject} titleStyle 标题样式
- * @property {UTSJSONObject} keys 字段别名配置(例:{value: 'id', label: 'name'})
- * @property {PickerColumn[]} columns 选择器列数据(必填)
- * @property {PickerValue[]} modelValue 选中值(支持v-model)
- * @property {PickerValue[]} defaultValue 默认选中值
- * @property {PickerValue[]} value 选中值(兼容旧版)
- * @property {boolean} loading 是否显示加载状态
- * @property {string} loadingColor 加载图标颜色
- * @property {string} loadingMaskColor 加载遮罩颜色
- * @property {string} loadingSize 加载图标尺寸
- * @property {string} itemHeight 选项行高度
- * @property {string} itemColor 选项文字颜色
- * @property {string} itemFontSize 选项字体大小
- * @property {string} itemActiveColor 选中项颜色
- * @property {string} indicatorStyle 指示器样式
- * @property {string} bgColor 背景颜色
- * @property {string} groupHeight 选项组高度
- * @property {string} radius 圆角半径
- * @property {boolean} resetIndex 是否重置选中索引
- *
- * @event {Function} confirm 点击确定时触发(事件参数:PickerConfirmEvent)
- * @event {Function} cancel 点击取消时触发
- * @event {Function} change 值变化时触发(事件参数:PickerPickEvent)
- * @event {Function} column-change 列数据变化时触发(事件参数:PickerChangeInfo)
- */
- import type { PickerProps, PickerColumn, PickerValue, PickerColumnItem, PickerConfirmEvent, PickerPickEvent } from './type';
- import { defineComponent, computed, ref, watch, onMounted, nextTick, onBeforeUnmount, provide, reactive, toRaw } from '@/uni_modules/lime-shared/vue';
- import pickerProps from './props';
-
- export default defineComponent({
- name: 'l-picker',
- props: pickerProps,
- emits: ['change', 'cancel', 'pick','confirm' ,'update:modelValue', 'update:value'],
- setup(props, {emit, expose}) {
- const pickerItemInstanceArray = ref<LPickerItemComponentPublicInstance[]>([]);
-
- const modelValue = ref<PickerValue[]>(props.value || props.modelValue || props.defaultValue || [])
- const pickerValue = computed({
- set(value: PickerValue[]) {
- if(value.join('') == modelValue.value.join('')) return
- modelValue.value = value;
- emit('update:modelValue', value)
- emit('change', value)
- // #ifdef VUE2
- emit('input', value)
- // #endif
- },
- get():PickerValue[] {
- return props.value || props.modelValue || modelValue.value
- }
- } as WritableComputedOptions<PickerValue[]>)
-
- const isEmpty = computed(():boolean => {
- return props.columns.length == 0 && pickerItemInstanceArray.value.every(child => child.options.length == 0)
- })
- const styles = computed(()=>{
- const style:Record<string, any> = {}
- if(props.bgColor) {
- style['background'] = props.bgColor!
- }
- if(props.radius) {
- style['border-top-left-radius'] = props.radius!
- style['border-top-right-radius'] = props.radius!
- }
- return style
- })
-
- const curIndexArray = ref<number[]>([]);
- const curValueArray = ref([...pickerValue.value]);
- const curItemArray:PickerColumnItem[] = []
- const realColumns = computed(():PickerColumn[] => {
- const pickerColumns = pickerItemInstanceArray.value.map((child):PickerColumn => child.options)
- if(pickerColumns.length > 0) {
- return pickerColumns
- }
- return props.columns
- })
- const valueArrayEquals = computed(():boolean => pickerValue.value.join('') == curValueArray.value.join(''))
-
- const manageChildInList = (child: LPickerItemComponentPublicInstance, shouldAdd: boolean) => {
- const index = pickerItemInstanceArray.value.indexOf(child);
- if(shouldAdd) {
- if(index != -1) return
- pickerItemInstanceArray.value.push(child)
- } else {
- if(index == -1) return
- pickerItemInstanceArray.value.splice(index, 1);
- }
- }
-
- const updateItems = (item: PickerColumnItem, index:number, column: number) => {
- curIndexArray.value[column] = index
- curValueArray.value[column] = item.value
- curItemArray[column] = item;
-
- // clearTimeout(timer)
- // timer = setTimeout(()=>{
- // emit('change', [...curValueArray.value])
- // },50)
- };
-
- const updatePickerItems = () => {
- const _indexs : number[] = []
- const _values : any[] = []
- pickerItemInstanceArray.value.forEach((child, column)=>{
- if(child.options.length == 0) return
- const value = curValueArray.value.length > column ? curValueArray.value[column] : null
- // #ifdef VUE3
- const index = value == null ? 0 : child._.exposed.getIndexByValue(value)
- child._.exposed.setIndex(index)
- // #endif
- // #ifdef VUE2
- const index = value == null ? 0 : child.getIndexByValue(value)
- child.setIndex(index)
- // #endif
- const item = child.options[index]
- _indexs.push(index)
- _values.push(item.value)
-
- // curIndexArray.value[column] = index
- // curValueArray.value[column] = item.value
- curItemArray[column] = item
-
- // 不能改变单向数据流, 只有值不存在时候才处理
- // if(pickerValue.value.length == 0) {
- // pickerValue.value = [...curValueArray.value]
- // }
- // if(pickerValue.value.join('') == curValueArray.value.join('')) return
- // pickerValue.value = [...curValueArray.value]
-
- })
- if (curValueArray.value.join('') == _values.join('') && curIndexArray.value.join('') == _indexs.join('')) return
- // if (curIndexArray.value.join('') == _indexs.join('')) return
- curIndexArray.value = _indexs
- curValueArray.value = _values
- // if(pickerValue.value.length == 0) {
- pickerValue.value = [...curValueArray.value]
- // }
- }
-
- const onPick = (item: PickerColumnItem, index:number, column: number) => {
- if( curIndexArray.value[column] == index &&
- curValueArray.value[column] == item.value) return
-
- curIndexArray.value[column] = index
- curValueArray.value[column] = item.value
- curItemArray[column] = item
- const obj:PickerPickEvent = {
- values: curValueArray.value,
- column,
- index
- }
- pickerValue.value = [...curValueArray.value]
- emit('pick', obj)
- };
-
- const onCancel = (e: UniPointerEvent) => {
- updatePickerItems()
- emit('cancel', e)
- }
- const onConfirm = (e: UniPointerEvent) => {
- const values = [...curValueArray.value];
- const indexs = [...curIndexArray.value];
- const items = curItemArray.map((item):PickerColumnItem => toRaw(item))
- if(pickerValue.value.join('') != values.join('')) {
- pickerValue.value = values;
- }
-
- const obj:PickerConfirmEvent = {
- values,
- indexs,
- items
- }
- emit('confirm', obj)
- }
-
- const stopPickerValue = watch(pickerValue, () => {
- nextTick(()=>{
- curValueArray.value = pickerValue.value.map((item: PickerValue) => item);
- updatePickerItems()
- })
- })
- const stopColumns = watch(realColumns, ()=>{
- // nextTick(()=>{
- // updatePickerItems()
- // })
- updatePickerItems()
- })
-
- onMounted(()=>{
- nextTick(()=>{
- if(
- !valueArrayEquals.value &&
- pickerValue.value.length > 0) {
- curValueArray.value = [...pickerValue.value]
- updatePickerItems()
- }
- })
- })
-
- onBeforeUnmount(()=> {
- stopPickerValue()
- stopColumns()
- })
-
-
- const getSelectedOptions = (): PickerConfirmEvent => {
- const values = [...curValueArray.value];
- const indexs = [...curIndexArray.value];
- const items = curItemArray.map((item) : PickerColumnItem => toRaw(item))
- if (pickerValue.value.join('') != values.join('')) {
- pickerValue.value = values;
- }
- const obj : PickerConfirmEvent = {
- values,
- indexs,
- items
- }
- return obj
- }
-
- // #ifdef VUE3
- expose({
- confirm: onConfirm,
- getSelectedOptions,
- })
- // #endif
- provide('limePicker', props)
- provide('limePickerOnPick', onPick)
- provide('limePickerUpdateItems', updateItems)
- provide('limePickerItems', pickerItemInstanceArray)
- provide('limePickerManageChildInList', manageChildInList)
-
- return {
- styles,
- pickerValue,
- isEmpty,
- onCancel,
- onConfirm,
-
- // #ifdef VUE2
- confirm: onConfirm,
- getSelectedOptions,
- // #endif
- }
-
- }
- })
-
-
-
- </script>
- <style lang="scss">
- @import './index.scss';
- </style>
|