<template> <div class="drp_component" :class="classname"> <p @click="openDrp" class="ws-n" ref="drpDef" title=""> <slot></slot> </p> </div> <transition :name="openType"> <div :style="{ top: top + 'px', left: left + 'px' }" class="drp_item_wrap" ref="drpItemWrap" v-if="show" @click="show = false" title="" > <slot name="dropdown"></slot> <span class="arrow" :class="{ arror_top: arrowPosition === 'top', arror_bottom: arrowPosition === 'bottom', }" :style="{ left: arrowLeft + 'px' }" ></span> </div> </transition> </template> <script> export default { name: "HelloWorld", }; </script> <script setup> import { nextTick, ref, watch } from "vue"; import $ from "jquery"; const openType = ref(""); const classname = ref(Math.random().toString(36).substr(2)); const show = ref(false); const top = ref(9999999); const left = ref(9999999); const arrowLeft = ref(0); const arrowPosition = ref(""); const openDrp = () => { show.value = !show.value; if (!show.value) return; nextTick(() => { const body = document.querySelector("body"); if (body.append) { body.append(drpItemWrap.value); } else { body.appendChild(drpItemWrap.value); } let dcWidth = document.body.clientWidth; let dcHeight = document.body.clientHeight; let pLeft = $(`.${classname.value}`).offset().left - document.documentElement.scrollLeft; let pTop = $(`.${classname.value}`).offset().top - document.documentElement.scrollTop; let pWidth = $(`.${classname.value}`).outerWidth(); let pHeight = $(`.${classname.value}`).outerHeight(); let itemWidth = $(".drp_item_wrap").outerWidth(); let itemHeight = $(".drp_item_wrap").outerHeight(); if (pTop + pHeight + itemHeight - dcHeight > 0) { top.value = pTop - itemHeight - 10; arrowPosition.value = "bottom"; openType.value = "el-zoom-in-bottom"; } else { top.value = pTop + pHeight + 10; arrowPosition.value = "top"; openType.value = "el-zoom-in-top"; } if (pLeft + pWidth / 2 - itemWidth / 2 < 0) { left.value = 10; arrowLeft.value = pLeft - 10 + pWidth / 2 - 7; } else if (pLeft + pWidth / 2 + itemWidth / 2 > dcWidth) { left.value = dcWidth - itemWidth - 10; arrowLeft.value = pLeft - left.value + pWidth / 2 - 7; } else { left.value = pLeft + pWidth / 2 - itemWidth / 2; arrowLeft.value = itemWidth / 2 - 7; } show.value = !show.value; setTimeout(() => { show.value = !show.value; }); }); }; const colse = () => { if (show.value) show.value = false; }; const drpDef = ref(null); const drpItemWrap = ref(null); const cm = (e) => { if ( drpItemWrap.value && !drpItemWrap.value.contains(e.target) && drpDef.value && !drpDef.value.contains(e.target) ) { colse(); } }; watch(show, (v) => { if (v) { window.addEventListener("scroll", colse); window.addEventListener("wheel", colse); window.addEventListener("mousedown", cm); } else { window.removeEventListener("scroll", colse); window.removeEventListener("wheel", colse); window.removeEventListener("mousedown", cm); } }); </script> <style lang="less"> .drp_component { line-height: 1; } .drp_item_wrap { line-height: 1; background-color: #fff; padding: 5px 0 5px; border: 1px solid var(--el-border-color-light); box-shadow: var(--el-box-shadow-light); position: fixed; z-index: 9999999; border-radius: 4px; > div { padding: 10px 16px; cursor: pointer; user-select: none; font-size: 14px; text-align: left; white-space: nowrap; } > div:hover { background-color: var(--el-color-primary-light-9); color: var(--el-color-primary); } > button { border: none; outline: none; padding: 6px 16px; cursor: pointer; user-select: none; font-size: 14px; text-align: left; white-space: nowrap; background-color: #fff; display: block; } > button:hover { background-color: var(--el-color-primary-light-9); color: var(--el-color-primary); } > button[disabled] { background-color: #fff; cursor: not-allowed; color: #8F9BB3; } .arrow { position: absolute; width: 10px; height: 10px; border: 1px solid var(--el-border-color-light); z-index: -1; transform: rotate(45deg); background-color: #fff; } .arror_top { top: -5px; border-bottom-color: transparent; border-right-color: transparent; } .arror_bottom { bottom: -5px; border-top-color: transparent; border-left-color: transparent; } } </style>
标签:const,dropdown,color,border,show,value,vue3,手写,ref From: https://www.cnblogs.com/turkey-Rabbit/p/17097353.html