vue/tab切换

1,143 阅读2分钟

页面使用时

<Tabs :currentIndex="currentIndex" @onIndexChange="getIndex">
  <Tab index="1" tabName="标题1">
    <div>内容1</div>
  </Tab>
  <Tab index="2" tabName="标题2">
    <div>内容2</div>
  </Tab>
  <Tab index="3" tabName="标题3">
    <div>内容3</div>
  </Tab>
</Tabs>

<script>
export default {
  name: 'App',
  data(){
    return{
      currentIndex:0
    }
  },
  methods:{
    getIndex(index){
      this.currentIndex = index
    }
  }
}
</script>

定义为全局组件index.js

import Tabs from "./tabs"
import Tab from "./tab"
export default (Vue) => {
    Vue.component(Tabs.name,Tabs)
    Vue.component(Tab.name,Tab)
}

在主入口文件main.js中引入

import Tabs from './components/Tabs/index'
Vue.use(Tabs)

tabs.vue

<script>
import Content from "./content";
export default {
    name: "Tabs",
    data() {
        return {
            contents:[]
        };
    },
    components: {
        Content
    },
    props: {
        currentIndex: {
            type: [String, Number],
            default: "0"
        }
    },
    methods: {
        onChangeIndex(index) {
            this.$emit("onIndexChange", index);
        }
    },
    render() {
        return (
                <div>
                    <ul class="tabs-header">{this.$slots.default}</ul>
                    <Content contents={ this.contents }/>
                </div>
        );
    }
};
</script>

tab.vue

<script>
export default {
    name: "Tab",
    data() {
        return {};
    },
    props: {
        index: {
            type: [String, Number],
            default: "1"
        },
        tabName:{
            type:String,
            default:"tab"
        }
    },
    mounted() {
        // this:当前组件
        this.$parent.contents.push(this);
    },
    computed: {
        active() {
            return this.$parent.currentIndex == this.index;
        }
    },
    methods:{
        clickTabHandler(){
            this.$parent.onChangeIndex(this.index);
        }
    },
    render() {
        let className = {
            tab: true,
            active: this.active
        };
        return <li class={className} onClick={this.clickTabHandler}>{ this.tabName }</li>;
    }
};
</script>

content.vue

<script>
export default {
    name:"Content",
    data(){
        return{

        }
    },
    props:{
        contents:{
            type:Array
        }
    },
    render(){
        return(
            <div>
                {
                    this.contents.map((element,index) => {
                        return (
                            <div>
                                { element.active ? element.$slots.default : '' }
                            </div>
                        )
                    })
                }
            </div>
        )
    }
}
</script>

1. 使用页面中homeTab.vux:

Tabs

  • 动态绑定:currentIndex='currentIndex'

  • 点击事件发生时,重新设置currentIndex

<Tabs :currentIndex="currentIndex" @onchangeIndex="getIndex">
data() {
    return {
      currentIndex: 0,
      tabData: []
    };
},
methods: {
    getIndex(index) {
      this.currentIndex = index;
    }
}

Tab

通过网络请求获取数据tabData,循环遍历生成Tab,绑定index,tabName传送给Tab.vux

import axios from "axios";
mounted() {
    const _this = this;
    function newsList() {
      return _this.$api.getMusicList({
        method: "baidu.ting.billboard.billList",
        type: 1,
        size: 5,
        offset: 0
      });
    }
    function oldList() {
      return _this.$api.getMusicList({
        method: "baidu.ting.billboard.billList",
        type: 2,
        size: 5,
        offset: 0
      });
    }
    function classicList() {
      return _this.$api.getMusicList({
        method: "baidu.ting.billboard.billList",
        type: 22,
        size: 5,
        offset: 0
      });
    }
    axios.all([newsList(), oldList(), classicList()]).then(
      axios.spread((newsListData, oldListData, classicListData) => {
        _this.tabData.push(
          newsListData.data,
          oldListData.data,
          classicListData.data
        );
      })
    );
  }

例子:

