当前位置:网站首页>User login 【 I 】
User login 【 I 】
2022-06-12 05:54:00 【Snow flies fast】
Login process analysis

Interface and logic simplification
template modify
- Modify the title
<h3 class="title"> Xiao Mu reads </h3> - Delete prompt area
<div style="position:relative">...</div> - modify
inputOfplaceholderIn Chinese , modifyel-buttonThe Chinese characters are Chinese - Delete
el-dialogCode
script modify
- Delete
SocialSignReference and registration of , DeleteloginComponent'scomponentsFolder - Delete
showDialogVariable - modify
dataThe form verification text in is Chinese - Delete
createdanddestroyedHook functions and annotatedafterQRScanCode
WebstormDuring the development process, you may encounterscriptTag source codeeslintAboutindentThe error of , The solution is as follows :ctrl + alt + LAfter formatting the code ,scriptThere may beindentWarning of , There are two solutions :
close
eslintMediumindentCheckmodify
WebstorminindentSet up
Webstorm => Preferences => Editor => Code Style => HTML => Otherstay
do not indent of childrenaddscriptthat will do
VSCodeInsideprettierThe plug-in format does not exist. This problem can be ignored
Routing instance processing
Start modifying file :
Create components
src/views/book/create.vue, Write something casuallyConfigure the routing , modify
src/router/index.jsOfasyncRoutes:childrenYour route needs to havenameattribute , YesnameAttribute will be intags-viewShow it inmetaProperties inrolesSet the permission of this route , Multiple permissions are supportedtitleSet the route in the sidebar and breadcrumb display texticonCorrespondingsrc/icons/svg, Also supportelement-uiOf icon
For other configuration items, please refer to :vue-element-admin Routing and sidebar Configuration item
export const asyncRoutes = [ { path: '/book', component: Layout, redirect: '/book/create', meta: { title: ' Book management ', icon: 'documentation', roles: ['admin'] }, children: [ { path: '/book/create', component: () => import('@/views/book/create'), name: 'book', meta: { title: ' Upload books ', icon: 'edit', roles: ['admin'] } } ] }, // 404 page must be placed at the end !!! { path: '*', redirect: '/404', hidden: true } ]
Preliminary knowledge
Routing and permission verification

The analysis of the middle and background routes is as follows :
- Obtained Token:
- visit
/login: Redirect to/ - visit
/login?redirect=/xxx: Redirect to/xxx - visit
/loginOther routes : Direct access/xxx
- visit
- Not obtained Token:
- visit
/login: Direct access/login - visit
/loginOther routes : Such as visit/dashboard, The actual access path is/login?redirect=%2Fdashboard, After logging in, you will be redirected directly/dashboard
- visit
Routing logic source code
main.jsGlobal routing guard is loaded inimport './permission'permissionGlobal routing guard is defined// White list const whiteList = ['/login', '/auth-redirect'] router.beforeEach(async(to, from, next) => { // Start progress bar NProgress.start() // Modify page title document.title = getPageTitle(to.meta.title) // from Cookie obtain Token const hasToken = getToken() // Judge Token Whether there is if (hasToken) { // If the current path is login Direct redirection to the home page if (to.path === '/login') { next({ path: '/' }) NProgress.done() } else { // Determine whether the user's role exists const hasRoles = store.getters.roles && store.getters.roles.length > 0 // If the user role exists , Direct access to if (hasRoles) { next() } else { try { // Get the user's role asynchronously const { roles } = await store.dispatch('user/getInfo') // According to the user role , Dynamically generate routing const accessRoutes = await store.dispatch('permission/generateRoutes', roles) // call router.addRoutes Dynamic add route router.addRoutes(accessRoutes) // Use replace Access routing , Not in history Leave a record in the book next({ ...to, replace: true }) } catch (error) { // remove Token data await store.dispatch('user/resetToken') // Display error message Message.error(error || 'Has Error') // Redirect to login page next(`/login?redirect=${ to.path}`) NProgress.done() } } } } else { // If you visit URL On the white list , Direct access to if (whiteList.indexOf(to.path) !== -1) { next() } else { // If you visit URL Not on the white list , Redirect directly to the login page , And will visit URL Add to redirect Parameters in next(`/login?redirect=${ to.path}`) NProgress.done() } } }) router.afterEach(() => { // Stop progress bar NProgress.done() })
NProgress
// Start progress bar
NProgress.start()
// End progress bar
NProgress.done()
// Controls whether the circular progress bar on the right displays
NProgress.configure({
showSpinner: false })
Error in dynamically generating route or getting route
- Distribution execution
store.dispatch('user/resetToken'), eliminateToken、 Resetroles - Display error message
Message.error(error || 'Has Error') - Redirect to landing page
next('/login?redirect=${to.path}'), Then end the progress bar
const actions = {
resetToken({
commit }) {
return new Promise(resolve => {
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
removeToken()
resolve()
})
},
}
const TokenKey = 'Admin-Token'
export function removeToken() {
return Cookies.remove(TokenKey)
}
Dynamic routing analysis
There are two kinds of routes here :
constantRoutes: Represents routes that do not require dynamic judgment permission , Like landing page 、404、 And other common pagesasyncRoutes: On behalf of those requirements, dynamically judge permissions and passaddRoutesDynamically added pages
When a user logs in to the system , Routes will be generated dynamically , among constantRoutes Inevitable inclusion ,asyncRoutes It will be filtered
asyncRoutes The logic of filtering is to see whether the route contains meta and meta.roles attribute
If this property is not available , Is a general routing , Permission verification is not required
If you include
rolesattribute , It will determine whether the user's role has hit any permission in the routeIf hit , Save the route
If you miss , Then directly discard the route
asyncRoutes After processing , Hui He constantRoutes Merge into a new routing object , And save to vuex Of permission/routes in
- After the user logs in to the system , The sidebar will start from
vuexIn order to getstate.permission.routes, Dynamically render the user menu according to the route

Get user rights , Generate dynamic routing
const {
roles } = await store.dispatch('user/getInfo')
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
The source code for generating dynamic routing is located in src/store/modules/permission.js Medium generateRoutes Method
import {
asyncRoutes, constantRoutes } from '@/router'
const actions = {
generateRoutes({
commit }, roles) {
// return Promise object
return new Promise(resolve => {
let accessedRoutes
if (roles.includes('admin')) {
// If the role contains admin, Skip judgment directly , Direct will asyncRoutes All return
accessedRoutes = asyncRoutes || []
} else {
// If the role does not contain admin, Call filterAsyncRoutes Filter routes
accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
}
// Save route to vuex in
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
})
}
}
commit('SET_ROUTES', accessedRoutes) Save the route in store in
const state = {
routes: [],
addRoutes: []
}
const mutations = {
SET_ROUTES: (state, routes) => {
state.addRoutes = routes
state.routes = constantRoutes.concat(routes)
}
}
If the role is not admin, It will call filterAsyncRoutes Method :
export function filterAsyncRoutes(routes, roles) {
const res = []
// Traverse all routes
routes.forEach(route => {
// Make a shallow copy of the route , Be careful children No copying , Because there's no need to be right about children Judge , So you can use a shallow copy
const tmp = {
...route }
// Check whether the user has access to the route
if (hasPermission(roles, tmp)) {
// When the route has access , Determine whether the route has children attribute
if (tmp.children) {
// When the route contains children when , Yes children Iterative call filterAsyncRoutes Method
tmp.children = filterAsyncRoutes(tmp.children, roles)
}
// When the route has access , take temp Save to res in
res.push(tmp)
}
})
return res
}
Check permission method hasPermission Source code is as follows :
function hasPermission(roles, route) {
// Check whether the route contains meta and meta.roles attribute
if (route.meta && route.meta.roles) {
// Judge route.meta.roles Whether user roles are included in the roles Any one of the permissions in
return roles.some(role => route.meta.roles.includes(role))
} else {
// If the route does not meta or meta.roles attribute , It is deemed that the route does not need permission control ( All users have access to this route )
return true
}
}
Sidebar
sidebarQuote fromlayoutComponents , Component is locatedsrc/layout/index.vuesidebarThe component source code is located insrc/layout/components/Sidebar/index.vue
el-menu Usage analysis
<template>
<el-row class="tac">
<el-col :span="12">
<el-menu default-active="1-1" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b" mode="vertical" unique-opened :collapse="isCollapse" :collapse-transition="false" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose" @select="handleSelect" >
<el-submenu index="1">
<template slot="title">
<i class="el-icon-location"></i>
<span> Navigation one </span>
</template>
<el-menu-item-group>
<template slot="title"> Group one </template>
<el-menu-item index="1-1"> Options 1</el-menu-item>
<el-menu-item index="1-2"> Options 2</el-menu-item>
</el-menu-item-group>
<el-menu-item-group title=" grouping 2">
<el-menu-item index="1-3"> Options 3</el-menu-item>
</el-menu-item-group>
<el-submenu index="1-4">
<template slot="title"> Options 4</template>
<el-menu-item index="1-4-1"> Options 1</el-menu-item>
</el-submenu>
</el-submenu>
<el-submenu index="2">
<template slot="title">
<i class="el-icon-menu"></i>
<span slot="title"> Navigation two </span>
</template>
<el-menu-item index="2-1"> Options 2-1</el-menu-item>
</el-submenu>
<el-menu-item index="3" disabled>
<i class="el-icon-document"></i>
<span slot="title"> Navigation three </span>
</el-menu-item>
<el-menu-item index="4">
<i class="el-icon-setting"></i>
<span slot="title"> Navigation four </span>
</el-menu-item>
</el-menu>
</el-col>
<el-col>
<el-button @click="isCollapse = !isCollapse"> Fold </el-button>
</el-col>
</el-row>
</template>
<script> export default {
data() {
return {
isCollapse: false } }, methods: {
handleSelect(index, indexPath) {
console.log('handleSelect', index, indexPath) }, handleOpen(index, indexPath) {
console.log('handleOpen', index, indexPath) }, handleClose(index, indexPath) {
console.log('handleClose', index, indexPath) } } } </script>
el-menu Represents the menu container component :
default-active: Current active menuindex, Be careful : If there is a submenu , You need to fill in the submenu IDunique-opened: Whether to keep only one submenu expandedcollapse: Is the menu folded up horizontally ( Only inmodebyverticalYou can use )It can be used in combination with buttons , Click to collapse and click to expand
collapse-transition: Whether to display the collapse animation@select: Click menu event . Callback function :index: Select... Of the menu item index;indexPath: Select... Of the menu item index path, You can get1-4-1Of all the parent menus of the menu IDhandleSelect 1-4-1 ['1', '1-4', '1-4-1']@open: The event is triggered when the parent menu is opened@close: The event is triggered when the parent menu is closed
el-submenu Represents the submenu container :el-submenu And el-menu Different ,el-menu Represents the entire menu , and el-submenu Represents a specific menu ,el-submenu It can be customized slot Of title Customize menu styles :
<el-submenu index="1">
<template slot="title">
<i class="el-icon-location"></i>
<span> Navigation one </span>
</template>
</el-submenu>
el-submenu In container default Of slot Used to store submenus , It can contain three submenu components :
el-menu-item-group: Menu grouping , Add a title to a group of menus ,el-menu-item-groupThe contents of the container need to be storedel-menu-itemComponents , SupporttitleOfslotTo customize the title styleel-submenu:el-submenuSupport circular nestingel-submenu, This enables more than two levels of subcomponents to be implementedel-menu-item: Submenu component
sidebar Source code analysis
src/layout/components/Sidebar/index.vue
<template>
<div :class="{
'has-logo':showLogo}">
<logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu :default-active="activeMenu" :collapse="isCollapse" :background-color="variables.menuBg" :text-color="variables.menuText" :unique-opened="false" :active-text-color="variables.menuActiveText" :collapse-transition="false" mode="vertical" >
<sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
</el-menu>
</el-scrollbar>
</div>
</template>
<script> import {
mapGetters } from 'vuex' import Logo from './Logo' import SidebarItem from './SidebarItem' import variables from '@/styles/variables.scss' export default {
components: {
SidebarItem, Logo }, computed: {
...mapGetters([ 'permission_routes', 'sidebar' ]), activeMenu() {
const route = this.$route const {
meta, path } = route if (meta.activeMenu) {
return meta.activeMenu } return path }, showLogo() {
return this.$store.state.settings.sidebarLogo }, variables() {
return variables }, isCollapse() {
return !this.sidebar.opened } } } const state = {
sidebar: {
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true } } </script>
:default-active="activeMenu": adoptmeta.activeMenuattribute , Specify the highlighted menu corresponding to the routemeta.activeMenuYou need to provide a legal route , Otherwise, it will not take effect:collapse="isCollapse":NavBarClick the button in , Will modifyCookieMediumsidebarStatus, fromvuexWhen the value is taken, thesidebarStatusToBoolean, And determine whether the left menu bar needs to be shrunk by defaultv-if="showLogo": Judgesettings.jsWhether the configuration items in need to be displayedLogotext-color="variables.menuText": from@/styles/variables.scssIn order to getscssobject , To get the style
sidebar Pass through v-for Loop traversal sidebar-item Implement submenu :
<sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
sidebar-item Source code analysis
src/layout/components/Sidebar/SidebarItem.vue
Be careful : Components can call their own... In their own templates , But you need to give this component name attribute , Will report a mistake For recursive components, make sure to provide the "name" option.
<template>
<div v-if="!item.hidden">
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{
'submenu-title-noDropdown':!isNest}">
<item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" />
</el-menu-item>
</app-link>
</template>
<el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
<template slot="title">
<item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
</template>
<sidebar-item v-for="child in item.children" :key="child.path" :is-nest="true" :item="child" :base-path="resolvePath(child.path)" class="nest-menu" />
</el-submenu>
</div>
</template>
<script> import path from 'path' import {
isExternal } from '@/utils/validate' import Item from './Item' import AppLink from './Link' import FixiOSBug from './FixiOSBug' export default {
name: 'SidebarItem', components: {
Item, AppLink }, mixins: [FixiOSBug], props: {
// route object item: {
type: Object, required: true }, isNest: {
type: Boolean, default: false }, basePath: {
type: String, default: '' } }, data() {
// To fix https://github.com/PanJiaChen/vue-admin-template/issues/237 // TODO: refactor with render function this.onlyOneChild = null return {
} }, methods: {
hasOneShowingChild(children = [], parent) {
const showingChildren = children.filter(item => {
if (item.hidden) {
return false } else {
// Temp set(will be used if only has one showing child) this.onlyOneChild = item return true } }) // When there is only one child router, the child router is displayed by default if (showingChildren.length === 1) {
return true } // Show parent if there are no child router to display if (showingChildren.length === 0) {
this.onlyOneChild = {
... parent, path: '', noShowingChildren: true } return true } return false }, resolvePath(routePath) {
if (isExternal(routePath)) {
return routePath } if (isExternal(this.basePath)) {
return this.basePath } return path.resolve(this.basePath, routePath) } } } </script>
sidebar-item Of props as follows :
item: Routing objectsbasePath: Routing path
sidebar-item Show logical analysis :
adopt
item.hiddenControl whether the menu is displayed
adopt
hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.always ShowlogictemplateWhether the menu is displayed ,templateRepresents a single menuhasOneShowingChild: Determine whether there is only one sub route to be displayed!onlyOneChild.children||onlyOneChild.noShowingChildren: Determine the submenu to be displayed , Does it includechildrenattribute , If you include , It means that there may be sub menus in the sub menu , At this point, we need to judge againnoShowingChildrenattribute!item.alwaysShow: Determine whether there is... In the routealwaysShowattribute , If there is , Then return tofalse, Don't showtemplatemenu , That is to say, as long as you configurealwaysShowAttributes will go directly toel-submenuComponents
hasOneShowingChild Method source code details :
children:routerObject'schildrenattributeitem:routerobject

