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

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

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


静态文本 assets


assets 静态img、svg、style


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


组件 components


breadcrumb 面包屑


从路由中获取面包屑路径

<template>
  <el-breadcrumb class="app-breadcrumb" separator="/">
    <transition-group name="breadcrumb">
      <el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
        <span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{ item.meta.title }}</span>
        <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
      </el-breadcrumb-item>
    </transition-group>
  </el-breadcrumb>
</template>
<script setup>
const route = useRoute();
const router = useRouter();
const levelList = ref([])
function getBreadcrumb() {
  // only show routes with meta.title
  let matched = route.matched.filter(item => item.meta && item.meta.title);
  const first = matched[0]
  // 判断是否为首页
  if (!isDashboard(first)) {
    matched = [{ path: '/index', meta: { title: '首页' } }].concat(matched)
  }
  levelList.value = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
}
function isDashboard(route) {
  const name = route && route.name
  if (!name) {
    return false
  }
  return name.trim() === 'Index'
}
function handleLink(item) {
  const { redirect, path } = item
  if (redirect) {
    router.push(redirect)
    return
  }
  router.push(path)
}
watchEffect(() => {
  // if you go to the redirect page, do not update the breadcrumbs
  if (route.path.startsWith('/redirect/')) {
    return
  }
  getBreadcrumb()
})
getBreadcrumb();
</script>
<style lang='scss' scoped>
.app-breadcrumb.el-breadcrumb {
  display: inline-block;
  font-size: 14px;
  line-height: 50px;
  margin-left: 8px;
  .no-redirect {
    color: #97a8be;
    cursor: text;
  }
}
</style>


hamburger


展示按钮svg图标


headerSearch 搜索框


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


pagination 分页


treeSelect 树选取器


topNav 顶部导航


<template>
  <el-menu
    :default-active="activeMenu"
    mode="horizontal"
    @select="handleSelect"
  >
    <template v-for="(item, index) in topMenus">
      <el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber"
        ><svg-icon :icon-class="item.meta.icon" />
        {{ item.meta.title }}</el-menu-item
      >
    </template>
    <!-- 顶部菜单超出数量折叠 -->
    <el-sub-menu :style="{'--theme': theme}" index="more" v-if="topMenus.length > visibleNumber">
      <template #title>更多菜单</template>
      <template v-for="(item, index) in topMenus">
        <el-menu-item
          :index="item.path"
          :key="index"
          v-if="index >= visibleNumber"
          ><svg-icon :icon-class="item.meta.icon" />
          {{ item.meta.title }}</el-menu-item
        >
      </template>
    </el-sub-menu>
  </el-menu>
</template>
<script setup>
import { constantRoutes } from "@/router"
import { isHttp } from '@/utils/validate'
// 顶部栏初始数
const visibleNumber = ref(null);
// 是否为首次加载
const isFrist = ref(null);
// 当前激活菜单的 index
const currentIndex = ref(null);
const store = useStore();
const route = useRoute();
// 主题颜色
const theme = computed(() => store.state.settings.theme);
// 所有的路由信息
const routers = computed(() => store.state.permission.topbarRouters);
// 顶部显示菜单
const topMenus = computed(() => {
  let topMenus = [];
  routers.value.map((menu) => {
    if (menu.hidden !== true) {
      // 兼容顶部栏一级菜单内部跳转
      if (menu.path === "/") {
          topMenus.push(menu.children[0]);
      } else {
          topMenus.push(menu);
      }
    }
  })
  return topMenus;
})
// 设置子路由
const childrenMenus = computed(() => {
  let childrenMenus = [];
  routers.value.map((router) => {
    for (let item in router.children) {
      if (router.children[item].parentPath === undefined) {
        if(router.path === "/") {
          router.children[item].path = "/redirect/" + router.children[item].path;
        } else {
          if(!isHttp(router.children[item].path)) {
            router.children[item].path = router.path + "/" + router.children[item].path;
          }
        }
        router.children[item].parentPath = router.path;
      }
      childrenMenus.push(router.children[item]);
    }
  })
  return constantRoutes.concat(childrenMenus);
})
// 默认激活的菜单
const activeMenu = computed(() => {
  const path = route.path;
  let activePath = defaultRouter.value;
  if (path !== undefined && path.lastIndexOf("/") > 0) {
    const tmpPath = path.substring(1, path.length);
    activePath = "/" + tmpPath.substring(0, tmpPath.indexOf("/"));
  } else if ("/index" == path || "" == path) {
    if (!isFrist.value) {
      isFrist.value = true;
    } else {
      activePath = "index";
    }
  }
  let routes = activeRoutes(activePath);
  if (routes.length === 0) {
    activePath = currentIndex.value || defaultRouter.value
    activeRoutes(activePath);
  }
  return activePath;
})
// 默认激活的路由
const defaultRouter = computed(() => {
  let router;
  Object.keys(routers.value).some((key) => {
    if (!routers.value[key].hidden) {
      router = routers.value[key].path;
      return true;
    }
  });
  return router;
})
function setVisibleNumber() {
  const width = document.body.getBoundingClientRect().width / 3;
  visibleNumber.value = parseInt(width / 85);
}
function handleSelect(key, keyPath) {
  currentIndex.value = key;
  if (isHttp(key)) {
    // http(s):// 路径新窗口打开
    window.open(key, "_blank");
  } else if (key.indexOf("/redirect") !== -1) {
    // /redirect 路径内部打开
    router.push({ path: key.replace("/redirect", "") });
  } else {
    // 显示左侧联动菜单
    activeRoutes(key);
  }
}
function activeRoutes(key) {
  let routes = [];
  if (childrenMenus.value && childrenMenus.value.length > 0) {
    childrenMenus.value.map((item) => {
      if (key == item.parentPath || (key == "index" && "" == item.path)) {
        routes.push(item);
      }
    });
  }
  if(routes.length > 0) {
    store.commit("SET_SIDEBAR_ROUTERS", routes);
  }
  return routes;
}
onMounted(() => {
  window.addEventListener('resize', setVisibleNumber)
})
onBeforeUnmount(() => {
  window.removeEventListener('resize', setVisibleNumber)
})
onMounted(() => {
  setVisibleNumber()
})
</script>
<style lang="scss">
.topmenu-container.el-menu--horizontal > .el-menu-item {
  float: left;
  height: 50px !important;
  line-height: 50px !important;
  color: #999093 !important;
  padding: 0 5px !important;
  margin: 0 10px !important;
}
.topmenu-container.el-menu--horizontal > .el-menu-item.is-active, .el-menu--horizontal > .el-sub-menu.is-active .el-submenu__title {
  border-bottom: 2px solid #{'var(--theme)'} !important;
  color: #303133;
}
/* sub-menu item */
.topmenu-container.el-menu--horizontal > .el-sub-menu .el-submenu__title {
  float: left;
  height: 50px !important;
  line-height: 50px !important;
  color: #999093 !important;
  padding: 0 5px !important;
  margin: 0 10px !important;
}
</style>


