认识路由

路由( routing)就是通过互联的网络把信息从源地址传输到目的地址的活动。--维基百科

路由器提供了两种机制:路由和转送

  • 路由是决定数据包从来源到目的地的路径。
  • 转送将输入端的数据转移到合适的输出端

路由中有一个非常重要的概念叫路由表

  • 路由表本质上就是一个映射表, 决定了数据包的指向

后端路由阶段,后端渲染

后端渲染: jsp ...用户发送请求后,根据路由 由后端渲染页面。一般是从数据库读取数据并动态放在页面中返回至用户。每一个 url 都代表着一个页面,是由后端处理 url 和页面之间的映射关系, 这种路由方式被称为 后端路由

服务器直接生产渲染好对应的 HTML 页面,返回给客户端进行展示

  • 一个页面有自己对应的网址,也就是 URL.
  • URL 会发送到服务器,服务器会通过正则对该 URL 进行匹配,并且最后交给一个 Controller 进行处理。
  • Controller 进行各种处理最终生成 HTML 或者数据,返回给前端

后端路由:

  • 当我们页面中需要请求不同的路径内容时,交给服务器来进行处理,服务器渲染好整个页面,并且将页面返回给客户端
  • 这种情况下渲染好的页面,不需要单独加载任何的 js 和 cs5 可以直接交给浏览器展示,这样也有利于 SEO 的优化

后端路由的缺点:

  • 一种情况是整个页面的模块由后端人员来编写和维护的
  • 另一种情况是前端开发人员如果要开发页面,需要通过 PHP 和 ava 等语言来编写页面代码
  • 而且通常情況下 HTML 代码和数据以及对应的逻辑会混在一起,编写和维护都是非常糟糕的事情。

前后端分离阶段,前端渲染

