FloatingFrame.vue 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <script setup lang="ts">
  2. import {useDraggable, useZIndex} from "element-plus";
  3. import XEUtils from "xe-utils";
  4. import {Close} from "@element-plus/icons-vue";
  5. import {onDeactivated} from "@vue/runtime-core";
  6. const props = withDefaults(defineProps<{
  7. width?: string | number,
  8. height?: string | number,
  9. x?: string | number,
  10. y?: string | number,
  11. title?: string,
  12. modelValue: boolean
  13. }>(), {
  14. width: '300px',
  15. height: '400px',
  16. x: 30,
  17. y: 40,
  18. title: '标题'
  19. })
  20. const emits = defineEmits<{
  21. (e: "update:modelValue", value: boolean): void,
  22. }>()
  23. const vodyRef = ref()
  24. const vRef = ref()
  25. const zIndex = ref(useZIndex().nextZIndex())
  26. const draggable = computed(() => {
  27. return true
  28. })
  29. const addUnit = (val: number | string) => XEUtils.addUnit(val)
  30. const boxStyle = computed(() => {
  31. return {
  32. height: addUnit(props.height),
  33. width: addUnit(props.width),
  34. left: addUnit(props.x),
  35. top: addUnit(props.y),
  36. zIndex: zIndex.value
  37. }
  38. })
  39. watch(() => props.modelValue, (value, oldValue, onCleanup) => {
  40. if (value)
  41. zIndex.value = useZIndex().nextZIndex()
  42. })
  43. useDraggable(vodyRef, vRef, draggable)
  44. onDeactivated(() => {
  45. emits('update:modelValue', false)
  46. })
  47. onUnmounted(() => {
  48. emits('update:modelValue', false)
  49. })
  50. </script>
  51. <template>
  52. <transition name="el-fade-in-linear">
  53. <div class="floating_frame-box"
  54. :style="boxStyle"
  55. v-show="props.modelValue"
  56. ref="vodyRef">
  57. <header class="floating_frame-drag_reference" ref="vRef">
  58. <div class="floating_frame-title">
  59. {{ props.title }}
  60. </div>
  61. <div class="floating_frame-close_icon">
  62. <el-icon :size="16" @click="emits('update:modelValue' , false)">
  63. <Close/>
  64. </el-icon>
  65. </div>
  66. </header>
  67. <div class="floating_frame-body">
  68. <slot/>
  69. </div>
  70. </div>
  71. </transition>
  72. </template>
  73. <style scoped lang="scss">
  74. .floating_frame-box {
  75. position: fixed;
  76. box-sizing: border-box;
  77. border-radius: 5px;
  78. background: white;
  79. box-shadow: var(--el-box-shadow);
  80. padding: 5px 16px;
  81. div {
  82. box-sizing: border-box;
  83. background: white;
  84. }
  85. .floating_frame-drag_reference {
  86. height: 30px;
  87. width: 100%;
  88. cursor: all-scroll;
  89. user-select: none;
  90. position: relative;
  91. border-bottom: 1px solid var(--el-border-color);
  92. .floating_frame-title {
  93. text-align: center;
  94. line-height: 30px;
  95. }
  96. .floating_frame-close_icon {
  97. position: absolute;
  98. height: inherit;
  99. width: 30px;
  100. right: 0;
  101. display: flex;
  102. top: 0;
  103. justify-content: center;
  104. align-items: center;
  105. cursor: pointer;
  106. }
  107. }
  108. .floating_frame-body {
  109. height: calc(100% - 30px);
  110. overflow: auto;
  111. }
  112. }
  113. </style>