前言
因為以前會經常在一些背景系統中看到這種tab功能,如下:(随便截得一個圖)
剛好我也想做點東西,我就想着自己能不能寫出來,項目位址在後面
需求分析
1、技術
因為我一開始是自己查的資料,然後很多資料都指向
jquery ui
,但是因為是自己造一個,是以我就看了一下他的寫法。
2、功能
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
html布局
<style>
* {
margin: ;
padding: ;
}
li {
list-style: none;
}
a {
text-decoration: none;
}
.warp {
width: %;
height: px;
margin: px auto;
border: px solid #ccc;
display: flex;
}
.left,
.right {
height: %;
box-sizing: border-box;
}
.left {
border-right: px solid #ccc;
width: px;
padding: px;
}
.right {
width: calc(% - px)
}
.topNav {
height: px;
border-bottom: px solid #ccc;
}
.topNav li {
width: rem;
height: px;
display: inline-block;
overflow: hidden;
line-height: px;
}
.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">導航1</a>
</li>
<li class="navItem">
<a href="javascript:void(0)" data-value="./nav2.html">導航2</a>
</li>
<li class="navItem">
<a href="javascript:void(0)" data-value="./nav3.html">導航3</a>
</li>
</ul>
</div>
<div class="right">
<div class="topNav">
<ul id="topNav">
<!-- <li><a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >添加的</a></li>
<li><a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >添加的</a></li> -->
</ul>
</div>
<div class="content" id="content">
</div>
</div>
</div>
1、左側點選新增頁面
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().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 + , url.length - );
let idName = 'tab_' + item;
//防止添加失敗
for(var i = ,l=tabList.length;i<l;i++){
if(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(`<li class="tabNav"><a href="#" class="${idName} active " data-value="${idName}">${text}</a></li>`)
//其餘内容隐藏
$('#'+this.contentId).children().removeClass('active')
//添加主内容
$('#'+this.contentId).append(`<div id="${idName}" class="active"></div>`);
$('#'+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(); // 阻止預設行為
})
效果
2、tab左右滑動點選
造假資料
<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 = ;
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 = ; //标簽總長度
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 == ) {
$('#left').show();
$('#right').show()
$('.topNav').css('padding', '0 20px');
$('.topNav ul').css('left', '25px');
key = ;
this.init(); //重新計算
} else {
itemInfo.tabW = tabW;
itemInfo.itemNum = itemNum;
itemInfo.length = length;
itemInfo.itemIndex = itemIndex-;
itemInfo.itemShowNum = itemIndex;
// console.log(tabW, itemNum, length, itemIndex)
if(key == ){
l = itemInfo.length - itemInfo.tabW;
// console.log(l)
let left = l - ;
$('.topNav ul').css('left', -left);
itemInfo.itemIndex = itemInfo.itemNum -;
// console.log(itemInfo.itemIndex)
}
}
}
//擷取從0到index直接tab的寬度
tabScrool.prototype.getLength = function(index){
let length =;
for(let i = ;i<=index;i++){
length += Math.ceil(parseFloat($('#topNav li').eq(i).outerWidth()));
}
let left = length -itemInfo.tabW -;
if(left<){
left = -
}
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-;
return false;
}else if(itemInfo.itemIndex+ < 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 + >=itemInfo.itemNum){
itemInfo.itemIndex = itemInfo.itemNum-;
}else if(index == ){
itemInfo.itemIndex = itemInfo.itemShowNum-;
}else if(itemInfo.itemIndex - index >= itemInfo.itemShowNum){
let offset = itemInfo.itemIndex - index - itemInfo.itemShowNum +
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 = ;
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 = ; //标簽總長度
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 == ) {
$('#left').show();
$('#right').show()
$('.topNav').css('padding', '0 20px');
$('.topNav ul').css('left', '25px');
key = ;
this.init(); //重新計算
} else {
itemInfo.tabW = tabW;
itemInfo.itemNum = itemNum;
itemInfo.length = length;
itemInfo.itemIndex = itemIndex-;
itemInfo.itemShowNum = itemIndex;
// console.log(tabW, itemNum, length, itemIndex)
if(key == ){
l = itemInfo.length - itemInfo.tabW;
// console.log(l)
let left = l - ;
$('.topNav ul').css('left', -left);
itemInfo.itemIndex = itemInfo.itemNum -;
// console.log(itemInfo.itemIndex)
}
}
}
//擷取從0到index直接tab的寬度
tabScrool.prototype.getLength = function(index){
let length =;
for(let i = ;i<=index;i++){
length += Math.ceil(parseFloat($('#topNav li').eq(i).outerWidth()));
}
let left = length -itemInfo.tabW -;
if(left<){
left = -
}
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-;
return false;
}else if(itemInfo.itemIndex+ < 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 + >=itemInfo.itemNum){
itemInfo.itemIndex = itemInfo.itemNum-;
}else if(index == ){
itemInfo.itemIndex = itemInfo.itemShowNum-;
}else if(itemInfo.itemIndex - index >= itemInfo.itemShowNum){
let offset = itemInfo.itemIndex - index - itemInfo.itemShowNum +
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().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 + , url.length - );
let idName = 'tab_' + item;
//防止添加失敗
for (var i = , 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(
`<li class="tabNav"><a href="#" class="${idName} active " data-value="${idName}">${text}</a></li>`
)
//其餘内容隐藏
$('#' + this.contentId).children().removeClass('active')
//添加主内容
$('#' + this.contentId).append(`<div id="${idName}" class="active"></div>`);
$('#' + 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