tyler 2 лет назад
Родитель
Сommit
eb87147d8d
3 измененных файлов с 332 добавлено и 91 удалено
  1. 2 1
      public/index.html
  2. 200 0
      src/components/decTabs/index.vue
  3. 130 90
      src/views/user/welcome-pack.vue

+ 2 - 1
public/index.html

@@ -4,10 +4,11 @@
     <meta charset="utf-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
     <meta name="renderer" content="webkit">
-    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+    <!-- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> -->
     <meta http-equiv="cache-control" content="no-cache,no-store, must-revalidate" />
     <meta http-equiv="pragma" content="no-cache" />
     <meta http-equiv="Expires" content="0" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no,minimum-scale=1.0, maximum-scale=1.0">
 
     <!--    <link rel="icon" href="<%= BASE_URL %>favicon.ico">-->
     <title><%= webpackConfig.name %></title>

+ 200 - 0
src/components/decTabs/index.vue

@@ -0,0 +1,200 @@
+<template>
+    <div
+      id="scrollTab"
+      ref="tab"
+      @touchstart="startFn"
+      @touchmove.prevent="moveFn"
+      @touchend="endFn"
+    >
+      <div
+        class="srcoll-tab"
+        @transitionend="transEndFn"
+        :style="{
+          transform: `translateX(${transX}px)`,
+          transition: transState ? `transform .35s ease-in-out` : '',
+        }"
+      >
+        <div
+          class="item-wrap"
+          ref="itemWrap"
+          v-for="(item, index) in tabList"
+          :key="index"
+          @click.stop="onClick(index)"
+          :style="{
+            width: `${wrapWidth}%`,
+            paddingRight: `${wrapPaddingRight}px`,
+          }"
+        >
+          <slot :item="item" :index="index" :activite-index="activiteIndex" />
+        </div>
+      </div>
+    </div>
+  </template>
+  
+  <script>
+//   import { isArray } from 'lodash';
+  export default {
+    name: "ScrollTab",
+    props: {
+      tabList: {
+        type: Array,
+        default: () => [],
+      },
+      // 起始tab索引
+      startIndex: {
+        type: Number,
+        default: () => 0,
+      },
+      // 动画持续时间  ms
+      duration: {
+        type: Number,
+        default: () => 400,
+      },
+      // 单个tabItem的宽度 %
+      wrapWidth: {
+        type: Number,
+        default: () => 25,
+      },
+      // 相邻tabItem的间距 px
+      wrapPaddingRight: {
+        type: Number,
+        default: () => 10,
+      },
+    },
+    data() {
+      return {
+        activiteIndex: 0, // 激活的tabItem索引值
+        tabWidth: 0, // scrollTab宽度,px 精准值
+        tabItemWrapWidth: 0, //tabWrapItem宽度,px 精准值
+        minTranX: 0, // 最小滚动距离,px
+        startX: 0, // 起始滑动值,px
+        diffX: 0, // 滚动距离差值,px
+        preX: 0, // 是否在滑动中
+        transX: 0, // 滑动距离,px
+        transState: false, // 滑动状态
+        timeStamp:0, // 时间戳
+      };
+    },
+    computed: {
+      // tabItem数
+      tabListLen() {
+        return Array.isArray(this.tabList);
+      },
+      // 是否允许滚动
+      isTrans() {
+        return this.transState || (this.tabItemWrapWidth * (this.tabListLen - 1) > this.tabWidth);
+      },
+    },
+    created() {
+      this.activiteIndex = this.startIndex;
+      this.$emit("click", this.activiteIndex);
+    },
+    mounted() {
+      this.init();
+      // 根据startIndex值初始化位置
+      if (this.isTrans) {
+        this.transX = this.preX = this.calcTransX(this.activiteIndex);
+      }
+      window.addEventListener("resize", this.resetInit);
+    },
+    beforeDestroy() {
+      window.removeEventListener("resize", this.resetInit);
+    },
+    methods: {
+      resetInit() {
+        this.$nextTick(this.init);
+      },
+      // 初始化
+      init() {
+        this.tabWidth = this.$refs.tab.getBoundingClientRect().width;
+        this.tabItemWrapWidth = this.$refs.itemWrap[0].getBoundingClientRect().width;
+        this.minTranX = this.calcMinTransX(this.tabListLen - 1);
+        if (this.isTrans) {
+          this.transX = this.preX = this.calcTransX(this.activiteIndex);
+        }
+      },
+      // 滑动开始 - start
+      startFn(e) {
+        if (!this.isTrans) return;
+        this.timeStamp = e.timeStamp;
+        this.diffX = 0;
+        this.startX = this.getTransX(e);
+      },
+      // 滑动中 - move
+      moveFn(e) {
+        if (!this.isTrans) return;
+        this.diffX = this.getTransX(e) - this.startX;
+        this.transX = this.diffX + this.preX;
+      },
+      // 滑动结束 - end
+      endFn() {
+        if (!this.isTrans) return;
+        // 修正滑动位置
+        this.transX = this.preX  = this.fixTransX(this.transX)
+      },
+      // 动画结束
+      transEndFn() {
+        this.transState = false;
+      },
+        // 点击tab
+      onClick(i) {
+        this.transState = true;
+        this.activiteIndex = i;
+        this.transX = this.preX =  this.calcTransX(i);
+        this.$emit("click", this.activiteIndex);
+      },
+      // 修正滑动位置
+      fixTransX(transX) {
+        if (transX > 0) {
+          this.transState = true;
+          return 0;
+        } else if (transX < this.minTranX) {
+          this.transState = true;
+          return this.minTranX;
+        } else {
+          return transX;
+        }
+      },
+      // 获取位置
+      getTransX(e) {
+        return e.touches[e.touches.length - 1].clientX;
+      },
+      // 计算点击tabItem滚动到中间的位置
+      calcTransX(i) {
+        return this.fixTransX(-(
+          this.$refs.itemWrap[i].offsetLeft -
+          this.tabWidth / 2 -
+          this.wrapPaddingRight / 2 +
+          this.tabItemWrapWidth / 2
+        ))
+      },
+      // 计算最小滚动位置
+      calcMinTransX(i) {
+        return -(
+          this.$refs.itemWrap[i].offsetLeft +
+          this.tabItemWrapWidth -
+          this.tabWidth
+        );
+      },
+    },
+  };
+  </script>
+  
+  <style scoped lang="scss">
+  #scrollTab {
+    overflow-x: scroll;
+    .srcoll-tab {
+      width: 100%;
+      position: relative;
+      display: flex;
+  
+      .item-wrap {
+        flex: none;
+        box-sizing: border-box;
+        // 修复移动端点击该元素出现黑色闪动
+        -webkit-tap-highlight-color: transparent;
+      }
+    }
+  }
+  </style>
+  

