一、前言-问题描述🌟
当我们把鼠标移动到某个区域,hover显示出功能图标后,我们点击图标弹出功能菜单,但当鼠标移出hover区域或者移动到弹出的功能菜单时,原来的功能图标消失了,这显然不是我们需要的效果,效果如下:
现在我们希望当弹出功能菜单后,鼠标移出hover区域或者移动到弹出的功能菜单时,此时hover区域的功能图标不消失,我们需要怎样实现了?
二、解决方案🙉
解决思路
我们创建一个class,使之和hover动作的样式一致,当我们点击功能图标弹出功能菜单时,我们给hover区域的dom元素加上这个class,而当功能菜单弹窗消失时,我们就去掉这个class。
具体实现
先梳理一下上面gif图的html结构:
class="app-list"的dom节点下有多个class="app-item"的dom, 其中每个列表项的应用ref="'app'+item.app_id",这样我们就可以通过app_id找到每个列表项。当我们把鼠标hover至每个app-item时,app-item中class="app-options"的dom会显示出来,app-options中包含了一个class="more-btn"的dom节点,该节点使用了ElementUI的dropdown下拉菜单组件,当点击more-btn时,下拉菜单显示。
<ul class="app-list">
<li class="app-item" :ref="'app'+item.app_id" v-for="item in appList" :key="item.app_id" @click="toAppManage(item.app_id)">
<div class="ipu-flex">
<img class="app-logo" :src="item.app_logo">
<div class="ipu-flex ipu-flex-vertical ipu-flex-justify-space ipu-flex-grow-1">
<div class="app-name">{{item.app_name}}</div>
<div class="create-time">{{item.create_date}}</div>
</div>
</div>
<div class="app-description">{{item.app_desc}}</div>
<div class="ipu-flex-grow-1"></div>
<div class="app-options" @click.stop>
<el-tooltip effect="dark" content="预览" placement="top" :enterable="false">
<i class="ri-eye-fill"></i>
</el-tooltip>
<el-dropdown trigger="click" @command="onAppAction" placement="bottom-start" @visible-change="visibleChange($event, item.app_id)">
<div class="more-btn">
<i class="ri-more-fill"></i>
</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item class="ipu-flex-middle" :command="{type:'set', appId: item.app_id}">
<span class="child-action-name">应用设置</span>
</el-dropdown-item>
<el-dropdown-item class="ipu-flex-middle" :command="{type:'delete', appId: item.app_id}">
<span class="child-action-name">删除应用</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</li>
</ul>
再来看CSS部分的代码,CSS部分采用SCSS预处理器编写:
.app-options在普通状态下由于transform: translateY(42px);向下移了42px而隐藏,当鼠标移至.app-item上时,我们给它的hover事件上设置了transform: translateY(4px);这时.app-options由于上移而显示,同时我们在.app-item上定义了一个.select样式,它的样式与hover事件的样式一致。
.app-list {
margin-top: 30px;
display:flex;
flex-wrap: wrap;
gap: 20px;
.app-item {
overflow: hidden;
cursor: pointer;
position: relative;
width: 258px;
height: 206px;
padding:20px;
background: #FFFFFF;
border: 1px solid #F2F6FC;
border-radius: 4px;
display: flex;
flex-direction: column;
&:hover {
box-shadow: 0px 2px 12px rgba(0, 0, 0, 0.06);
.app-options {
transform: translateY(4px);
}
}
&.select {
box-shadow: 0px 2px 12px rgba(0, 0, 0, 0.06);
.app-options {
transform: translateY(4px);
}
}
.app-logo {
background: #fff;
border-radius: 6px;
width: 50px;
height: 50px;
margin-right: 14px;
}
.app-name {
font-size: 16px;
line-height: 24px;
color: #606266;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.create-time {
font-size: 14px;
line-height: 22px;
color: rgba(0, 0, 0, .45);
}
.app-description {
margin-top: 19px;
font-size: 12px;
line-height: 20px;
color: #909399;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
.app-options {
align-self: flex-end;
display: flex;
justify-content: flex-end;
transform: translateY(42px);
transition: transform .3s ease-in-out;
i {
font-size: 20px;
line-height: 20px;
color: rgba(144, 147, 153, 1);
}
.more-btn {
margin-left:20px;
}
}
}
}
JS部分梳理:
ElementUI的dropdown下拉菜单组件可以通过监听visible-change事件
,获取下拉菜单的状态,出现则为 true,隐藏则为 false。于是我们在组件上添加@visible-change="visibleChange($event, item.app_id),并传入app_id
。我们可以通过app_id找到对应的dom节点,然后根据下拉菜单的状态给此dom节点添加或移除select样式
。
visibleChange(e, appId) {
if (e) {
this.$refs['app' + appId][0].classList.add('select')
} else {
this.$refs['app' + appId][0].classList.remove('select')
}
}
最终我们实现了当弹出功能菜单后,鼠标移出hover区域或者移动到弹出的功能菜单时,此时hover区域的功能图标不消失的效果,如下图:
三、总结与举一反三✨
创建一个class,使之和hover动作的样式一致,当我们点击功能图标弹出功能菜单时,我们给hover区域的dom元素加上这个class,而当功能菜单弹窗消失时,我们就去掉这个class。通过这个原理我们实现了想要的效果,类似的ElementUI的 Popover 弹出框组件、Tooltip 文字提示组件,我们想在移动到弹出框、文字提示区域时,原来hover显示的图标不消失,都可以运用此技巧~