浏览代码

fix(picker): 在Taro中卡顿的问题 (#1685)

* fix: picker 解决惯性滚动问题

* feat: taro-picker 问题修改

* fix: 组件picker新增点击确定停止滚动逻辑

* fix: 解决Taro高度问题

* fix: 组件datePicker添加 swipeDuration 与 three-dimensional 属性

* fix: #1572问题修改

* feat: 更新Picker组件在Taro中获取高度的方式

* fix: picker-item文本过程省略号

* feat: 京东小程序适配address

* feat: picker 备份

* feat: 使用原生

* fix: 修复Picker在Taro中的卡顿问题

* fix: 解决 Picker 组件在Taro中卡顿的问题

* fix: 修复 ImagePreview 在Taro编译成H5后报错的问题

* fix: 兼容 Picker 组件在 Taro 下转换成 H5无法使用
yangxiaolu1993 3 年之前
父节点
当前提交
6596ceb52a

+ 1 - 1
src/packages/__VUE/picker/Column.vue

@@ -140,7 +140,7 @@ export default create({
     const onTouchMove = (event: TouchEvent) => {
       touch.move(event);
 
-      if ((touch as any).isVertical) {
+      if ((touch as any).isVertical()) {
         moving.value = true;
         preventDefault(event, true);
       }

+ 13 - 1
src/packages/__VUE/picker/ColumnTaro.vue

@@ -132,7 +132,8 @@ export default create({
         }
 
         const { transform } = window.getComputedStyle(dom);
-        state.scrollDistance = +parseInt(transform.split(', ')[1]);
+
+        state.scrollDistance = +transform.slice(7, transform.length - 1).split(', ')[5];
       }
 
       state.touchParams.startY = touch.deltaY.value;
@@ -305,6 +306,17 @@ export default create({
       }
     );
 
+    watch(
+      () => props.lineSpacing,
+      (val) => {
+        console.log('更新');
+        modifyStatus(false);
+      },
+      {
+        deep: true
+      }
+    );
+
     onMounted(() => {
       modifyStatus(false);
     });

+ 3 - 0
src/packages/__VUE/picker/doc.md

@@ -6,6 +6,8 @@
 
 ### 组件重构
 
+> 自 `v3.2.3` 起,@nutui/nutui-taro 中的 Picker 组件不在支持 3D 展示效果。依赖 Taro 版本 `V3.5.6`
+
 Picker 组件在 3.1.18 版本进行重构,调整了之前 API 设计不合理的地方,主要变更如下:
 
 * 支持通过 `v-model` 绑定当前选中的值,移除 `default-index` 属性
@@ -436,6 +438,7 @@ Picker 组件在底部和顶部分别设置了插槽,可进行自定义设置
 | three-dimensional`v3.1.23`          | 是否开启3D效果               | Boolean  | true   |
 | swipe-duration`v3.2.2`          | 惯性滚动时长        | Number、String  | 1000   |
 
+注:自 `v3.2.3` 起,在 @nutui/nutui-taro 中,取消 3D 展示效果,`three-dimensional` 废弃。
 ### Columns 数据结构
 
 | 参数         | 说明                             | 类型   | 默认值           |

+ 14 - 0
src/packages/__VUE/picker/index.scss

@@ -149,6 +149,20 @@
       text-overflow: ellipsis;
       white-space: nowrap;
     }
+
+    &-item-tarotile {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: center;
+      width: 100%;
+      color: $picker-item-text-color;
+      font-size: $picker-item-text-font-size;
+
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
   }
 
   &-roller-mask {

+ 116 - 17
src/packages/__VUE/picker/index.taro.vue

@@ -19,7 +19,30 @@
         }}</view>
       </view>
       <slot name="top"></slot>
-      <view class="nut-picker__column">
+
+      <!-- Taro 下转换成 微信小程序 -->
+      <picker-view
+        v-if="ENV == ENV_TYPE.WEAPP"
+        indicator-style="height: 34px;"
+        :value="defaultIndexes"
+        style="width: 100%; height: 252px"
+        :immediate-change="true"
+        @change="tileChange"
+        @pickstart="handlePickstart"
+        @pickend="handlePickend"
+      >
+        <picker-view-column v-for="(column, columnIndex) in columnsList" :key="columnIndex">
+          <view
+            class="nut-picker-roller-item-tarotile"
+            v-for="(item, index) in column"
+            :key="item.value ? item.value : index"
+          >
+            {{ item.text }}
+          </view>
+        </picker-view-column>
+      </picker-view>
+      <!-- Taro 下转换成 H5 -->
+      <view class="nut-picker__column" v-if="ENV == ENV_TYPE.WEB">
         <view class="nut-picker__hairline" ref="pickerline" :id="'pickerline' + refRandomId"></view>
         <view class="nut-picker__columnitem" v-for="(column, columnIndex) in columnsList" :key="columnIndex">
           <nut-picker-column
@@ -29,7 +52,7 @@
             :readonly="readonly"
             :columnsType="columnsType"
             :value="defaultValues[columnIndex]"
-            :threeDimensional="threeDimensional"
+            :threeDimensional="false"
             :swipeDuration="swipeDuration"
             :lineSpacing="lineSpacing"
             @change="
@@ -100,13 +123,17 @@ export default create({
     const state = reactive({
       show: false,
       formattedColumns: props.columns as import('./types').PickerOption[],
-      lineSpacing: 36
+      lineSpacing: 36,
+      picking: false,
+      ENV: Taro.getEnv(),
+      ENV_TYPE: Taro.ENV_TYPE
     });
 
     const pickerline = ref(null);
-
     // 选中项
     let defaultValues = ref<(number | string)[]>(props.modelValue);
+    // 选中项的位置
+    let defaultIndexes = ref<number[]>([]);
 
     const pickerColumn = ref<any[]>([]);
 
@@ -148,6 +175,7 @@ export default create({
       }
       return 'single';
     });
+
     // 将传入的 columns 格式化
     const columnsList = computed(() => {
       switch (columnsType.value) {
@@ -185,6 +213,7 @@ export default create({
       return formatted;
     };
 
+    // 关闭
     const close = () => {
       emit('close', {
         selectedValue: defaultValues.value,
@@ -193,6 +222,7 @@ export default create({
       emit('update:visible', false);
     };
 
+    // 选择
     const changeHandler = (columnIndex: number, option: import('./types').PickerOption) => {
       if (option && Object.keys(option).length) {
         if (columnsType.value === 'cascade') {
@@ -221,38 +251,96 @@ export default create({
       }
     };
 
-    const confirmHandler = () => {
-      pickerColumn.value.length > 0 &&
-        pickerColumn.value.forEach((column) => {
-          column.stopMomentum();
+    const defaultValuesConvert = computed(() => {
+      let defaultIndexs = [];
+      if (defaultValues.value.length > 0) {
+        defaultValues.value.forEach((value, index) => {
+          for (let i = 0; i < columnsList.value[index].length; i++) {
+            if (columnsList.value[index][i].value == value) {
+              defaultIndexs.push(i);
+              break;
+            }
+          }
         });
+      }
+
+      return defaultIndexs;
+    });
+
+    // 平铺展示时,滚动选择
+    const tileChange = ({ detail }) => {
+      console.log('选择');
+      const prevDefaultValue = defaultIndexes.value;
+      let changeIndex = 0;
+      // 判断变化的是第几个
+      detail.value.forEach((col, index) => {
+        if (prevDefaultValue[index] != col) changeIndex = index;
+      });
+
+      if (state.show) {
+        defaultIndexes.value = detail.value;
+        // 选择的是哪个 option
+        changeHandler(changeIndex, columnsList.value[changeIndex][detail.value[changeIndex]]);
+      }
+    };
+
+    // 确定
+    const confirmHandler = () => {
+      if (state.picking) {
+        console.log('滚动中');
+        setTimeout(() => {
+          confirmHandlerAwit();
+        }, 0);
+      } else {
+        confirmHandlerAwit();
+      }
+    };
 
+    const confirmHandlerAwit = () => {
       if (defaultValues.value && !defaultValues.value.length) {
         columnsList.value.forEach((columns) => {
           defaultValues.value.push(columns[0].value);
           selectedOptions.value.push(columns[0]);
         });
       }
-
+      console.log('确定', defaultValues.value);
       emit('confirm', {
         selectedValue: defaultValues.value,
         selectedOptions: selectedOptions.value
       });
       emit('update:visible', false);
+
+      state.show = false;
+    };
+
+    // 开始滚动
+    const handlePickstart = () => {
+      console.log('开始滚动');
+      state.picking = true;
+    };
+    // 开始滚动
+    const handlePickend = () => {
+      console.log('滚动结束');
+      state.picking = false;
     };
 
     const refRandomId = Math.random().toString(36).slice(-8);
 
     const getReference = async () => {
       const refe = await useTaroRect(pickerline, Taro);
+      console.log(refe.height);
       state.lineSpacing = refe.height ? refe.height : 36;
     };
 
     onMounted(() => {
       if (props.visible) {
-        setTimeout(() => {
-          getReference();
-        }, 200);
+        if (Taro.getEnv() == Taro.ENV_TYPE.WEB) {
+          setTimeout(() => {
+            getReference();
+          }, 200);
+        } else {
+          defaultIndexes.value = defaultValuesConvert.value;
+        }
         state.show = props.visible;
       }
     });
@@ -267,6 +355,7 @@ export default create({
         const isSameValue = JSON.stringify(newValues) === JSON.stringify(defaultValues.value);
         if (!isSameValue) {
           defaultValues.value = newValues;
+          defaultIndexes.value = defaultValuesConvert.value;
         }
       },
       { deep: true }
@@ -287,12 +376,17 @@ export default create({
       () => props.visible,
       (val) => {
         state.show = val;
+
         if (val) {
-          setTimeout(() => {
-            getReference();
-          }, 200);
+          if (Taro.getEnv() == Taro.ENV_TYPE.WEB) {
+            setTimeout(() => {
+              getReference();
+            }, 200);
 
-          pickerColumn.value = [];
+            pickerColumn.value = [];
+          } else {
+            defaultIndexes.value = defaultValuesConvert.value;
+          }
         }
       }
     );
@@ -314,11 +408,16 @@ export default create({
       changeHandler,
       confirmHandler,
       defaultValues,
+      defaultIndexes,
       translate,
       pickerColumn,
       swipeRef,
       refRandomId,
-      pickerline
+      pickerline,
+      tileChange,
+      defaultValuesConvert,
+      handlePickstart,
+      handlePickend
     };
   }
 });

+ 0 - 37
src/sites/mobile-taro/vue/src/dentry/pages/picker/index.vue

@@ -38,25 +38,6 @@
     >
     </nut-picker>
 
-    <h2>平铺展示</h2>
-    <nut-cell
-      title="请选择城市"
-      :desc="title"
-      @click="
-        () => {
-          showTitle = true;
-        }
-      "
-    ></nut-cell>
-    <nut-picker
-      v-model:visible="showTitle"
-      :columns="columns"
-      title="城市选择"
-      :three-dimensional="false"
-      @confirm="(options) => confirm('title', options)"
-    >
-    </nut-picker>
-
     <h2>多列样式</h2>
     <nut-cell
       title="请选择时间"
@@ -130,24 +111,6 @@
     >
       <nut-button block type="primary" @click="alwaysFun">永远有效</nut-button></nut-picker
     >
-
-    <!-- <h2>异步获取</h2>
-    <nut-cell
-      title="异步获取"
-      :desc="effect"
-      @click="
-        () => {
-          showPort = true;
-        }
-      "
-    ></nut-cell>
-    <nut-picker
-      v-model:visible="showPort"
-      :columns="portColumns"
-      title="异步获取"
-      @confirm="(options) => confirm('effect', options)"
-      @change="portChange"
-    ></nut-picker> -->
   </div>
 </template>
 <script lang="ts">

+ 3 - 1
vite.config.build.taro.vue.disperse.ts

@@ -35,7 +35,9 @@ export default defineConfig({
               tag.startsWith('scroll-view') ||
               tag.startsWith('swiper') ||
               tag.startsWith('swiper-item') ||
-              tag.startsWith('picker')
+              tag.startsWith('picker') ||
+              tag.startsWith('picker-view') ||
+              tag.startsWith('picker-view-column')
             );
           },
           whitespace: 'preserve'

+ 3 - 1
vite.config.build.taro.vue.ts

@@ -31,7 +31,9 @@ export default defineConfig({
               tag.startsWith('scroll-view') ||
               tag.startsWith('swiper') ||
               tag.startsWith('swiper-item') ||
-              tag.startsWith('picker')
+              tag.startsWith('picker') ||
+              tag.startsWith('picker-view') ||
+              tag.startsWith('picker-view-column')
             );
           },
           whitespace: 'preserve'