底部栏菜单动态切换

底部栏动态切换

底部动态栏样式仓库

1.创建页面

底部栏基础样式

1-2.HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div class="menu-box">
<div class="menu-item active">
<i class="menu-icon home"></i>
<span>首页</span>
</div>
<div class="menu-item">
<i class="menu-icon discover"></i>
<span>发现</span>
</div>
<div class="menu-item">
<i class="menu-icon search"></i>
<span>探索</span>
</div>
<div class="menu-item">
<i class="menu-icon my"></i>
<span>我的</span>
</div>
</div>

1-2.CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
:root {
--iconSize: 80px;
--borderW: 10px;
--bgClr: #f0f0f0;
--actClr: cadetblue;
--actTextClr: #ffffff;
}
.menu {
&-box {
width: 600px;
height: 80px;
background: var(--bgClr);
border-radius: 10px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
justify-content: space-around;
}
&-item {
width: 25%;
text-align: center;
position: relative;
z-index: 9;
span {
display: none;
}
}
&-icon {
width: var(--iconSize);
height: var(--iconSize);
background-repeat: no-repeat;
background-size: 40%;
background-position: 50%;
margin: 0 auto;
display: inline-block;
&.home {
background-image: url("./imgs/home.svg");
}
&.discover {
background-image: url("./imgs/discover.svg");
}
&.search {
background-image: url("./imgs/search.svg");
}
&.my {
background-image: url("./imgs/my.svg");
}
}
}

2.添加选中样式

底部栏选中样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
.menu {
&-item {
// ...
&.active {
.menu-icon {
transform: translate(0, -50%);
animation: active 1s;
}
@keyframes active {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(0, -50%);
}
}
span {
display: block;
color: var(--actTextClr);
transform: translate(0, -30px);
}
}
&:nth-child(1).active ~ .menu-indicator {
left: 12.5%;
}
&:nth-child(2).active ~ .menu-indicator {
left: 12.5% + 25%;
}
&:nth-child(3).active ~ .menu-indicator {
left: 12.5% + 2 * 25%;
}
&:nth-child(4).active ~ .menu-indicator {
left: 12.5% + 3 * 25%;
}
}
&-indicator {
width:var(--iconSize);
height: var(--iconSize);
border-radius: 50%;
box-sizing: border-box;
border: var(--borderW) solid #ffffff;
background-color: var(--actClr);
position: absolute;
transform: translate(-50%, -50%);
&:before {
content: '';
width: 20px;
height: 20px;
background: #f0f0f0;
border-top-right-radius: 20px;
display: inline-block;
position: absolute;
left: -27px;
bottom: 10px;
box-shadow: 0 -10px 0 0 #ffffff;
}
&:after {
content: '';
width: 20px;
height: 20px;
background: #f0f0f0;
border-top-left-radius: 20px;
display: inline-block;
position: absolute;
right: -27px;
bottom: 10px;
box-shadow: 0 -10px 0 0 #ffffff;
}
}
}

3.添加动态切换样式

3-1.根据当前选中的标签和之前选中的标签动态切换样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
let current = 0
const menus = document.getElementsByClassName('menu-item')
for (let i = 0; i < menus.length; i++) {
const menu = menus[i]
menu.addEventListener('click', e => {
e.preventDefault()
changeTab(i)
})
}
function changeTab(index) {
if (index === current) {
return
}
const menus = document.getElementsByClassName('menu-item')
if (!menus.length) {
return
}
for (let i = 0; i < menus.length; i++ ) {
if (i === index) {
menus[i].classList.add('active')
}else {
menus[i].classList.remove('active')
}
}
current = index
}

