vue2.x--- cube-ui重构饿了么

一,安装,cube-ui

安装cube-ui     vue add cube-ui (针对vue-cli3),安装会有一些配置提示, 以后会直接使用cube组件了,按需引入,
Use post-compile? 后编译 y
部分引用 Import type
自定义主题 Custom theme y
Use rem layout rem 布局 n
Use vw layout rem 布局的 n

安装重构后,vue项目中会自动theme.styl的样式,cube-ui.js的组件, 在main.js中引入即可

二,引入tab-bar组件,以及cube-slide轮播图组件

 
<template>
  <div class="tab">
    <!-- 切换栏 -->
    <cube-tab-bar
      :showSlider="true"
      v-model="selectedLabel"
      :data="tabs"
      ref="tabBar"
      class="border-bottom-1px"
    >
    </cube-tab-bar>
    <div class="slide-wrapper">
      <!-- 轮播 -->
      <cube-slide
        :loop="false"
        :auto-play="false"
        :initial-index="index"
        ref="slide"
      >
      <!-- 轮播结构 -->
        <cube-slide-item>
          <Goods></Goods>
        </cube-slide-item>
        <cube-slide-item>
          <Ratings></Ratings>
        </cube-slide-item>
        <cube-slide-item>
          <Sellers></Sellers>
        </cube-slide-item>
      </cube-slide>
    </div>
  </div>
</template>

<script>
import Goods from "@/views/igoods/igoods";
import Ratings from "@/views/iratings/iratings";
import Sellers from "@/views/isellers/isellers";
export default {
  data() {
    return {
      index: 0,
      tabs: [
        {
          label: "商品"
        },
        {
          label: "评价"
        },
        {
          label: "商家"
        }
      ]
    };
  },

  computed: {
    selectedLabel: {
      get() {
        return this.tabs[this.index].label;
      },
      set(newVal) {
        this.index = this.tabs.findIndex(value => {
          return value.label === newVal;
        });
      }
    }
  },

  components: {
    Goods,
    Ratings,
    Sellers
  }
};
</script>

<style scoped lang="stylus">
@import "../../assets/stylus/variable"
  .tab
    >>> .cube-tab
      padding: 10px 0
    display :flex
    flex-direction :column
    height :100px
    .slide-wrapper
      flex:1
      overflow: hidden
</style>

 

cube-tab-bar组件里头默认有三个cube-tab组件,根据tabs数组来定义的,用深度选择器的样式来作用

#Scoped CSS
当 <style> 标签有 scoped 属性时,它的 CSS 只作用于当前组件中的元素。这类似于 Shadow DOM 中的样式封装。
vue-loader官网介绍;https://vue-loader.vuejs.org/zh/guide/scoped-css.html#%E6%B7%B7%E7%94%A8%E6%9C%AC%E5%9C%B0%E5%92%8C%E5%85%A8%E5%B1%80%E6%A0%B7%E5%BC%8F
#子组件的根元素
使用 scoped 后,父组件的样式将不会渗透到子组件中。不过一个子组件的根节点会同时受其父组件的 scoped CSS 和子组件的 scoped CSS 的影响。
这样设计是为了让父组件可以从布局的角度出发,调整其子组件根元素的样式。 #深度作用选择器 如果你希望 scoped 样式中的一个选择器能够作用得“更深”,例如影响子组件,你可以使用
>>> 操作符:

 

此时左右滑动轮播图,上面的切换栏不会自动跟随切换,此时我们需要实现一个上下联动,需要添加change事件

      <!-- 轮播 -->
      <cube-slide
        :loop="false"
        :auto-play="false"
        :initial-index="index"
        ref="slide"
        @change="onChange"
      >
 methods:{
    // Slide 页面切换时触发,参数为当前索引值
    onChange(currentIndex){
      this.index = currentIndex
    }
  },

此时上下联动效果已完成,但是还不够完美,我们还要实现左右滑动有一个渐变效果,轮播图添加scroll事件

 

逻辑分析,知道滑动的距离占总轮播图的宽度的距离的比值,乘以切换栏的宽度,利用切换栏的cube-tab-bar的setSliderTransform方法即可

     <!-- 轮播 -->
      <cube-slide
        :loop="false"
        :auto-play="false"
        :initial-index="index"
        ref="slide"
        @change="onChange"
        @scroll= "onScroll"
        :options="slideOptions"
      >
 // 滚动中实时派发
    onScroll(pos){
      // console.log(ops.x)
      // 通过refs获取切换栏tab-bar组件的宽度,需要.$el
      const tabBarWidth = this.$refs.tabBar.$el.clientWidth
      // 获取轮播图silde组件的宽度,是全部滚动的宽度
      const slideWidth = this.$refs.slide.slide.scrollWidth
      // 滑动的宽度 / 总滚动轮播的宽度 * 切换栏的宽度
      const transform = -pos.x / slideWidth * tabBarWidth
      this.$refs.tabBar.setSliderTransform(transform)
      
    }

 

切换栏还需要配置选项,以及关闭过渡效果(默认开启)

 

 slideOptions:{
        listenScroll:true,
        // 在滑动不止时
        probeType:3,
        directionLockThreshold:0
      }
