IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> vue3自定义下拉菜单组件,支持popperjs和滚动到指定元素 -> 正文阅读

[JavaScript知识库]vue3自定义下拉菜单组件,支持popperjs和滚动到指定元素

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>

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-24 09:20:29  更:2022-04-24 09:21:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:58:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码