浏览代码

upd: tab组件使用组内的swiper (#501)

* fix: 优化tab组件使用swiper

* fix: 还原config

* fix: 删除注释

Co-authored-by: richard1015 <51844712@qq.com>
zhenyulei 4 年之前
父节点
当前提交
063937298d

+ 11 - 2
src/config.json

@@ -437,7 +437,16 @@
           "sort": 1,
           "cName": "标签组件",
           "type": "component",
-          "show": false,
+          "show": true,
+          "desc": "标签组件",
+          "author": "zhenyulei"
+        },
+        {
+          "name": "TabPanel",
+          "sort": 2,
+          "cName": "标签组件",
+          "type": "component",
+          "show": true,
           "desc": "标签组件",
           "author": "zhenyulei"
         },
@@ -672,4 +681,4 @@
       ]
     }
   ]
-}
+}

+ 11 - 7
src/packages/__VUE/tab/demo.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="demo full">
-    <h2>基础用法</h2>
+    <h2>基础用法,默认tab-title宽度均分相等</h2>
     <nut-tab>
       <nut-tab-panel tab-title="全部"
         ><p class="content">这里是页签全部内容</p></nut-tab-panel
@@ -65,11 +65,10 @@
       >
     </nut-tab>
 
-    <h2
-      >标签数量超过 5
-      个时,标签栏可以在水平方向上滚动,切换时会自动将当前标签居中。</h2
+    <h2>
+      设置scrollType="scroll",标签栏可以在水平方向上滚动,切换时会自动将当前标签居中。</h2
     >
-    <nut-tab :animated-time="500">
+    <nut-tab :animated-time="500" scrollType="scroll">
       <nut-tab-panel tab-title="全部"
         ><p class="content">这里是页签全部内容</p></nut-tab-panel
       >
@@ -91,7 +90,7 @@
     </nut-tab>
 
     <h2>设置slot:header可以自定义标签</h2>
-    <nut-tab>
+    <nut-tab scrollType="scroll">
       <nut-tab-panel tab-title="全部">
         <template v-slot:header><nut-icon name="dongdong"></nut-icon></template>
         <p class="content">这里是页签全部内容</p>
@@ -114,7 +113,12 @@
     </nut-tab>
 
     <h2>左右tab布局</h2>
-    <nut-tab direction="vertical" :animated-time="500" :default-index="2">
+    <nut-tab
+      direction="vertical"
+      :animated-time="500"
+      :default-index="2"
+      scrollType="scroll"
+    >
       <nut-tab-panel tab-title="页签一"
         ><p class="content">这里是页签一内容</p></nut-tab-panel
       >

+ 143 - 72
src/packages/__VUE/tab/doc.md

@@ -2,107 +2,180 @@
 
 常用于平级区域大块内容的的收纳和展现,支持内嵌标签形式和渲染循环数据形式。
 
-
-## 基础样式
+## 基础样式,默认 tab-title 宽度均分相等
 
 ```html
 <nut-tab>
-  <nut-tab-panel tab-title="全部"><p class="content">这里是页签全部内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="待付款"><p class="content">这里是页签待付款内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="待收获"><p class="content">这里是页签待收获内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="已完成"><p class="content">这里是页签已完成内容</p></nut-tab-panel>
+  <nut-tab-panel tab-title="全部"
+    ><p class="content">这里是页签全部内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="待付款"
+    ><p class="content">这里是页签待付款内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="待收获"
+    ><p class="content">这里是页签待收获内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="已完成"
+    ><p class="content">这里是页签已完成内容</p></nut-tab-panel
+  >
 </nut-tab>
 ```
 
-## 默认显示tab:
-defaultIndex设置默认显示tab
-switchTab监听切换tab返回事件
+## 默认显示 tab:
+
+defaultIndex 设置默认显示 tab
+switchTab 监听切换 tab 返回事件
 
 ```html
-<nut-tab  :defaultIndex="1" @switchTab="switchTab">
-  <nut-tab-panel tab-title="全部"><p class="content">这里是页签全部内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="待付款"><p class="content">这里是页签待付款内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="待收获"><p class="content">这里是页签待收获内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="已完成"><p class="content">这里是页签已完成内容</p></nut-tab-panel>
+<nut-tab :defaultIndex="1" @switchTab="switchTab">
+  <nut-tab-panel tab-title="全部"
+    ><p class="content">这里是页签全部内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="待付款"
+    ><p class="content">这里是页签待付款内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="待收获"
+    ><p class="content">这里是页签待收获内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="已完成"
+    ><p class="content">这里是页签已完成内容</p></nut-tab-panel
+  >
 </nut-tab>
 <script lang="ts">
-import { createComponent } from '../../utils/create';
-const { createDemo } = createComponent('tab');
-export default createDemo({
-  setup() {
-    function switchTab(activeInddex:number,event:MouseEvent){
-      console.log(activeInddex,event);
+  import { createComponent } from '@/packages/utils/create';
+  const { createDemo } = createComponent('tab');
+  export default createDemo({
+    setup() {
+      function switchTab(activeInddex: number, event: MouseEvent) {
+        console.log(activeInddex, event);
+      }
+      return {
+        switchTab
+      };
     }
-    return {
-      switchTab
-    };
-  }
-});
+  });
 </script>
 ```
 
 ## animatedTime 开启切换标签内容时的转场动画时间