router.js中指定了布局

import Layout from '@/layout'
{
    path: '/user',
    // 页面布局
    component: Layout,
    hidden: true,
    redirect: 'noredirect',
    children: [
      {
        path: 'profile',
        component: () => import('@/views/system/user/profile/index'),
        name: 'Profile',
        meta: { title: '个人中心', icon: 'user' }
      }
    ]
  },


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

<template>
  <div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme }">
    <div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
    <!-- 菜单栏 -->
    <sidebar class="sidebar-container" />
    <!-- 标签 -->
    <div :class="{ hasTagsView: needTagsView }" class="main-container">
      <div :class="{ 'fixed-header': fixedHeader }">
        <navbar @setLayout="setLayout" />
        <tags-view v-if="needTagsView" />
      </div>
      <!-- 主视图 -->
      <app-main />
      <settings ref="settingRef" />
    </div>
  </div>
</template>


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

目录
相关文章
|
2天前
|
JavaScript 编译器 API
vue2和vue3区别
vue2和vue3区别
11 4
|
1天前
|
存储 JavaScript 前端开发
vue3获取本地的当前时间转化为年月日显示然后计算之后一周的时间
vue3获取本地的当前时间转化为年月日显示然后计算之后一周的时间
|
1天前
|
存储 JavaScript API
Vue 3 中实现引导页
Vue 3 中实现引导页
|
1天前
|
前端开发 JavaScript
vue3中覆盖组件样式的方法
vue3中覆盖组件样式的方法
|
3天前
|
JavaScript
解决vue3中不支持.sync语法糖
解决vue3中不支持.sync语法糖
10 3
|
4天前
|
前端开发 JavaScript API
Vue.js:渐进式JavaScript框架-前端开发
Vue.js:渐进式JavaScript框架-前端开发
14 3
|
4天前
|
JavaScript 前端开发 Unix
vue3毫秒级时间戳转换
该内容介绍了一个关于时间戳转换的工具包,包括将时间转换为时间戳和时间戳转换为时间的两个JavaScript函数。`Jh_convertTimeStamp`函数将日期字符串转换为时间戳,而`Jh_timeStampToTime`函数则将时间戳转换回指定格式的日期字符串。此外,还提到了一个在线时间戳转换工具的链接和一个名为Tools-Web的开源工具站,可用于搭建个人综合工具站。
|
6天前
|
缓存 JavaScript 前端开发
Vue 3的响应式系统
【5月更文挑战第31天】Vue 3的响应式系统
9 1
|
6天前
|
JavaScript Java 测试技术
基于ssm+vue.js的框架失物招领信息交互平台附带文章和源代码设计说明文档ppt
基于ssm+vue.js的框架失物招领信息交互平台附带文章和源代码设计说明文档ppt
13 1
|
7天前
|
JavaScript 前端开发 API
vue2 /vue3【nextTick】的使用方法及实现原理,一文全搞懂!
vue2 /vue3【nextTick】的使用方法及实现原理,一文全搞懂!