Vue3$View-SPA&Router

92 阅读3分钟

Vue3$View-SPA&Router

1. SPA

An SPA (Single-page application) is a web app implementation that loads only a single web document, and then updates the body content of that single document via JavaScript APIs such as Fetch when different content is to be shown. MDN_SPA

单页面应用:

  • 好处:可以利用已有资源,不用刷新整个页面
  • 坏处:SEO 不好(HTML 的内容是 JavaScript 生成的)

最初的网站是多页面的。比如我们在首页 http://www.a.com/index.html。我们想到关于页,就点击一个超链接,向后端发起一个请求,后端返回一个新的 HTML,地址变成了 http://www.a.com/about.html

多页面网站存在的问题是浪费资源。首页和关于页的标题和菜单等可能一样,但是两个页面都需要包含这部分内容,无法复用。

Ajax 的出现允许我们局部刷新页面:通过点击按钮等方式,我们向后端发送请求,返回的不是新的 HTML 文件,而是 JSON 等类型的数据。之后我们通过浏览器提供的 APIs 生成或者改变 DOM 节点,从而实现页面的更新。这样就做到了一个 HTML 文件 + APIs 来实现整个网站。

单页面应用还需要考虑路由。多页面网站是通过不同的地址来区分不同的页面,这样有助于分享。多页面的地址一般是以 some-page.html 结尾的。单页面应用则是以 some-resource 结尾的。

  • 触发地址变化:多页面网站是通过 a 标签来切换不同的页面的。单页面应用则是通过更改浏览器的地址,并监听地址变化,从而加载不同的资源。实际使用时,触发地址改变有两种方式:
    • 声明式导航。比如 vue-router 中,RouterLink 组件就像是 a 标签,在页面上点击它就能实现加载对应资源。
    • 编程式导航。在 js 代码中使用库提供的方法。
  • 响应地址变化:多页面网站中,返回的是 HTML,不需要处理。单页面应用中,需要告诉浏览器在哪里加载对应的资源。在 vue-router 中,RouterView 标签的位置就是加载资源的位置。

为了实现不同的地址加载不同的资源,单页面应用需要路由器来配置路由信息。

2. Router

路由是地址和资源的映射。路由器用来管理路由(组织和操作)。

前端路由:URL -> 页面

  • 多页面网站:每个 URL 对应一个 .html 文件
  • 单页面应用:每个 URL 对应一段 js 代码。当 URL变化时,js 代码执行,生成 DOM 节点,加载到页面对应的位置

后端路由:URL -> Function

  • 每个 URL 对应一个函数,该函数接收 request, 返回 response

MND_Router

路由配置

不同的框架有不同的路由方案,这里以 Vue 的 vue-router为例。 除了配置 URL (path) 和 内容 (component)。在 vue-router 中,路由还可以配置其他内容:

const route = {
	path: '/users/:id?',
	name: 'user',
	component: User,
	meta: {
    requiresAuth: true
	},
	redirect: '/customers/:id', // alias
	strict: true, // sensitive
	props: true, // boolean | object | function
	beforeEnter(to, from){},
	children: [{}]
}

路由器配置

在 vue-router 中,路由器常用的配置:

const router = createRouter({
  history: createMemoryHistory(), // createWebHashHistory() | createWebHistory()
  routes,
  linkActiveClass: 'border-indigo-500',
  linkExactActiveClass: 'border-indigo-700',
  scrollBehavior (to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition
    } else {
      return { top: 0 }
    }
  }
})