《Vue.j实战》一书 p117 页练习 1 & 2 试做源代码

Demo 在线效果浏览

练习1 : 给pane 组件新增一个prop: closable 的布尔值, 来支持是否可以关闭这个pane , 如
果开启, 在tabs 的标签标题上会有一个关闭的按钮。

提示:初始化pane 时我们是在 mounted里通知的,关闭时,你会用到 beforedestroy

练习2 : 尝试在切换pane 的显示与隐藏时,使用滑动的动画。提示: 可以使用css 3 的transform:
translateX 。

IDE:VScode

项目由 main.js, app.vue, tabs.vue, pane.vue 4个文件构成。

main.js(略)

app.vue:

<template>
  <div id="app">
    <tabs v-model="activeKey" @on-click="handleOnclick" @on-close="handleOnclose">
      
      <pane v-for="item in pans" 
      :key="item.mes"
      :label="item.label"
      :name="item.name"
      :closable="item.closable"
      >
        {{item.mes}}
      </pane>
    </tabs>
  </div>
</template>
<script>
import tabs from './components/tabs';
import pane from './components/pane';
export default {
  components:{
    tabs,
    pane
  },
  data(){
    return{
      activeKey:'1',
      pans:[
        {
          label:'标签一',
          name:'1',
          closable:true,
          mes:'标签一的内容'
        },
        {
          label:'标签二',
          name:'2',
          closable:true,
          mes:'标签二的内容'
        },
        {
          label:'标签三',
          name:'3',
          closable:true,
          mes:'标签三的内容'
        },
      ]
    }
  },

  methods:{
    handleOnclick(name){

    },
    handleOnclose(name){
        var index=0;
        for(var i=0;i<this.pans.length;i++)    {
          if(this.pans[i].name===name){
            index=i;
            break;
          }
        }
        this.pans.splice(index,1);
    }
  },
  beforeDestroy(){
    this.$off('on-click',this.handleOnclick);
    this.$off('on-close',this.handleOnclose);
  }
}
</script>

tabs.vue(不含style)

<template>
    <div class="tabs">
        <div class="tabs-bar">

            <div
            :class="tabCls(item)"
            v-for="(item, index) in navList"
            :key="item.name"
            @click.self="handleChange(index)">
            {{ item.label }}
            <template v-if="item.closable">
            <a href="#" class="del" v-show="item.name===currentValue"
            @click="handleClose(item,index)"
            >x</a>
            </template>
            </div>

         </div>
            <div class="tabs-content">
                <slot></slot>
            </div>
    </div>
</template>
<script>
export default {
    props:{
        value:{
            type:[String, Number]
        },
    },
    data(){
        return{
            currentValue:this.value,
            navList:[]
        }
    },
    methods:{
        handleClose(item,index){
            this.navList.splice(index,1);
            //console.log(this.navList.length);
            var name = item.name;
            //console.log(name)
            this.handleChange(0)
            this.$emit('on-close',name);            
        },
        tabCls(item){
            return[
                'tabs-tab',
                {
                    'tabs-tab-active':item.name === this.currentValue
                }
            ]
        },
        getTabs(){
            return this.$children.filter(function(item){
                return item.$options.name === 'pane';
            });
        },
        updateNav(){
            this.navList=[];
            var _this = this;

            this.getTabs().forEach(function(pane, index){
                _this.navList.push({
                    label:pane.label,
                    name: pane.name || index,
                    closable:pane.closable
                });
                if(!pane.name) pane.name = index;
                if(index === 0){
                    if(!_this.currentValue){
                        _this.currentValue = pane.name || index;
                    }
                }
            });
            this.updateStatus();
        },
        updateStatus(){
            var tabs = this.getTabs();
            var _this = this;

            tabs.forEach(function(tab){
                return tab.show = tab.name === _this.currentValue;
            })
        },
        handleChange(index){
            if(this.navList.length){
            var nav = this.navList[index];            
            var name = nav.name;
            //console.log(name)
            this.currentValue = name;
            this.$emit('input',name);
            this.$emit('on-click',name);
            }
        }
    },
    watch:{
        value(val){
            this.currentValue = val;
        },
        currentValue(){
            this.updateStatus();
        }
    },

}
</script>

pane.vue

<template>
<transition name="fade" mode="out-in">

    <div class="pane" v-show="show">
        <slot></slot>
    </div>

</transition>
</template>
<script>
export default {
    name:'pane',
    data(){
        return{
            show:true
        }
    },
    props:{
        name:{
            type:String
        },
        label:{
            type:String,
            default:''
        },
        closable:{
            type:Boolean,
            default:true
        }
    },
    methods:{
        updateNav(){
            this.$parent.updateNav();
        }
    },
    watch:{
        label(){
            this.updateNav();
        },

    },
    mounted(){
        this.updateNav();
    },
    beforeDestroy(){
        
    }
}
</script>
<style>
.pane{
    display: inline-block;
}
 .fade-enter-active,.fade-leave-active{
     position: absolute;
     transition: all .8s ease;
}
.fade-enter, .fade-leave-to{
    transform: translateX(100px);
    opacity: 0;
}
</style>
原文地址:https://www.cnblogs.com/sx00xs/p/11322346.html