1. ss-dropdown/index.vue组件:2
<template>
<div class="ss-dropdown" ref="ssDropdownDom" @click="clickOpen">
<span class="current-num">{{ current }}年</span>
<img src="../../assets/arrow-top.png" class="arrow-top-icon" :class="[isShowTooltip && 'arrow-top-icon-active']" />
</div>
<ul id="ss-dropdown-tooltip" ref="ssDropdownTooltipDom" v-if="isShowTooltip">
<li v-for="item in list" :class="['ss-dropdown-tooltip-li',item === current && 'ss-dropdown-tooltip-li-active']"
@click="clickHandle(item)" :ref="getTooltipLiDom" :data-num="item">{{ item }}年</li>
</ul>
</template>
<script setup lang="ts">
import { ref, onMounted, nextTick, watch, onUnmounted } from 'vue';
import { createPopper } from '@popperjs/core';
const ssDropdownDom = ref(null);
const ssDropdownTooltipDom = ref(null);
const instance = ref(null);
const isShowTooltip = ref(false);
const tooltipLiDomList= ref(new Map());
interface Props {
current?: number;
list?: Array<number>;
}
const props = withDefaults(defineProps<Props>(), {
current: 2022,
list: Array.from({ length: 200 }).map((item, index) => (index + 1) + 1900)
})
const emit = defineEmits(['update:current']);
const getTooltipLiDom = el=>{
if(el){
tooltipLiDomList.value.set(Number(el.dataset['num']),el)
}
}
const clickHandle = (val: number) => {
emit('update:current', val);
isShowTooltip.value = false;
}
const clickOpen = async () => {
isShowTooltip.value = !isShowTooltip.value;
await nextTick();
if(isShowTooltip.value){
const currentNumDom = tooltipLiDomList.value.get(props.current);
currentNumDom.scrollIntoView({ behavior:"smooth", block: "center", inline: "start"})
/**
behavior 表示滚动方式。auto 表示使用当前元素的 scroll-behavior 样式。instant 和 smooth
表示 直接滚到底 和 使用平滑滚动。
block 表示块级元素排列方向要滚动到的位置。对于默认的 writing-mode: horizontal-tb
来说,就是竖直方向。start 表示将视口的顶部和元素顶部对齐;center
表示将视口的中间和元素的中间对齐;end表示将视口的底部和元素底部对齐;nearest 表示就近对
齐。
inline 表示行内元素排列方向要滚动到的位置。对于默认的 writing-mode: horizontal-tb
来说,就是水平方向。其值与 block 类似
**/
}
}
// 点击某个DOM元素之外的方法
const handlerDocClick = event => {
let isSelf = ssDropdownDom.value?.contains(event.target) || ssDropdownTooltipDom.value?.contains(event.target) // 这个是自己的区域
if (!isSelf) {
isShowTooltip.value = false;
}
}
watch([ssDropdownDom, ssDropdownTooltipDom], () => {
if (ssDropdownDom.value && ssDropdownTooltipDom.value) {
instance.value = createPopper(ssDropdownDom.value, ssDropdownTooltipDom.value, {
placement: 'bottom',
modifiers: [
{
name: 'offset',
options: {
offset: [0, 6],
},
},
],
});
}
}, {
deep: true,
immediate: true
})
onMounted(async () => {
await nextTick();
document.addEventListener('click', handlerDocClick)
})
onUnmounted(() => {
document.removeEventListener('click', handlerDocClick)
})
</script>
<style scoped>
.ss-dropdown {
display: inline-block;
width: 96px;
height: 30px;
border: 1px solid #D7D9E0;
box-sizing: border-box;
padding: 7px 10px;
border-radius: 6px;
line-height: 1;
cursor: pointer;
position: relative;
background: #FFFFFF;
user-select: none;
word-wrap: break-word;
word-break: break-all;
color: #333;
font-size: 13px;
display: flex;
align-items: center;
justify-content: space-between;
}
.arrow-top-icon {
width: 14px;
transform: rotateX(-180deg);
}
.arrow-top-icon-active {
transform: rotateX(0deg);
}
.ss-dropdown:hover {
border: 1px solid #A7AAB5;
}
#ss-dropdown-tooltip {
list-style: none;
background: white;
width: 90px;
max-height: 200px;
overflow: auto;
box-shadow: 0px 0px 12px rgba(0, 0, 0, .12);
border-radius: 6px;
cursor: pointer;
padding: 5px 10px;
}
.ss-dropdown-tooltip-li {
height: 27px;
line-height: 27px;
word-wrap: break-word;
word-break: break-all;
color: #333;
font-size: 13px;
}
.ss-dropdown-tooltip-li:hover,
.ss-dropdown-tooltip-li-active {
color: #315EFB;
}
#ss-dropdown-tooltip[data-popper-reference-hidden] {
visibility: hidden;
pointer-events: none;
}
::-webkit-scrollbar {
width: 4px;
height: 4px;
background-color: transparent;
}
/*滚动条的轨道*/
::-webkit-scrollbar-track {
background-color: transparent;
}
/*滚动条的滑块按钮*/
::-webkit-scrollbar-thumb {
border-radius: 8px;
background-color: rgba(0, 0, 0, 0.1);
box-shadow: inset 0 0 2px rgba($color: #000000, $alpha: 0.04);
}
/*滚动条的上下两端的按钮*/
::-webkit-scrollbar-button {
height: 0;
background-color: transparent;
}
</style>
2.? 使用组件:
<template>
<SsDropdown v-model:current="current"></SsDropdown>
</template>
<script setup lang="ts">
import {ref} from 'vue
import SsDropdown from '../ss-dropdown/index.vue';
const current= ref(2022);
</script>
|