Blazor和Vue对比学习(进阶.路由导航二):布局(母版/嵌套)

单文件组件框架中,当更改请求地址时,并不会引发页面跳转,而是由框架捕获请求地址(在框架中我们称之为路由),然后根据路由与组件的映射关系,在页面的指定位置切换和显示组件。在哪个位置显示(称之为路由出口),就是布局要解决的问题。无论是Vue,还是Blazor,我们都能以母版页的方式来理解和使用布局。母版页,就是布局的整个页面环境,我们可以在母版页的指定位置,放一个占位符,这个占位符作为路由出口,Vue使用【<router-view />】组件作为占位符,而Blazor中使用【@Body】指令。母版页本质上也是组件,所以我们可以将“在路由出口”显示的组件也成为母版页,这样就可以实现复杂的嵌套布局。文字描述,比较晦涩,下面通过案例直接上手。

 

一、案例说明:如图所示,首屏为左右结构,左侧显示文字链接“关于”和“动物”,右侧是一个路由出口。点击“关于”时,直接在路由出口上显示“About组件”。点击“动物”时,切换到Animal组件,Animal组件也是一个母版页,上下结构,上方显示文字链接“PandaDetail”和DogDetail“”,下方是动物组件的路由出口,点击上方链接时,将切换显示“PandaDetail组件”和“DogDetail组件”。

 

  

 

二、Blazor实现(忽略CSS样式)。文件结构包括:App.razor(路由管理器并设置顶层母版)、MainLayout.razor(默认顶层母版)、Index.razor(首页)、About.razor、Animal.razor(二层母版)、PandaDetail.razor、DogDetail.razor。

1、App.razor(路由管理器并设置顶层母版) 

<!--创建项目时自动创建立,基本没有变化,对布局来说,主要是指定的默认母版页ManiLayout-->
<Router AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
    <NotFound>
        <PageTitle>Not found</PageTitle>
        <LayoutView Layout="@typeof(MainLayout)">
            <p role="alert">抱歉,未找到请求的页面.</p>
        </LayoutView>
    </NotFound>
</Router>

 2、MainLayout.razor(默认顶层母版) 

<!--将本组件转为母版页,LayoutComponentBase提供了Body属性
Body为RenderFragment类型,作为占位符渲染子组件,称之为路由出口-->
@inherits LayoutComponentBase

<PageTitle>嵌套布局</PageTitle>
<div class="page">
    <div class="sidebar">
        <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
            <h1>首页</h1>
        </NavLink>
        <NavLink class="nav-link" href="about">
            <h1>关于</h1>
        </NavLink>
        <NavLink class="nav-link" href="animal">
            <h1>动物</h1>
        </NavLink>
    </div>
    <main>
        @Body
    </main>
</div>

3、Index.razor(首页,本案例中没有实际意义)

<!--路由为首页,隐式使用默认母版页MainLayout-->
@page "/"

<PageTitle>首页</PageTitle>
<h1>这里是首页</h1>
@code{
}

4、About.razor

<!--路由为about,隐式使用默认母版页MainLayout-->
@page "/about"

<PageTitle>关于</PageTitle>
<h3>这里是关于页About.razor</h3>
@code {
}

5、Animal.razor(二层母版)

<!--路由为animal,使用母版页MainLayout。
注意,如果组件转为母版页,需要显式指定母版页,不能隐式使用默认母版页。-->
@page "/animal"
@layout MainLayout
<!--将组件转为母版页,可以使用@Body占位符-->
@inherits LayoutComponentBase

<PageTitle>动物</PageTitle>
<h3>这里是动物页Animal.razor</h3>
<NavLink class="nav-link" href="animal/panda-detail"><h5>熊猫详情</h5></NavLink>
<NavLink class="nav-link" href="animal/dog-detail"><h5>狗狗详情</h5></NavLink>
<main>
    @Body
</main>
@code {
}

6、PandaDetail.razor、DogDetail.razor,Animal的子页面

<!--PandaDetail.razor-->
<!--路由animal/panda-detail,母版页为Animal.razor-->
@page "/animal/panda-detail"
@layout Animal

<h3>这里是熊猫详情页PandaDetail.razor</h3>
@code {
}

<!--DogDetail.razor-->
<!--路由animal/dog-detail,母版页为Animal.razor-->
@page "/animal/dog-detail"
@layout Animal

<h3>这里是狗狗详情页DogDetail.razor</h3>
@code {
}

 

 
三、Vue的实现(忽略CSS样式)。文件结构包括:Router/index.js(路由管理器)、App.vue(顶层母版)、About.vue、Animal.vue(二层母版)、PandaDetail.vue、DogDetail.vue。

1、App.vue(顶层母版)

<template>
  <header>
    <h1><router-link to="/">首页</router-link></h1>
    <h1><router-link to="/about">关于</router-link></h1>
    <h1><router-link to="/animal">动物</router-link></h1>
  </header>
  <main>
    <!--顶层路由出口-->
    <router-view></router-view>
  </main>
</template>

2、About.vue 

<!--普通组件-->
<template>
  <h2>这里是关于页About.vue</h2>
</template>

 

3、Animal.vue(二层母版) 

<template>
  <h2>这里是关于动物页Animal.vue</h2>
  <header>
    <h1><router-link to="/panda-detail">熊猫详情</router-link></h1>
    <h1><router-link to="/dog-detail">狗狗详情</router-link></h1>
  </header>
  <main>
    <!--第二层路由出口-->
    <router-view></router-view>
  </main>
</template>

4、PandaDetail.vue和DogDetail.vue

<!--普通组件-->
<template>
    <h2>这里是熊猫详情页PandaDetail.vue</h2>
</template>

<!--普通组件-->
<template>
    <h2>这里是狗狗详情页DogDetail.vue</h2>
</template>

5、Router/index.js(路由管理器),嵌套设置主要在路由管理器中进行

//路由使用了name属性,用于指定路由的别名
//导航时即可以使用路径path: <RouterLink to="/about">关于</RouterLink>
//也可以使用别名name: <RouterLink :to="{name:'about'}">关于</RouterLink>
//RouterLink和router-link一样
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
  {
    path: '/',
    name: 'home', 
    component: ()=> import('../views/Index.vue'),
  },
  {
    path: '/about',
    name: 'about',
    component: () => import('../views/About.vue')
  },
  {
    path: '/animal',
    name: 'animal',
    component: () => import('../views/Animal.vue'),
    //Animal的子路由,以下路由的组件,在Animal组件的路由出口的切换显示
    children:[
      {
        path:'/panda-detail',
        name:'panda-detail',
        component: () => import('../views/PandaDetail.vue')
      },
      {
        path:'/dog-detail',
        name:'dog-detail',
        component:() => import('../views/DogDetail.vue')
      }
    ]
  }
]

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes
})

export default router

 

 

 

四、总结:通过嵌套路由实现,应该可以明显的感受到Blazor和Vue的路由和布局差异:

  1. Blazor是一个向上的过程,通过指定母版页,来确定母子嵌套关系。而Vue是一个向下的过程,通过指定子页面,来确定母子嵌套关系。
  2. Blazor的布局构件,包括了@page、@layout、@inherits LayoutComponentBase、@body。而Vue,就一个router-view,然后就是在路由配置文件(Router/index.js)中进行配置。它们的区别和路由一样,Blazor分散到各个组件中,而Vue集中到路由配置文件中。

posted @ 2022-12-10 16:32  functionMC  阅读(814)  评论(0编辑  收藏  举报