場景:下拉彈框顯示時,想要點擊其他地方即隱藏(不使用蒙板,下拉彈框定位到點擊顯示的位置)
tabindex可以使得相應的節點具有 focus 和 blur 事件
tabindex=負值
(通常是tabindex='-1'),表示元素是可聚焦的,但是不能通過鍵盤導航來訪問到該元素,用JS做頁面小組件內部鍵盤導航的時候非常有用。
tabindex='0',
表示元素是可聚焦的,並且可以通過鍵盤導航來聚焦到該元素,它的相對順序是當前處於的DOM結構來決定的。
tabindex=正值,
表示元素是可聚焦的,並且可以通過鍵盤導航來訪問到該元素;它的相對順序按照tabindex 的數值遞增而滯后獲焦。如果多個元素擁有相同的 tabindex,它們的相對順序按照他們在當前DOM中的先后順序決定。
注:tabindex 的最大值不應超過 32767。如果沒有指定,它的默認值為 -1。
tabindex == -1 時無法通過tab鍵選中該節點
tabindex == 0 或 1 都可以通過tab鍵選中該節點(不同的賦值表示不同的優先級)
template
<template>
<div class="dropDownBox">
<div class="drop-button" tabindex="0" @click="clickFunc" @blur="blurFunc">
<div> {{ data[activeIndex].text }} </div>
<div class="icon" :class="isShowBox ? 'rotate' : ''"> </div>
<div class="box" v-show="isShowBox">
<div
class="item"
:class="activeIndex === index ? 'select-color' : ''"
v-for="(item, index) in data"
:key="index"
@click="changeOption(index)"
>
{{ item.text }}
</div>
</div>
</div>
</div>
</template>
script方法
export default {
name: 'DropDownBox',
data() {
return {
// 下拉框選項數據
data: [
{
text: 'DOW J',
},
{
text: 'S/P 500',
},
{
text: 'NASDAQ',
},
],
// 是否顯示下拉框
isShowBox: false,
// 當前選項
activeIndex: 0,
};
},
methods: {
clickFunc() {
this.isShowBox = !this.isShowBox;
},
blurFunc() {
this.isShowBox = false;
},
changeOption(index) {
if (this.activeIndex === index) {
return;
}
this.activeIndex = index;
}
}
}
</script>
style
<style lang="less" scoped>
.dropDownBox {
.drop-button {
position: relative;
display: flex;
justify-content: center;
align-items: center;
outline: none;
.rotate {
transform: rotate(180deg);
}
.icon {
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 6px solid #000;
}
.drop-down-box-bg {
background-color: #e6e6e6;
}
.select-color {
color: #fb7299,
}
.box {
position: absolute;
top: 20px;
z-index: 11;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 20px;
background-color: #fff;
box-shadow: 0px 3px 29px 0px rgba(59,74,116,0.14);
border-radius: 8px;
.item {
font-size: 16px;
line-height: 16px;
font-weight: 500;
padding: 6px 0;
}
}
}
}
</style>
完整代碼
<template>
<div class="dropDownBox">
<div class="drop-button" tabindex="0" @click="clickFunc" @blur="blurFunc">
<div> {{ data[activeIndex].text }} </div>
<div class="icon" :class="isShowBox ? 'rotate' : ''"> </div>
<div class="box" v-show="isShowBox">
<div
class="item"
:class="activeIndex === index ? 'select-color' : ''"
v-for="(item, index) in data"
:key="index"
@click="changeOption(index)"
>
{{ item.text }}
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'DropDownBox',
data() {
return {
// 下拉框選項數據
data: [
{
text: 'DOW J',
},
{
text: 'S/P 500',
},
{
text: 'NASDAQ',
},
],
// 是否顯示下拉框
isShowBox: false,
// 當前選項
activeIndex: 0,
};
},
methods: {
clickFunc() {
this.isShowBox = !this.isShowBox;
},
blurFunc() {
this.isShowBox = false;
},
changeOption(index) {
if (this.activeIndex === index) {
return;
}
this.activeIndex = index;
}
}
}
</script>
<style lang="less" scoped>
.dropDownBox {
.drop-button {
position: relative;
display: flex;
justify-content: center;
align-items: center;
outline: none;
.rotate {
transform: rotate(180deg);
}
.icon {
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 6px solid #000;
}
.drop-down-box-bg {
background-color: #e6e6e6;
}
.select-color {
color: #fb7299,
}
.box {
position: absolute;
top: 20px;
z-index: 11;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 20px;
background-color: #fff;
box-shadow: 0px 3px 29px 0px rgba(59,74,116,0.14);
border-radius: 8px;
.item {
font-size: 16px;
line-height: 16px;
font-weight: 500;
padding: 6px 0;
}
}
}
}
</style>
下拉框滾動遮擋問題
問題: 因為需要下拉框顯示時阻止滾動,這導致顯示時可能被遮擋
解決方法: 先滾到到完整顯示,再使用overflow阻止滾動,隱藏時再移除overflow
完整代碼:
<template>
<div class="dropDownBoxCover">
<div class="drop-button" tabindex="0" @click="clickFunc" @blur="blurFunc">
<div> {{ data[activeIndex].text }} </div>
<div class="icon" :class="isShowBox ? 'rotate' : ''"> </div>
<div ref="box" class="box" v-show="isShowBox">
<div
class="item"
:class="activeIndex === index ? 'select-color' : ''"
v-for="(item, index) in data"
:key="index"
@click="changeOption(index)"
>
{{ item.text }}
</div>
</div>
</div>
<!-- 蒙板 -->
<div class="cover" v-show="isShowBox"></div>
</div>
</template>
<script>
export default {
name: 'DropDownBoxCover',
data() {
return {
// 下拉框選項數據
data: [
{
text: 'DOW J',
},
{
text: 'S/P 500',
},
{
text: 'NASDAQ',
},
],
// 是否顯示下拉框
isShowBox: false,
// 當前選項
activeIndex: 0,
};
},
methods: {
// 點擊顯示下拉框
clickFunc() {
this.isShowBox = !this.isShowBox;
if (this.isShowBox) {
this.$nextTick(() => {
// 否則拿不到 $refs.box
this.showFullBox();
})
this.switchScroll(false);
} else {
this.switchScroll(true);
}
},
// blur失焦
blurFunc() {
this.isShowBox = false;
this.switchScroll(true);
},
// 切換選項
changeOption(index) {
if (this.activeIndex === index) {
return;
}
this.activeIndex = index;
},
// 是否開放滾動
switchScroll(isScroll) {
if (isScroll) {
document.body.style.overflow = '';
} else {
document.body.style.overflow = 'hidden';
}
},
// 計算滾動距離並滾動顯示完整
showFullBox() {
// 按鈕距離底部距離
const toBottom = document.documentElement.clientHeight - this.$refs.box.getBoundingClientRect().bottom;
console.log(1, document.documentElement.clientHeight);
console.log(2, this.$refs.box.getBoundingClientRect())
if (toBottom < 0) {
window.console.log('box 被遮擋了')
const {scrollTop} = document.documentElement;
// 需要滾動的距離(被遮擋的高度)
const distance = -toBottom;
document.documentElement.scrollTop = scrollTop + distance;
}
}
}
}
</script>
<style lang="less" scoped>
.dropDownBoxCover {
.drop-button {
position: relative;
display: flex;
justify-content: center;
align-items: center;
outline: none;
.rotate {
transform: rotate(180deg);
}
.icon {
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 6px solid #000;
}
.drop-down-box-bg {
background-color: #e6e6e6;
}
.select-color {
color: #fb7299,
}
.box {
position: absolute;
top: 20px;
z-index: 11;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 20px;
background-color: #fff;
box-shadow: 0px 3px 29px 0px rgba(59,74,116,0.14);
border-radius: 8px;
.item {
font-size: 16px;
line-height: 16px;
font-weight: 500;
padding: 6px 0;
}
}
}
.cover {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10;
background-color: rgba(0,0,0,0.3);
}
}
</style>