SPA(Single Page Application):单页面富应用

  • 单页面应用: 所有功能在一个页面上实现=》组件组成,完成开发=》组件化开发

前端路由:专门为SPA提供页面(组件 .vue文件)的跳转支持

单页面-多页面对比

对比部分 单页应用(最流行) 多页面应用(传统方式)
页面组成 一个html文件多个组件组成 多个html文件
静态资源共用 共用,一次性加载完毕,借助ssr优化 不共用,每个页面都加载一遍
刷新方式 页面局部刷新 整页加载
url模式 itcast.com/#/pageone itcast.com/pageone.html
用户体验 用户体验良好 页面切换加载缓慢体验较差
数据传递 容易 依赖url传参,cookie,localStorage
搜索引擎优化 不利于seo优化,需要ssr优化 支持良好
使用场景 追求高体验 不要求seo 高度要求seo
开发成本 较高 需要依赖专业的框架, 开发效率高 较低 重复代码多, 开发效率低

说明:ssr(server side render)指服务端渲染
优点:

  • 整体不刷新页面,用户体验更好
  • 组件化,数据传递容易, 开发效率高

缺点:

  • 一定的学习成本
  • 首次加载会比较慢一点
  • 不利于seo搜索引擎优化

    总结: 单页面应用, 用户体验好, 开发效率高

工作原理

