bug
jiangping
2023-11-07 64b432916af9c9218ab3f3eca614e26c542142ae
minipro_standard/uni_modules/uview-ui/components/u-picker/u-picker.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,283 @@
<template>
   <u-popup
      :show="show"
      @close="closeHandler"
   >
      <view class="u-picker">
         <u-toolbar
            v-if="showToolbar"
            :cancelColor="cancelColor"
            :confirmColor="confirmColor"
            :cancelText="cancelText"
            :confirmText="confirmText"
            :title="title"
            @cancel="cancel"
            @confirm="confirm"
         ></u-toolbar>
         <picker-view
            class="u-picker__view"
            :indicatorStyle="`height: ${$u.addUnit(itemHeight)}`"
            :value="innerIndex"
            :immediateChange="immediateChange"
            :style="{
               height: `${$u.addUnit(visibleItemCount * itemHeight)}`
            }"
            @change="changeHandler"
         >
            <picker-view-column
               v-for="(item, index) in innerColumns"
               :key="index"
               class="u-picker__view__column"
            >
               <text
                  v-if="$u.test.array(item)"
                  class="u-picker__view__column__item u-line-1"
                  v-for="(item1, index1) in item"
                  :key="index1"
                  :style="{
                     height: $u.addUnit(itemHeight),
                     lineHeight: $u.addUnit(itemHeight),
                     fontWeight: index1 === innerIndex[index] ? 'bold' : 'normal'
                  }"
               >{{ getItemText(item1) }}</text>
            </picker-view-column>
         </picker-view>
         <view
            v-if="loading"
            class="u-picker--loading"
         >
            <u-loading-icon mode="circle"></u-loading-icon>
         </view>
      </view>
   </u-popup>
</template>
<script>
/**
 * u-picker
 * @description é€‰æ‹©å™¨
 * @property {Boolean}         show            æ˜¯å¦æ˜¾ç¤ºpicker弹窗(默认 false ï¼‰
 * @property {Boolean}         showToolbar         æ˜¯å¦æ˜¾ç¤ºé¡¶éƒ¨çš„æ“ä½œæ ï¼ˆé»˜è®¤ true ï¼‰
 * @property {String}         title            é¡¶éƒ¨æ ‡é¢˜
 * @property {Array}         columns            å¯¹è±¡æ•°ç»„,设置每一列的数据
 * @property {Boolean}         loading            æ˜¯å¦æ˜¾ç¤ºåŠ è½½ä¸­çŠ¶æ€ï¼ˆé»˜è®¤ false ï¼‰
 * @property {String | Number}   itemHeight         å„列中,单个选项的高度(默认 44 ï¼‰
 * @property {String}         cancelText         å–消按钮的文字(默认 '取消' ï¼‰
 * @property {String}         confirmText         ç¡®è®¤æŒ‰é’®çš„æ–‡å­—(默认 '确定' ï¼‰
 * @property {String}         cancelColor         å–消按钮的颜色(默认 '#909193' ï¼‰
 * @property {String}         confirmColor      ç¡®è®¤æŒ‰é’®çš„颜色(默认 '#3c9cff' ï¼‰
 * @property {String | Number}   visibleItemCount   æ¯åˆ—中可见选项的数量(默认 5 ï¼‰
 * @property {String}         keyName            é€‰é¡¹å¯¹è±¡ä¸­ï¼Œéœ€è¦å±•示的属性键名(默认 'text' ï¼‰
 * @property {Boolean}         closeOnClickOverlay   æ˜¯å¦å…è®¸ç‚¹å‡»é®ç½©å…³é—­é€‰æ‹©å™¨ï¼ˆé»˜è®¤ false ï¼‰
 * @property {Array}         defaultIndex      å„列的默认索引
 * @property {Boolean}         immediateChange      æ˜¯å¦åœ¨æ‰‹æŒ‡æ¾å¼€æ—¶ç«‹å³è§¦å‘change事件(默认 false ï¼‰
 * @event {Function} close      å…³é—­é€‰æ‹©å™¨æ—¶è§¦å‘
 * @event {Function} cancel      ç‚¹å‡»å–消按钮触发
 * @event {Function} change      å½“选择值变化时触发
 * @event {Function} confirm   ç‚¹å‡»ç¡®å®šæŒ‰é’®ï¼Œè¿”回当前选择的值
 */
