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>
相关推荐
Z兽兽2 小时前
React@18+Vite项目配置env文件
前端·react.js·前端框架
SuniaWang2 小时前
《Spring AI + 大模型全栈实战》学习手册系列 · 专题六:《Vue3 前端开发实战:打造企业级 RAG 问答界面》
java·前端·人工智能·spring boot·后端·spring·架构
A_nanda3 小时前
根据AI提示排查vue前端项目
前端·javascript·vue.js
happymaker06263 小时前
web前端学习日记——DAY05(定位、浮动、视频音频播放)
前端·学习·音视频
~无忧花开~3 小时前
React状态管理完全指南
开发语言·前端·javascript·react.js·前端框架
LegendNoTitle4 小时前
计算机三级等级考试 网络技术 选择题考点详细梳理
服务器·前端·经验分享·笔记·php
@大迁世界4 小时前
1.什么是 ReactJS?
前端·javascript·react.js·前端框架·ecmascript
BJ-Giser4 小时前
Cesium 基于EZ-Tree的植被效果
前端·可视化·cesium
王码码20355 小时前
Flutter for OpenHarmony:Flutter 三方库 algoliasearch 毫秒级云端搜索体验(云原生搜索引擎)
android·前端·git·flutter·搜索引擎·云原生·harmonyos
发现一只大呆瓜6 小时前
深入浅出 AST:解密 Vite、Babel编译的底层“黑盒”
前端·面试·vite