样式需要自定义,elementplus样式跟项目主题不太匹配。
<div class="navigate">
<!-- 搜索输入框 -->
<input
id="navInput"
class="input"
type="text"
v-model="data.navigateWords"
placeholder="指标导航"
@focus="updateNavigateDropVisible(true)"
@focusout="updateNavigateDropVisible(false)"
/>
<el-icon
style="
position: absolute;
top: 50%;
right: 30px;
transform: translateY(-50%);
"
size="20px"
:color="'#fff'"
>
<ArrowUp v-if="data.navigateDropListVisible" />
<ArrowDown v-else />
</el-icon>
<!-- 推荐词列表 -->
<transition name="el-zoom-in-top">
<!-- -->
<div
v-show="
data.navigateDropListVisible &&
data.navigateDropList.length &&
data.navInside
"
v-clickinside="handleClickInside"
class="navigate_drop"
:style="{
width: data.navigateDropSecondList.length ? '300px' : '150px',
}"
>
<div
:class="[
'first',
data.navigateDropSecondList.length ? 'border' : '',
]"
style="width: 150px"
>
<div
v-for="(item, index) in data.navigateDropList"
:key="index"
:class="[
'keyword-item',
data.navCurSelectFirstIndex === index ? 'active' : '',
]"
:title="item.firstNavigate"
@mousedown="selectNavFirst(item, index)"
>
{{ item.firstNavigate }}
<el-icon size="20px" :color="'#666'">
<ArrowRight />
</el-icon>
</div>
</div>
<div
v-if="data.navigateDropSecondList.length"
class="second"
style="width: 150px"
>
<div
v-for="(item, index) in data.navigateDropSecondList"
:key="`${item}-${index}`"
class="second keyword-item"
:title="item"
@mousedown="selectNavSecond(item)"
>
{{ item }}
</div>
</div>
</div>
</transition>
</div>
const data = reactive({
navigateWords: '',
navigateDropListVisible: false,
navigateDropList: [],
navigateDropSecondList: [],
navCurSelectFirstIndex: '',
navInside: true,
})
/**
* 设置导航的下拉是否显示
* @param {Boolean} status
*/
const updateNavigateDropVisible = status => {
if (status) {
data.navigateDropListVisible = status
data.navigateDropList = proxy._t.cloneDeep(dropList)
data.navigateDropSecondList = []
data.navCurSelectFirstIndex = ''
}
}
/**
* 初始化 navigate的数据
*/
const initNavigateDrop = async () => {
const res = await proxy.$api.getIndexNavigateInfo()
dropList = res.data
}
/**
* 选择了一级
*/
const selectNavFirst = (item, index) => {
data.navigateDropSecondList = item.secondNavigateList
data.navCurSelectFirstIndex = index
}
/**
* 选择了二级
*/
const selectNavSecond = item => {
emit('search', item, item)
data.navigateDropListVisible = false
}
// 当前鼠标是否点击到drop内,内的话保留,外的话drop消失
const handleClickInside = (e, target) => {
// console.log(
// 'eeeee',
// data.navigateDropListVisible,
// e,
// target.getAttribute('id'),
// )
const id = target.getAttribute('id')
if (data.navigateDropListVisible && !e && id === 'navInput') return
if (data.navigateDropListVisible) {
data.navInside = e
}
if (!e) {
data.navigateDropListVisible = false
data.navInside = true
}
}
自定义指令
// 判断鼠标点在指定区域外
clickinside: {
// 初始化指令
mounted(el, binding, vnode) {
function documentHandler(e) {
if (binding.value) {
binding.value(el.contains(e.target), e.target)
}
}
// 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
el.__vueClickinside__ = documentHandler
document.addEventListener('click', documentHandler)
},
beforeUnmount(el, binding) {
// 解除事件监听
document.removeEventListener('click', el.__vueClickinside__)
delete el.__vueClickinside__
},
},
main.js
// 判断鼠标点在指定区域内
app.directive('clickinside', directive.clickinside)
.input {
// width: 1000px;
width: 690px;
height: 56px;
box-sizing: border-box;
border: 1px solid #fff;
// border-radius: 10px;
font-size: 16px;
padding: 0 180px 0 20px;
line-height: 56px;
}
.input:focus {
border: 1px solid $themColor;
}
.navigate {
width: 150px;
position: relative;
.input {
background: $themColor;
border: 1px solid $themColor;
border-radius: 10px 0 0 10px;
color: #fff;
&::placeholder {
color: #fff;
}
}
}
.navigate_drop {
box-sizing: border-box;
display: flex;
z-index: 99;
position: absolute;
top: 60px;
left: 0;
width: 150px;
max-height: 372px;
background-color: #fff;
border: 1px solid $themColor;
border-radius: 10px;
padding: 10px 0;
overflow-y: scroll;
// padding-left: 20px;
.keyword-item {
padding: 0 20px;
height: 44px;
line-height: 44px;
font-size: 16px;
color: #666666;
cursor: pointer;
width: 150px;
box-sizing: border-box;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
.el-icon {
vertical-align: middle;
}
&.active {
color: $themColor;
.el-icon {
color: $themColor;
}
}
}
.keyword-item:hover {
background-color: #c7d5ff;
font-weight: 500;
color: $themColor;
.el-icon {
color: $themColor;
}
}
}
.first {
overflow-y: scroll;
max-height: 372px;
text-align: center;
&.border {
border-right: 1px solid #ccc;
// padding-left: 20px;
}
}
.second {
overflow-y: scroll;
max-height: 372px;
}