<!-- 切换栏 -->
    <cube-tab-bar
      :showSlider="true"
      v-model="selectedLabel"
      :data="tabs"
      ref="tabBar"
      class="border-bottom-1px"
      :useTransition="false"
    >
    </cube-tab-bar>

 

二,优化,组件抽象和封装,动态组件设置,组件名称和数据在父组件app中定义,传入子组件,动态设置组件,利用component组件

import { mapState } from "vuex";
import tab from "@/components/tab/tab";
import Goods from "@/views/igoods/igoods";
import Ratings from "@/views/iratings/iratings";
import Sellers from "@/views/isellers/isellers";

 

 computed: {
    ...mapState(["sellers"]),
    tabs(){
      return  [
        {
          label:'商品',
          component:Goods,
          data:{
            sellers:this.sellers
          }

        },
        {
          label:'评价',
          component:Ratings,
          data:{
            sellers:this.sellers
          }

        },
        {
          label:'商家',
          component:Sellers,
          data:{
            sellers:this.sellers
          }

        },
      ]
    }
  },
<div class="tab-wrapper">
      <tab :tabs ="tabs"></tab>
    </div>

优化后,动态设置组件,vue.js官网动态组件

我们在一个多标签的界面中使用 is attribute 来切换不同的组件:

<component v-bind:is="currentTabComponent"></component>

 

<template>
  <div class="tab">
    <!-- 切换栏 -->
    <cube-tab-bar
      :showSlider="true"
      v-model="selectedLabel"
      :data="tabs"
      ref="tabBar"
      class="border-bottom-1px"
      :useTransition="false"
    >
    </cube-tab-bar>
    <div class="slide-wrapper">
      <!-- 轮播 -->
      <cube-slide
        :loop="false"
        :auto-play="false"
        :initial-index="index"
        ref="slide"
        @change="onChange"
        @scroll="onScroll"
        :options="slideOptions"
      >
        <!-- 轮播结构 -->
        <cube-slide-item v-for="(tab, index) in tabs" :key="index">
          <component :is="tab.component" :data="tab.data"></component>
        </cube-slide-item>
        <!-- <cube-slide-item>
          <Goods></Goods>
        </cube-slide-item> -->
        <!-- <cube-slide-item>
          <Ratings></Ratings>
        </cube-slide-item>
        <cube-slide-item>
          <Sellers></Sellers>
        </cube-slide-item> -->
      </cube-slide>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      index: 0,
      // tabs: [
      //   {
      //     label: "商品"
      //   },
      //   {
      //     label: "评价"
      //   },
      //   {
      //     label: "商家"
      //   }
      // ],
      slideOptions: {
        listenScroll: true,
        // 在滑动不止时
        probeType: 3,
        directionLockThreshold: 0
      }
    };
  },

  props: ["tabs"],

  methods: {
    // Slide 页面切换时触发,参数为当前索引值
    onChange(currentIndex) {
      this.index = currentIndex;
    },
    // 滚动中实时派发
    onScroll(pos) {
      // console.log(ops.x)
      // 通过refs获取切换栏tab-bar的宽度,需要.$el
      const tabBarWidth = this.$refs.tabBar.$el.clientWidth;
      // 获取轮播图silde组件的宽度,是全部滚动的宽度
      const slideWidth = this.$refs.slide.slide.scrollWidth;
      // 滑动的宽度 / 总滚动轮播的宽度 * 切换栏的宽度
      const transform = (-pos.x / slideWidth) * tabBarWidth;
      this.$refs.tabBar.setSliderTransform(transform);
    }
  },

  computed: {
    selectedLabel: {
      get() {
        return this.tabs[this.index].label;
      },
      set(newVal) {
        this.index = this.tabs.findIndex(value => {
          return value.label === newVal;
        });
      }
    }
  }

  // components: {
  //   Goods,
  //   Ratings,
  //   Sellers
  // }
};
</script>

<style scoped lang="stylus">
@import "../../assets/stylus/variable"
  .tab
    >>> .cube-tab
      padding: 10px 0
    display :flex
    flex-direction :column
    height :100px
    .slide-wrapper
      flex:1
      overflow: hidden
</style>

 

三,在goods组价中,获取goods数据

1.我们不在mouted中dispatch下从vuex中获取数据,而是在tabs父组件中的change事件(切换栏触发)时调用子组件goods的请求数据的函数

  <!-- 轮播结构 -->
        <cube-slide-item v-for="(tab, index) in tabs" :key="index">
          <component :is="tab.component" :data="tab.data" ref="component"></component>
        </cube-slide-item>

在父组件中调用子组件的方法

 methods: {
    // Slide 页面切换时触发,参数为当前索引值
    onChange(currentIndex) {
      this.index = currentIndex;
      // 切换tab栏,发送请求,获取goods数据
      const component = this.$refs.component[currentIndex]
      component.fetch && component.fetch()
    },

子组件goods定义获取数据的函数

 methods: {
    fetch() {
      this.$store.dispatch("reqgoods");
    }
  },
 computed: {
    ...mapState(["goods"])
  }

第一次渲染页面,也要调用该函数

  mounted(){
    this.onChange(this.index)
  },

 

 

 

posted @ 2021-02-06 20:24  全情海洋  阅读(297)  评论(0编辑  收藏  举报