hasOneShowingChild(children = [], parent) {
const showingChildren = children.filter(item => {
// If children The route in contains hidden attribute , Then return to false
if (item.hidden) {
return false
} else {
// Assign a sub route to onlyOneChild, Used to display when only one route is included
this.onlyOneChild = item
return true
}
})
// If after filtering , Show only one route , Then return to true
if (showingChildren.length === 1) {
return true
}
// If there are no sub routes to show , Will onlyOneChild Of path Set an empty route , And add noShowingChildren attribute , Indicates that although there are sub routes , But there is no need to show the sub route
if (showingChildren.length === 0) {
this.onlyOneChild = {
...parent, path: '', noShowingChildren: true }
return true
}
// return false, It means that there is no need to show sub routes , Or more than one sub route to be shown
return false
}
If displayed template Components , First, we will show app-link Components , And then there was el-menu-item, The innermost nest is item Components
item Components need to be routed meta Contained in the title and icon attribute , Otherwise, the content will be rendered as empty vnode object
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{
'submenu-title-noDropdown':!isNest}">
<item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" />
</el-menu-item>
</app-link>
If template The menu does not show , Show el-submenu menu ,el-submenu Nested components are used in logic , take sidebar-item Nested in el-submenu in :
<el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
<template slot="title">
<item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
</template>
<sidebar-item v-for="child in item.children" :key="child.path" :is-nest="true" :item="child" :base-path="resolvePath(child.path)" class="nest-menu" />
</el-submenu>
app-link Source code analysis
app-link Is a dynamic component , Through analysis to Parameters , If you include http The prefix becomes a a label , Otherwise it will become a router-link Components
componentIs a built-in componentprops:is、inline-templateeffect : according to
is, To decide which component is rendered
<template>
<component :is="type" v-bind="linkProps(to)">
<slot />
</component>
</template>
<script> import {
isExternal } from '@/utils/validate' export default {
props: {
to: {
type: String, required: true } }, computed: {
isExternal() {
return isExternal(this.to) }, type() {
if (this.isExternal) {
return 'a' } return 'router-link' } }, methods: {
linkProps(to) {
if (this.isExternal) {
return {
href: to, target: '_blank', rel: 'noopener' } } return {
to: to } } } } </script>
isExternal Function is matched by a regular expression http link :
export function isExternal(path) {
return /^(https?:|mailto:|tel:)/.test(path)
}
item Source code analysis
item Components are defined by render Function to complete component rendering
- If
itemCan't getmetaMediumiconThe parent route will be takenicon
render Function parameter :
createElementfunction : The return value is a dummy DOM, namely VNode, That is, the rendered nodecreateElementThere are three parameters :- To render
htmllabel 、 Components :{ String | Object | Function } htmlProperties of :{ Object }- Virtual child nodes
VNodes, At presenthtmlThe child elements of the tag :{ String | Array }
- To render
context: It containspropsEqual parameter
<script> export default {
name: 'MenuItem', functional: true, props: {
icon: {
type: String, default: '' }, title: {
type: String, default: '' } }, render(h, context) {
const {
icon, title } = context.props const vnodes = [] if (icon) {
if (icon.includes('el-icon')) {
vnodes.push(<i class={
[icon, 'sub-el-icon']} />) } else {
vnodes.push(<svg-icon icon-class={
icon}/>) } } if (title) {
vnodes.push(<span slot='title'>{
(title)}</span>) } return vnodes } } </script>
summary
sidebar:sidebar It mainly includes el-menu Container assembly ,el-menu Middle traversal vuex Medium routes, Generate sidebar-item Components .sidebar The main configuration items are as follows :
activeMenu: According to the current routemeta.activeMenuProperties control the highlighted menu in the sidebarisCollapse: according toCookieOfsidebarStatusControls whether the sidebar is collapsedvariables: adopt@/styles/variables.scssfillel-menuBasic style of
sidebar-item : It is mainly divided into two parts :
- The first part is when only one
childrenOr notchildrenShow when , The components shown include :app-link: Dynamic components ,pathWhen is a link , Is shown asalabel ,pathWhen routing , Is shown asrouter-linkComponentsel-menu-item: A menu item , Whensidebar-itemFor the wrongnestWhen the component ,el-menu-itemWill increasesubmenu-title-noDropdownOfclassitem:el-menu-itemContents of Li , Mainlyiconandtitle, WhentitleEmpty is , The entire menu item will not show
- The second part is when
childrenShow when there are more than two items , The components shown include :el-submenu: Submenu component container , For nested submenu componentssidebar-item:el-submenuIterations nestedsidebar-itemComponents , staysidebar-itemThere are two changes in the component :- Set up
is-nestThe attribute istrue - according to
child.pathGeneratedbase-pathProperty passed insidebar-itemComponents
- Set up
vue elementui navmenu Multi level navigation menu ( level 、 vertical )
Front end development and high-end operation
Type conversion
Fast turn Number
var a = '1'
console.log(typeof a)
console.log(typeof Number(a)) // Common writing
console.log(typeof +a) // High end writing
Fast turn Boolean
var a = 0
console.log(typeof a)
console.log(typeof Boolean(a)) // Common writing
console.log(typeof !!a) // High end writing
Mixed writing
- First to Number, And then to Boolean
var a = '0'
console.log(!!a) // Direct transfer will get true, Fall short of expectations
console.log(!!+a) // First to Number And then to Boolean, In line with expectations
JS and CSS Dual purpose style
template You need to dynamically define styles in , General practice :
<template>
<div :style="{ color: textColor }">Text</div>
</template>
<script> export default {
data() {
return {
textColor: '#ff5000' } } } </script>
Definition SCSS file
$menuActiveText:#409EFF;
:export {
menuActiveText: $menuActiveText;
}
stay JS I quote :
- Use
importquote SCSS file - Definition
computedtake styles Object becomes a responsive object - stay template Use in syles object
<template>
<div :style="{ color: styles.menuActiveText }">Text</div>
</template>
<script> import styles from '@/styles/variables.scss' export default {
computed: {
styles() {
return styles } } } </script>
Continuous deconstruction
Extract an attribute from the first object element of the array , such as :err Object contains a errors Array ,errors Each object of the array contains a msg attribute
err = {
errors: [
{
msg: 'this is a message'
}
]
}
// The fast extraction method is
const [{
msg }] = err.errors
// If you don't use deconstruction, it is written as
const msg = err.errors[0].msg
Redirect
Login redirection
src/views/login/index.vueChinese vs$routemonitor :
watch: {
$route: {
handler: function(route) {
const query = route.query
if (query) {
this.redirect = query.redirect
this.otherQuery = this.getOtherQuery(query)
}
},
immediate: true
}
}
this.getOtherQuery(query) The purpose of is to get the division redirect Query criteria other than , After successful login :
this.$store
.dispatch('user/login', this.loginForm)
.then(() => {
this.$router.push({
path: this.redirect || '/',
query: this.otherQuery
})
this.loading = false
})
.catch(() => {
this.loading = false
})
Complete the redirected code :
this.$router.push({
path: this.redirect || '/',
query: this.otherQuery
})
vue-element-admin Special redirection components are provided , Source code is as follows :
<script> export default {
created() {
const {
params, query } = this.$route const {
path } = params this.$router.replace({
path: '/' + path, query }) }, render: function(h) {
return h() // avoid warning message } } </script>
Redirection component
The redirection component is configured with dynamic routing :
*Indicates that zero or more routes are matched , For example, the route is/redirectwhen , Can still matchredirectComponents . If you will*Get rid ofAt this point the route
/redirectWill only match toLayoutComponents , And cannot matchredirectComponents
{
path: '/redirect',
component: Layout,
hidden: true,
children: [
{
path: '/redirect/:path(.*)',
component: () => import('@/views/redirect/index')
}
]
},
Breadcrumb navigation
el-breadcrumb-item
el-breadcrumb: Breadcrumb navigation container ,separatorControls the breadcrumb navigation text dividerel-breadcrumb-item: Bread crumbs sub project , have access totoProperty to switch routes ,slotCan containaLabel to jump to the outer chain
Use to Properties and a The difference between label switching and routing is :to Attribute switching routing is a dynamic replacement App.vue Routing content in , and a Label switching routes will refresh the page
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }"> home page </el-breadcrumb-item>
<el-breadcrumb-item><a href="/"> Activity management </a></el-breadcrumb-item>
<el-breadcrumb-item> Activity list </el-breadcrumb-item>
<el-breadcrumb-item> Activity details </el-breadcrumb-item>
</el-breadcrumb>
Routing and breadcrumb navigation mapping
Breadcrumb navigation template source code :
el-breadcrumb-itemI made a judgment , If it is the last element or routeredirectProperty specified asnoRedirectThen no link is generated , Otherwise... Will be usedaTag event triggers , But here we use@click.preventThe default... Is blockedaTag event triggers , Instead of using customhandleLinkMethod to handle route jumps
<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>
The more important thing is levelList , It's through getBreadcrumb Method generated
The breadcrumb navigation implementation logic is as follows :
- obtain
this.$route.matched, And filter that it does not containitem.meta.titleThe item , Generate a new breadcrumb navigation arraymatched - Judge
matchedWhether the first item isdashboard, If not , Then adddashboardNavigate the first item for breadcrumbs - Filter again
matchedinitem.meta.titleEmpty items anditem.meta.breadcrumbbyfalseThe item
getBreadcrumb() {
// only show routes with meta.title
let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
const first = matched[0]
if (!this.isDashboard(first)) {
matched = [{
path: '/dashboard', meta: {
title: 'Dashboard' }}].concat(matched)
}
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
},
isDashboard(route) {
const name = route && route.name
if (!name) {
return false
}
return name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()
},
When the route is switched , Will also call again getBreadcrumb Method generation
watch: {
$route(route) {
// if you go to the redirect page, do not update the breadcrumbs
if (route.path.startsWith('/redirect/')) {
return
}
this.getBreadcrumb()
}
},
handleLink The source code of the method is as follows :
- there
pathCompileUsed to solve the matching problem of dynamic routing
handleLink(item) {
const {
redirect, path } = item
if (redirect) {
this.$router.push(redirect)
return
}
this.$router.push(this.pathCompile(path))
}
pathCompile(path) {
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
const {
params } = this.$route
var toPath = pathToRegexp.compile(path)
return toPath(params)
},
边栏推荐
- Redis transaction
- Analysis of pointer
- Database Experiment 2: data update
- Wireshark filter rule
- Rtmp/rtsp/hls public network real available test address
- [daily question on niuke.com] two point search
- [untitled]
- The relation between virtual function and pure virtual function
- [fastapi] use pycharm to configure and use environment variables for fastapi projects
- 虚函数与纯虚函数的关系
猜你喜欢

beginning一款非常优秀的emlog主题v3.1,支持Emlog Pro

肝了一個月的 DDD,一文帶你掌握

Win10 desktop unlimited refresh

Simple introduction to key Wizard

What is the lszrz protocol used at ordinary times? Talk about xmodem/ymodem/zmodem

March 22, 2021

Heap classical problem

IO to IO multiplexing from traditional network

MySQL 主从,6 分钟带你掌握

Halcon uses points to fit a plane
随机推荐
网络加速谁更猛?CDN领域再现新王者
Halcon 3D 1 Reading 3D data
项目开发流程简单介绍
Glossary of Chinese and English terms for pressure sensors
[untitled]
Flex/fixed upper, middle and lower (mobile end)
Conversion of Halcon 3D depth map to 3D image
FPGA语法的细节
json-c常用API
Role and understanding of proc/cmdline
XML parameter schema, the same MTK SW version is compatible with two different sets of audio parameters
Go interface oriented programming practice
UBI details and JFFS2 square FS UBIFS
Nrf52832 -- official routine ble_ app_ UART adds the LED feature to enable the computer UART and mobile app to control the LED on and off of the development board
Redis memory obsolescence strategy
[fastapi] use pycharm to configure and use environment variables for fastapi projects
Heap classical problem
Wireshark filter rule
beginning一款非常优秀的emlog主题v3.1,支持Emlog Pro
Market trend report, technical innovation and market forecast of Chinese stump crusher