06#Web 实战:可滑动的标签页
实现效果图

本随笔只是记录一下大概的实现思路,如果感兴趣的小伙伴可以通过代码和本随笔的说明去理解实现过程。我的 Gitee 和 GitHub 地址。注意哦:这个只是 PC 上的标签页,手机端的没用,因为监听器是 mouse,而不是手势。在线浏览地址:标签页。
构建静态页面
可滑动的页面需要 5 个 div,标签也需要 5 个。只有页面是随着我们操作而变化,标签处于静态,标签下面有一个滑块也是随着我们操作而变化。所以,构建基本的 HTML 骨架如下:
<div>
<!-- 标签 -->
<div class="tab-bar flex-space">
<div class="bar-item flex-center">标签5</div>
<div class="bar-item flex-center">标签1</div>
<div class="bar-item flex-center">标签2</div>
<div class="bar-item flex-center">标签3</div>
<div class="bar-item flex-center">标签4</div>
<!-- 滑块 -->
<div class="slider"></div>
</div>
<!-- 标签页 -->
<div class="tab-page">
<div class="page-item page-5">Index 5</div>
<div class="page-item page-1">Index 1</div>
<div class="page-item page-2">Index 2</div>
<div class="page-item page-3">Index 3</div>
<div class="page-item page-4">Index 4</div>
</div>
</div>
我写的这个标签页的起始标签是5,而不是标签1。下面直接给上默认的 CSS,如果不全,就去仓库找:
.tab-bar {
width: 100%;
height: 40px;
position: relative;
margin-bottom: 8px;
}
.bar-item {
margin: 0;
padding: 0;
cursor: pointer;
}
.slider {
position: absolute;
background-color: #5677fc;
transform: translateX(0%);
width: 35px;
height: 3px;
background-color: blue;
border-radius: 3px;
bottom: 0;
transition: all 0.2s ease-in-out;
}
.tab-page {
overflow-x: hidden;
position: relative;
width: 100%;
height: calc(100vh - 64px);
transition: all 0.2s ease-in-out;
transform: translate(0%, 0px) translateZ(0px);
}
.page-item {
cursor: pointer;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
transition: all 0.5s ease-in-out;
text-align: center;
font-size: 50px;
}
.page-1 {
background-color: rgb(169, 187, 228);
}
.page-2 {
background-color: #5677fc;
}
.page-3 {
background-color: rgb(101, 192, 225);
}
.page-4 {
background-color: rgb(153, 60, 235);
}
.page-5 {
background-color: coral;
}
slider 滑块通过transform: translateX()来平移,默认滑块所在位置是标签1 的位置,现在的问题是如何定义滑块默认的位置、以及每一次往前移动一个标签需要多少距离。
实现滑块的移动
获取 tab-bar 滑块容器的宽度,并且去除容器的 padding 和 margin 值,计算每一个标签所占的长度是多少:
let tabbarWidth = $(".tab-bar").width();
let barItemLength = $(".tab-bar").find("div").length - 1;
let barItemPerWidth = tabbarWidth / barItemLength;
滑块的宽度是 35px,假设一个标签的宽度是 99px。要让这个滑块处于标签的中间,就得让滑块左边缘定在如下图所示的地方:

标签的一半再减去滑块的一半就是滑块左边缘的位置,从而使得滑块处于标签的中央。滑块的宽度可以用一个变量来代替,可以考虑让滑块自适应 tab-bar 容器宽度,这里就用实际数字了:
let sliderTranslateX = barItemPerWidth / 2 - 35 / 2;
滑块往前移动,移动多少呢?实际可以如下图这样思考,第一个标签往前移动了一个标签的长度,相当于滑块也跟随着这个标签往前移动,来到了下一个标签的位置。当然,这个标签是不会动的,只有滑块在移动。

滑块往前移动一次,到下一个标签,实际就是 sliderTranslateX + barItemPerWidth。前面说了,滑块默认在标签1 的下面:
$(".slider").css({ transform: `translateX(${sliderTranslateX + barItemPerWidth}px)` });
刷新页面,如下图所示,滑块来到了标签1 的下面:

