前沿
小编在开发项目过程中遇到一个交互的需求,带动画的Navbar,就是类似于element-ui的tabs标签页的动画效果,由于种种原因吧,小编就开始自己搞了一个,在这过程中发现了<slot></slot>
插槽这个非常有价值的鬼,于是就开始研究了,终于搞了一个可以复用的组件,分享出来大家一块学习。
声明:
slot 的介绍在代码中会有体现,话不多说,上代码。
1,新建一个公共的承载NavBar的组件,这里起名为NavBar.vue,这个公共的组件中主要是NavBar中的Title以及点击事件和一些动画效果的实现,为了实现真正意义上的组件,这里将所需要的内容以插槽(slot)的形式插入到NavBar这个组件中,以达到灵活控制。
<template>
<div class="MBslidebar">
<div class="TopNavbarTitle">
<div class="NavbarTitle" v-for="(item,index) in Navtabs" :class="{'NavbarTitleActive':activeIndex == index }" @click="tabClick(index,$event)">{{item}}</div>
<div class="navbar__slider" v-bind:style="{'transform':'translate3d('+sliderOffset+'px,0,0)'}"></div>
</div>
<div class="NavBarBody">
<p>第一个slot</p>
<!-- 加入name="first"属性与父组件中的<span slot="first">我的slot</span>相呼应达到插槽的作用范围的控制 -->
<slot name="first"></slot>
<p>第二个slot</p>
<!-- 若要给插槽内传值,在slot中写入:activeIndex="activeIndex"(类似于父子组件传值,这里要注意的是接受的时候用到的是【slot-scope="props"】接受,再引用的页面会有体现。) -->
<slot name="second" :activeIndex="activeIndex"></slot>
</div>
</div>
</template>
<script>
export default{
props:['Navtabs'],
data(){
return{
activeIndex: 0,
sliderOffset: 0,
}
},
methods:{
tabClick(index,e){
this.sliderOffset = e.currentTarget.offsetLeft;
this.activeIndex = index;
}
}
}
</script>
<style>
.MBslidebar {
width: 500px;
height: 200px;
border: 1px solid;
position: relative;
}
.TopNavbarTitle {
width: 100%;
height: 50px;
position: absolute;
z-index: 500;
top: 0;
}
.TopNavbarTitle:hover{
cursor: pointer;
}
.NavbarTitle{
width: 25%;
height: 50px;
float: left;
line-height: 50px;
text-align: center;
}
.NavbarTitleActive{
color: #f08300;
}
/* 这个是切换的动画,采用css3来控制 */
.navbar__slider {
position: absolute;
content: " ";
left: 0px;
bottom: 0;
width: 25%;
height: 3px;
background-color: #f08300;
-webkit-transition: -webkit-transform 0.3s;
transition: -webkit-transform 0.3s;
transition: transform 0.3s;
transition: transform 0.3s, -webkit-transform 0.3s;
}
.NavBarBody{
margin-top: 60px;
}
.navbar-content-item{
width: 500px;
height: 100px;
border: 1px solid red;
}
</style>
2,新建一个你要引用的页面,这是叫homepage.vue
<template>
<div class="mytemplate">
<p>我是引用页面</p>
<navbar :Navtabs="tabseve">
<!-- 这就是之前所说的与前边相呼应的地方,为了控制slot的作用范围,加上slot="first",与NavBar.vue中的 <slot name="first"></slot>呼应 -->
<span slot="first">我的slot</span>
<!-- 第一种是直接将html插入到NavBar.vue 中,然后再引用页面直接操作就ok. -->
<div class="NavBarBody" slot="second" slot-scope="props">
<p>{{props.activeIndex}}</p>
<div class="navbar-content-item" v-show="props.activeIndex == 0">我是微信充值slot</div>
<div class="navbar-content-item" v-show="props.activeIndex == 1">我是充值卡充值</div>
<div class="navbar-content-item" v-show="props.activeIndex == 2">我是充值记录</div>
<div class="navbar-content-item" v-show="props.activeIndex == 3">我是充值明细</div>
</div>
<!-- 第二种是将另一个组件插入到NavBar.vue 中 -->
<!-- 这里就是跟父子组件通信不一样的地方,slot-scope="props"为接受过来的值,然后再通过:slotTochild="props"传到Content页面 -->
<NavContent slot="second" slot-scope="props" :slotTochild="props"></NavContent>
</navbar>
</div>
</template>
<script>
import navbar from './BaseNav.vue'
import NavContent from './itemContent.vue'
export default{
components:{
navbar,
NavContent
},
data(){
return{
tabseve:["微信充值", "充值卡充值", "充值记录","充值明细"]
}
}
}
</script>
<style>
</style>
3,若采用将组件插入的形式,需要再建一个页面叫itemContent.vue,这里主要是展示切换的选项卡的内容
<template>
<div class="NavBarBody" >
<p>{{slotTochild}}</p>
<div class="navbar-content-item" v-show="slotTochild.activeIndex == 0">我是微信充值</div>
<div class="navbar-content-item" v-show="slotTochild.activeIndex == 1">我是充值卡充值</div>
<div class="navbar-content-item" v-show="slotTochild.activeIndex == 2">我是充值记录</div>
<div class="navbar-content-item" v-show="slotTochild.activeIndex == 3">我是充值明细</div>
</div>
</template>
<script>
export default{
props:['activeIndex','slotTochild'],
data(){
return{
}
}
}
</script>
<style>
.NavBarBody{
margin-top: 60px;
}
.navbar-content-item{
width: 500px;
height: 100px;
border: 1px solid red;
}
</style>
至此整个功能就完成了,这里边主要的收获还是slot插槽的使用,虽然不是特别的透彻,但还是理解了一部分,目前的使用是木有问题的,后续在更新自己的理解。有什么错误希望多多指正。