<template>
  <div class="tabs">
    <Tabs :currentIndex="currentIndex" @onchangeIndex="getIndex">
      <Tab
        v-for="(element,index) in tabData"
        :key="index"
        :index="index"
        :tabName="element.billboard.name"
      >
        <div class="panel hotsongs on">
          <ul class="list">
            <li class="song url" v-for="(item,index) in element.song_list" :key="index">
              <div class="poster">
                <img :src="item.pic_big" :alt="item.title" />
              </div>
              <div class="info">
                <div class="name">{{ item.title }}</div>
                <div class="author">{{ item.artist_name }}</div>
              </div>
            </li>
          </ul>
          <div class="more-songs url">查看该榜单&gt;</div>
        </div>
      </Tab>
    </Tabs>
  </div>
</template>
<script>
import axios from "axios";
export default {
  name: "HomeTab",
  data() {
    return {
      currentIndex: 0,
      tabData: []
    };
  },
  methods: {
    getIndex(index) {
      this.currentIndex = index;
    }
  },
  mounted() {
    const _this = this;
    function newsList() {
      return _this.$api.getMusicList({
        method: "baidu.ting.billboard.billList",
        type: 1,
        size: 5,
        offset: 0
      });
    }
    function oldList() {
      return _this.$api.getMusicList({
        method: "baidu.ting.billboard.billList",
        type: 2,
        size: 5,
        offset: 0
      });
    }
    function classicList() {
      return _this.$api.getMusicList({
        method: "baidu.ting.billboard.billList",
        type: 22,
        size: 5,
        offset: 0
      });
    }
    axios.all([newsList(), oldList(), classicList()]).then(
      axios.spread((newsListData, oldListData, classicListData) => {
        console.log(newsListData, oldListData, classicListData);
        _this.tabData.push(
          newsListData.data,
          oldListData.data,
          classicListData.data
        );
      })
    );
  }
};

2. Tabs.vux中引入Content组件,并传递数据contents,通过自定义事件将当前点击的index传入使用页面

例子:

<script>
import Content from './content'
export default {
    name:'Tabs',
    data(){
        return{
            contents:[]
        }
    },
    components:{Content},
    render(){
        return(
            <div>
                <ul class="tabs-header">{this.$slots.default}</ul>
                <Content contents={this.contents}/>
            </div>
        )
    },
    props:{
        currentIndex:{
            type:[String,Number]
        }
    },
    methods:{
        changeIndex(index){
            this.$emit('onchangeIndex',index)
        }
    },
   
}
</script>

3. Tab.vux

接收index,tabName;

调用父组件中的事件,将当前index传递过去;

调用父组件的currentIndex,设置当前选中的li的样式;

将当前组件保存在conten中,供content渲染页面;

例子:

<script>
export default {
  name: "Tab",
  props: {
    tabName: {
      type: String,
      default: 'tab'
    },
    index: {
      type: [Number, String],
      default: 0
    }
  },
  mounted() {
    this.$parent.contents.push(this);
  },
  computed: {
    active() {
      return this.$parent.currentIndex == this.index;
    }
  },
  methods: {
    clickEvent() {
      this.$parent.changeIndex(this.index);
    }
  },
  render() {
    let className = {
      tab: true,
      active: this.active
    };
    return (
      <li class={className} onClick={this.clickEvent}>
        {this.tabName}
      </li>
    );
  }
};
</script>
<style>
.tab {
  flex: 1;
  list-style: none;
  line-height: 40px;
  margin-right: 30px;
  position: relative;
  text-align: center;
}

.tab.active {
  border-bottom: 2px solid blue;
}
</style>

4. content.vue

通过class的true/false决定当前显示内容

<script>
export default {
    name:'Content',
    props:{
        contents:{
            type:Array
        }
    },
    render(){
        return(
            <div>
                {
                    this.contents.map((ele,index)=>{
                        return (
                            <div>
                                {
                                    ele.active?ele.$slots.default:''
                                }
                            </div>
                        )
                    })
                }
            </div>
        )
    }
}
</script>