fix: 修正 nav 使用者無法按出drop down

This commit is contained in:
MJM_2025_05\polly 2025-09-24 16:28:18 +08:00
parent 36e390d300
commit ead85a5652
2 changed files with 122 additions and 115 deletions

View File

@ -1,12 +1,6 @@
<script setup> <script setup>
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
import { computed, defineProps, onMounted, ref, watch } from "vue"; import { defineProps } from "vue";
/* ----------------------------------------------------------------
id名.showModal(): 開啟 modal
id名.close(): 關閉 modal
詳細請參考 daisyUI
------------------------------------------------------------------- */
const props = defineProps({ const props = defineProps({
id: String, id: String,
@ -14,52 +8,40 @@ const props = defineProps({
onCancel: Function, onCancel: Function,
modalClass: String, modalClass: String,
width: Number || String, width: Number || String,
draggable: { draggable: { type: Boolean, default: false },
type: Boolean, backdrop: { type: Boolean, default: true },
default: false, modalStyle: { type: Object, default: () => ({}) },
},
backdrop: {
type: Boolean,
default: true,
},
modalStyle: {
type: Object,
default: {},
},
}); });
const dom = ref(null)
onMounted(() => {
document.querySelector(`#${props.id}[open]`)?.addEventListener("load",()=>{
console.log("loading")
})
document.querySelector(`#${props.id}`).addEventListener("load",()=>{
console.log("loading")
})
})
</script> </script>
<template> <template>
<!-- Open the modal using ID.showModal() method --> <dialog
<!-- :class="twMerge('modal', open && innerOpen ? 'modal-open' : 'modal-close')" --> :id="id"
<dialog ref="dom" :id="id" :class="twMerge( :class="
twMerge(
'modal', 'modal',
backdrop backdrop ? '' : 'focus-visible:outline-none backdrop:bg-transparent'
? '' )
: 'focus-visible:outline-none backdrop:bg-transparent', "
)" :style="modalStyle" v-draggable="draggable"> :style="modalStyle"
<div :class="twMerge( v-draggable="
'modal-box static rounded-md border border-info py-5 px-6 overflow-y-scroll bg-normal', draggable ? { handle: '[data-drag-handle]', target: '.modal-box' } : false
"
>
<div
:class="
twMerge(
'modal-box static rounded-md border border-info py-5 px-6 overflow-y-auto bg-normal',
modalClass modalClass
) )
" :style="{ maxWidth: isNaN(width) ? width : `${width}px` }"> "
<div class="text-2xl font-bold"> :style="{ maxWidth: isNaN(width) ? width : `${width}px` }"
<slot name="modalTitle"> >
{{ title }} <!-- 把手只在這裡按下才可拖動 -->
</slot> <div class="text-2xl font-bold select-none" data-drag-handle>
<slot name="modalTitle">{{ title }}</slot>
</div> </div>
<div class="min-h-[200px]"> <div class="min-h-[200px]">
<slot name="modalContent"></slot> <slot name="modalContent"></slot>
</div> </div>
@ -68,25 +50,17 @@ onMounted(() => {
<slot name="modalAction"></slot> <slot name="modalAction"></slot>
</div> </div>
</div> </div>
<form v-if="backdrop" method="dialog" class="modal-backdrop"> <form v-if="backdrop" method="dialog" class="modal-backdrop">
<button @click="() => { <button
onCancel ? onCancel() : cancel(); @click="
() => {
onCancel && onCancel();
} }
"> "
>
close close
</button> </button>
</form> </form>
</dialog> </dialog>
</template> </template>
<style lang="css" scoped>
.modal-box::before {
@apply fixed top-1 right-1 h-5 w-5 rotate-90 bg-no-repeat z-10 bg-[url('../../assets/img/table/content-box-background01.svg')] bg-center;
content: "";
}
.modal-action::after {
@apply absolute -bottom-3 -left-4 h-5 w-5 rotate-90 bg-no-repeat z-10 bg-[url('../../assets/img/table/content-box-background05.svg')] bg-center;
content: "";
}
</style>

View File

@ -1,64 +1,97 @@
const moveModal = (elmnt) => { // src/directives/draggable.js
console.log(elmnt); // 用法:在 Modal 外層加 v-draggable="{ handle: '[data-drag-handle]', target: '.modal-box' }"
var pos1 = 0, // - handle只在這個節點按下才可拖動
pos2 = 0, // - target實際被拖動的 DOM預設用 el 本身)
pos3 = 0,
pos4 = 0;
document.body.addEventListener("mousedown", dragMouseDown, {
passive: false,
});
function dragMouseDown(e) { function createDraggable(el, options = {}) {
console.log("dragMouseDown", e); const cancelSelector =
e = e || window.event; 'input, textarea, select, button, [contenteditable="true"], [data-drag-cancel]';
const target =
(options.target && el.querySelector(options.target)) ||
el.querySelector('.modal-box') ||
el;
const handle =
(options.handle && el.querySelector(options.handle)) || target;
let startX = 0,
startY = 0,
originLeft = 0,
originTop = 0,
dragging = false;
// 只在「左鍵」且「不是表單控制項」時啟動拖曳
function onMouseDown(e) {
if (e.button !== 0) return;
// 點到可互動元件就不要拖(也不要 preventDefault讓它能聚焦
if (e.target.matches(cancelSelector) || e.target.closest(cancelSelector)) {
return;
}
// 這裡才開始準備拖曳
dragging = true;
const rect = target.getBoundingClientRect();
originLeft = rect.left;
originTop = rect.top;
startX = e.clientX;
startY = e.clientY;
// 只有在真的要拖時才阻止預設,避免選字/圖片拖移
e.preventDefault(); e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX; // 以視窗為座標系比較直觀
pos4 = e.clientY; target.style.position = 'fixed';
document.body.addEventListener("mouseup", closeDragElement, { target.style.left = '0px';
passive: false, target.style.top = '0px';
}); target.style.transform = `translate(${originLeft}px, ${originTop}px)`;
// call a function whenever the cursor moves:
document.body.addEventListener("mousemove", elementDrag, { window.addEventListener('mousemove', onMouseMove, { passive: false });
passive: false, window.addEventListener('mouseup', onMouseUp, { passive: true });
});
} }
function elementDrag(e) { function onMouseMove(e) {
e = e || window.event; if (!dragging) return;
e.preventDefault(); const dx = e.clientX - startX;
// calculate the new cursor position: const dy = e.clientY - startY;
pos1 = pos3 - e.clientX; target.style.transform = `translate(${originLeft + dx}px, ${originTop + dy}px)`;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.top = elmnt.offsetTop - pos2 + "px";
elmnt.style.left = elmnt.offsetLeft - pos1 + "px";
} }
function closeDragElement() { function onMouseUp() {
// stop moving when mouse button is released: dragging = false;
document.body.removeEventListener("mouseup", closeDragElement); window.removeEventListener('mousemove', onMouseMove);
document.body.removeEventListener("mousemove", elementDrag); window.removeEventListener('mouseup', onMouseUp);
} }
handle.style.cursor = 'move';
handle.addEventListener('mousedown', onMouseDown, { passive: false });
// 提供清理函式給 unmounted 用
return () => {
handle.removeEventListener('mousedown', onMouseDown);
window.removeEventListener('mousemove', onMouseMove);
window.removeEventListener('mouseup', onMouseUp);
}; };
}
export const draggable = { export const draggable = {
install(app) { install(app) {
app.directive("draggable", { app.directive('draggable', {
mounted: (el, binding, vnode, prevVnode) => { mounted(el, binding) {
console.log("draggable", $(`#${el.id}`).draggable); // 允許 v-draggable 或 v-draggable="true" 或 v-draggable="{ handle, target }"
if (binding.value) { const enabled =
if ($(`#${el.id}`).draggable) { binding.value === '' || binding.value === true || typeof binding.value === 'object';
$(`#${el.id}`).draggable({ if (!enabled) return;
cursor: "move",
scroll: true, // 以前用 jQuery UI 的判斷會在沒有 $ 或 .draggable 時噴錯,直接移除
container: ".app-container", const options = typeof binding.value === 'object' ? binding.value : {};
}); el.__dragCleanup__ = createDraggable(el, options);
} else { },
moveModal(el); unmounted(el) {
} if (el.__dragCleanup__) {
el.__dragCleanup__();
delete el.__dragCleanup__;
} }
}, },
}); });