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) },