モーダルウインドウの実装例
/src/views/SideBar.vue
<li>タグを右クリックすると現れるモーダルウインドウを実装
@contextmenu.prevent="handleRightClick(record, $event)"
と書いて右クリックイベント実装
<template>
<div>
<label>サイドバー</label>
<!-- リストの表示範囲を制限してスクロール可能にする -->
<ul class="max-h-[calc(100dvh_-_50px)] overflow-y-auto space-y-2 bg-white shadow-md rounded-md custom-scrollbar">
<li
v-for="(record) in filteredRecords"
:key="record.data_id"
class="border-b border-gray-200 last:border-b-0 flex items-center cursor-pointer"
@click="handleClick(record)"
@contextmenu.prevent="handleRightClick(record, $event)"
>
<!-- 動的に画像パスをバインド -->
<img :src="`./thumbnail/${record.img_path}`" alt="record image">
</li>
</ul>
<!-- モーダルウィンドウ -->
<div
v-if="isModalVisible"
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"
>
<div class="bg-white p-4 rounded shadow-md w-96">
<h3 class="text-lg font-semibold mb-2">Record Details</h3>
<p><strong>Data ID:</strong> {{ selectedRecord?.data_id }}</p>
<p><strong>Image Path:</strong> {{ selectedRecord?.img_path }}</p>
<button
@click="closeModal"
class="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
Close
</button>
<button
@click="OpenPic_btn"
class="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
画像を開く
</button>
</div>
</div>
</div>
</template>
<script>
import { ref, reactive, computed, watch, onMounted, toRefs,getCurrentInstance } from 'vue';
import { useUserStore } from "../stores/userStore";
export default {
name: "SideBar",
setup() {
const filteredRecords = ref([]);
const userStore = useUserStore();
const isModalVisible = ref(false); // モーダルの表示状態
const selectedRecord = ref(null); // 選択されたレコード
// フィルタリングロジック
const updateFilteredRecords = () => {
if (!userStore.records || !Array.isArray(userStore.records)) {
filteredRecords.value = [];
return;
}
filteredRecords.value = userStore.records;
};
// `userStore.records` の変更を監視
watch(
() => userStore.records,
(newRecords, oldRecords) => {
console.log("userStore.recordsが変更されました:", {
newRecords,
oldRecords,
});
updateFilteredRecords();
},
{ deep: true, immediate: true }
);
// 左クリックイベントの処理
const handleClick = (record) => {
console.log("クリックされたレコード:", record);
userStore.setSelectItem(record);
};
// 右クリックイベントの処理
const handleRightClick = (record, event) => {
console.log("右クリックされたレコード:", record);
event.preventDefault(); // デフォルトのコンテキストメニューを防止
selectedRecord.value = record; // 選択されたレコードを保存
isModalVisible.value = true; // モーダルを表示
};
// 新しいタブでリンクを開く
const OpenPic_btn = () => {
if (selectedRecord.value && selectedRecord.value.img_path) {
const link = `./images/${selectedRecord.value.img_path}`;
window.open(link, "_blank"); // 新しいタブでリンクを開く
}
isModalVisible.value = false;
selectedRecord.value = null;
};
// モーダルを閉じる
const closeModal = () => {
isModalVisible.value = false;
selectedRecord.value = null;
};
const { proxy } = getCurrentInstance();
const showSuccessToast = () => {
if (!proxy || !proxy.$toast) {
console.error("Toast instance is undefined. Ensure VueToast is properly registered.");
return;
}
proxy.$toast.open({
message: "操作が成功しました!",
type: "success",
duration: 5000,
});
};
return {
//----------------------------------//
showSuccessToast,
//---------------------------------//
filteredRecords,
userStore,
handleClick,
handleRightClick,
isModalVisible,
selectedRecord,
closeModal,
OpenPic_btn,
};
},
};
</script>
<style>
/* カスタムスクロールバーのデザイン */
.custom-scrollbar {
scrollbar-width: thin;
scrollbar-color: #888 #f0f0f0;
}
.custom-scrollbar::-webkit-scrollbar {
width: 8px;
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background-color: #888;
border-radius: 4px;
}
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
background-color: #555;
}
/* モーダルスタイル */
.fixed {
position: fixed;
}
.inset-0 {
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.bg-opacity-50 {
background-color: rgba(0, 0, 0, 0.5);
}
.z-50 {
z-index: 50;
}
.flex {
display: flex;
}
.items-center {
align-items: center;
}
.justify-center {
justify-content: center;
}
.shadow-md {
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
</style>
モーダルウインドウ本体部分
<!-- モーダルウィンドウ -->
<div
v-if="isModalVisible"
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"
>
<div class="bg-white p-4 rounded shadow-md w-96">
<h3 class="text-lg font-semibold mb-2">Record Details</h3>
<p><strong>Data ID:</strong> {{ selectedRecord?.data_id }}</p>
<p><strong>Image Path:</strong> {{ selectedRecord?.img_path }}</p>
<button
@click="closeModal"
class="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
Close
</button>
<button
@click="OpenPic_btn"
class="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
画像を開く
</button>
</div>
</div>