+ 130 - 90
src/views/user/welcome-pack.vue

@@ -1,38 +1,51 @@
 <template>
-  <div v-loading="loading">
-    <!-- new start -->
-    <div class="dec-header flexJcsbAc" style="">
+  <div v-loading="loading" class="dec">
+    <div class="dec-header" style="">
       <div class="classification">
-        <el-tabs id="el-tabs" v-model="activeName" @tab-click="handleClick">
+        <el-tabs id="el-tabs" ref="elTabs" v-model="activeName" @tab-click="handleClick">
           <el-tab-pane
             v-for="(item, index) in tabList"
             :key="index"
             :label="item.title"
             :name="item.name"
-          ></el-tab-pane>
+          >
+            {{ item.title }}
+          </el-tab-pane>
         </el-tabs>
+        <div class="openAllClassification flexfc" @click="drawer = true">
+          <span class="">全部</span>
+          <i class="el-icon-more-outline"></i>
+        </div>
+        <!-- 全部分类 -->
       </div>
-      <div class="openAllClassification flexfc" @click="drawer = true">
-        <span class="">全部</span>
-        <i class="el-icon-more-outline"></i>
-      </div>
-      <!-- 全部分类 -->
       <el-drawer
-        title="我是标题"
+        title="全部分类"
         :visible.sync="drawer"
         :direction="direction"
