使用tabs还是使用路由
1 .单页面应用中,一个页面中选项卡太多的话,是把所有的逻辑写在一个组件中,用tabs组件,还是拆分称过多个路由比较好。
2 .在Vue里面使用动态组件
3 .算了,都实现一遍,到时候选吧。做完这个看下路由的高级
4 .分享的时候无法准确定位每个tab
动态组件
1 .为什么vue的出名组件库,组件的写法都使用了jsx
核心代码:内外解耦的情况下
<div class="tabs">
<div class="tab-nav">
<div
v-for="tab in tablist"
//传入一个数组,里面包含了要导航的信息
:class=" tabIndex == tab.index ? 'tabs-active' : '' "
//通过当前tab的index,和传入的currentindex两个变量来判断当前该选那个组件,这个是tab的css渲染,要是之前就要在这里面包一个v-if来判断,现在使用跟这个就简单了
@click="changeTab(tab)"
//每一次点击切换的事件
>
{{tab.name}}
</div>
</div>
</div>
//第一部分:切换按钮选项
<transition name="component-fade" mode="out-in" class="tabs-content">
<keep-alive>
//缓存之前渲染过的tabitem
<slot></slot>
//使用slot动态分发下面的item
</keep-alive>
</transition>
组件使用:
<tabs
:tablist="tablist"
:tabIndex="tabIndex"
@changeTab="changeTab"
>
<component :is="currentContent">
</component>
</tabs>
tablist:[
{
index:0,
name:'选项1',
component:'one'
},{
index:1,
name:'选项2',
component:'two'
}
],
tabIndex:0,
currentContent:'one'
功能实现
1 .切换的过渡,要顺滑,或者有配置参数可以选择
2 .位置:通过配置参数来对布局进行定位
3 .动态增加标签?真实的项目会有需求么?
4 .切换到tab加载数据,数据传递。
5 .这个和走马灯的区别
6 .页签要可以加图标
7 .鼠标选中页面icon会动。
8 .鼠标切入,相应文字按钮出现复杂动画。比如标签进来的动画,按钮的border-top变颜色,如果使用active来操作的话,非常的不自然,所以需要加个辅助元素。使用i标签。
9 .js去掉字符串的最后两位str.substring(0,str.length-3)
支持传入的css参数
1 .整个tab的宽,高
2 .上面转换标签的高度,下面的显示是自适应
vue缺点
1 .style绑定的时候,return 的时候是不能使用transform,这个里面是不能返回函数的。
2 .这样就可以通过切换class来实现。但是切换class需要提前写好样式。还是直接写style可以
3 .其实通过配置项是很容易改写组件的布局样式,主要是代码的量变多,所以在实际写的时候还是需要结合项目实际的需求,在传入配置需求和实际项目之间进行取舍。
4 .
遇到问题
1 .svg图标使用animejs进行动画的时候会出现残留,只能使用js操作style来模拟了。。
2 .鼠标mouse事件
3 .缓动函数参考 https://easings.net/zh-cn
<template>
<div :style="tabs" class="tabs">
<div
:style="tabsNav"
class="tabs-nav">
<div
v-for='tab in tablist'
:class=" tabIndex == tab.index ? 'tabs-active' : '' "
@mouseenter="changeTab(tab,$event)"
@mouseleave="outSome()"
class="tabs-item"
>
<span>{{tab.name}}</span>
<svg v-if="tab.icon" class="icon tabsicon" aria-hidden="true">
<use :xlink:href="tab.icon"></use>
</svg>
</div>
<i
class="iactive-top"
:style="activeTop"
></i>
</div>
<div class="tabs-content">
<transition name="component-fade" mode="out-in" >
<keep-alive>
<slot></slot>
</keep-alive>
</transition>
</div>
</div>
</template>
<script>
import anime from 'animejs'
export default {
data:function(){
return {
left:0,
}
},
props:{
tablist:{
type:Array,
require:true,
},
tabIndex:{
type:Number,
require:true,
},
tabswh:{
type:Object,
default:function(){
return {
w:'478',
h:'460',
navh:'60px',
navw:'100',
}
}
},
type:{
type:String,
default:'youzuo'
}
},
methods:{
changeTab:function(tab,event){
this.$emit('changeTab',tab)
this.left=tab.index;
let _this=this
if(tab.icon){
event.stopPropagation()
this.svgSrc=event.target.querySelector('svg')
// this.svgSrc.style.left='3px'
this.anime=anime({
targets:this.svgSrc,
left:'5px',
easing: 'easeInQuint',
duration:100,
})
}
},
outSome:function(){
this.anime=anime({
targets:this.svgSrc,
left:'0px',
duration:0,
})
}
},
computed:{
tabs:function(){
if(this.type=='default'||this.type=="xiashang"){
// 上下
return {
'width':this.tabswh.w+'px',
'height':this.tabswh.h+'px',
'flex-direction': 'column'
}
}else if(this.type=="zuoyou"||this.type=="youzuo"){
// 左右
return {
'width':this.tabswh.w+'px',
'height':this.tabswh.h+'px',
'just-content':'center'
}
}
},
//整体布局
tabsNav:function(){
if(this.type=='default'){
return{
height:this.tabswh.navh,
'flex-direction':'row'
}
}else if(this.type=="zuoyou"){
return {
width:this.tabswh.navw+'px',
'flex-direction':'column'
}
}else if(this.type=="youzuo"){
return {
width:this.tabswh.navw+'px',
'flex-direction':'column',
order:2
}
}else if(this.type=="xiashang"){
return{
height:this.tabswh.navh,
'flex-direction':'row',
order:2
}
}
},
//标签的样式
activeTop:function(){
if(this.type=="default"||this.type=='xiashang'){
let width=Math.ceil(this.tabswh.w/this.tablist.length)
return{
'width':width+'px',
left:this.left*width+'px',
height: '3px',
top:0,
}
}
if(this.type=="youzuo"||this.type=="zuoyou"){
let height=Math.ceil(this.tabswh.h/this.tablist.length)
return {
'height':height+'px',
width:'3px',
right:0,
top:this.left*height+'px'
}
}
},
//横线有关的样式
iwidth:function(){
// console.log(Math.ceil(this.tabswh.w/this.tablist.length))
// return Math.ceil(this.tabswh.w/this.tablist.length)
}
},
mounted:function(){
// console.log(this.activeTop)
}
}
</script>
<style>
.component-fade-enter-active, .component-fade-leave-active{
transition: opacity .3s ease;
}
.component-fade-enter, .component-fade-leave-to{
opacity: 0;
}
.tabs{
display: flex;
}
.tabs-nav{
display: flex;
position: relative;
}
.tabs-item{
display: flex;
justify-content: center;
align-items: center;
flex:1;
color:#3c3c3c;
text-overflow: ellipsis;
white-space: normal;
font-family: 'fantasy';
cursor: pointer;
font-size: 16px;
border-top:transparent solid 3px;
}
.tabs-item span{
/* flex:1;
height: 100%; */
}
.tabs-active{
color:#f24854;
}
.iactive-top{
position:absolute;
background: #f24854;
transition:all ease .3s;
}
.tabs-content{
flex:1
}
.tabsicon{
position: relative;
transition:all 0.2s ease-in-out;
/* left: 3px; */
}
</style>
未来要做
1 .含有下拉菜单的选项卡
2 .含有翻页的选项卡,一般来说这么多就够了,6个页签了。。
3 .标签文字产生换行的时候,最多可以有两行
4 .切换的滚动画面,现在是淡入淡出的,左右移动的。
5 .