3-2.为动态切换添加动画效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
function changeTab(index) {
// ...
for (let i = 0; i < menus.length; i++ ) {
if (i === index) {
// ...
setKeyframes(`move${index + 1}`, current, index)
document.getElementsByClassName('menu-indicator')[0].style.animation = `move${index + 1} 1s`
}else {
// ...
}
}
// ...
}
function setKeyframes(key_name, current, index) {
const token = window.WebKitCSSKeyframesRule ? '-webkit-':'';
const nameRule = getKeyframes(key_name);
let rules = `
@${token}keyframes ${key_name}{
0% {
left: ${12.5 + 25 * current}%
}
100% {
left: ${12.5 + 25 * index}%;
}
}
`
if(JSON.stringify(nameRule) == '{}'){
document.styleSheets[0].insertRule(rules,0);
}else{
nameRule.styleSheet.deleteRule(nameRule.index)
nameRule.styleSheet.insertRule(rules,nameRule.index)
}
}
function getKeyframes(name){
const animation={}
const styleSheets=document.styleSheets
for(let i=0;i<styleSheets.length;i++){
const item = styleSheets[i];
for (let j = 0; j < item.cssRules.length; j ++) {
if(item.cssRules[j] && item.cssRules[j].name && item.cssRules[j].name == name){
animation.cssRule = item.cssRules[j];
animation.styleSheet = item;
animation.index = j;
}
}
}
return animation;
}

底部栏菜单动态切换

全部代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
let current = 0
const menus = document.getElementsByClassName('menu-item')
for (let i = 0; i < menus.length; i++) {
const menu = menus[i]
menu.addEventListener('click', e => {
e.preventDefault()
changeTab(i)
})
}
function changeTab(index) {
if (index === current) {
return
}
const menus = document.getElementsByClassName('menu-item')
if (!menus.length) {
return
}
for (let i = 0; i < menus.length; i++ ) {
if (i === index) {
menus[i].classList.add('active')
setKeyframes(`move${index + 1}`, current, index)
document.getElementsByClassName('menu-indicator')[0].style.animation = `move${index + 1} 1s`
}else {
menus[i].classList.remove('active')
}
}
current = index
}
function setKeyframes(key_name, current, index) {
const token = window.WebKitCSSKeyframesRule ? '-webkit-':'';
const nameRule = getKeyframes(key_name);
let rules = `
@${token}keyframes ${key_name}{
0% {
left: ${12.5 + 25 * current}%
}
100% {
left: ${12.5 + 25 * index}%;
}
}
`
if(JSON.stringify(nameRule) == '{}'){
document.styleSheets[0].insertRule(rules,0);
}else{
nameRule.styleSheet.deleteRule(nameRule.index)
nameRule.styleSheet.insertRule(rules,nameRule.index)
}
}
function getKeyframes(name){
const animation={}
const styleSheets=document.styleSheets
for(let i=0;i<styleSheets.length;i++){
const item = styleSheets[i];
for (let j = 0; j < item.cssRules.length; j ++) {
if(item.cssRules[j] && item.cssRules[j].name && item.cssRules[j].name == name){
animation.cssRule = item.cssRules[j];
animation.styleSheet = item;
animation.index = j;
}
}
}
return animation;
}

