因为以前会经常在一些后台系统中看到这种tab功能,如下:(随便截得一个图)
刚好我也想做点东西,我就想着自己能不能写出来,项目地址在后面
因为我一开始是自己查的资料,然后很多资料都指向jquery ui
,但是因为是自己造一个,所以我就看了一下他的写法。
1、左边点击新增页面和tab标签(不能重复添加)
2、tab标签过多会自动隐藏并且左侧点击后平滑到视野范围内
3、tab标签有左右移动、点击选中当前页
ajax_tabs--|
|--index.html (暂定版)
|--index1_1.html (左侧新增页面功能拆分)
|--index1.html (原始左侧新增)
|--index2_1.html (tab滑动功能拆分)
|--index2.html (tab滑动原始)
|--index3.html (失败版)
|--nav1.html
|--nav2.html
|--nav3.html
|--nav4.html
|--nav5.html
<style>
* {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
a {
text-decoration: none;
}
.warp {
width: 50%;
height: 400px;
margin: 20px auto;
border: 1px solid #ccc;
display: flex;
}
.left,
.right {
height: 100%;
box-sizing: border-box;
}
.left {
border-right: 1px solid #ccc;
width: 200px;
padding: 20px;
}
.right {
width: calc(100% - 200px)
}
.topNav {
height: 50px;
border-bottom: 1px solid #ccc;
}
.topNav li {
width: 3rem;
height: 50px;
display: inline-block;
overflow: hidden;
line-height: 50px;
}
.content>div.active{
display:block;
}
.content>div{
display:none;
}
.topNav li>a.active,.navItem>a.active{
color:red;
}
style>
<div class="warp">
<div class="left">
<ul>
<li class="navItem">
<a href="javascript:void(0)" data-value="./nav1.html">导航1a>
li>
<li class="navItem">
<a href="javascript:void(0)" data-value="./nav2.html">导航2a>
li>
<li class="navItem">
<a href="javascript:void(0)" data-value="./nav3.html">导航3a>
li>
ul>
div>
<div class="right">
<div class="topNav">
<ul id="topNav">
ul>
div>
<div class="content" id="content">
div>
div>
div>
index1_1.htm
l
//初始化 首页或者什么页
var tabs = (function(){
//存储已打开的页面
let tabList = [];
//命名 右上角id 内容块id,导航li的类名
function tabs(obj){
this.contentId = obj.contentId;
this.tabId = obj.tabId;
this.navClass = obj.nav;
}
//初始化
tabs.prototype.init = function(){
let elClass = '.' + this.navClass;
let el = $(elClass).eq(0).find('a')
this.addTo(el)
}
//添加新内容
tabs.prototype.addTo = function(el){
$(el).addClass('active').parent().siblings().find('a').removeClass('active')
let url = $(el).attr('data-value');
let text = $(el).text();
let index = url.lastIndexOf('/');
let item = url.substring(index + 1, url.length - 5);
let idName = 'tab_' + item;
//防止添加失败
for(var i = 0,l=tabList.length;iif(tabList[i] == idName){
this.sameNav(idName)
return;
}
}
//存储已存在的
tabList.push(idName);
this.addContent(idName,url,text);
}
//添加内容
tabs.prototype.addContent = function(idName,url,text){
//添加tab选项
$('#'+this.tabId).find('a').removeClass('active')
$('#'+this.tabId).append(`"tabNav">"#" class="${idName} active " data-value="${idName}">${text} `)
//其余内容隐藏
$('#'+this.contentId).children().removeClass('active')
//添加主内容
$('#'+this.contentId).append(`"${idName}" class="active">`);
$('#'+idName).load(url);
},
//点击已存在的tab
tabs.prototype.sameNav = function(idName){
$('#'+idName).addClass('active').siblings().removeClass('active')
$('.'+idName).addClass('active').parent().siblings().find('a').removeClass('active');
}
return tabs;
})();
var test = new tabs({contentId:'content',tabId:'topNav',nav:'navItem'})
test.init();
$('.navItem>a').bind('click', function () {
test.addTo(this);
});
$('body').on('click', '.tabNav>a', function (e) {
if($(this).hasClass('activ')){
return;
}
let idName = $(this).attr('data-value');
test.sameNav(idName)
e.stopPropagation(); // 阻止事件冒泡
e.preventDefault(); // 阻止默认行为
})
造假数据
<ul id="topNav">
<li class="tabNav">
<a href="#" class="">导航一a>
li>
<li class="tabNav">
<a href="#" class="">导航二a>
li>
<li class="tabNav">
<a href="#" class="">导航三a>
li>
<li class="tabNav">
<a href="#" class="">导航一一a>
li>
<li class="tabNav">
<a href="#" class="">导航一二a>
li>
<li class="tabNav">
<a href="#" class="">导航一三a>
li>
<li class="tabNav">
<a href="#" class="">导航二一a>
li>
<li class="tabNav">
<a href="#" class="">导航二二a>
li>
<li class="tabNav">
<a href="#" class="">导航二三a>
li>
<li class="tabNav">
<a href="#" class="">导航三一a>
li>
<li class="tabNav">
<a href="#" class="">导航三二a>
li>
<li class="tabNav">
<a href="#" class="">导航三三a>
li>
ul>
index2_1.html
var tabScrool = (function () {
let key = 0;
let itemInfo = {
tabW: '',//tab内容块的宽度
itemNum: '',//标签个数
length: '',//标签总长度
itemIndex: '',//当前完整显示的最右边的index值
itemShowNum: '', //能够完整显示几个
}
function tabScrool() {
}
tabScrool.prototype.init = function () {
let tabW = parseFloat($('.topNav').width()) //获取tab内容块的宽度
let itemNum = $('#topNav li').length; //标签个数
let length = 0; //标签总长度
let itemIndex = itemNum; //标签页能够完整第几个
$('#topNav li').each(function () {
if (length < tabW) {
length += Math.ceil(parseFloat($(this).outerWidth()));
if (length > tabW) {
itemIndex = $(this).index();
}
}else{
length += Math.ceil(parseFloat($(this).outerWidth()));
}
})
// console.log(tabW, itemNum, length, itemIndex)
if (itemIndex < itemNum && key == 0) {
$('#left').show();
$('#right').show()
$('.topNav').css('padding', '0 20px');
$('.topNav ul').css('left', '25px');
key = 1;
this.init(); //重新计算
} else {
itemInfo.tabW = tabW;
itemInfo.itemNum = itemNum;
itemInfo.length = length;
itemInfo.itemIndex = itemIndex-1;
itemInfo.itemShowNum = itemIndex;
// console.log(tabW, itemNum, length, itemIndex)
if(key == 1){
l = itemInfo.length - itemInfo.tabW;
// console.log(l)
let left = l - 20;
$('.topNav ul').css('left', -left);
itemInfo.itemIndex = itemInfo.itemNum -1;
// console.log(itemInfo.itemIndex)
}
}
}
//获取从0到index直接tab的宽度
tabScrool.prototype.getLength = function(index){
let length =0;
for(let i = 0;i<=index;i++){
length += Math.ceil(parseFloat($('#topNav li').eq(i).outerWidth()));
}
let left = length -itemInfo.tabW -20;
if(left<0){
left = -25
}
return left;
}
tabScrool.prototype.goDir = function(dir){
itemInfo.itemIndex = dir == 'left' ? --itemInfo.itemIndex : ++itemInfo.itemIndex
if(itemInfo.itemIndex>=itemInfo.itemNum){
// console.log(1)
itemInfo.itemIndex = itemInfo.itemNum-1;
return false;
}else if(itemInfo.itemIndex+1 < itemInfo.itemShowNum){
// console.log(2)
itemInfo.itemIndex = itemInfo.itemShowNum;
return false;
}
let left = this.getLength(itemInfo.itemIndex);
$('.topNav ul').css('left', -left);
console.log(itemInfo.itemIndex)
}
tabScrool.prototype.goIndex = function(index){
// console.log(index)
if(index +1 >=itemInfo.itemNum){
itemInfo.itemIndex = itemInfo.itemNum-1;
}else if(index == 0){
itemInfo.itemIndex = itemInfo.itemShowNum-1;
}else if(itemInfo.itemIndex - index >= itemInfo.itemShowNum){
let offset = itemInfo.itemIndex - index - itemInfo.itemShowNum +1
itemInfo.itemIndex = itemInfo.itemIndex - offset;
}else{
itemInfo.itemIndex = index;
}
let left = this.getLength(itemInfo.itemIndex);
$('.topNav ul').css('left', -left);
}
return tabScrool;
})()
var tabTop = new tabScrool();
tabTop.init();
$('.tabNav a').bind('click', function () {
let index = $(this).parent().index();
//tab点击
tabTop.goIndex(index)
})
//按钮绑定
$('#left').bind('click', function () {
tabTop.goDir('left')
})
$('#right').bind('click', function () {
tabTop.goDir('right')
})
index.html
这里就两点,一个是将tab初始放在添加新页面方法里面;一个是左侧点击,如果已存在标签,则标签会平滑到视野内。
var tabScrool = (function () {
let key = 0;
let itemInfo = {
tabW: '',//tab内容块的宽度
itemNum: '',//标签个数
length: '',//标签总长度
itemIndex: '',//当前完整显示的最右边的index值
itemShowNum: '', //能够完整显示几个
}
function tabScrool() {
}
tabScrool.prototype.init = function () {
let tabW = parseFloat($('.topNav').width()) //获取tab内容块的宽度
let itemNum = $('#topNav li').length; //标签个数
let length = 0; //标签总长度
let itemIndex = itemNum; //标签页能够完整第几个
$('#topNav li').each(function () {
if (length < tabW) {
length += Math.ceil(parseFloat($(this).outerWidth()));
if (length > tabW) {
itemIndex = $(this).index();
}
}else{
length += Math.ceil(parseFloat($(this).outerWidth()));
}
})
// console.log(tabW, itemNum, length, itemIndex)
if (itemIndex < itemNum && key == 0) {
$('#left').show();
$('#right').show()
$('.topNav').css('padding', '0 20px');
$('.topNav ul').css('left', '25px');
key = 1;
this.init(); //重新计算
} else {
itemInfo.tabW = tabW;
itemInfo.itemNum = itemNum;
itemInfo.length = length;
itemInfo.itemIndex = itemIndex-1;
itemInfo.itemShowNum = itemIndex;
// console.log(tabW, itemNum, length, itemIndex)
if(key == 1){
l = itemInfo.length - itemInfo.tabW;
// console.log(l)
let left = l - 24;
$('.topNav ul').css('left', -left);
itemInfo.itemIndex = itemInfo.itemNum -1;
// console.log(itemInfo.itemIndex)
}
}
}
//获取从0到index直接tab的宽度
tabScrool.prototype.getLength = function(index){
let length =0;
for(let i = 0;i<=index;i++){
length += Math.ceil(parseFloat($('#topNav li').eq(i).outerWidth()));
}
let left = length -itemInfo.tabW -24;
if(left<0){
left = -25
}
return left;
}
tabScrool.prototype.goDir = function(dir){
itemInfo.itemIndex = dir == 'left' ? --itemInfo.itemIndex : ++itemInfo.itemIndex
if(itemInfo.itemIndex>=itemInfo.itemNum){
// console.log(1)
itemInfo.itemIndex = itemInfo.itemNum-1;
return false;
}else if(itemInfo.itemIndex+1 < itemInfo.itemShowNum){
// console.log(2)
itemInfo.itemIndex = itemInfo.itemShowNum;
return false;
}
let left = this.getLength(itemInfo.itemIndex);
$('.topNav ul').css('left', -left);
console.log(itemInfo.itemIndex)
}
tabScrool.prototype.goIndex = function(index){
// console.log(index)
if(index +1 >=itemInfo.itemNum){
itemInfo.itemIndex = itemInfo.itemNum-1;
}else if(index == 0){
itemInfo.itemIndex = itemInfo.itemShowNum-1;
}else if(itemInfo.itemIndex - index >= itemInfo.itemShowNum){
let offset = itemInfo.itemIndex - index - itemInfo.itemShowNum +1
itemInfo.itemIndex = itemInfo.itemIndex - offset;
}else{
itemInfo.itemIndex = index;
}
let left = this.getLength(itemInfo.itemIndex);
$('.topNav ul').css('left', -left);
}
return tabScrool;
})()
var tabTop = new tabScrool();
//初始化 首页或者什么页
var tabs = (function () {
//存储已打开的页面
let tabList = [];
//命名 右上角id 内容块id,导航li的类名
function tabs(obj) {
this.contentId = obj.contentId;
this.tabId = obj.tabId;
this.navClass = obj.nav;
}
//初始化
tabs.prototype.init = function () {
let elClass = '.' + this.navClass;
let el = $(elClass).eq(0).find('a')
this.addTo(el)
}
//添加新内容
tabs.prototype.addTo = function (el) {
$(el).addClass('active').parent().siblings().find('a').removeClass('active')
let url = $(el).attr('data-value');
let text = $(el).text();
let index = url.lastIndexOf('/');
let item = url.substring(index + 1, url.length - 5);
let idName = 'tab_' + item;
//防止添加失败
for (var i = 0, l = tabList.length; i < l; i++) {
if (tabList[i] == idName) {
this.sameNav(idName)
tabTop.goIndex(i)
return;
}
}
//存储已存在的
tabList.push(idName);
this.addContent(idName, url, text);
//计算tab宽度
tabTop.init();
}
//添加内容
tabs.prototype.addContent = function (idName, url, text) {
//添加tab选项
$('#' + this.tabId).find('a').removeClass('active')
$('#' + this.tabId).append(
`"tabNav">"#" class="${idName} active " data-value="${idName}">${text} `
)
//其余内容隐藏
$('#' + this.contentId).children().removeClass('active')
//添加主内容
$('#' + this.contentId).append(`"${idName}" class="active">`);
$('#' + idName).load(url);
},
//点击已存在的tab
tabs.prototype.sameNav = function (idName) {
$('#' + idName).addClass('active').siblings().removeClass('active')
$('.' + idName).addClass('active').parent().siblings().find('a').removeClass('active');
}
return tabs;
})();
var test = new tabs({
contentId: 'content',
tabId: 'topNav',
nav: 'navItem'
})
test.init();
$('.navItem>a').bind('click', function () {
test.addTo(this);
});
$('#left').bind('click', function () {
tabTop.goDir('left')
})
$('#right').bind('click', function () {
tabTop.goDir('right')
})
$('body').on('click', '.tabNav>a', function (e) {
if ($(this).hasClass('activ')) {
return;
}
let idName = $(this).attr('data-value');
test.sameNav(idName)
let index = $(this).parent().index();
//tab点击
tabTop.goIndex(index)
e.stopPropagation(); // 阻止事件冒泡
e.preventDefault(); // 阻止默认行为
})
至此,一个小demo出现了,不过还有不足,比如标签页的删除,不过我觉得这是小问题了(手动笑脸)
项目:ajax_tabs
演示:ajax_tabs