某次刷掘金UI设计版块看到一个移动端的菜单gif动图,效果如下:
实现过程也不难,最后效果如下:
接下来是代码:
首先是html结构
<body>
<div class="content">
<div id="main"></div>
<div id="menu">
<div class="bar">
<div class="item active-item" data-index=1 data-atr="menuLink">
<span class="icon">
<i class="iconfont icon-70BasicIcons-all-12"></i>
</span>
<span class="text">home</span>
</div>
<div class="item" data-index=2 data-atr="menuLink">
<span class="icon">
<i class="iconfont icon-70BasicIcons-all-13"></i>
</span>
<span class="text">edit</span>
</div>
<div class="item" data-index=3 data-atr="menuLink">
<span class="icon">
<i class="iconfont icon-70BasicIcons-all-05"></i>
</span>
<span class="text">profile</span>
</div>
</div>
<div class="active-box-filter"></div>
</div>
</div>
</body>
结构说明:
<div id="menu">
用fixed固定在页面底部,
底部的容器实际是<div class="bar">...</bar>
使用了flex布局方式
icon和text分别使用<span>
标签包裹起来,方便分别处理CSS效果
在三个菜单Item之后有一个class
为active-box-filter
的div
,其实就是gif中的半透明背景
观察gif效果可以看出:
-
选中时:icon有像左移动的效果,整个item有一个半透明的背景,并且是从上一个item那里移动过来的,文字出 现
-
离开时:icon向右归位,半透明背景移动到下一个item,文字渐渐消失
实现:
- Item未被选中时,给包裹Icon的span一个
translateX(130%)
,目的是水平往右移动,重叠在text的位置,而包裹text的span则将其opacity
设为0,两者都添加一个0.2s的过渡效果transtion
.icon{
display: inline-block;
transform: translateX(130%);
transition: all .2s ease-in-out;
}
.text {
opacity: 0;
transition: all .2s ease-in-out;
}
Item被选中时,将Icon所属span的translateX(-15%)
,span会水平向左移动,text所属span的opacity
设为1
.active-item .icon{
transform: translateX(-15%);
}
.active-item .text{
opacity: 1;
}
上述完成后已经可以实现Icon的移动和Text的渐显
接下来是半透明背景
默认选中第一个菜单Item,
选中的item
添加一个activeClassactive-item
,背景的div的position
设为absolute
;并且其父元素添加相对位置属性,
<div class="item active-item" ></div>
...
<div class="active-box-filter"></div>
.active-item{
color:white;
transition: all .1s ease-in-out;
}
.active-box-filter{
display: inline-block;
position: absolute;
width: 30%;
height: 54%;
background-color: rgba(255, 255, 255, 0.2);
top: 23%;
left: 2%;
border-radius: 10px;
transform: translateX(0px);
transition: all .3s ease-in-out;
}
完整的CSS在文章最后
最后是JS,在html中我给三个菜单Item都分别添加自定义属性data-index
和data-attr
,目的无外乎是为了在js操作更加便捷。
思路:
- 选中时:判断event的target,如果target上
data-attr=="menuLink"
,表示当前节点currentNode=e.target
,否则currentNode=e.target.parentNode
。 - 接下来获取菜单Item节点列表,利用
data-index
比较其和currentNode
是否相等, - 若相等,则设置activeClass并且修改半透明背景块的水平移动距离
translateX
完整js如下
<script>
let barNode = document.querySelector('.bar')
barNode.addEventListener("click", nodeClick, false)
function nodeClick(e) {
let currentNode;
let filterNode = document.querySelector(".active-box-filter")
if (e.target.dataset.atr == "menuLink") {
currentNode = e.target;
} else if (e.target.parentNode.dataset.atr == "menuLink") {
currentNode = e.target.parentNode
}
if (currentNode == undefined) return false;
//childNode是一个NodeList,其自带一个forEach方法
let childNode = document.querySelectorAll(".item");
childNode.forEach((node, index) => {
if (node.dataset.index !== currentNode.dataset.index) {
node.className = "item"
} else {
node.className = "item active-item"
filterNode.style["transform"] = `translateX(${110*(node.dataset.index-1)}%)`
}
})
}
</script>
总结:
整个看下来,其实比较关键的是如何只使用一个半透明背景块做不定距离的移动,笔者尝试过使用一个after伪元素,但其在js计算translate的时候不太方便,弃之,
最后选择了一个单独的div做处理,并且利用translateX
动画结合transtion
的过渡,这样就能在视觉上看到背景块的所有运动。
如果你有更好的方案欢迎交流~~
完整CSS
*,
html,
body {
margin: 0;
padding: 0;
font-size:16px;
}
.content {
position: relative;
}
#main {
background-color: #e9ecff;
min-height: 800px;
}
#menu {
background-color: rgb(67, 47, 191);
position: fixed;
bottom: 0;
left: 0;
height: 4.375rem;
width: 100%;
}
.bar {
display: flex;
width: inherit;
height: inherit;
justify-content: space-around;
align-items: center;
}
.item {
width: 5.625rem;
position: relative;
text-align: center;
color:#9a9a9a;
line-height: 2.81rem;
transition: all .1s ease-in-out;
}
.active-box-filter{
display: inline-block;
position: absolute;
width: 30%;
height: 54%;
background-color: rgba(255, 255, 255, 0.2);
top: 23%;
left: 2%;
border-radius: 10px;
transform: translateX(0px);
transition: all .3s ease-in-out;
}
.active-item{
color:white;
transition: all .1s ease-in-out;
}
.icon{
display: inline-block;
transform: translateX(130%);
transition: all .2s ease-in-out;
}
.text{
opacity: 0;
transition: all .2s ease-in-out;
}
.active-item .icon{
transform: translateX(-15%);
}
.active-item .text{
opacity: 1;
}
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!