+
 ```html
 <nut-tab :animatedTime="500">
-  <nut-tab-panel tab-title="全部"><p class="content">这里是页签全部内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="待付款"><p class="content">这里是页签待付款内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="待收获"><p class="content">这里是页签待收获内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="已完成"><p class="content">这里是页签已完成内容</p></nut-tab-panel>
+  <nut-tab-panel tab-title="全部"
+    ><p class="content">这里是页签全部内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="待付款"
+    ><p class="content">这里是页签待付款内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="待收获"
+    ><p class="content">这里是页签待收获内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="已完成"
+    ><p class="content">这里是页签已完成内容</p></nut-tab-panel
+  >
 </nut-tab>
 ```
 
-
-## 禁止tab内容滑动
+## 禁止 tab 内容滑动
 
 ```html
 <nut-tab :no-swiping="true">
-  <nut-tab-panel tab-title="全部"><p class="content">这里是页签全部内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="待付款"><p class="content">这里是页签待付款内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="待收获"><p class="content">这里是页签待收获内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="已完成"><p class="content">这里是页签已完成内容</p></nut-tab-panel>
+  <nut-tab-panel tab-title="全部"
+    ><p class="content">这里是页签全部内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="待付款"
+    ><p class="content">这里是页签待付款内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="待收获"
+    ><p class="content">这里是页签待收获内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="已完成"
+    ><p class="content">这里是页签已完成内容</p></nut-tab-panel
+  >
 </nut-tab>
 ```
 
-## 标签数量超过 5 个时,标签栏可以在水平方向上滚动
+## 设置 scrollType="scroll",标签栏可以在水平方向上滚动
+
 切换时会自动将当前标签居中。
 
 ```html
 <nut-tab :animatedTime="500">
-  <nut-tab-panel tab-title="全部"><p class="content">这里是页签全部内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="待付款"><p class="content">这里是页签待付款内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="待收获"><p class="content">这里是页签待收获内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="已完成"><p class="content">这里是页签已完成内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="已取消"><p class="content">这里是页签已取消内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="待评价"><p class="content">这里是页签待评价内容</p></nut-tab-panel>
+  <nut-tab-panel tab-title="全部"
+    ><p class="content">这里是页签全部内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="待付款"
+    ><p class="content">这里是页签待付款内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="待收获"
+    ><p class="content">这里是页签待收获内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="已完成"
+    ><p class="content">这里是页签已完成内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="已取消"
+    ><p class="content">这里是页签已取消内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="待评价"
+    ><p class="content">这里是页签待评价内容</p></nut-tab-panel
+  >
 </nut-tab>
 ```
 
-## 设置slot:header可以自定义标签
+## 设置 slot:header 可以自定义标签
+
 ```html
 <nut-tab>
   <nut-tab-panel tab-title="全部">
     <template v-slot:header><nut-icon name="dongdong"></nut-icon></template>
     <p class="content">这里是页签全部内容</p>
   </nut-tab-panel>
-  <nut-tab-panel tab-title="待付款"><p class="content">这里是页签待付款内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="待收获"><p class="content">这里是页签待收获内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="已完成"><p class="content">这里是页签已完成内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="已取消"><p class="content">这里是页签已取消内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="待评价"><p class="content">这里是页签待评价内容</p></nut-tab-panel>
+  <nut-tab-panel tab-title="待付款"
+    ><p class="content">这里是页签待付款内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="待收获"
+    ><p class="content">这里是页签待收获内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="已完成"
+    ><p class="content">这里是页签已完成内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="已取消"
+    ><p class="content">这里是页签已取消内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="待评价"
+    ><p class="content">这里是页签待评价内容</p></nut-tab-panel
+  >
 </nut-tab>
 ```
