tab封装(一)/原理分析/刨析和滚动有关的位置边界处理
2021-03-25 本文已影响0人
Raral
在前端开发中,我们大量使用开源很多UI框架和js框架,让我们使用的越好,做项目越快,但是同时让我们也对最基本的css属性和js最基本和最底层的api都遗忘,所以我们通过自己封装插件和组件,让我们更容易拾起最基本的知识点;以下我会从3个部分总结这个过程:1.原生js和jquery实现基本tab效果,2.使用面向对象js和jquery常用封装方法,3.通过vue封装和优化tab组件
1. 实现简单不滚动切换
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
.container {
width: 100%;
overflow: hidden;
}
ul {
overflow: hidden;
}
ul>li {
text-align: center;
float: left;
box-sizing: border-box;
width: 25%;
border-bottom: 1px solid #eee;
border-left: 1px solid #eee;
line-height: 40px;
position: relative;
}
li::after {
content: "";
height: 0;
width: 0%;
border-bottom: 2px solid #f00;
position: absolute;
left: 50%;
bottom: 0;
transform: translateX(-50%);
transition: all .3s ease;
}
.active {
color: #f00;
}
.active::after {
width: 80%;
}
</style>
</head>
<body>
<div class="container">
<ul>
<li class="item1 ">item1</li>
<li class="item2">item2</li>
<li class="item3">item3</li>
<li class="item4">item4</li>
</ul>
</div>
</body>
<script>
var oContainer = document.querySelector(".container");
var currentLi = null;//记录当前节点
var oLis = document.querySelectorAll("li");
//初始化
currentLi = oLis[0];
currentLi.classList.add("active");
oContainer.addEventListener('click', function(e) {
console.log(e.target == currentLi)
//判断点击的节点和当前节点一样
if(e.target != currentLi) {
currentLi.classList.remove("active");
e.target.classList.add("active")
currentLi = e.target;
}
})
</script>
</html>
2. 实现简单不滚动滑块过渡切换
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
.container {
width: 100%;
overflow: hidden;
}
ul {
overflow: hidden;
position: relative;
}
ul>li {
text-align: center;
float: left;
box-sizing: border-box;
width: 25%;
border-bottom: 1px solid #eee;
border-left: 1px solid #eee;
line-height: 40px;
position: relative;
}
/* 小滑块的线 */
.line_slider {
width: 40px;
height: 3px;
background-color: #f00;
position: absolute;
left: 0;
bottom: 0;
}
</style>
</head>
<body>
<div class="container">
<ul>
<li class="item">item1</li>
<li class="item">item2</li>
<li class="item">item3</li>
<li class="item">item4</li>
<div class="line_slider"></div>
</ul>
</div>
</body>
<script>
var oContainer = document.querySelector(".container");
var oLis = document.querySelectorAll("li");
var oSlider = document.querySelector(".line_slider");
var oW = oContainer.clientWidth || document.body.clientWidth || window.innerWidth;//320
var num = oLis.length;// 4
var itemWidth = oW / num;// 80
var sliderWidth = oSlider.offsetWidth;
//初始化滑块状态
init();
//点击滑块移动
oContainer.addEventListener("click", function(e) {
var cIndex = Array.prototype.findIndex.call(oLis,function(item) {
return item.textContent == e.target.textContent;
})
// 计算出 要想 让滑块初始化到第一个item中间位置,需要向右移动 多少。
sLiderMove(cIndex);
})
//初始化第一次滑块的初始位置
function init() {
let first = calcMidPosition(0, itemWidth, sliderWidth,oW )
oSlider.style.transform = `translateX(${first}px)`
}
// 滑块移动
function sLiderMove(index) {
let offsetLeft = calcMidPosition(index,itemWidth, sliderWidth,oW);
oSlider.style.transition = `all .3s ease`;
oSlider.style.transform = `translateX(${offsetLeft}px)`
}
/*
index: 移动到第几个item, 从 0 开始
itemWith: item的宽度
allWith: 容器总长度
*/
function calcMidPosition(index, itemW, sliderW,allW) {
return index * itemW + (itemW - sliderW) / 2
}
</script>
</html>
3.实现简单滚动切换
- 代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
margin: 0;
}
div {
margin: 0;
}
.ss-scroll-navbar {
white-space: nowrap;
}
.uni-scroll-view {
position: relative;
/* overflow: hidden; */
}
.uni-scroll-view-content {
font-size: 0;
width: 100%;
height: 100%;
transition: all 0.4s;
transform: translateX(0px);
}
.nav-item {
box-sizing: border-box;
height: 38px;
text-align: center;
padding: 0 10px;
color: #303133;
display: inline-block;
position: relative;
font-size: 12px;
background-color: #eee;
}
.title {
display: inline-block;
line-height: 38px;
}
.nav-item::after {
content: "";
width: 0;
height: 0;
border-bottom: 1px solid #1ba035;
position: absolute;
left: 50%;
bottom: 0;
transform: translateX(-50%);
transition: all .3s;
}
.current {
color: #1ba035;
}
.current::after {
width:50%;
}
</style>
</head>
<body>
<div class="ss-scroll-navbar">
<div class="uni-scroll-view">
<div class="uni-scroll-view" style="overflow: auto hidden;">
<div class="uni-scroll-view-content">
<div id="item-0" class="nav-item current"><span class="title">item0</span></div>
<div id="item-1" class="nav-item"><span class="title">item1</span></div>
<div id="item-2" class="nav-item"><span class="title">item2</span></div>
<div id="item-3" class="nav-item"><span class="title">item3</span></div>
<div id="item-4" class="nav-item"><span class="title">item4</span></div>
<div id="item-5" class="nav-item"><span class="title">item5</span></div>
<div id="item-6" class="nav-item"><span class="title">item6</span></div>
<div id="item-7" class="nav-item"><span class="title">item7</span></div>
<div id="item-8" class="nav-item"><span class="title">item8</span></div>
</div>
</div>
</div>
</div>
</body>
<script>
var view = document.querySelector(".uni-scroll-view");
var container = document.querySelector(".uni-scroll-view-content");
var items = document.querySelectorAll(".nav-item");
var cItem = document.querySelectorAll(".nav-item")[0];
var widthList = [];
var scrollWidth = 0;
var screenWith = 0;
//绑定事件
Array.prototype.forEach.call(items, item => {
item.onclick = clickItemHandler;
})
//计算屏幕的宽度
function calculateWidowWith(){
screenWith = document.body.clientWidth || window.innerWidth;
}
//计算每一个item的宽度,放入到一个数组里
function calculateItemWith() {
let arr = [];
Array.prototype.forEach.call(items, function(node){
let cWidth = node.getBoundingClientRect().width;
arr.push(cWidth)
})
widthList = arr;
}
function clickItemHandler(e) {
let index = parseInt(e.currentTarget.id.substring(5));
cItem.classList.remove("current");
items[index].classList.add("current");
cItem = items[index] ;
scrollWidth = 0;
for(var i = 0; i < index + 1; i++) {
scrollWidth += widthList[i];
}
let currentWith = widthList[index];
boundHandler(scrollWidth,currentWith)
}
function boundHandler(scrollWidth,currentWith) {
let allItemWith = widthList.reduce((pre, cur) => {
pre += cur;
return pre;
}, 0)
if(scrollWidth < (screenWith / 2) + (currentWith/2) && scrollWidth >= 0) {
view.style.overflow =" hidden";
container.style.transform = `translateX(0px)`;
}else if(scrollWidth > screenWith /2 + (currentWith/2) ) {
scrollWidth = scrollWidth - screenWith/2 - currentWith/2;
console.log(scrollWidth, allItemWith - screenWith)
//处理最右边不能滚动临界位置
if(scrollWidth <= allItemWith - screenWith) {
view.style.overflow ="auto hidden";
container.style.transform = `translateX(-${scrollWidth}px)`;
}else {
view.style.overflow ="auto hidden";
container.style.transform = `translateX(-${allItemWith - screenWith}px)`;
}
}
}
calculateWidowWith();
calculateItemWith();
</script>
</html>
-
分析滚动边界原理图
888.png
下篇文章基于这篇原理分析tab,实现原生js封装一个tab插件