NavBar.vue 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. <template>
  2. <!-- 头部 -->
  3. <header>
  4. <div class="inner">
  5. <div class="logo">厦门市文化遗产保护中心</div>
  6. <!-- 导航 -->
  7. <nav class="main-nav" :class="{ show: isMenuOpen }">
  8. <div class="container">
  9. <ul class="nav-list">
  10. <li v-for="item in navItems.content.value" :key="item.url" class="nav-item" :class="{ active: isActive(item.url) }">
  11. <a v-if="item.type === 'link'" :href="item.outlink" target="_blank">{{ item.name }}</a>
  12. <router-link v-else :to="item.url">{{ item.name }}</router-link>
  13. </li>
  14. </ul>
  15. </div>
  16. </nav>
  17. <div class="d-flex flex-row align-items-center">
  18. <button class="mobile-menu-toggle" @click="toggleMenu"><Icon name="material-symbols:menu" /></button>
  19. <div class="search-bar">
  20. <button @click="toggleSearch"><Icon name="material-symbols:search-rounded" /></button>
  21. <input type="text" placeholder="搜索..." v-model="keyword" @blur="hideSearch" @keydown.enter="goSearch" :class="{ show: isSearchOpen }">
  22. </div>
  23. </div>
  24. </div>
  25. </header>
  26. </template>
  27. <script setup lang="ts">
  28. import { ref } from 'vue';
  29. import { useRoute } from 'vue-router';
  30. import { useSSrSimpleDataLoader } from '~/composeable/SimpleDataLoader';
  31. const route = useRoute();
  32. const navItems = await useSSrSimpleDataLoader('navItems', async () => {
  33. const data = (await $fetch('/api/channel/nav')).data || [];
  34. const specialPages = [] as any[];
  35. // 政策法规 特殊页
  36. const lawsPage = data.find(item => item.name === '政策法规');
  37. if (lawsPage) {
  38. lawsPage.url = '/channel/laws/?id=' + lawsPage.id;
  39. }
  40. const contactPage = data.find(item => item.name === '联系我们');
  41. if (contactPage) {
  42. contactPage.url = '/about';
  43. }
  44. specialPages.push(lawsPage, contactPage);
  45. return data.map(item => {
  46. const isSpeical = (specialPages.includes(item));
  47. return {
  48. ...item,
  49. url: isSpeical ? item.url :
  50. (item.type === 'list' ? `/channel/${item.id}` : item.outlink),
  51. }
  52. });
  53. });
  54. const isMenuOpen = ref(false);
  55. const isSearchOpen = ref(false);
  56. const keyword = ref('');
  57. function isActive(url: string): boolean {
  58. return route.path.startsWith(url);
  59. }
  60. function toggleMenu() {
  61. isMenuOpen.value = !isMenuOpen.value;
  62. }
  63. function toggleSearch() {
  64. isSearchOpen.value = !isSearchOpen.value;
  65. }
  66. function hideSearch() {
  67. isSearchOpen.value = false;
  68. }
  69. function goSearch() {
  70. if (keyword.value.trim()) {
  71. window.location.href = `/search/?keyword=${encodeURIComponent(keyword.value.trim())}`;
  72. }
  73. }
  74. </script>