-## 左右tab布局
+
+## 左右 tab 布局
+
 ```html
 <nut-tab direction="vertical" :animatedTime="500" :defaultIndex="2">
-  <nut-tab-panel tab-title="页签一"><p class="content">这里是页签一内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="页签二"><p class="content">这里是页签二内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="页签三"><p class="content">这里是页签三内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="页签四"><p class="content">这里是页签四内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="页签五"><p class="content">这里是页签五内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="页签六"><p class="content">这里是页签六内容</p></nut-tab-panel>
-  <nut-tab-panel tab-title="页签七"><p class="content">这里是页签七内容</p></nut-tab-panel>
+  <nut-tab-panel tab-title="页签一"
+    ><p class="content">这里是页签一内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="页签二"
+    ><p class="content">这里是页签二内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="页签三"
+    ><p class="content">这里是页签三内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="页签四"
+    ><p class="content">这里是页签四内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="页签五"
+    ><p class="content">这里是页签五内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="页签六"
+    ><p class="content">这里是页签六内容</p></nut-tab-panel
+  >
+  <nut-tab-panel tab-title="页签七"
+    ><p class="content">这里是页签七内容</p></nut-tab-panel
+  >
 </nut-tab>
 ```
+
 ## 异步操作
 
 ```html
@@ -143,29 +216,27 @@ export default createDemo({
 </script>
 ```
 
-
 ### Prop
 
 ### nut-tab
 
-| 字段 | 说明 | 类型 | 默认值
-|----- | ----- | ----- | ----- 
-| direction | 页签栏的分布,可选值 horizontal/vertical | String | horizontal
-| default-index | 默认选中的页签栏 | Number | 0
-| animated-time | 开启切换标签内容时的转场动画时间 | Number | 0
-| no-swiping |禁止tab内容滑动|Boolean|false
-
+| 字段          | 说明                                                             | 类型    | 默认值     |
+| ------------- | ---------------------------------------------------------------- | ------- | ---------- |
+| direction     | 页签栏的位置,可选值 horizontal/vertical                         | String  | horizontal |
+| default-index | 默认选中的页签栏                                                 | Number  | 0          |
+| animated-time | 开启切换标签内容时的转场动画时间                                 | Number  | 0          |
+| no-swiping    | 禁止 tab 内容滑动                                                | Boolean | false      |
+| scrollType    | 页签栏的分布,默认平均分布,设置为"scroll",有最小宽度,发生滚动 | string  | “default“  |
 
 ### nut-tab-panel
 
-| 字段 | 说明 | 类型 | 默认值
-|----- | ----- | ----- | ----- 
-| tab-title| 页签的标题 | String | ''
-| slot:header | 页签title的自定义slot | vnode | --
+| 字段        | 说明                     | 类型   | 默认值 |
+| ----------- | ------------------------ | ------ | ------ |
+| tab-title   | 页签的标题               | String | ''     |
+| slot:header | 页签 title 的自定义 slot | vnode  | --     |
 
 ### Event
 
-| 事件名称 | 说明 | 回调参数 
-|----- | ----- | ----- 
-| switch-tab | 切换页签时触发事件 | 点击的索引值和触发元素
-
+| 事件名称   | 说明               | 回调参数               |
+| ---------- | ------------------ | ---------------------- |
+| switch-tab | 切换页签时触发事件 | 点击的索引值和触发元素 |

+ 14 - 8
src/packages/__VUE/tab/index.scss

@@ -15,7 +15,6 @@
       position: absolute;
     }
     .tab-title-box {
-      min-width: 75px;
       height: 100%;
       display: flex;
       flex: 1;
@@ -25,6 +24,9 @@
       text-align: center;
       font-size: 14px;
     }
+    .tab-title-box-scroll {
+      min-width: 75px;
+    }
     .nut-tab-active {
       color: #1a1a1a;
       font-weight: bold;
@@ -43,7 +45,7 @@
       }
     }
   }
