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>

下篇文章基于这篇原理分析tab,实现原生js封装一个tab插件

上一篇 下一篇

猜你喜欢

热点阅读