前端路由的本质, 对url的hash值进行改变和监听,切换对应页面组件的dom结构

  • 前端路由 : 是浏览器 URL 中的哈希值( # hash) 与 展示视图内容(组件) 之间的对应规则
  • 为什么要学习路由:
    • SPA渐进式 =>vue => vuer-router (管理组件之间的跳转)
    • 提升网页显示的速度, 提高网站的性能
  • vue 中的路由 : 是 hashcomponent 的对应关系, 一个哈希值对应一个组件页面

总结: 路由本质是就是hash值和组件的对应关系

路由的使用

安装

如果使用vue-cli创建项目,没有选择路由插件,需要单独安装和写下边初始化代码
npm i vue-router

  • 导入路由

import VueRouter from 'vue-router'

配置路由

router/index.js中的配置

  • 框架注册
    • 在vue中,使用vue的插件,都需要调用Vue.use()
    • router/index.js中注册之后才能使用
    • Vue.use(VueRouter)
  • 创建路由规则数组
    • const routes = []
    • router/index.js中创建一个routes数组
    • 实际开发在这里配置跳转规则
  • 创建路由对象
    • const router = new VueRouter({
      • routes
    • })
  • 导出路由实例

    • export default router
    • 导入和挂载

      main.js中的配置

  • 导入路由实例

    • **import**router**from**'./router/index.js'
    • index.js可以省略
  • 挂载实例到vue组件
    • new Vue({router})内写router
    • 挂载之后给vue组件提供了方法:$router$route方法
    • $router 用方法 $route 用数据 ```javascript import Vue from ‘vue’ import VueRouter from ‘vue-router’

// 框架注册 Vue.use(VueRouter) // 创建路由数组 const routes = [ ] // 创建路由对象 const router = new VueRouter({ routes }) // 导出路由实例 export default router

  1. ```javascript
  2. import Vue from 'vue'
  3. import App from './App.vue'
  4. // 导入实例
  5. import router from './router'
  6. Vue.config.productionTip = false
  7. // 挂载实例
  8. new Vue({
  9. router,
  10. render: h => h(App)
  11. }).$mount('#app')

规则

语法:{path:'/地址名', component:页面的组件对象}

  • 默认显示某个页面,只需要把该页面的path值改成'/'
  • path内是访问页面需要的地址一般写/名字
  • 页面组件需要improt导入(同组件化)

    导入写法

    语法:@/文件夹/文件

  • @指向src目录

    页面中使用

    router-view

    语法:<router-view />

  • 路由提供的占位组件

  • 路由的path地址对应的component渲染的组件占位
  • 不会渲染任何东西,只用来占位

    router-link

  • 最终生成的是一个a标签,所以控制样式时写a

  • to属性
    • 语法:<router-link to="path值"> 首页 </ router-link>
    • 使用router-link组件跳转页面,配合to属性 ```vue
  1. <a name="OOKXy"></a>
  2. ### 跳转传参
  3. - query传参
  4. - 语法:`地址?key=val&key=val` key=val (键值对)
  5. - 在to属性的值后面写`?键值对`多个键值对使用`&`连接
  6. - 通过`this.$route.query`接收传参
  7. - params传参
  8. - 语法:`path:'地址/:参数名1/:参数名2'`
  9. 在path路径写`/:参数名``:参数名`定义的是接收时候的属性名
  10. - 动态路由跳转时,在to属性的值把`:参数名`替换成参数值
  11. - 通过`this.$route.params`接收传参
  12. ```vue
  13. <template>
  14. <div id="app">
  15. <nav class="box">
  16. <router-link to="/home?a=1&b=2">首页</router-link>
  17. <router-link to="/new">新闻页</router-link>
  18. <router-link to="/login">登录页</router-link>
  19. <router-link to="/news/123">新闻1</router-link>
  20. </nav>
  21. <router-view />
  22. </div>
  23. </template>
  24. <style lang="less" scoped>
  25. .box {
  26. a {
  27. display: inline-block;
  28. margin: 15px;
  29. }
  30. }
  31. </style>
  1. created () {
  2. console.log(this.$route.params.id)
  3. console.log(this.$route.query)
  4. }
  1. import Vue from 'vue'
  2. import VueRouter from 'vue-router'
  3. import Home from '../views/home.vue'
  4. import Login from '../views/login.vue'
  5. import New from '../views/new.vue'
  6. import News from '../views/index.vue'
  7. // 框架注册
  8. Vue.use(VueRouter)
  9. // 创建路由数组
  10. const routes = [
  11. { path: '/home', component: Home },
  12. { path: '/login', component: Login },
  13. { path: '/new', component: New },
  14. { path: '/news/:id', component: News }
  15. ]
  16. // 创建路由对象
  17. const router = new VueRouter({
  18. routes
  19. })
  20. // 导出路由实例
  21. export default router

路由重定向

语法:path: '重定向地址', redirect: '页面地址'
用户什么也没有输入,默认显示某个页面可以通过redisrect:'页面地址'重新定向
router/index.js - 修改配置

  1. const routes = [
  2. { path: '/', redirect: '/home' },
  3. { path: '/home', component: Home }
  4. ]

404页面配置

语法:path: '*', component: NotFound

  • 当所有的路由都不匹配,匹配这个通配符,显示NotFound页面

    1. const routes = [
    2. { path: '*', component: NotFond }
    3. ]

    $route其他方法

    $route.path可以获取到path地址,用做菜单显示判断
    $route.matched[0].path获取404的path*用做菜单显示判断

    1. v-if="
    2. $route.path !== '/login' &&
    3. $route.matched[0].path !== '*'"

    路由模式

  • 实例化时候的mode属性

    • hash是默认值 (哈希模式)
    • history (h5的history模式)
    • 功能一样(跳转页面)
    • 区别
      • 哈希有# history没有#
      • hash模式兼容性更好
        1. // 创建路由对象
        2. const router = new VueRouter({
        3. routes,
        4. // mode: 'history'
        5. mode: 'hash'
        6. })

编程式导航

用js方法跳转路由就是编程式导航

跳转方法

  • 通过$router.push()跳转
    • 语法:$router.push('/地址' || {path:'/地址'})
      • js中需要加this.调用,模板中不需要
  • 通过$router.replace('/地址')跳转
    • 语法:$router.replace('/地址' || {path:'/地址'})
  • 通过$router.back()返回上一个页面

    push和replace总结

  • 两个方法的使用完全一样

  • 区别
    • push方法跳转,新增一条跳转记录
    • replace方法跳转,替换当前的记录进行跳转,不能返回上次跳转的页面(push可以),可以返回上上次 ```vue
  1. <a name="TDbmx"></a>
  2. #### 传参
  3. - query传参(静态路由)
  4. - 传参写法
  5. - `$router.push('/地址?key=val')`
  6. - `$router.push({path:'/地址?key=val'})`
  7. - `$router.push({path:'/地址', query:{key:val}})`
  8. - 接收
  9. - `this.$route.query`
  10. - params传参(动态路由)
  11. - 写法
  12. - 在path路径写`/:参数名``:参数名`定义的是接收时候的属性名
  13. - `this.$router.push({path:'/地址/参数值1/值2'})`
  14. - 接收
  15. - `this.$route.query.参数名`
  16. <a name="hpZix"></a>
  17. ### 路由嵌套
  18. 语法:在父路由内写`children:[{子路由}]`
  19. - 子路由 = `path:'/父地址/地址',component:组件名`
  20. - path值必须带上父路由地址
  21. - 嵌套的路由也需要在父页面写一个挂载`<router-view/>`
  22. - 如果和父路由的path地址一致,就会默认展示这个子路由
  23. ```javascript
  24. import Vue from 'vue'
  25. import VueRouter from 'vue-router'
  26. import Home from '../views/home.vue'
  27. import About from '../views/about.vue'
  28. import New from '../views/new.vue'
  29. import News from '../views/index.vue'
  30. import NotFond from '@/views/404'
  31. import Login from '@/views/login'
  32. import Find from '@/views/find'
  33. import My from '@/views/myMusic'
  34. import Song from '@/views/find/components/song.vue'
  35. import Top from '@/views/find/components/top.vue'
  36. import Recom from '@/views/find/components/recom.vue'
  37. // 框架注册
  38. Vue.use(VueRouter)
  39. // 创建路由数组
  40. const routes = [
  41. { path: '*', component: NotFond },
  42. { path: '/', redirect: '/home' },
  43. { path: '/home', component: Home },
  44. { path: '/about/:name', component: About },
  45. { path: '/new', component: New },
  46. { path: '/news/:id', component: News },
  47. { path: '/login', component: Login },
  48. { path: '/find', component: Find, children: [{ path: '/find', component: Recom }, { path: '/find/top', component: Top }, { path: '/find/song', component: Song }] },
  49. { path: '/my', component: My }
  50. ]
  51. // 创建路由对象
  52. const router = new VueRouter({
  53. routes,
  54. // mode: 'history'
  55. mode: 'hash'
  56. })
  57. // 导出路由实例
  58. export default router
  1. <template>
  2. <div>
  3. <h1>发现</h1>
  4. <nav class="nav">
  5. <router-link to="/find">推荐</router-link>
  6. <router-link to="/find/top">榜单</router-link>
  7. <router-link to="/find/song">歌单</router-link>
  8. </nav>
  9. <div class="box">
  10. <router-view />
  11. </div>
  12. </div>
  13. </template>
  14. <script>
  15. export default {
  16. }
  17. </script>
  18. <style lang="less" scoped>
  19. .nav {
  20. a {
  21. display: inline-block;
  22. margin: 5px;
  23. color: skyblue;
  24. }
  25. }
  26. .box {
  27. height: 40px;
  28. border: 1px solid orange;
  29. }
  30. </style>

高级用法

全局前置守卫

语法:router.beforeEach((to, from, next) => {})

  • router/index.js中配置
  • 访问页面之前,执行这个回调函数
  • 三个参数

    • to 表示去哪里(访问那个页面)
    • from 表示从哪来
    • next 是个方法
      • next() 直接调用,表示都可以访问
      • next(path地址) 跳转页面
        1. // 前置守卫
        2. router.beforeEach((to, from, next) => {
        3. // 访问/my页面的时候,用token判断是否登录
        4. const token = localStorage.getItem('my-token')
        5. if (to.path === '/my' && !token) {
        6. next('/login')
        7. } else {
        8. // 其他页面直接方向
        9. next()
        10. }
        11. })

        全局后置守卫

        语法:router.afterEach((to, from, next) => {})
  • router/index.js中配置

  • 访问页面之后,执行这个回调函数
  • 俩个参数
    • to 表示去哪里
    • from 表示从哪来
  • 统计用户访问某个页面的次数(数据采集)