vue3 多页签导航

<template>
  <div class="px-10px bg-white flex ">
    <a-tabs v-model:activeKey="tabsMenuValue" @tabClick="tabClick" class="flex-1">
      <a-tab-pane v-for="item in tabsMenuList" :key="item.path">
        <template #tab>
          <span>
            <dashboard-outlined />
            {{ item.title }}
            <close-outlined v-if="item.close" @click.stop="tabRemove(item)" class="ml-4px" />
          </span>
        </template>
      </a-tab-pane>
    </a-tabs>
    <div style="width: 80px;" class="flex align-items-center justify-content-center ">
      <a-dropdown>
        <a-button type="primary" size="small">
          {{ $t("tabs.more") }}
          <DownOutlined />
        </a-button>
        <template #overlay>
          <a-menu>
            <a-menu-item>
              <a href="javascript:;" @click="closeCurrent">{{ $t("tabs.closeCurrent") }}</a>
            </a-menu-item>
            <a-menu-item>
              <a href="javascript:;" @click="closeOtherTab">{{ $t("tabs.closeOther") }}</a>
            </a-menu-item>
          </a-menu>
        </template>
      </a-dropdown>
    </div>
  </div>
</template>
<script  lang='ts' setup>
import Sortable from "sortablejs";
import { onMounted, ref, computed, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router';
import { useTabsStore } from '@/store/useTabsStore'
import { useKeepAliveStore } from '@/store/keepAlive'
import { DashboardOutlined, CloseOutlined, DownOutlined } from '@ant-design/icons-vue'
const route = useRoute()
const router = useRouter()
const tabsMenuValue = ref(route.fullPath);
const tabStore = useTabsStore();
const keepAliveStore = useKeepAliveStore();
const tabsMenuList = computed(() => tabStore.tabsMenuList);

// 监听路由的变化(防止浏览器后退/前进不变化 tabsMenuValue)
watch(
  () => route.fullPath,
  () => {
    if (route.meta.isFull) return;
    tabsMenuValue.value = route.fullPath;
    const tabsParams = {
      icon: route.meta.icon as string,
      title: route.meta.title as string,
      path: route.fullPath,
      name: route.name as string,
      close: !route.meta.isAffix
    };
    tabStore.addTabs(tabsParams);
    route.meta.isKeepAlive && keepAliveStore.addKeepAliveName(route.name as string);
  },
  { immediate: true }
);
onMounted(() => {
  tabsDrop()
})

const tabClick = (path: string) => {
  console.log(path)
  router.push(path);
}
// Remove Tab
const tabRemove = (item: any) => {
  console.log('item', item)
  const { path }: { path: string } = item
  const name = tabStore.tabsMenuList.filter(item => item.path == path)[0].name || "";
  keepAliveStore.removeKeepAliveName(name);
  tabStore.removeTabs(path as string, path == route.fullPath);
};

function closeCurrent() {
  console.log(route)
  if (route.meta.isAffix) return
  tabStore.removeTabs(route.fullPath)
  keepAliveStore.removeKeepAliveName(route.name as string)
}
function closeOtherTab() {

  tabStore.closeMultipleTab(route.fullPath)
  keepAliveStore.setKeepAliveName([route.name] as string[])
}

// tabs 拖拽排序
const tabsDrop = () => {
  Sortable.create(document.querySelector(".ant-tabs-nav-list") as HTMLElement, {
    draggable: ".ant-tabs-tab",
    animation: 300,
    // onEnd({ newIndex, oldIndex }:{ newIndex: number, oldIndex: number }) {
    //   const tabsList = [...tabStore.tabsMenuList];
    //   const currRow = tabsList.splice(oldIndex as number, 1)[0];
    //   tabsList.splice(newIndex as number, 0, currRow);
    //   tabStore.setTabs(tabsList);
    // }
  });
};
</script>
<style lang="scss" scoped>
:deep(.ant-tabs-nav) {
  margin-bottom: 0 !important;
}
</style>
import router from "@/router";
import { defineStore } from 'pinia'
import { TabsMenuProps, TabsState } from './interface/index'
export const useTabsStore = defineStore('useTabsStore', {
  state: (): TabsState => ({
    tabsMenuList: []
  }),
  actions: {
    // Add Tabs
    async addTabs(tabItem: TabsMenuProps) {
      if (this.tabsMenuList.every(item => item.path !== tabItem.path)) {
        this.tabsMenuList.push(tabItem);
      }
    },
    // Remove Tabs
    async removeTabs(tabPath: string, isCurrent = true) {
      const tabsMenuList = this.tabsMenuList;
      if (isCurrent) {
        tabsMenuList.forEach((item, index) => {
          if (item.path !== tabPath) return;
          const nextTab = tabsMenuList[index + 1] || tabsMenuList[index - 1];
          if (!nextTab) return;
          router.push(nextTab.path);
        });
      }
      this.tabsMenuList = tabsMenuList.filter(item => item.path !== tabPath);
    },
    // Close MultipleTab
    async closeMultipleTab(tabsMenuValue?: string) {
      this.tabsMenuList = this.tabsMenuList.filter(item => {
        return item.path === tabsMenuValue || !item.close;
      });
    },
    // Set Tabs
    async setTabs(tabsMenuList: TabsMenuProps[]) {
      this.tabsMenuList = tabsMenuList;
    },
    // Set Tabs Title
    async setTabsTitle(title: string) {
      const nowFullPath = location.hash.substring(1);
      this.tabsMenuList.forEach(item => {
        if (item.path == nowFullPath) item.title = title;
      });
    }
  },
})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,以下是使用Vue 3创建前端导航页面的步骤: 1. 安装Vue 3 首先需要在你的项目中安装Vue 3。你可以使用npm或者yarn进行安装。在命令行中运行如下命令: ``` npm install vue@next ``` 或者 ``` yarn add vue@next ``` 2. 创建Vue实例 在你的HTML文件中创建一个Vue实例。你可以通过`<script>`标Vue实例引入到你的HTML文件中。在Vue实例中,你需要定义一个`data`属性,该属性包含一个数组,用于存储导航链接的信息。如下所示: ```html <div id="app"> <ul> <li v-for="link in links" :key="link.id"> <a :href="link.url">{{ link.text }}</a> </li> </ul> </div> <script> const app = Vue.createApp({ data() { return { links: [ { id: 1, text: '首页', url: '/' }, { id: 2, text: '新闻', url: '/news' }, { id: 3, text: '关于我们', url: '/about' }, { id: 4, text: '联系我们', url: '/contact' } ] } } }) app.mount('#app') </script> ``` 在这个例子中,我们定义了一个`data`属性,其中包含了一个包含导航链接信息的数组。然后,我们使用`v-for`指令在`<ul>`元素中遍历数组,并使用`v-bind`指令动态绑定链接的`href`属性和链接文本的`text`属性。 3. 样式处理 现在我们已经有了导航链接,我们需要添加一些样式来使页面看起来更好。我们可以使用CSS或者SCSS来为页面添加样式。下面是一个简单的样式表: ```css ul { list-style-type: none; margin: 0; padding: 0; display: flex; justify-content: space-between; align-items: center; } li { margin: 0 10px; } a { color: #333; text-decoration: none; font-size: 16px; font-weight: 600; } ``` 这个样式表设置了`<ul>`元素的样式为一个水平列表,每个列表项之间有一定的间距。链接的样式包括字体颜色、字体大小和字体粗细。 4. 添加动态数据 我们可以让页面更加动态,通过使用Vue的计算属性和方法,根据不同条件动态添加导航链接。 ```html <div id="app"> <ul> <li v-for="link in links" :key="link.id"> <a :href="link.url">{{ link.text }}</a> </li> <li v-if="isLoggedIn"><a href="/dashboard">仪表板</a></li> </ul> </div> <script> const app = Vue.createApp({ data() { ### 回答2: 使用Vue3技术创建前端导航页面非常简单。首先,我们需要安装Vue3,并创建一个新的Vue应用程序。 接下来,我们可以创建一个名为Navigation的组件,用于呈现导航页面的内容。在该组件中,我们可以定义一个数据属性,用于保存导航条目的信息。每个导航条目可以包含一个标题和一个URL。 然后,我们可以在组件的模板中使用Vue的指令和插值语法,动态地生成导航菜单。我们可以使用v-for指令在导航条目的数组上循环,并使用v-bind指令绑定要显示的数据。我们还可以使用v-bind指令绑定一个点击事件处理程序,当用户点击导航条目时,可以执行相关操作。 最后,我们可以在应用程序的主组件中导入并使用Navigation组件。我们可以在模板中放置一个导航菜单的div,并在其中使用Navigation组件来呈现导航页面的内容。 使用Vue3的响应式特性,当导航条目的信息发生变化时,导航页面会自动更新。这使得我们可以轻松地添加、编辑或删除导航条目。 总之,使用Vue3技术创建一个前端导航页面是非常简单的。通过建立一个导航组件,使用Vue的指令和插值语法来动态生成导航菜单,并使用Vue的响应式特性来自动更新页面,我们可以轻松地创建一个灵活且易于维护的导航页面。 ### 回答3: 使用Vue 3技术可以轻松地创建一个功能强大的前端导航页面。首先,我们可以使用Vue 3的组件化开发特性,将页面拆分为多个组件,使代码更加模块化和可维护。 在创建导航页面的时候,可以使用Vue Router来管理路由。Vue Router是Vue官方提供的路由管理工具,它可以帮助我们在前端实现多页面间的跳转和路由配置。 在导航页面中,我们可以创建一个顶部导航栏组件和一个左侧菜单栏组件。顶部导航栏组件可以包含网站的Logo、搜索框和用户登录信息,可以通过Vue的数据绑定和计算属性来实现动态展示。 左侧菜单栏组件可以根据用户权限动态生成菜单列表,通过Vue的条件渲染和循环渲染来实现。当用户点击菜单项时,可以通过Vue Router的路由配置来跳转到相应的页面。 除了基本的导航功能,我们还可以使用Vue 3的动画特性来实现页面过渡效果,让导航页面更加流畅和美观。例如,可以给菜单栏添加展开和收起的动画,让用户操作更加友好。 最后,我们可以使用Vue 3的状态管理工具Vuex来管理全局的状态和数据。例如,可以通过Vuex来保存用户登录信息、菜单权限等数据,方便在各个组件中进行访问和更新。 总结来说,使用Vue 3技术可以实现一个功能强大的前端导航页面,具备模块化、动态路由、动画效果和全局状态管理等特性,提升用户体验并方便后续的扩展和维护。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值