-  .nutui-tab-swiper {
+  .tab-swiper {
     overflow: hidden;
     display: block;
     width: 100%;
@@ -54,9 +56,9 @@
 }
 .vertical-tab {
   display: flex;
-  height: 150px;
+  height: 175px;
   .tab-title {
-    width: 70px;
+    width: 100px;
     height: 100%;
     display: flex;
     flex-direction: column;
@@ -68,19 +70,23 @@
       width: 100%;
       flex: 1;
       display: flex;
-      justify-content: flex-start;
+      justify-content: center;
       align-items: center;
-      min-height: 35px;
+      background-color: #f5f5f5;
+    }
+    .tab-title-box-scroll {
+      min-height: 50px;
     }
     .nut-tab-active {
       color: #1a1a1a;
       font-weight: bold;
       font-size: 16px;
       position: relative;
+      background-color: #fff;
       &::after {
         content: '';
         position: absolute;
-        right: 5px;
+        right: -4px;
         top: 50%;
         left: auto;
         transform: translateY(-50%) rotate(270deg);
@@ -91,7 +97,7 @@
       }
     }
   }
-  .nutui-tab-swiper {
+  .tab-swiper {
     overflow: hidden;
     display: block;
     flex: 1;

+ 37 - 39
src/packages/__VUE/tab/index.vue

@@ -2,7 +2,11 @@
   <view :class="[direction === 'vertical' ? 'vertical-tab' : 'nutui-tab']">
     <view class="tab-title" ref="navlist">
       <view
-        :class="['tab-title-box', { 'nut-tab-active': activeIndex == index }]"
+        :class="[
+          'tab-title-box',
+          { 'nut-tab-active': activeIndex == index },
+          { 'tab-title-box-scroll': scrollType == 'scroll' }
+        ]"
         v-for="(item, index) in titles"
         :key="index"
         @click="switchTitle(index, $event)"
@@ -12,21 +16,27 @@
       </view>
       <view class="underline"></view>
     </view>
-    <view :class="['nutui-tab-swiper', swiperClassName]">
-      <view :class="['swiper-wrapper', { 'swiper-no-swiping': noSwiping }]">
-        <slot></slot>
-      </view>
-    </view>
+    <nut-swiper
+      :init-page="defaultIndex"
+      :pagination-visible="false"
+      :duration="animatedTime"
+      pagination-color="#426543"
+      @change="changeTab"
+      ref="nutuiSwiper"
+      :touchable="!noSwiping"
+      :direction="direction"
+      class="tab-swiper"
+    >
+      <slot></slot>
+    </nut-swiper>
   </view>
 </template>
 <script lang="ts">
 import { PropType, reactive, ref, onMounted, watch, VNode } from 'vue';
-import { createComponent } from '../../utils/create';
+import { createComponent } from '@/packages/utils/create';
+import tabpanel from '@/packages/__VUE/tabpanel/index.vue';
 const { create } = createComponent('tab');
 import TabTitle from './tabTitle';
-import Swiper from 'swiper';
-import 'swiper/dist/css/swiper.min.css';
-// import { extend } from '@vue/shared';
 type TabDirection = 'horizontal' | 'vertical';
 
 interface DataTitle {
@@ -39,6 +49,7 @@ type currChild = {
 } & VNode[];
 
 export default create({
+  children: [tabpanel],
   props: {
     defaultIndex: {
       type: Number,
@@ -55,6 +66,10 @@ export default create({
     noSwiping: {
       type: Boolean,
       default: false
+    },
+    scrollType: {
+      type: String,
+      default: 'flex'
     }
   },
   components: {
@@ -62,10 +77,10 @@ export default create({
   },
   setup(props, ctx) {
     const titles: Array<DataTitle> = reactive([]);
-    let mySwiper = reactive({});
     const isLock = ref(false);
     const activeIndex = ref(props.defaultIndex);
     const navlist = ref<null | HTMLElement>(null);
+    const nutuiSwiper = ref(null);
     // 生成随机的id
     function createHash() {
       return Array.from(Array(10), () =>
@@ -97,35 +112,19 @@ export default create({
         }
       }
     }
+    const changeTab = (index: number) => {
+      console.log(index);
+      activeIndex.value = index;
+      centerTitle(index);
 
+      //
+    };
     //切换tab
     function switchTitle(index: number) {
       activeIndex.value = index;
       centerTitle(index);
-      (mySwiper as Swiper).slideToLoop(index, props.animatedTime, false);
-    }
-    function initSwiper(currIndex: number) {
-      mySwiper = new Swiper('.' + swiperClassName.value, {
-        loop: true /** 循环模式选项 */,
-        noSwiping: true,
-        observer: true, //修改swiper自己或子元素时,自动初始化swiper
-        observeParents: true, //修改swiper的父元素时,自动初始化swiper
-        setWrapperSize: true,
-        direction: props.direction,
-        initialSlide: currIndex,
-        on: {
-          touchStart: function () {
-            isLock.value = true;
-          },
-          transitionEnd: function (): void {
-            ctx.emit('switchTab', (mySwiper as Swiper).realIndex, mySwiper);
-            if (isLock.value) {
-              activeIndex.value = (mySwiper as Swiper).realIndex;
-              centerTitle((mySwiper as Swiper).realIndex);
-            }
-          }
-        }
-      });
+      console.log(nutuiSwiper.value);
+      nutuiSwiper.value.to(index);
     }
     function initTitle() {
       titles.length = 0;
@@ -149,9 +148,6 @@ export default create({
             });
           });
       }
-      setTimeout(() => {
-        initSwiper(activeIndex.value);
-      }, 0);
     }
     onMounted(() => {
       initTitle();
@@ -167,7 +163,9 @@ export default create({
       titles,
       navlist,
       activeIndex,
-      switchTitle
+      switchTitle,
+      changeTab,
+      nutuiSwiper
     };
   }
 });

+ 2 - 2
src/packages/__VUE/tabpanel/index.vue

@@ -1,7 +1,7 @@
 <template>
-  <div class="swiper-slide">
+  <nut-swiper-item>
     <slot></slot>
-  </div>
+  </nut-swiper-item>
 </template>
 <script lang="ts">
 import { createComponent } from '../../utils/create';