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>
相关推荐
万少3 小时前
HarmonyOS 开发必会 5 种 Builder 详解
前端·harmonyos
橙序员小站5 小时前
Agent Skill 是什么?一文讲透 Agent Skill 的设计与实现
前端·后端
炫饭第一名8 小时前
速通Canvas指北🦮——基础入门篇
前端·javascript·程序员
王晓枫8 小时前
flutter接入三方库运行报错:Error running pod install
前端·flutter
符方昊8 小时前
React 19 对比 React 16 新特性解析
前端·react.js
ssshooter8 小时前
又被 Safari 差异坑了:textContent 拿到的值居然没换行?
前端
曲折8 小时前
Cesium-气象要素PNG色斑图叠加
前端·cesium
Forever7_8 小时前
Electron 淘汰!新的桌面端框架 更强大、更轻量化
前端·vue.js
不会敲代码18 小时前
前端组件化样式隔离实战:React CSS Modules、styled-components 与 Vue scoped 对比
css·vue.js·react.js
Angelial8 小时前
Vue3 嵌套路由 KeepAlive:动态缓存与反向配置方案
前端·vue.js