随着 jax 的出现有了前后端分离的开发模式

  • 后端只提供 API 来返回数据,前端通过 ax 获取数据,并且可以通过 javascript 将数据渲染到页面中
  • 这样做最大的优点就是前后端责任的清晰,后端专注于数据上前端专注于交互和可视化上
  • 并且当移动端( iOS/ Android 出现后,后端不需要进行任何处理依然使用之前的一套 API 即可

目前很多的网站依然采用这种模式开发, 流程图 图示

单页面富应用阶段, 前端路由,前端渲染

  • 其实 SPA 最主要的特点就是在前后端分离的基础上加了一层前端路由
  • 也就是前端来维护一套路由规则

SPA 单页富应用, 整个网页只有一个 html 页面

图示

前端路由的核心是: 改变 URL,但是页面不进行整体的刷新。

如何改变 url, 而不刷新页面呢?

1 url 的 hash

  • URL 的 hash 也就是锚点(#),本质上是改变 window. location 的 href 属性
  • 我们可以通过直接赋值 location.hash 来改变 href 但是页面不发生刷新

2 HTML5 的 history 模式: pushState , replaceState

  • pushState 的改变是一个栈结构进栈操作。 可以是使用 history.back() 返回(出栈)上一个 url。history.go(-2) 返回前第二页. history.forward() 前进一页。这些操作等同于浏览器的前进后退
  • replaceState 等同于直接改变 url, 不会有 可以前进后退选项
# 浏览器命令行
location.hash = 'foo'
# or
history.pushState({}, '', 'foo')

# 浏览器url发生改变:.../foo

目前前端流行的三大框架,都有自己的路由实现

  • Angular 的 ngRouter
  • React 的 Reactrouter
  • Vue 的 vue-router

Tips: hash: hyper reference 超链接

vue-router 基本使用

vue-router 是 VueJs 官方的路由插件,它和 vue. js 是深度集成的,适合用于构建单页面应用

vue-router 是基于路由和组件的

  • 路由用于设定访问路径,将路径和组件映射起来。
  • 在 vue-router 的单页面应用中,页面的路径的改变就是组件的切换

开始使用

vue-router 安装:

pip install vue-router --save

使用:

  1. 导入路由对象,并且调用 Vue.use( Vuerouter)
  2. 创建路由实例,并且传入路由映射配置
  3. 在 Vue 实例中挂载创建的路由实例
  4. 使用路由 通过 <router-link to=""><router-view />

<router-link to="" tag="div" replace active-class="active">的属性:

  • tag: 可以指定之后渲染成什么组件(标签,比如上面的代码会被渲染成一个 div 元素,而不是默认的 a
  • replace: 路由的改变使用 history.replaceState()的方式,不可以返回前进
  • active-class="active": 更改被选中的(活跃的)路由的默认 类名

Tips: vue-router 给每个实例增加了一个$router属性(data 中)。使得在任何组件内可以通过 this.$router 访问路由器

代码示例

创建一个组件

<!-- \src\views\About.vue -->
<template>
  <div>
    <h2>我是about</h2>
  </div>
</template>

配置 vue-router

// /src/router/index.js 配置路由

import VueRouter from "vue-router"
import Vue from "vue"

import Home from "../views/Home"
import About from "../views/About"


// 1. 通过vue.use(插件),安装插件
Vue.use(VueRouter)

// 2. 创建 Vuerouter对象
const routes = [
  // 重定向
  {path: '/home', redirect: '/'},
  { path: "/", name: "Home", component: Home },
  { path: "/about", component: About },
]

// 3. 将 router对象传入到vue实例
const router = new VueRouter({
  //配置路由和组件之间的应用关系

  // routes, 使用词语法,注意参数命名。坑
  routes:routes,
  // 路由的跳转使用 html5 'history'的模式,没有 #
  mode: 'history',

  // 更改被选中的(活跃的)路由的默认 类名
  // linkActiveClass: 'active-2',
})

export default router

入口程序挂载

// /src/main.js
import Vue from 'vue'
import App from './App.vue'

// 如果导入的是一个目录,则自动导入其下的 index文件
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

在页面中使用

<!-- /src/App.vue -->
<template>
  <div id="app">
    <router-view/>
    <router-link to="/home" tag="li">Homes </router-link>
    <router-link to="/about" tag="div">About</router-link>    
    <button @click="aboutClick">点击跳转 About</button>
  </div>
</template>

<script>
export default {
  methods: {
    aboutClick(){
      // 手动跳转
      this.$router.push('/about')
      // this.$router.replace('/about')
    }
  }
}
</script>

动态路由

在某些情況下,一个页面的 path 路径可能是不确定的,比如我们进入用户界面时,希望是如下的路径:/user/a or /user/b 除了有前面的/user 之外,后面还跟上了用户的 ID 这种path 和 component 的匹配关系,我们称之为动态路由(也是路由传递数据的一种方式

Tips: $router$route 前者代表了整个路由对象,后者代表当前活跃(被显示的路由对象本身。

代码片段

配置这个路由

// 2. 创建 Vuerouter对象
const routes = [
  { path: "/user/:userId", component: User}
]
// ...

使用这个路由

<!-- /src/App.vue -->
<template>
  <div id="app">
    <router-view/>
    <router-link :to="'/user/' + 'msg'">user</router-link>
  </div>
</template>

这个路由(组件本身

<!-- \src\views\User.vue -->
<template>
  <section>
    <h2>你好:{{userId}}</h2>
    <!-- $route.params.userId  -->
  </section>
</template>

<script>
export default {
  computed:{
    userId(){
      // 获取路由参数
      // 注意此属性不是上次的 $router, 这个属性代表了当前活跃的路由      
      return this.$route.params.userId
    }
  }
}
</script>

路由懒加载

当打包构建应用时, Javascript 包会变得非常大。甚至用户的电脑上还出现了短暂空白的的情况,影响页面加载。

如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了

路由懒加载做了什么

  • 路由懒加载的主要作用就是将路由对应的组件打包成一个个的 js 代码块
  • 只有在这个路由被访问到的时候,才加载对应的组件

懒加载的方式

1 结合 Vue 的异步组件和 Webpack 的代码分析

const Home = resolve => { require.ensure(['../components/Home.vue'], () =>
  { resolve(require('../components/Home.vue')) })}

2 AMD 写法

const About = resolve => require(["./components/About.vue"], resolve)

3 在 ES6 中,我们可以有更加简单的写法来组织 vue 异步组件和 Webpack 的代码分割

// /src/router/index.js 配置路由

// const User = () => import("../views/User")
const routes = [
  // 路由懒加载
  { path: "/user/:userId", component: () => import("../views/User") },
]

vue- router 嵌套路由

嵌套路由是一个很常见的功能

  • 比如在 home 页面中,我们希望通过/home/news 和/home/message 访可一些内容
  • 一个路径映射一个组件,访词这两个路径也会分别渲染两个组件

实现嵌套路由有两个步骤

  1. 创建对应的子组件,并且在路由映射中配置对应的子路由。
  2. 在组件内部使用<router-view>标签

代码:

// /src/router/index.js 配置路由

// 懒加载
const AboutNews = () => import("../components/AboutNews")
const AboutMsg = () => import("../components/AboutMsg")

// 2. 创建 Vuerouter对象
const routes = [
  {
    path: "/about",
    component: About,
    children: [
      {
        // 匹配默认路径跳转至 /about/news
        path: '/',        
        redirect: 'news'
      },
      {
        path: "news",
        component: AboutNews,
      },
      {
        path: "msg",
        component: AboutMsg,
      },
    ],
  }, 
]

使用

<template>
  <div>
    <h2>我是about</h2>
    <router-link to="/about/news">新闻</router-link>
    <router-link to="/about/msg">消息</router-link>
    <router-view></router-view>
  </div>
</template>

vue- router 参数传递

传递参数主要有两种类型: params 和 query

params 的类型

  1. 配置路由格式: /router/:id
  2. 传递的方式:在 path 后面跟上对应的值, 字符串
  3. 传递后形成的路径:/ router/123,/ router/abc
  4. 实例通过$route.params 取出参数

query 的类型

  1. 配置路由格式:/router也 就是普通配置
  2. 传递的方式对象中使用 query 的 key 作为传递方式 ,{ path: '/profile', query: { name: 'whh', age: 18 } }
  3. 传追后形成的路径:/profile?name=whh&age=18

  4. 在实例通过$route.query取出参数

vue- router 导航守卫

什么是导航守卫?

  • vue- router 提供的导航守卫主要用来监听监听路由的进入和离开的
  • vue- router 提供了 beforeeach和 aftereach的钩子函数,它们会在路由即将改变前和改变后触发.

使用 beforeeach 完成路由变更时标题的修改

// /src/router/index.js 配置路由

const routes = [
  {
    path: "/",
    component: Home,
    meta: {
      title: "首页",
    },
  },
  {
    path: "/about",
    component: About,
    children: [
      {
        // 匹配默认路径跳转至 /about/news
        path: "/",
        redirect: "news",
      },
      {
        path: "news",
        component: AboutNews,
      },
      {
        path: "msg",
        component: AboutMsg,
      },
    ],
    meta: {
      title: "About",
    },
  },  
]

const router = new VueRouter({  
  routes: routes,
  mode: "history",
})

// 全局导航守卫, 前置钩子
router.beforeEach((to, from, next) => {
  // 从 from 跳转至 to
  // document.title = to.meta.title
  // console.log(to);
  document.title = to.matched[0].meta.title  

  // 执行被覆盖方法本该执行的操作
  next()
})

export default router

aftereach 后置钩子( hoot )

router.afterEach((to, form) => {})

Tips: 上面两种使用的守卫被称为全局守卫,除此之外还有。路由独享的守卫,及组件内的守卫......

keep-alive

Tips: 路由的进入和离开,一般会带来组件的创建与销毁

  • keep- alive 是 vue 内置的个组件,可以使被包含的组件保留状态,或避兔重新渲染. 他有两个重要的属性
  • include-字符串或正则表达式,只有匹配的组件会被缓存
  • exclude-字符串或正则表达式,任何匹配的组件都不会被缓存
  • router-view 也是一个组件,如果直接被包在 keep-alive 里面,所有路径匹配到的视图组件都会被缓存
<keep-alive exclude="Profile,User"><router-view /></keep-alive>

关于此的一些生命周期:

<!-- src\views\Home.vue -->

<script>
export default {
  name: "Home",
  created() {
    // 生命周期函数,组件被创建时执行
    console.log("home created")
  },
  destroyed() {
    // 组件被销毁时。
    console.log("home destroyed")
  },
  // 由 keep-alive 带来的两个生命周期函数,只有该组件被保持了状态使用了keep-alive时,才是有效的
  activated() {
    // 组件活跃(进入时被执行
    console.log("home activated")
  },
  deactivated() {
    // 组件离开时执行
    console.log("home activeted")
  },
}
</script>

相关推荐:

来自系列:Vue 笔记

分类 前端下文章:

微信小程序开发 days1 关注点:文件结构,json配置文件, 模板语法

小程序开发学习笔记 days2。 关注点:view, text, rich-text, button, image, navigator, icon, swiper, radio, checkbox

小程序学习笔记 days3。 关注点:生命周期,自定义组件

小程序学习笔记 days4。 关注点:scroll-view, Promise

css3 选择器,背景定义(定位), 盒子定位,弹性布局,栅格系统。还有一些常用的 css 属性。

更多...

评论([[comments.sum]])

发表

加载更多([[item.son.length-2]])...

发表

2020-11 By chuan.

Python-flask & bootstrap-flask

图片外链来自:fghrsh

互联网ICP备案号:蜀ICP备2020031846号