import props from './props.js';
export default {
   name: 'u-picker',
   mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
   data() {
      return {
         // ä¸Šä¸€æ¬¡é€‰æ‹©çš„列索引
         lastIndex: [],
         // ç´¢å¼•值 ï¼Œå¯¹åº”picker-view的value
         innerIndex: [],
         // å„列的值
         innerColumns: [],
         // ä¸Šä¸€æ¬¡çš„变化列索引
         columnIndex: 0,
      }
   },
   watch: {
      // ç›‘听默认索引的变化,重新设置对应的值
      defaultIndex: {
         immediate: true,
         handler(n) {
            this.setIndexs(n, true)
         }
      },
      // ç›‘听columns参数的变化
      columns: {
         immediate: true,
         handler(n) {
            this.setColumns(n)
         }
      },
   },
   methods: {
      // èŽ·å–item需要显示的文字,判别为对象还是文本
      getItemText(item) {
         if (uni.$u.test.object(item)) {
            return item[this.keyName]
         } else {
            return item
         }
      },
      // å…³é—­é€‰æ‹©å™¨
      closeHandler() {
         if (this.closeOnClickOverlay) {
            this.$emit('close')
         }
      },
      // ç‚¹å‡»å·¥å…·æ çš„取消按钮
      cancel() {
         this.$emit('cancel')
      },
      // ç‚¹å‡»å·¥å…·æ çš„确定按钮
      confirm() {
         this.$emit('confirm', {
            indexs: this.innerIndex,
            value: this.innerColumns.map((item, index) => item[this.innerIndex[index]]),
            values: this.innerColumns
         })
      },
      // é€‰æ‹©å™¨æŸä¸€åˆ—的数据发生变化时触发
      changeHandler(e) {
         const {
            value
         } = e.detail
         let index = 0,
            columnIndex = 0
         // é€šè¿‡å¯¹æ¯”前后两次的列索引,得出当前变化的是哪一列
         for (let i = 0; i < value.length; i++) {
            let item = value[i]
            if (item !== (this.lastIndex[i] || 0)) { // æŠŠundefined转为合法假值0
               // è®¾ç½®columnIndex为当前变化列的索引
               columnIndex = i
               // index则为变化列中的变化项的索引
               index = item
               break // ç»ˆæ­¢å¾ªçŽ¯ï¼Œå³ä½¿å°‘ä¸€æ¬¡å¾ªçŽ¯ï¼Œä¹Ÿæ˜¯æ€§èƒ½çš„æå‡
            }
         }
         this.columnIndex = columnIndex
         const values = this.innerColumns
         // å°†å½“前的各项变化索引,设置为"上一次"的索引变化值
         this.setLastIndex(value)
         this.setIndexs(value)
         this.$emit('change', {
            // #ifndef MP-WEIXIN || MP-LARK
            // å¾®ä¿¡å°ç¨‹åºä¸èƒ½ä¼ é€’this,会因为循环引用而报错
            picker: this,
            // #endif
            value: this.innerColumns.map((item, index) => item[value[index]]),
            index,
            indexs: value,
            // values为当前变化列的数组内容
            values,
            columnIndex
         })
      },
      // è®¾ç½®index索引,此方法可被外部调用设置
      setIndexs(index, setLastIndex) {
         this.innerIndex = uni.$u.deepClone(index)
         if (setLastIndex) {
            this.setLastIndex(index)
         }
      },
      // è®°å½•上一次的各列索引位置
      setLastIndex(index) {
         // å½“能进入此方法,意味着当前设置的各列默认索引,即为“上一次”的选中值,需要记录,是因为changeHandler中
         // éœ€è¦æ‹¿å‰åŽçš„变化值进行对比,得出当前发生改变的是哪一列
         this.lastIndex = uni.$u.deepClone(index)
      },
      // è®¾ç½®å¯¹åº”列选项的所有值
      setColumnValues(columnIndex, values) {
         // æ›¿æ¢innerColumns数组中columnIndex索引的值为values,使用的是数组的splice方法
         this.innerColumns.splice(columnIndex, 1, values)
         // æ‹·è´ä¸€ä»½åŽŸæœ‰çš„innerIndex做临时变量,将大于当前变化列的所有的列的默认索引设置为0
         let tmpIndex = uni.$u.deepClone(this.innerIndex)
         for (let i = 0; i < this.innerColumns.length; i++) {
            if (i > this.columnIndex) {
               tmpIndex[i] = 0
            }
         }
         // ä¸€æ¬¡æ€§èµ‹å€¼ï¼Œä¸èƒ½å•个修改,否则无效
         this.setIndexs(tmpIndex)
      },
      // èŽ·å–å¯¹åº”åˆ—çš„æ‰€æœ‰é€‰é¡¹
      getColumnValues(columnIndex) {
         // è¿›è¡ŒåŒæ­¥é˜»å¡žï¼Œå› ä¸ºå¤–部得到change事件之后,可能需要执行setColumnValues更新列的值
         // ç´¢å¼•如果在外部change的回调中调用getColumnValues的话,可能无法得到变更后的列值,这里进行一定延时,保证值的准确性
         (async () => {
            await uni.$u.sleep()
         })()
         return this.innerColumns[columnIndex]
      },
      // è®¾ç½®æ•´ä½“各列的columns的值
      setColumns(columns) {
         this.innerColumns = uni.$u.deepClone(columns)
         // å¦‚果在设置各列数据时,没有被设置默认的各列索引defaultIndex,那么用0去填充它,数组长度为列的数量
         if (this.innerIndex.length === 0) {
            this.innerIndex = new Array(columns.length).fill(0)
         }
      },
      // èŽ·å–å„åˆ—é€‰ä¸­å€¼å¯¹åº”çš„ç´¢å¼•
      getIndexs() {
         return this.innerIndex
      },
      // èŽ·å–å„åˆ—é€‰ä¸­çš„å€¼
      getValues() {
         // è¿›è¡ŒåŒæ­¥é˜»å¡žï¼Œå› ä¸ºå¤–部得到change事件之后,可能需要执行setColumnValues更新列的值
         // ç´¢å¼•如果在外部change的回调中调用getValues的话,可能无法得到变更后的列值,这里进行一定延时,保证值的准确性
         (async () => {
            await uni.$u.sleep()
         })()
         return this.innerColumns.map((item, index) => item[this.innerIndex[index]])
      }
   },
}
</script>
<style lang="scss" scoped>
   @import "../../libs/css/components.scss";
   .u-picker {
      position: relative;
      &__view {
         &__column {
            @include flex;
            flex: 1;
            justify-content: center;
            &__item {
               @include flex;
               justify-content: center;
               align-items: center;
               font-size: 16px;
               text-align: center;
               /* #ifndef APP-NVUE */
               display: block;
               /* #endif */
               color: $u-main-color;
               &--disabled {
                  /* #ifndef APP-NVUE */
                  cursor: not-allowed;
                  /* #endif */
                  opacity: 0.35;
               }
            }
         }
      }
      &--loading {
         position: absolute;
         top: 0;
         right: 0;
         left: 0;
         bottom: 0;
         @include flex;
         justify-content: center;
         align-items: center;
         background-color: rgba(255, 255, 255, 0.87);
         z-index: 1000;
      }
   }
</style>