现在,实现点击事件,往前(往右)挨个点击标签,滑块跟随我们点击的位置进行平移。
let moveTranslateX = 0;
function moveSlider(index) {
// 0 1 2 3 4 5 6
// 17 77 137 207 .. .. ..
moveTranslateX = sliderTranslateX + barItemPerWidth * index;
$(".slider").css({ transform: `translateX(${moveTranslateX}px)` });
}
$(".tab-bar")
.find(".bar-item")
.each((index, elem) => {
// 平均地设置每一个 tabBar 的宽度
$(elem).css({ width: `${barItemPerWidth}px` });
// 给每一个 tabBar 添加踢点击事件
$(elem).on("click", e => {
moveSlider(index);
});
});
主要看moveSlider()这个函数,通过 each 遍历每一个标签,并给其注册一个点击事件,点击事件中,给 moveSlider 传递当前标签的 index(索引值)。假设,index 大于 0,说明我们是往前挨个点击着走的,那么,moveTranslateX 的值就是 sliderTranslateX 加上 barItemPerWidth,以及乘以 index。

index 是 1,就是往前滑动一个标签的距离。但目前,我们只可能(只考虑往前点击)从 index 1 开始点击,所以 index 是 2,滑块从标签5 的位置往前移动了两个标签的距离,来到了标签3 的底下:

Now!滑块的移动功能就已经实现了:

实现页面的滑动
往前滑动
我是把页面放在数组里面进行思考的。第一行是初始的状态,5、1、2、3、4 标签页在数组中排着。往前拉(鼠标往右滑动)标签页1、2、3、4 的 index 依次往前 +1;唯独标签页5 排在数组末尾处。

继续往前拉,标签页2、3、4、5 的 index 依次往前 +1;标签页1 排在数组末尾处。依次类推,直到第5行的下一次,才跳回到第1行继续循环上面的规律。
第1行变成第2行的样子,要经历 5 次排序,每一次排序都会破坏原有的数组结构,因此我在写的时候,定义了两个空数组,一个用来存储之前的顺序,且不改变这个数组的结构和顺序,排序完成之后的元素依次插入到第二个数组中。
let tempTabPageBox = [];
let movedTabPageBox = [];
这里还考察到了一个知识点,JS 中对象通过等号赋值是地址引用,而不是拷贝。所以,我这里用的
new Array(...arr)来拷贝了一份新的数组对象给第二个数组。我推荐看对象引用和复制来理解对象的拷贝知识。
原本我用的是JSON.parse(JSON.stringfy(arr))拷贝一个数组,但是这种方式会丢失很多 DOM 原本的字段。因为,数组里面存储的是一个个 DOM 对象,所以这种方式拷贝不适用于现在的情况。所以,我就改用了new Array(...arr)来 new 一个新数组,可能会导致性能降低,因为一直都在 new 数组,不过 JS 应该会给我回收垃圾吧?
tempTabPageBox 存储上一次的数组顺序和结构,movedTabPageBox 保存排序之后的顺序和结构。
function movePageToRight() {
for (let i = 0; i < tempTabPageBox.length; i++) {
if (i > 0) movedTabPageBox[i - 1] = tempTabPageBox[i];
else movedTabPageBox[tempTabPageBox.length - 1] = tempTabPageBox[i];
}
for (let i = 0; i < movedTabPageBox.length; i++) {
$(movedTabPageBox[i]).css({ transform: `translate(${tabPageTranslateX[i]}%, 0px) translateZ(0px)`, "z-index": 999 });
}
tempTabPageBox = new Array(...movedTabPageBox);
}
$(".tab-page")
.find(".page-item")
.each((index, elem) => {
// 初始化每一个 page 到暂存容器中
tempTabPageBox.push(elem);
// 初始化 page-item
if (index == 0) {
$(elem).css({ transform: `translate(${tabPageTranslateX[0]}%, 0px) translateZ(0px)`, "z-index": 999 });
} else {
$(elem).css({ transform: `translate(${tabPageTranslateX[index]}%, 0px) translateZ(0px)`, "z-index": 999 });
}
$(elem).on("mousedown", e => {
e.preventDefault();
$(elem).on("mouseup", e => {
if (/* 往右拉 */) {
movePageToRight();
} else if (/* 往左拉 */) {
movePageToLeft();
}
$(elem).unbind("mousemove");
});
});
});
这里贴上的代码省略了很多细节啊!但主要还是看movePageToRight()函数。结合上面说的和图片,每一次都是第一个元素被直接放在了末尾处,其余的元素依次往前移动。函数中第二个 for 是根据排序好的 movedTabPageBox 依次设置页面的 translate,实现平移。最后再把这一次的排序结果拷贝给 tempTabPageBox,然后等待下一次的循环。
往后滑动

