Vue3封装可拖拽的弹窗

  • 核心代码(复制就可以使用了)
javascript 复制代码
<template>
  <div :style="popupStyle">
    <div ref="dialogEl" class="popup" :style="{ left: ml, top: mt }">
      <div class="popup-tit" @mousedown="mouseDown">
        <div class="txt">{{ title }}</div>
        <div class="close" title="关闭" @click="close">X</div>
      </div>
      <div class="popup-content">
        <slot></slot>
      </div>
    </div>
  </div>
</template>
<script setup>
import { computed, ref } from 'vue';

const { width, height, title } = defineProps({
  width: {
    type: String,
    default: '623px',
  },
  height: {
    type: String,
    default: '379px',
  },
  title: {
    type: String,
    default: '',
  },
});
const emit = defineEmits(['close']);
const ml = ref('50%');
const mt = ref('50%');
const dialogEl = ref();
const dialogB = ref(false);

const size = computed(() => {
  let k = '',
    j = '';

  if (width.includes('rem')) {
    k = 'rem';
  } else if (width.includes('px')) {
    k = 'px';
  } else if (width.includes('vw')) {
    k = 'vw';
  }

  if (height.includes('rem')) {
    j = 'rem';
  } else if (height.includes('px')) {
    j = 'px';
  } else if (height.includes('vw')) {
    j = 'vw';
  }

  return {
    w: width.split(k)[0],
    h: height.split(j)[0],
    j,
    k,
  };
});

const popupStyle = computed(() => {
  const baseTitH = 65 / 390;

  return `--Tw:${width};--Th:${height};--titH:${baseTitH * size.value.h}${size.value.j};`;
});

const mouseDown = (e) => {
  let windowH = window.innerHeight; //获取浏览器的可用高度
  // let windowW = window.innerWidth;//获取浏览器的可用宽度
  let el = dialogEl.value; //获取需要拖拽移动的容器
  var disX = e.clientX - el.offsetLeft;
  var disY = e.clientY - el.offsetTop;

  dialogB.value = true;

  document.onselectstart = function () {
    return false;
  };

  document.onmousemove = (e) => {
    if (!dialogB.value) return false;

    let left = e.clientX - disX;
    let top = e.clientY - disY;

    if (top < 0 || top > windowH - 40) return false; //当到达顶部或者底部时就不让继续拖动了
    ml.value = left + 'px';
    mt.value = top + 'px';
  };

  document.onmouseup = () => {
    if (dialogB.value) {
      dialogB.value = false;
    }
  };
};

// 关闭
const close = () => {
  emit('close');
};
</script>
<style scoped lang="scss">
.popup {
  position: absolute;
  z-index: 100;
  display: flex;
  flex-direction: column;
  width: var(--Tw);
  height: var(--Th);
  padding: 5px 15px 15px 15px;
  background-image: url('../assets/images/icon/弹窗1.png');
  background-repeat: no-repeat;
  background-size: 100% 100%;
  transform: translateX(-50%) translateY(-50%);

  .popup-tit {
    position: relative;
    display: flex;
    box-sizing: border-box;
    width: 100%;
    height: var(--titH);
    padding-left: 40px;
    color: #fff;
    font-size: 20px;
    line-height: var(--titH);
    cursor: all-scroll;
    .close {
      position: absolute;
      right: 20px;
      cursor: pointer;
    }
  }
  .popup-content {
    flex: auto;
    // background-color: #fff;
  }
}
</style>
  • 使用方式
javascript 复制代码
<script setup>
import TPopUp from '@/common/TPopUp.vue';
</script>

<template>
 <TPopUp  width="743px" height="469px" title="碳储量计算" @close="popVis=false">
      <div class="box">
        <div class="forms">
          <div class="form-item">
            <div class="lab">地上生物量:</div>
            <div class="numbers">1</div>
            <div class="numbers">2</div>
            <div class="numbers">3</div>
            <div class="numbers">4</div>
          </div>
          <div class="form-item">
            <div class="lab">地下生物量:</div>
            <div class="numbers">1</div>
            <div class="numbers">2</div>
            <div class="numbers">3</div>
            <div class="numbers">4</div>
          </div>
          <div class="form-item">
            <div class="lab">枯死木:</div>
            <div class="numbers">1</div>
            <div class="numbers">2</div>
            <div class="numbers">3</div>
            <div class="numbers">4</div>
          </div>
          <div class="form-item">
            <div class="lab">枯落物:</div>
            <div class="numbers">1</div>
            <div class="numbers">2</div>
            <div class="numbers">3</div>
            <div class="numbers">4</div>
          </div>
          <div class="form-item">
            <div class="lab">土壤有机质:</div>
            <div class="numbers">1</div>
            <div class="numbers">2</div>
            <div class="numbers">3</div>
            <div class="numbers">4</div>
          </div>
        </div>
    
 
      </div>
    </TPopUp>
</template>
相关推荐
叫我一声阿雷吧6 分钟前
JS 入门通关手册(48):本地存储全解析(localStorage/sessionStorage/cookie,面试高频)
javascript·本地存储·cookie·localstorage·存储方案· 前端面试·essionstorage
英俊潇洒美少年14 分钟前
前端组件化开发最佳实践 + 高频面试题(Vue & React)
前端·vue.js·react.js
凌览17 分钟前
别再手搓 Skill 了,用这个工具 5 分钟搞定
前端·后端
zero159719 分钟前
TypeScript 快速实战系列:函数进阶|TypeScript 函数 + 异步:大模型 API 调用核心
前端·typescript·大模型编程语言
無名路人21 分钟前
用 codex AI 更新了下之前写的浏览器云书签标签页扩展
前端·openai·ai编程
月弦笙音26 分钟前
【pnpm 】pnpm 执行 xxx 的 底层原理
前端
玄空z35 分钟前
通俗理解 RAG 与微调:给大模型“翻书”还是“洗脑”
javascript
Devin_chen1 小时前
单例模式渐进式学习指南
前端·javascript
苏西的网络日志1 小时前
基于 Element Plus 的企业级主题定制方案:SCSS 变量覆盖 + Vite 全局注入实战
前端
吴声子夜歌1 小时前
Vue3——计算属性和监听属性
前端·vue.js