• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

若依框架 -------- vue3+element-plus(三)

武飞扬头像
童小纯
帮助1

后端管理系统,前后端分离的框架若依管理后台,来看下vue3 element-plus版本。

静态文本 assets

assets 静态img、svg、style

main.js import '@/assets/styles/index.scss' // global css 引入了全局样式

 组件 components

breadcrumb 面包屑

从路由中获取面包屑路径

  1.  
    <template>
  2.  
    <el-breadcrumb class="app-breadcrumb" separator="/">
  3.  
    <transition-group name="breadcrumb">
  4.  
    <el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
  5.  
    <span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{ item.meta.title }}</span>
  6.  
    <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
  7.  
    </el-breadcrumb-item>
  8.  
    </transition-group>
  9.  
    </el-breadcrumb>
  10.  
    </template>
  11.  
     
  12.  
    <script setup>
  13.  
    const route = useRoute();
  14.  
    const router = useRouter();
  15.  
    const levelList = ref([])
  16.  
     
  17.  
    function getBreadcrumb() {
  18.  
    // only show routes with meta.title
  19.  
    let matched = route.matched.filter(item => item.meta && item.meta.title);
  20.  
    const first = matched[0]
  21.  
    // 判断是否为首页
  22.  
    if (!isDashboard(first)) {
  23.  
    matched = [{ path: '/index', meta: { title: '首页' } }].concat(matched)
  24.  
    }
  25.  
     
  26.  
    levelList.value = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
  27.  
    }
  28.  
    function isDashboard(route) {
  29.  
    const name = route && route.name
  30.  
    if (!name) {
  31.  
    return false
  32.  
    }
  33.  
    return name.trim() === 'Index'
  34.  
    }
  35.  
    function handleLink(item) {
  36.  
    const { redirect, path } = item
  37.  
    if (redirect) {
  38.  
    router.push(redirect)
  39.  
    return
  40.  
    }
  41.  
    router.push(path)
  42.  
    }
  43.  
     
  44.  
    watchEffect(() => {
  45.  
    // if you go to the redirect page, do not update the breadcrumbs
  46.  
    if (route.path.startsWith('/redirect/')) {
  47.  
    return
  48.  
    }
  49.  
    getBreadcrumb()
  50.  
    })
  51.  
    getBreadcrumb();
  52.  
    </script>
  53.  
     
  54.  
    <style lang='scss' scoped>
  55.  
    .app-breadcrumb.el-breadcrumb {
  56.  
    display: inline-block;
  57.  
    font-size: 14px;
  58.  
    line-height: 50px;
  59.  
    margin-left: 8px;
  60.  
     
  61.  
    .no-redirect {
  62.  
    color: #97a8be;
  63.  
    cursor: text;
  64.  
    }
  65.  
    }
  66.  
    </style>

hamburger

展示按钮svg图标

headerSearch 搜索框

Fuse.js——用于JavaScript中数据的模糊搜索

pagination 分页

treeSelect 树选取器