源码

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>BottomNavigationMenu</title>
<link rel="stylesheet/less" type="text/css" href="./style.less" />
<script src="https://cdn.jsdelivr.net/npm/less@4.1.2/dist/less.min.js" ></script>
</head>
<body>
<div class="menu-box">
<div class="menu-item active">
<i class="menu-icon home"></i>
<span>首页</span>
</div>
<div class="menu-item">
<i class="menu-icon discover"></i>
<span>发现</span>
</div>
<div class="menu-item">
<i class="menu-icon search"></i>
<span>探索</span>
</div>
<div class="menu-item">
<i class="menu-icon my"></i>
<span>我的</span>
</div>
<div class="menu-indicator"></div>
</div>
<script>
let current = 0
const menus = document.getElementsByClassName('menu-item')
for (let i = 0; i < menus.length; i++) {
const menu = menus[i]
menu.addEventListener('click', e => {
e.preventDefault()
changeTab(i)
})
}
function changeTab(index) {
if (index === current) {
return
}
const menus = document.getElementsByClassName('menu-item')
if (!menus.length) {
return
}
for (let i = 0; i < menus.length; i++ ) {
if (i === index) {
menus[i].classList.add('active')
setKeyframes(`move${index + 1}`, current, index)
document.getElementsByClassName('menu-indicator')[0].style.animation = `move${index + 1} 1s`
}else {
menus[i].classList.remove('active')
}
}
current = index
}
function setKeyframes(key_name, current, index) {
const token = window.WebKitCSSKeyframesRule ? '-webkit-':'';
const nameRule = getKeyframes(key_name);
let rules = `
@${token}keyframes ${key_name}{
0% {
left: ${12.5 + 25 * current}%
}
100% {
left: ${12.5 + 25 * index}%;
}
}
`
if(JSON.stringify(nameRule) == '{}'){
document.styleSheets[0].insertRule(rules,0);
}else{
nameRule.styleSheet.deleteRule(nameRule.index)
nameRule.styleSheet.insertRule(rules,nameRule.index)
}
}
function getKeyframes(name){
const animation={}
const styleSheets=document.styleSheets
for(let i=0;i<styleSheets.length;i++){
const item = styleSheets[i];
for (let j = 0; j < item.cssRules.length; j ++) {
if(item.cssRules[j] && item.cssRules[j].name && item.cssRules[j].name == name){
animation.cssRule = item.cssRules[j];
animation.styleSheet = item;
animation.index = j;
}
}
}
return animation;
}
</script>
</body>
</html>

CSS

使用less

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
:root {
--iconSize: 80px;
--borderW: 10px;
--bgClr: #f0f0f0;
--actClr: cadetblue;
--actTextClr: #ffffff;
}
.menu {
&-box {
width: 600px;
height: 80px;
background: var(--bgClr);
border-radius: 10px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
justify-content: space-around;
}
&-item {
width: 25%;
text-align: center;
position: relative;
z-index: 9;
span {
display: none;
}
&.active {
.menu-icon {
transform: translate(0, -50%);
animation: active 1s;
}
@keyframes active {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(0, -50%);
}
}
span {
display: block;
color: var(--actTextClr);
transform: translate(0, -30px);
}
}
&:nth-child(1).active ~ .menu-indicator {
left: 12.5%;
}
&:nth-child(2).active ~ .menu-indicator {
left: 12.5% + 25%;
}
&:nth-child(3).active ~ .menu-indicator {
left: 12.5% + 2 * 25%;
}
&:nth-child(4).active ~ .menu-indicator {
left: 12.5% + 3 * 25%;
}
}
&-icon {
width: var(--iconSize);
height: var(--iconSize);
background-repeat: no-repeat;
background-size: 40%;
background-position: 50%;
margin: 0 auto;
display: inline-block;
&.home {
background-image: url("./imgs/home.svg");
}
&.discover {
background-image: url("./imgs/discover.svg");
}
&.search {
background-image: url("./imgs/search.svg");
}
&.my {
background-image: url("./imgs/my.svg");
}
}
&-indicator {
width:var(--iconSize);
height: var(--iconSize);
border-radius: 50%;
box-sizing: border-box;
border: var(--borderW) solid #ffffff;
background-color: var(--actClr);
position: absolute;
transform: translate(-50%, -50%);
&:before {
content: '';
width: 20px;
height: 20px;
background: #f0f0f0;
border-top-right-radius: 20px;
display: inline-block;
position: absolute;
left: -27px;
bottom: 10px;
box-shadow: 0 -10px 0 0 #ffffff;
}
&:after {
content: '';
width: 20px;
height: 20px;
background: #f0f0f0;
border-top-left-radius: 20px;
display: inline-block;
position: absolute;
right: -27px;
bottom: 10px;
box-shadow: 0 -10px 0 0 #ffffff;
}
}
}

最后更新: 2021年12月09日 13:46