Vue 标签页组件

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xukongjing1/article/details/86560317

效果:

 index.html

<html>
 <head> 
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
  <title>标签页组件</title>
  <style>
  [v-cloak]{
  	display: none;
  }
  .tabs{
	  font-size:14px;
	  color:#657180;
	}
	.tabs-bar:after{
	  content: '';
	  display: block;
	  width:100%;
	  height:1px;
	  background:#d7dde4;
	  margin-top:-1px;
	}
	.tabs-tab{
	  display: inline-block;
	  padding:5px 10px;
	  border:1px solid #d7dde4;
	  margin:0 10px;
	}
	.tabs-tab-active{
	  color:#3399ff;
	  border-top:2px solid #3399ff;
	  border-bottom:1px solid #fff;
	}
	.tabs-tab-active:before{
	  content:'';
	  display: inline;
	  height:1px;
	  background:#3399ff;
	  position: absolute;
	  top:0;
	  left:0;
	  right:0;
	}
	.tabs-content{
	  padding: 8px 0;
	}
	</style>
 </head> 
 <body> 
  <div id="app" v-cloak> 
    <tabs v-model="activeKey">
	    <pane label='标签一' name="1">
	      <h1>ReactNative </h1>
	      <p>使用JavaScript和React编写原生移动应用</p>
	    </pane>
	    <pane label='标签二' name="2">
	    	<p>重磅 | iView 发布 3.0 版本,以及开发者社区等 5 款新品</p>
	    </pane>
	    <pane label='标签三' name="3">
	    	<h6>
	    		Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
	    	</h6>
	    </pane>
	  </tabs>
  </div>  
<script src = "../lib/vue.min.js" ></script> 
<script src = "pane.js" ></script> 
<script src = "tabs.js" ></script> 
<script>
var app = new Vue({
  el: '#app',
  data: {
    activeKey: '1'
  }
}) 
</script> 
 </body>
</html>

tabs.js

Vue.component('tabs',{
  name: 'pane',
  template:`
    <div class="tabs">
      <div class="tabs-bar">
        <!-- 标签页标题,这里要用 v-for -->
        <div :class='tabCls(item)' v-for="(item,index) in navList" :key='index' @click="handleChange(index)">
          {{item.label}}
        </div>
      </div>
      <div class="tabs-content">
        <!-- 这里的slot就是嵌套的pane -->
        <slot></slot>
      </div>
    </div>
  `,
  props:{
    value :{type:[String,Number]}
  },
  data(){
    return{
      //用于渲染 tabs 的标题
      navList: [],
      //因为不能修改 value,所以复制一份自己维护
      currentValue: this.value,
    }
  },
  methods:{
    tabCls(item){
      return[
        'tabs-tab',
        {
          //给当前选中的tab 加一个 class
          'tabs-tab-active': item.name === this.currentValue
        }
      ]
    },
    handleChange(index){
      var nav = this.navList[index];
      var {name} = nav;
      //改变当前选中的tab,并触发下面的 watch
      this.currentValue = name;
      //更新 value
      this.$emit('input', name);
      //触发一个自定义事件,供父级使用
      this.$emit('on-click', name);
    },
    getTabs(){
      //通过遍历子组件,得到所有的 pane 组件
      return this.$children.filter((item)=>{
        return item.$options.name === 'pane';
      })
    },
    updateNav(){
      this.navList = [];
      this.getTabs().forEach((pane, index)=>{
        this.navList.push({
          label: pane.label,
          name: pane.name || index
        })
        //如果没有给 pane 设置 name,默认设置它的索引
        if(!pane.name) pane.name = index;
        //设置当前选中的tab 的索引,
        if(index === 0){
          if(!this.currentValue){
            this.currentValue = pane.name || index;
          }
        }
      })
      this.updateStatus();
    },
    updateStatus(){
      var tabs = this.getTabs();
      tabs.forEach((tab)=>{
        return tab.show = tab.name === this.currentValue;
      })
    }
  },
  watch:{
    value(val){
      this.currentValue = val;
    },
    currentValue(){
      //在当前选中的 tab 发生变化时,更新pane的显示状态
      this.updateStatus();
    }
  }
})


pane.js 

Vue.component('pane',{
  name: 'pane',
  template:`
    <div class="pane" v-show="show">
      <slot></slot>
    </div>
  `,
  props:{
    name: {type: String},
    label: {type: String, default: ''}
  },
  data(){
    return{
      show: true,
    }
  },
  methods: {
    updateNav(){
      this.$parent.updateNav();
    }
  },
  watch:{
    label(){
      this.updateNav();
    }
  },
  mounted() {
    this.updateNav();
  },
})


猜你喜欢

转载自blog.csdn.net/xukongjing1/article/details/86560317