topNav 顶部导航

  1.  
    <template>
  2.  
    <el-menu
  3.  
    :default-active="activeMenu"
  4.  
    mode="horizontal"
  5.  
    @select="handleSelect"
  6.  
    >
  7.  
    <template v-for="(item, index) in topMenus">
  8.  
    <el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber"
  9.  
    ><svg-icon :icon-class="item.meta.icon" />
  10.  
    {{ item.meta.title }}</el-menu-item
  11.  
    >
  12.  
    </template>
  13.  
     
  14.  
    <!-- 顶部菜单超出数量折叠 -->
  15.  
    <el-sub-menu :style="{'--theme': theme}" index="more" v-if="topMenus.length > visibleNumber">
  16.  
    <template #title>更多菜单</template>
  17.  
    <template v-for="(item, index) in topMenus">
  18.  
    <el-menu-item
  19.  
    :index="item.path"
  20.  
    :key="index"
  21.  
    v-if="index >= visibleNumber"
  22.  
    ><svg-icon :icon-class="item.meta.icon" />
  23.  
    {{ item.meta.title }}</el-menu-item
  24.  
    >
  25.  
    </template>
  26.  
    </el-sub-menu>
  27.  
    </el-menu>
  28.  
    </template>
  29.  
     
  30.  
    <script setup>
  31.  
    import { constantRoutes } from "@/router"
  32.  
    import { isHttp } from '@/utils/validate'
  33.  
     
  34.  
    // 顶部栏初始数
  35.  
    const visibleNumber = ref(null);
  36.  
    // 是否为首次加载
  37.  
    const isFrist = ref(null);
  38.  
    // 当前激活菜单的 index
  39.  
    const currentIndex = ref(null);
  40.  
     
  41.  
    const store = useStore();
  42.  
    const route = useRoute();
  43.  
     
  44.  
    // 主题颜色
  45.  
    const theme = computed(() => store.state.settings.theme);
  46.  
    // 所有的路由信息
  47.  
    const routers = computed(() => store.state.permission.topbarRouters);
  48.  
     
  49.  
    // 顶部显示菜单
  50.  
    const topMenus = computed(() => {
  51.  
    let topMenus = [];
  52.  
    routers.value.map((menu) => {
  53.  
    if (menu.hidden !== true) {
  54.  
    // 兼容顶部栏一级菜单内部跳转
  55.  
    if (menu.path === "/") {
  56.  
    topMenus.push(menu.children[0]);
  57.  
    } else {
  58.  
    topMenus.push(menu);
  59.  
    }
  60.  
    }
  61.  
    })
  62.  
    return topMenus;
  63.  
    })
  64.  
     
  65.  
    // 设置子路由
  66.  
    const childrenMenus = computed(() => {
  67.  
    let childrenMenus = [];
  68.  
    routers.value.map((router) => {
  69.  
    for (let item in router.children) {
  70.  
    if (router.children[item].parentPath === undefined) {
  71.  
    if(router.path === "/") {
  72.  
    router.children[item].path = "/redirect/" router.children[item].path;
  73.  
    } else {
  74.  
    if(!isHttp(router.children[item].path)) {
  75.  
    router.children[item].path = router.path "/" router.children[item].path;
  76.  
    }
  77.  
    }
  78.  
    router.children[item].parentPath = router.path;
  79.  
    }
  80.  
    childrenMenus.push(router.children[item]);
  81.  
    }
  82.  
    })
  83.  
    return constantRoutes.concat(childrenMenus);
  84.  
    })
  85.  
     
  86.  
    // 默认激活的菜单
  87.  
    const activeMenu = computed(() => {
  88.  
    const path = route.path;
  89.  
    let activePath = defaultRouter.value;
  90.  
    if (path !== undefined && path.lastIndexOf("/") > 0) {
  91.  
    const tmpPath = path.substring(1, path.length);
  92.  
    activePath = "/" tmpPath.substring(0, tmpPath.indexOf("/"));
  93.  
    } else if ("/index" == path || "" == path) {
  94.  
    if (!isFrist.value) {
  95.  
    isFrist.value = true;
  96.  
    } else {
  97.  
    activePath = "index";
  98.  
    }
  99.  
    }
  100.  
    let routes = activeRoutes(activePath);
  101.  
    if (routes.length === 0) {
  102.  
    activePath = currentIndex.value || defaultRouter.value
  103.  
    activeRoutes(activePath);
  104.  
    }
  105.  
    return activePath;
  106.  
    })
  107.  
    // 默认激活的路由
  108.  
    const defaultRouter = computed(() => {
  109.  
    let router;
  110.  
    Object.keys(routers.value).some((key) => {
  111.  
    if (!routers.value[key].hidden) {
  112.  
    router = routers.value[key].path;
  113.  
    return true;
  114.  
    }
  115.  
    });
  116.  
    return router;
  117.  
    })
  118.  
    function setVisibleNumber() {
  119.  
    const width = document.body.getBoundingClientRect().width / 3;
  120.  
    visibleNumber.value = parseInt(width / 85);
  121.  
    }
  122.  
    function handleSelect(key, keyPath) {
  123.  
    currentIndex.value = key;
  124.  
    if (isHttp(key)) {
  125.  
    // http(s):// 路径新窗口打开
  126.  
    window.open(key, "_blank");
  127.  
    } else if (key.indexOf("/redirect") !== -1) {
  128.  
    // /redirect 路径内部打开
  129.  
    router.push({ path: key.replace("/redirect", "") });
  130.  
    } else {
  131.  
    // 显示左侧联动菜单
  132.  
    activeRoutes(key);
  133.  
    }
  134.  
    }
  135.  
    function activeRoutes(key) {
  136.  
    let routes = [];
  137.  
    if (childrenMenus.value && childrenMenus.value.length > 0) {
  138.  
    childrenMenus.value.map((item) => {
  139.  
    if (key == item.parentPath || (key == "index" && "" == item.path)) {
  140.  
    routes.push(item);
  141.  
    }
  142.  
    });
  143.  
    }
  144.  
    if(routes.length > 0) {
  145.  
    store.commit("SET_SIDEBAR_ROUTERS", routes);
  146.  
    }
  147.  
    return routes;
  148.  
    }
  149.  
     
  150.  
    onMounted(() => {
  151.  
    window.addEventListener('resize', setVisibleNumber)
  152.  
    })
  153.  
    onBeforeUnmount(() => {
  154.  
    window.removeEventListener('resize', setVisibleNumber)
  155.  
    })
  156.  
     
  157.  
    onMounted(() => {
  158.  
    setVisibleNumber()
  159.  
    })
  160.  
    </script>
  161.  
     
  162.  
    <style lang="scss">
  163.  
    .topmenu-container.el-menu--horizontal > .el-menu-item {
  164.  
    float: left;
  165.  
    height: 50px !important;
  166.  
    line-height: 50px !important;
  167.  
    color: #999093 !important;
  168.  
    padding: 0 5px !important;
  169.  
    margin: 0 10px !important;
  170.  
    }
  171.  
     
  172.  
    .topmenu-container.el-menu--horizontal > .el-menu-item.is-active, .el-menu--horizontal > .el-sub-menu.is-active .el-submenu__title {
  173.  
    border-bottom: 2px solid #{'var(--theme)'} !important;
  174.  
    color: #303133;
  175.  
    }
  176.  
     
  177.  
    /* sub-menu item */
  178.  
    .topmenu-container.el-menu--horizontal > .el-sub-menu .el-submenu__title {
  179.  
    float: left;
  180.  
    height: 50px !important;
  181.  
    line-height: 50px !important;
  182.  
    color: #999093 !important;
  183.  
    padding: 0 5px !important;
  184.  
    margin: 0 10px !important;
  185.  
    }
  186.  
    </style>

