基于原生js单例模式打造的楼层导航,左右tab实时切换。【硬核】
作者:互联网
<!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>
</head>
<style>
* {
margin: 0;
padding: 0;
}
.maxbox {
width: 1000px;
margin: auto;
}
.nav {
width: 1000px;
height: 240px;
background-image: url('https://tse4-mm.cn.bing.net/th/id/OIP-C.q2IL0JNLOrJIxTvSM_yydAHaEI?w=323&h=180&c=7&r=0&o=5&dpr=1.25&pid=1.7');
background-repeat: no-repeat;
background-size: 100% 100%;
margin-top: 20px;
padding-top: 50px;
box-sizing: border-box;
}
header {
width: 50%;
height: 80%;
margin: auto;
border-radius: 5px;
background: rgba(244, 243, 244, 0.18);
box-shadow: 0 0.3px 0.7px rgba(0, 0, 0, 0.126),
0 0.9px 1.7px rgba(0, 0, 0, 0.179), 0 1.8px 3.5px rgba(0, 0, 0, 0.224),
0 3.7px 7.3px rgba(0, 0, 0, 0.277), 0 10px 20px rgba(0, 0, 0, 0.4);
backdrop-filter: blur(10px);
}
.content #dianying {
background-color: rgb(151, 90, 231);
}
.content #yifu {
background-color: rgb(74, 238, 82);
}
.content #shipin {
background-color: rgb(236, 223, 35);
}
.content #dianqi {
background-color: rgb(230, 46, 236);
}
.content #jiaju {
background-color: rgb(245, 74, 31);
}
.content div {
width: 100%;
height: 500px;
margin: 10px auto;
}
.scrollTopTo {
width: 50px;
height: 120px;
background-color: rgb(34, 143, 231);
box-sizing: border-box;
position: absolute;
top: 205px;
right: 59px;
}
.list p {
width: 100%;
height: 40px;
line-height: 40px;
text-align: center;
background-color: rgb(35, 166, 218);
}
.toTop {
height: 40px;
line-height: 40px;
text-align: center;
background-color: rgb(35, 166, 218);
font-size: 20px;
}
.scrollTopTo p:hover {
cursor: pointer;
}
.toTop:hover {
cursor: pointer;
}
.active {
background-color: rgb(223, 148, 35) !important;
color: red;
}
footer {
width: 100%;
height: 300px;
background-color: rgb(189, 182, 182);
}
</style>
<body>
<div class="maxbox">
<div class="nav">
<header>
<h1>头部</h1>
</header>
</div>
<div class="content">
<!-- 电影 -->
<div id="dianying">
<h1>电影</h1>
</div>
<div id="yifu">
<h1>衣服</h1>
</div>
<div id="shipin">
<h1>食品</h1>
</div>
<div id="dianqi">
<h1>电器</h1>
</div>
<div id="jiaju">
<h1>家具</h1>
</div>
</div>
<div class="scrollTopTo">
<div class="list"></div>
<!-- <p>电影</p>
<p>衣服</p>
<p>食品</p>
<p>电器</p>
<p>家具</p> -->
<div class="toTop">
∧
</div>
</div>
</div>
<footer>
<h1>底部版权信息</h1>
</footer>
</body>
<script>
// jquery 的offset 方法用来拿到距离顶部的高度的
function JqOffset(ele) {
let result = {
top: 0,
left: 0
}
// 当前为 IE11 以下,直接返回 {top: 0, left: 0}
if (!ele.getClientRects().length) {
return result
}
// 当前 DOM 节点的 display === 'none' 时,直接返回 {top: 0, left: 0}
if (window.getComputedStyle(ele)['display'] === 'none') {
return result
}
result = ele.getBoundingClientRect()
var docElement = ele.ownerDocument.documentElement
return {
top: result.top + window.pageYOffset - docElement.clientTop,
left: result.left + window.pageXOffset - docElement.clientLeft
}
}
// 节流方法
function throttle(func, wait = 100) { // 节流的处理
let Timeout
return function () {
if (!Timeout) {
Timeout = setTimeout(function () {
func()
Timeout = null
}, wait)
}
}
}
// 基于单例模式实现模块化开发
let navigationOptions = (function () {
let navigation = document.querySelector('.scrollTopTo')
HTML = document.documentElement
content = document.querySelector('.content')
list = document.querySelector('.list')
maxbox = document.querySelector('.maxbox')
// 初始化导航条的位置
const initPosition = function initPosition() {
// 计算出导航条距离右侧的位置 (HTML.clientWidth - 1000)得出两边的位置 / 2 得出一侧的位置
let n = ((HTML.clientWidth - 1000) / 2 - 75)
if (n < 0) {
navigation.style.display = 'none'
return
}
console.log(n);
navigation.style.display = 'block'
navigation.style.right = n + 'px'
// 随着页面滚动,控制它的定位
console.log(HTML.scrollTop);
if (HTML.scrollTop >= 200) {
console.log('2646555555555555');
navigation.style.position = 'fixed'
navigation.style.top = '20px'
return
}
navigation.style.position = 'absolute'
navigation.style.top = '250px'
}
// 构建数映射模型
let sourceMap = [{
id: 'dianying',
text: '电影',
top: 0,
active: false
}, {
id: 'yifu',
text: '衣服',
top: 1,
active: false
}, {
id: 'shipin',
text: '食品',
top: 2,
active: false
}, {
id: 'dianqi',
text: '电器',
top: 3,
active: false
}, {
id: 'jiaju',
text: '家具',
top: 4,
active: false
},]
let isEdit = false
// 计算每个每个版块的top值
const computedTop = function computedTop() {
sourceMap = sourceMap.map(item => {
let ele = document.querySelector(`#${item.id}`)
item.top = JqOffset(ele).top
console.log(item.top, 'wajroawjkldawwa');
return item
})
}
// 根据对应的数映射模型渲染右侧导航
const renderList = function renderList() {
let str = ``
sourceMap.forEach(item => {
// 这里标签一定给他闭合
str += `<p data-id="${item.id}" class="${item.active ? 'active' : ''} ">${item.text}</p>`
})
list.innerHTML = str
}
const renderContainer = function renderContainer() {
let frag = document.createDocumentFragment()
sourceMap.forEach(item => {
var ele = document.querySelector(`#${item.id}`)
frag.appendChild(ele)
})
content.appendChild(frag)
frag = null
}
// 滚动中哪一个选中
const computedActive = function computedActive() {
if (isEdit) { return }
// 获取滚动的高度
let top = HTML.scrollTop
console.log(top);
// 滚动的时候默认不选中
sourceMap = sourceMap.map(item => {
item.active = false
return item
})
if (top >= sourceMap[sourceMap.length - 1].top) { // 选中最后一个值
sourceMap[sourceMap.length - 1].active = true
} else if (top >= sourceMap[0].top) {// 说明第一个选中
for (let i = 0; i < sourceMap.length; i++) {
let item = sourceMap[i] // 拿到当前的值
next = sourceMap[i + 1] // 拿到下一个值
if (top >= item.top && top < next.top) { // 就让当前的状态等于 true
item.active = true
break
}
}
}
renderList()// 根据对应的数映射模型渲染右侧导航
}
// 点击右边的nav调到指定位置
const clickDelegate = function clickDelegate() {// 右侧导航条的事件
navigation.addEventListener('click', function (e) {
let target = e.target
targetTag = target.tagName
console.log(targetTag);
targetClass = target.classList
// 合并事件源
if (targetTag === "I") {
target = target.parentNode
targetTag = target.tagName
targetClass = target.classList
}
// 回到顶部
if (targetTag == 'DIV' && targetClass.contains('toTop')) {
let n = 30
const timer = setInterval(() => {
if (HTML.scrollTop <= 0) {
clearInterval(timer)
return
}
HTML.scrollTop -= n
}, 0.1)
}
// 这个是右侧的点击事件
if (targetTag == 'P') {
let data_id = target.getAttribute('data-id')
console.log(data_id)
result = sourceMap.find(item => item.id == data_id)
result.active = true
if (result) {
// 这边要以一个一获取坐标的时候没有取正所以有偏差
HTML.scrollTop = result.top + 1
}
}
})
renderList()// 根据对应的数映射模型渲染右侧导航
}
return {
init() {
// 命令业务 控制代码的执行顺序 业务功能
initPosition()
computedTop() // 计算每个版块高度
renderContainer()
clickDelegate() // 右侧导航条的事件
// 窗口改变监听 事件
window.addEventListener('resize', function () {
initPosition()
computedTop() // 计算每个版块高度
})
// 滚动状态频率过快
window.addEventListener('scroll', throttle(function () {
initPosition()
computedActive()
}))
}
}
})()
window.addEventListener('load', navigationOptions.init)
</script>
</html>
标签:function,background,top,js,item,sourceMap,let,tab,硬核 来源: https://blog.csdn.net/qq_54753561/article/details/122795782