HasChildren.vue 7.8 KB
<template>
  <div class="mb-6">
    <div class="flex items-center mb-2">
      <i
        :id="`term-${childData.id}`"
        class="iconfont text-lg mr-2"
        :class="[`icon-${childData.icon}`]"
      ></i>
      <h4 class="text-xl text-[#555] dark:text-[#888]">
        {{ childData.label }}
      </h4>
    </div>
    <div class="flex items-center flex-auto">
      <div
        class="scroll-container relative bg-black/10 dark:bg-[#17181a] rounded-[50px] md:overflow-hidden p-[3px] overflow-y-auto"
        slidertab="sliderTab"
      >
        <ul
          class="relative whitespace-nowrap flex"
          style="flex-wrap: inherit"
          role="tablist"
        >
          <li
            v-for="(child, index) in childData.children"
            :key="child.id"
            class="h-auto w-auto cursor-pointer rounded-[100px] transition-all duration-350"
            :class="[
              activeSubCategoryId === `term-${childData.id}-${child.id}` ||
              index === currentFilter
                ? 'bg-[#5961f9]'
                : '',
            ]"
          >
            <a
              :id="`term-${childData.id}-${child.id}`"
              class="h-7 leading-7 px-3 block relative text-[#888] text-center md:text-sm text-xs md:leading-7"
              :class="[
                activeSubCategoryId === `term-${childData.id}-${child.id}` ||
                index === currentFilter
                  ? 'text-white'
                  : '',
              ]"
              style="transition: 0.25s"
              :href="`#tab-${childData.id}-${child.id}`"
              @click.stop="onClick($event, child.alias, index)"
              >{{ child.label }}</a
            >
          </li>
        </ul>
      </div>
      <div class="flex-auto"></div>
      <a
        class="hidden md:block text-xs ml-2 text-[#282a2d] hover:text-[#5961f9]"
        :href="`${config.public.baseUrl}/category/${childAlias}`"
        >查看更多 &gt;&gt;</a
      >
      <a
        class="md:hidden text-xs ml-2 text-[#282a2d] hover:text-[#5961f9]"
        :href="`${config.public.baseUrl}/category/${childAlias}`"
        >&gt;&gt;</a
      >
    </div>
  </div>

  <!-- 内容区域 -->
  <div
    v-for="(childContentItem, childContentIndex) in childData.children"
    :key="childContentItem.id"
    v-show="
      activeSubCategoryId === `term-${childData.id}-${childContentItem.id}` ||
      childContentIndex === currentFilter
    "
    :id="`tab-${childData.id}-${childContentItem.id}`"
    class="grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 md:gap-6 gap-4"
  >
    <div
      v-for="appItem in childContentItem.appVos"
      :key="appItem.id"
      class="bg-white dark:bg-[#272929] rounded-xl shadow-md overflow-hidden hover:shadow-lg hover:translate-y-[-6px] transition-all duration-300"
    >
      <el-popconfirm
        v-if="appItem.isPopup == '1'"
        class="box-item"
        :title="appItem.popupContent"
        placement="top-start"
        width="280"
        :icon="Promotion"
        confirm-button-text="确认前往"
        cancel-button-text="取消"
        @confirm="onConfirm(appItem.id)"
      >
        <template #reference>
          <a
            :href="config.public.baseUrl + '/site-details/' + appItem.id"
            target="_blank"
            @click.stop="onNuxtLink"
          >
            <div class="group p-3">
              <div class="flex items-start space-x-4">
                <img
                  loading="lazy"
                  :src="config.public.apiUrl + appItem.image"
                  :alt="appItem.title"
                  class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg"
                />
                <div>
                  <h3
                    class="font-bold dark:text-[#c6c9cf] md:text-base text-sm line-clamp-1 text-gray-800 transition group-hover:text-[#5961f9] dark:group-hover:text-white"
                  >
                    {{ appItem.title }}
                  </h3>
                  <p
                    class="text-gray-600 dark:text-[#6c757d] text-xs mt-1 md:line-clamp-2 line-clamp-1"
                  >
                    {{ appItem.description }}
                  </p>
                </div>
              </div>
            </div>
          </a>
        </template>
      </el-popconfirm>
      <a
        v-else
        :href="config.public.baseUrl + '/site-details/' + appItem.id"
        target="_blank"
      >
        <div class="group p-3">
          <div class="flex items-start space-x-4">
            <img
              loading="lazy"
              :src="config.public.apiUrl + appItem.image"
              :alt="appItem.title"
              class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg"
            />
            <div>
              <h3
                class="font-bold dark:text-[#c6c9cf] md:text-base text-sm line-clamp-1 text-gray-800 transition group-hover:text-[#5961f9] dark:group-hover:text-white"
              >
                {{ appItem.title }}
              </h3>
              <p
                class="text-gray-600 dark:text-[#6c757d] text-xs mt-1 md:line-clamp-2 line-clamp-1"
              >
                {{ appItem.description }}
              </p>
            </div>
          </div>
        </div>
      </a>
    </div>
  </div>
</template>

<script setup lang="ts">
import { Promotion } from "@element-plus/icons-vue";

const props = defineProps<{
  childData: any;
}>();
const route = useRoute();
const childAlias = ref(props.childData.children[0].alias);
const config = useRuntimeConfig();
const { activeSubCategoryId, setActiveSubCategory } = useActiveSubCategory();

// 监听activeSubCategoryId的变化,当变化是把currentFilter更新为-1
watch(activeSubCategoryId, (newValue, oldValue) => {
  if (newValue !== oldValue) {
    currentFilter.value = -1;
  }
});

function onNuxtLink(event: any) {
  event.preventDefault();
}

function onConfirm(id: number) {
  window.open(`/site-details/${id}`);
}

const currentFilter = ref(0);

function onClick(event: any, alias: string, index: number) {
  event?.preventDefault();
  childAlias.value = alias;
  currentFilter.value = index;
  const targetId = `term-${props.childData.id}-${props.childData.children[index].id}`;
  setActiveSubCategory(targetId);
}

const scrollToSubCategory = () => {
  if (import.meta.client) {
    const hash = window.location.hash;
    if (hash && hash.startsWith("#term-")) {
      const parts = hash.replace("#term-", "").split("-");
      if (parts.length === 2) {
        const parentId = parts[0];
        const childId = parts[1];

        if (parentId === String(props.childData.id)) {
          const index = props.childData.children.findIndex(
            (child: any) => String(child.id) === childId
          );
          if (index !== -1) {
            currentFilter.value = index;
            childAlias.value = props.childData.children[index].alias;
            const targetId = `term-${parentId}-${childId}`;
            setActiveSubCategory(targetId);

            nextTick(() => {
              const element = document.getElementById(targetId);
              if (element) {
                element.scrollIntoView({
                  behavior: "smooth",
                  block: "center",
                });
              }
            });
          }
        }
      } else if (parts.length === 1) {
        const parentId = parts[0];
        if (parentId === String(props.childData.id)) {
          nextTick(() => {
            const element = document.getElementById(`term-${parentId}`);
            if (element) {
              element.scrollIntoView({
                behavior: "smooth",
                block: "center",
              });
            }
          });
        }
      }
    }
  }
};

onMounted(() => {
  scrollToSubCategory();
  window.addEventListener("hashchange", scrollToSubCategory);
});

onUnmounted(() => {
  window.removeEventListener("hashchange", scrollToSubCategory);
});
</script>