router.js中指定了布局

  1.  
    import Layout from '@/layout'
  2.  
     
  3.  
    {
  4.  
    path: '/user',
  5.  
    // 页面布局
  6.  
    component: Layout,
  7.  
    hidden: true,
  8.  
    redirect: 'noredirect',
  9.  
    children: [
  10.  
    {
  11.  
    path: 'profile',
  12.  
    component: () => import('@/views/system/user/profile/index'),
  13.  
    name: 'Profile',
  14.  
    meta: { title: '个人中心', icon: 'user' }
  15.  
    }
  16.  
    ]
  17.  
    },

layout/index.vue 实现了页面的布局

  1.  
    <template>
  2.  
    <div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme }">
  3.  
    <div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
  4.  
    <!-- 菜单栏 -->
  5.  
    <sidebar class="sidebar-container" />
  6.  
    <!-- 标签 -->
  7.  
    <div :class="{ hasTagsView: needTagsView }" class="main-container">
  8.  
    <div :class="{ 'fixed-header': fixedHeader }">
  9.  
    <navbar @setLayout="setLayout" />
  10.  
    <tags-view v-if="needTagsView" />
  11.  
    </div>
  12.  
    <!-- 主视图 -->
  13.  
    <app-main />
  14.  
    <settings ref="settingRef" />
  15.  
    </div>
  16.  
    </div>
  17.  
    </template>

前端框架的 组件及页面布局完成。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgehhag
系列文章
更多 icon
同类精品
更多 icon
继续加载