index.vue 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. <script setup lang="ts">
  2. import { onBeforeUnmount, onMounted, ref, watch } from "vue";
  3. import { addClass, removeClass } from "@/utils/index";
  4. const show = ref(false);
  5. defineProps({
  6. buttonTop: {
  7. default: 250,
  8. type: Number,
  9. },
  10. });
  11. watch(show, (value) => {
  12. if (value) {
  13. addEventClick();
  14. }
  15. if (value) {
  16. addClass(document.body, "showRightPanel");
  17. } else {
  18. removeClass(document.body, "showRightPanel");
  19. }
  20. });
  21. function addEventClick() {
  22. window.addEventListener("click", closeSidebar, { passive: true });
  23. }
  24. function closeSidebar(evt: any) {
  25. // 主题选择点击不关闭
  26. let parent = evt.target.closest(".right-panel-container");
  27. if (!parent) {
  28. show.value = false;
  29. window.removeEventListener("click", closeSidebar);
  30. }
  31. }
  32. const rightPanel = ref();
  33. function insertToBody() {
  34. const body = document.querySelector("body") as any;
  35. body.insertBefore(rightPanel.value, body.firstChild);
  36. }
  37. onMounted(() => {
  38. insertToBody();
  39. });
  40. onBeforeUnmount(() => {
  41. rightPanel.value.remove();
  42. });
  43. </script>
  44. <template>
  45. <div ref="rightPanel" :class="{ show: show }">
  46. <div class="right-panel-overlay" />
  47. <div class="right-panel-container">
  48. <div
  49. class="right-panel-btn"
  50. :style="{
  51. top: buttonTop + 'px',
  52. }"
  53. @click="show = !show"
  54. >
  55. <i-ep-close v-show="show" />
  56. <i-ep-setting v-show="!show" />
  57. </div>
  58. <div>
  59. <slot />
  60. </div>
  61. </div>
  62. </div>
  63. </template>
  64. <style lang="scss" scoped>
  65. .showRightPanel {
  66. position: relative;
  67. width: calc(100% - 15px);
  68. overflow: hidden;
  69. }
  70. .right-panel-overlay {
  71. position: fixed;
  72. top: 0;
  73. left: 0;
  74. background: rgb(0 0 0 / 20%);
  75. }
  76. .right-panel-container {
  77. position: fixed;
  78. top: 0;
  79. right: 0;
  80. z-index: 999;
  81. width: 100%;
  82. max-width: 300px;
  83. height: 100vh;
  84. background-color: var(--el-bg-color-overlay);
  85. box-shadow: 0 0 15px 0 rgb(0 0 0 / 5%);
  86. transition: all 0.25s cubic-bezier(0.7, 0.3, 0.1, 1);
  87. transform: translate(100%);
  88. }
  89. .show {
  90. transition: all 0.3s cubic-bezier(0.7, 0.3, 0.1, 1);
  91. .right-panel-overlay {
  92. z-index: 99;
  93. width: 100%;
  94. height: 100%;
  95. opacity: 1;
  96. }
  97. .right-panel-container {
  98. transform: translate(0);
  99. }
  100. }
  101. .right-panel-btn {
  102. position: absolute;
  103. left: -36px;
  104. width: 36px;
  105. height: 36px;
  106. color: var(--el-color-white);
  107. text-align: center;
  108. cursor: pointer;
  109. background-color: var(--el-color-primary);
  110. border-radius: 6px 0 0 6px;
  111. svg {
  112. width: 20px;
  113. height: 20px;
  114. vertical-align: -10px;
  115. }
  116. }
  117. </style>