如上图,往后滑动(也就是往左拉)每一行的数组变化情况。只有最后一个元素排在了第一位,其余的元素依次往后 +1。
function movePageToLeft() {
for (let i = 0; i < tempTabPageBox.length; i++) {
if (i >= 0 && i < tempTabPageBox.length - 1) {
movedTabPageBox[i + 1] = tempTabPageBox[i];
} else if (i === tempTabPageBox.length - 1) {
movedTabPageBox[0] = tempTabPageBox[i];
}
}
for (let i = 0; i < movedTabPageBox.length; i++) {
$(movedTabPageBox[i]).css({ transform: `translate(${tabPageTranslateX[i]}%, 0px) translateZ(0px)`, "z-index": 999 });
}
tempTabPageBox = new Array(...movedTabPageBox);
}
其余的代码和movePageToRight()函数是一样的,没有什么变化。
连接滑块和标签页
到目前为止,滑块的移动和标签页的移动都是独立的,现在要做的就是把他们连接起来。后面我也不想多写了,滑块移动的时候要把这个 index 赋值给一个全局的 index,标签页移动也是一样,而且还要记录上一次的 index。
通过一顿骚操作,把代码写出来,就实现了这个小案例了。具体还是看我仓库的代码吧 Gitee 和 GitHub 地址。
06#Web 实战:可滑动的标签页的更多相关文章
- 06#Web 实战:实现可滑动的标签页
实现效果图 本随笔只是记录一下大概的实现思路,如果感兴趣的小伙伴可以通过代码和本随笔的说明去理解实现过程.我的 Gitee 和 GitHub 地址.注意哦:这个只是 PC 上的标签页,手机端的没用,因 ...
- web前端中实现多标签页切换的效果
在这里,实现多标签页效果的方法有两个,一个是基于DOM的,另一个是基于jquery的,此次我写的是一个对于一个电话套餐的不同,显示不同的标签页 方法一: 首先,我们要把页面的大体框架和样式写出来,ht ...
- jquery实战---标签页效果
在前面的博客中,小编主要简单的介绍了jquery的一些基本知识,今天这篇博文,小编继续来学习jquery的相关知识,今天我们来学习一个标签页的小例子,相关源码小编已经上传,有需要的小伙伴可以自己去下载 ...
- Android Viewpager+Fragment实现滑动标签页
ViewPager 结合Fragment实现一个Activity里包含多个可滑动的标签页,每个标签页可以有独立的布局及响应. 主页布局 <?xml version="1.0" ...
- 07#Web 实战:实现 GitHub 个人主页项目拖拽排序
实现效果图 GitHub 和 Gitee 个人主页中可以对自己的项目进行拖拽排序,于是我就想自己实现一个.本随笔只是记录一下大概的实现思路,如果感兴趣的小伙伴可以通过代码和本随笔的说明去理解实现过程. ...
- 两个标签页定位第二个标签页元素时显示element not visible
问题描述 web页面有两个标签页, 当转换到第二个标签页定位元素时, 显示element not visible. 代码 ... //省略 WebElement ele= browser.getEle ...
- 实战Jquery(四)--标签页效果
这两天完毕了实战四五六的样例,实例四是标签页的实现方法,实例五是级联菜单下拉框,实例六是窗体效果,都是web层经常使用的效果.越到后面越发认为技术这东西,就是一种思路的展现,懂了要实现 ...
- Web编程基础--HTML、CSS、JavaScript 学习之课程作业“仿360极速浏览器新标签页”
Web编程基础--HTML.CSS.JavaScript 学习之课程作业"仿360极速浏览器新标签页" 背景: 作为一个中专网站建设出身,之前总是做静态的HTML+CSS+DIV没 ...
- jquery插件之tab标签页或滑动门
该插件乃本博客作者所写,目的在于提升作者的js能力,也给一些js菜鸟在使用插件时提供一些便利,老鸟就悠然地飞过吧. 此插件旨在实现目前较为流行的tab标签页或滑动门特效,在此插件中默认使用的是鼠标滑过 ...
- [置顶] JQuery实战总结三 标签页效果图实现
在浏览网站时我们会看到当我们鼠标移到多个选项卡上时,不同的选项卡会出现自己对应的界面的要求,在同一个界面上表达了尽量多的信息.大大额提高了空间的利用率.界面的切换效果也是不错的哦,这次自己可以实现啦. ...
随机推荐
- 2.6:Python数据存取-文件、文件夹及目录、数据库
一.Python文件读写 1.文件的打开模式 <class '_io.TextIOWrapper'>和<class '_io.BufferedReader'>.python使用 ...
- 【重难点总结】DMA与kafka零拷贝机制之间的关系
一.DMA介绍 1.概念 DMA(Direct Memory Access,直接存储器访问) 是一种内存访问技术,独立于CPU, 直接读.写系统存储器.外设等 主存与I/0设备之间使用DMA控制器控制 ...
- 【Phoenix】简介、架构、存储、入门、常用表操作、表的映射方式、配置二级索引
一.Phoenix简介 1.定义 构建在 HBase 之上的开源 SQL 层 可以使用标准的 JDBC API 去建表, 插入数据和查询 HBase 中的数据 避免使用 HBase 的客户端 API ...
- JavaScript Promises, async/await
new Promise() 的时候,传一个 executor 给 Promise. let promise = new Promise(function(resolve, reject) { // t ...
- 【Java面试指北】反射(1) 初识反射
如果你被问到:什么是反射?为什么需要反射.以及反射的应用?你会如何回答呢? 本篇会带大家初识反射,了解反射概念和基本应用.反射的原理以及深入源码的探究将会在后面几篇介绍. 一.什么是反射? 要理解什么 ...
- Django框架:8、聚合查询、分组查询、F与Q查询、ORM查询优化、ORM事务操作、ORM常用字段类型、ORM常用字段参数
Django 数据库 目录 Django 数据库 一.聚合查询 二.分组查询 三.F查询与Q查询 1.F查询 2.Q查询 3.Q查询进阶操作 四.ORM查询优化 1.only与defer 五.ORM事 ...
- 注意看,她叫小美,在地址栏输入URL地址后发生了什么?
注意看,这个用户叫小美,他在地址栏输入了一串URL地址,然后竟然发生了不可思议的事情! 01.输入URL发生了什么? 从输入URL开始,到页面呈现出来,简单来说分为四个步骤: ① 建立连接:建立与服务 ...
- buuctf_Dest0g3_crypto
babyAES: 题目如下: from Crypto.Cipher import AES import os iv = os.urandom(16) key = os.urandom(16) my_a ...
- TCS34725 颜色传感器设备驱动程序
一.概述 以前的传感器是用过中断的方式进行计数的,现在已经有 I2C 通行的颜色传感器,不在需要我们像之前那样,通过计数的方式获取数据,直接通过I2C读取即可.当然有通过串口的方式获取采集数据的,串口 ...
- sikulix___自动化办公___重复性_机械性_的电脑操作___python脚本___Java运行环境下德jar包完成自动化测试相关___截图编程控制键盘鼠标
sikulix___自动化办公___重复性_机械性_的电脑操作___python脚本___Java运行环境下德jar包完成自动化测试相关___截图编程控制键盘鼠标 应用场景: 公司内的大佬更改了xml ...