fix: 修正 nav 使用者無法按出drop down
This commit is contained in:
parent
36e390d300
commit
ead85a5652
@ -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="
|
||||||
'modal',
|
twMerge(
|
||||||
backdrop
|
'modal',
|
||||||
? ''
|
backdrop ? '' : 'focus-visible:outline-none backdrop:bg-transparent'
|
||||||
: 'focus-visible:outline-none backdrop:bg-transparent',
|
)
|
||||||
)" :style="modalStyle" v-draggable="draggable">
|
"
|
||||||
<div :class="twMerge(
|
:style="modalStyle"
|
||||||
'modal-box static rounded-md border border-info py-5 px-6 overflow-y-scroll bg-normal',
|
v-draggable="
|
||||||
modalClass
|
draggable ? { handle: '[data-drag-handle]', target: '.modal-box' } : false
|
||||||
)
|
"
|
||||||
" :style="{ maxWidth: isNaN(width) ? width : `${width}px` }">
|
>
|
||||||
<div class="text-2xl font-bold">
|
<div
|
||||||
<slot name="modalTitle">
|
:class="
|
||||||
{{ title }}
|
twMerge(
|
||||||
</slot>
|
'modal-box static rounded-md border border-info py-5 px-6 overflow-y-auto bg-normal',
|
||||||
|
modalClass
|
||||||
|
)
|
||||||
|
"
|
||||||
|
:style="{ maxWidth: isNaN(width) ? width : `${width}px` }"
|
||||||
|
>
|
||||||
|
<!-- 把手:只在這裡按下才可拖動 -->
|
||||||
|
<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>
|
|
||||||
|
@ -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__;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user