-        modal-append-to-body="false"
-        >
-        <span>我来啦!</span>
+        :modal-append-to-body="false"
+      >
+        <div class="allClassification flexFwW">
+          <div
+            class="title"
+            v-for="(item, index) in tabList"
+            :key="index"
+            :class="{ active: activeName == item.name }"
+            @click="drawerClassification(item, index)"
+          >
+            <span>{{ item.title }}</span>
+          </div>
+        </div>
       </el-drawer>
     </div>
 
-    
     <!-- new ens -->
   </div>
 </template>
 
 <script>
+// new
+import ScrollTab from "@/components/decTabs";
+// end
 import { deleteApproachOrder } from "@/api/shop";
 import {
 createWelcomePack,
@@ -51,7 +64,7 @@ import paystack from "vue-paystack";
 
 export default {
   name: "WelcomePack",
-  components: { Pagination, paystack },
+  components: { Pagination, paystack, ScrollTab },
   directives: { waves },
   filters: {
     bvFilter(row) {
@@ -114,7 +127,8 @@ export default {
         },
       ],
       drawer: false,
-      direction: 'ttb',
+      direction: "ttb",
+      drawerWidth: "50%",
       // new end
       loading: false,
       tool: tool,
@@ -273,7 +287,7 @@ export default {
     // 监听被选中的类目标签,使被选中的标签始终在屏幕中间显示
     activeName: {
       handler: function () {
-        
+
       },
     },
     isDec: {
@@ -291,30 +305,19 @@ export default {
   },
   methods: {
     //new start
-    handleClick(tab, event) {
-      console.log(tab.index);
-    // 获取到 container 整个盒子
-    var container = document.querySelector(".container");
-
-// 获取包裹盒子 container.offsetWidth
-var containerW = container.offsetWidth;
-
-// 找到所有需要被点击的 item 的集合
-var itemList = document.querySelectorAll(".item");
-
-// 遍历数组
-for (let i = 0; i < itemList.length; i++) {
-    // 给每个元素添加点击事件
-    itemList[i].onclick = function () {
+    handleClick(tab) {
+      console.log(tab);
+    },
+    drawerClassification(item, index) {
+      this.handleClick(this.$refs.elTabs.$children[index]);
+      console.log('获取组件内的DOM',this.$refs.elTabs.$children[index]);
 
-        // 获取到当前点击元素的 offsetLeft  - 包裹盒子 offsetWidth 的一半 + 当前点击元素 offsetWidth 的一半
-        var scrollLeftNum =itemList[i].offsetLeft - containerW / 2 + itemList[i].offsetWidth / 2; 
-        console.log(scrollLeftNum,'距离')
+      console.log(this.activeName);
 
-        // 赋值
-        container.scrollLeft = scrollLeftNum;
-    }
-} 
+      this.drawer = false;
+    },
+    onConfirm(val) {
+      console.log(val);
     },
     //end
     // 会员报单/BA升级
@@ -711,41 +714,72 @@ for (let i = 0; i < itemList.length; i++) {
   justify-content: space-between;
   align-items: center;
 }
+.flexFwW {
+  display: flex;
+  flex-wrap: wrap;
+}
+.active {
+  color: #1890ff;
+}
+.dec {
+  width: 100%;
+  height: calc(100vh - 100px);
+}
 .dec-header {
-  height: 80px;
   width: 100%;
-  overflow: hidden;
-  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+  height: 100%;
+  position: relative;
+
   .classification {
     width: 90%;
-    overflow: hidden;
+    // overflow: hidden;
     /* 可以使窗口平稳滚动 */
-    scroll-behavior: smooth; 
-  }
-  .openAllClassification {
-    width: 30px;
-    // box-shadow: 0px 0px 20px  rgba(0,0,0,.1);
-
-    span {
-      writing-mode: vertical-lr;
+    // scroll-behavior: smooth;
+    position: relative;
+    .openAllClassification {
+      width: 30px;
+      height: 60px;
+      // box-shadow: 0px 0px 20px  rgba(0,0,0,.1);
+      cursor: pointer;
+      align-self: baseline;
+      position: absolute;
+      top: 50%;
+      right: -10%;
+      transform: translate(-50%, -50%);
+      span {
+        writing-mode: vertical-lr;
+      }
     }
   }
-  ::v-deep {
+   
 
-    //tab
+  ::v-deep {
+    // tab
     .el-tabs__header {
       margin: 0;
+      height: 60px;
+      // box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      width: 100%;
+      overflow: hidden;
     }
     .el-tabs__nav-scroll {
-      overflow-x: scroll;
-      overflow-y: hidden;
-      /*解决ios上滑动不流畅*/
-      -webkit-overflow-scrolling: touch;
+      width: 100%;
+      // overflow-x: scroll;
+      // overflow-y: hidden;
+      overflow-x: auto;     /* winphone8和android4+ */
+      -webkit-overflow-scrolling: touch;    /* ios5+ */
     }
     ::-webkit-scrollbar {
       /*隐藏滚轮*/
       display: none;
     }
+    .el-tabs__nav-wrap{
+      overflow-x:hidden;
+    }
+
     .el-tabs__nav-wrap::after {
       content: "";
       position: absolute;
@@ -760,45 +794,51 @@ for (let i = 0; i < itemList.length; i++) {
       display: none;
     }
     .el-tabs__nav-prev {
-      opacity: 0;
+      display: none;
     }
-    .el-tabs__nav-wrap.is-scrollable {
-      padding: 0 0px 0 0px;
-      -webkit-box-sizing: border-box;
-      box-sizing: border-box;
+    // .el-tabs__nav-wrap.is-scrollable {
+    //   padding: 0 0px 0 0px;
+    //   -webkit-box-sizing: border-box;
+    //   box-sizing: border-box;
+    // }
+
+    // //drawer__wrapper
+    .classification {
+      position: relative;
     }
-
-    //drawer__wrapper
     .el-drawer__wrapper {
-        position: fixed;
-        top: 50px;
-        right: 0;
-        bottom: 0;
-        left: 0;
-        overflow: hidden;
-        margin: 0;
+      position: absolute;
+      // position: fixed;
+      top: 0px;
+      right: 0;
+      bottom: 0;
+      left: 0;
+      overflow: hidden;
+      margin: 0;
+    }
+     
+    .el-drawer__wrapper {
+      // min-height: 60%;
+      .el-drawer__body {
+        //  height: 400px;
+      }
+      .el-drawer__container ::-webkit-scrollbar {
+        // display: none;
+      }
+      .allClassification {
+        // justify-content: center;
+        text-align: center;
+        // height: auto;
+        .title {
+          width: 33%;
+          height: 50px;
+        }
+      }
     }
   }
 }
 </style>
 
 <style>
-.el-table th.el-table__cell > .cell {
-  white-space: nowrap;
-}
-
-.el-table td.el-table__cell > .cell {
-  word-break: keep-all;
-  white-space: pre-wrap;
-}
-.el-tabs--border-card > .el-tabs__content {
-  padding: 5px;
-}
-
-.el-radio.is-bordered + .el-radio.is-bordered {
-  margin: 5px 0;
-}
-.el-radio--medium.is-bordered {
-  margin: 5px 0;
-}
+/*  */
 </style>