尚硅谷 Vue2.0 + Vue3.0 入门到精通教程学习笔记 (六)和(七)

第六章:vue-router

6.1  相关理解

6.1.1  vue-router 的理解

  • vue 的一个插件库,专门用来实现 SPA 应用 

6.1.2  对 SPA 应用的理解

1. 单页 Web 应用(single page web application,SPA)。

2. 整个应用只有一个完整的页面

3. 点击页面中的导航链接不会刷新页面,只会做页面的局部更新

4. 数据需要通过 ajax 请求获取。 

6.1.3  路由的理解

1.  什么是路由?

①  一个路由就是一组映射关系(key - value

②  key 为路径, value 可能是 functioncomponent

2.  路由的分类

①  后端路由:

(a)理解:valuefunction, 用于处理客户端提交的请求。

(b)工作过程:服务器接收到一个请求时, 根据请求路径找到匹配的函数 来处理请求, 返回响应数据。

②  前端路由:

(a)理解:valuecomponent,用于展示页面内容。

(b)工作过程:当浏览器的路径改变时,对应的组件就会显示

6.2  基本路由

1. 下载 vue-router : npm i vue-router

【注】2022 年 2 月 7 日以后,vue-router 的默认版本为:4 版本,而 vue-router 4 只能在 vue 3中,vue-router 3 才能在 vue 2 中使用,若将 vue-router 4 强行安装在 vue 2 中会报如下错误:

简而言之:

vue2 中,要用 vue-router 的 3 版本 ;

vue3 中,要用 vue-router 的 4 版本 ;

由于本人安装的是 vue 2.7.14,所以直接安装 vue-router 3

npm i vue-router@3

2. 创建 src/router/index.js

// 该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router"
// 引入组件
import About from '../pages/About'
import Home from '../pages/Home'


//创建并暴露一个路由器
export default new VueRouter({
  routes: [
    {
      path: '/about',
      component:About
    },
     {
      path: '/home',
      component:Home
    },
    ]
})

3. 创建 src/main.js

// 引入 vue
import Vue from 'vue'
// 引入App
import App from './App.vue'
// 引入VueRouter
import VueRouter from 'vue-router'
//引入路由器
import router from "./router"

// 关闭Vue的生产提示
Vue.config.productionTip = false
// 应用插件
Vue.use(VueRouter)

//创建vm
new Vue({
    el: '#app',
    render: h => h(App),
    router:router
})

4. 创建 src/App.vue

<template>
  <div>
    <div class="row">
      <Banner />
    </div>
    <div class="row">
      <div class="col-xs-2 col-xs-offset-2">
        <div class="list-group">
          <!-- 原始html中我们使用a标签实现页面的跳转 -->
          <!-- <a class="list-group-item active" href="./about.html">About</a> -->
          <!-- <a class="list-group-item" href="./home.html">Home</a> -->

          <!-- Vue中借助router-link标签实现路由的切换 -->
          <router-link
            class="list-group-item"
            active-class=" active"
            to="/about"
            >About</router-link
          >
          <router-link class="list-group-item" active-class=" active" to="/home"
            >Home</router-link
          >
        </div>
      </div>
      <div class="col-xs-6">
        <div class="panel">
          <div class="panel-body">
            <!-- 指定组件的呈现位置 -->
            <router-view></router-view>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "App",
  components: { App },
}
</script>

5.创建 src/components/Home.vue

<template>
  <h2>我是Home的内容</h2>
</template>

<script>
export default {
  name: "Home",
}
</script>

 6.创建 src/components/About.vue

<template>
  <h2>我是About的内容</h2>
</template>

<script>
export default {
  name: "About",
}
</script>

效果:

总结:

1. 安装vue-router,命令:npm i vue-router (注意版本问题)

2. 应用插件:Vue.use(VueRouter) 

3. 编写 router 配置项:

//引入VueRouter
import VueRouter from 'vue-router'
//引入Luyou 组件
import About from '../components/About'
import Home from '../components/Home'

//创建router实例对象,去管理一组一组的路由规则
const router = new VueRouter({
	routes:[
		{
			path:'/about',
			component:About
		},
		{
			path:'/home',
			component:Home
		}
	]
})

//暴露router
export default router

4. 实现切换( active-class 可配置高亮样式)

<router-link active-class="active" to="/about">About</router-link>

5. 指定展示位置

 <router-view></router-view>

6.3  几个注意点

1. 路由组件通常存放在 pages 文件夹,一般组件通常存放在 components 文件夹。比如上一节中的 About.vue Home.vue 文件 可放在 pages 文件夹中,路径为 src/pages/About.vue 和 src/pages/Home.vue 。

  • src/pages/About.vue
<template>
  <h2>我是About的内容</h2>
</template>

<script>
export default {
  name: "About",
}
</script>
  • src/pages/Home.vue
<template>
  <h2>我是Home的内容</h2>
</template>

<script>
export default {
  name: "Home",
}
</script>
  •  src/router/index.js
// 该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router"
// 引入组件
import About from '../pages/About'
import Home from '../pages/Home'


//创建并暴露一个路由器
export default new VueRouter({
  routes: [
    {
      path: '/about',
      component:About
    },
     {
      path: '/home',
      component:Home
    },
    ]
})
  • src/components/Banner.vue
<template>
  <div class="col-xs-offset-2 col-xs-8">
    <div class="page-header">
      <h2>Vue Router Demo</h2>
    </div>
  </div>
</template>

<script>
export default {
  name: "Banner",
}
</script>
  • src/App.vue
<template>
  <div>
    <div class="row">
      <Banner />
    </div>
    <div class="row">
      <div class="col-xs-2 col-xs-offset-2">
        <div class="list-group">
          <!-- 原始html中我们使用a标签实现页面的跳转 -->
          <!-- <a class="list-group-item active" href="./about.html">About</a> -->
          <!-- <a class="list-group-item" href="./home.html">Home</a> -->

          <!-- Vue中借助router-link标签实现路由的切换 -->
          <router-link
            class="list-group-item"
            active-class=" active"
            to="/about"
            >About</router-link
          >
          <router-link class="list-group-item" active-class=" active" to="/home"
            >Home</router-link
          >
        </div>
      </div>
      <div class="col-xs-6">
        <div class="panel">
          <div class="panel-body">
            <!-- 指定组件的呈现位置 -->
            <router-view></router-view>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import Banner from "./components/Banner"
export default {
  name: "App",
  components: { Banner },
}
</script>

2. 通过切换,“ 隐藏 ” 了的路由组件,默认是被销毁掉的,需要的时候再去挂载。

3. 每个组件都有自己的 $route 属性,里面存储着自己的路由信息。

4. 整个应用只有一个 router,可以通过组件的 $router 属性获取到。

6.4  多级路由

  • src/pages/About.vue
<template>
  <h2>我是About的内容</h2>
</template>

<script>
export default {
  name: "About",
}
</script>
  •  src/pages/Home.vue
<template>
  <div>
    <h2>Home组件内容</h2>
    <div>
      <ul class="nav nav-tabs">
        <li>
          <router-link
            class="list-group-item"
            active-class="active"
            to="/home/news"
            >News</router-link
          >
        </li>
        <li>
          <router-link
            class="list-group-item"
            active-class="active"
            to="/home/message"
            >Message</router-link
          >
        </li>
      </ul>
      <router-view></router-view>
    </div>
  </div>
</template>

<script>
export default {
  name: "Home",
}
</script>
  • src/pages/Message.vue
<template>
  <div>
    <ul>
      <li><a href="/message1">message001</a>&nbsp;&nbsp;</li>
      <li><a href="/message2">message002</a>&nbsp;&nbsp;</li>
      <li><a href="/message/3">message003</a>&nbsp;&nbsp;</li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "Message",
}
</script>
  • src/pages/News.vue
<template>
  <ul>
    <li>news001</li>
    <li>news002</li>
    <li>news003</li>
  </ul>
</template>

<script>
export default {
  name: "News",
}
</script>
  • src/router/index.js
// 该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router"
// 引入组件
import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Message from '../pages/Message'


//创建并暴露一个路由器
export default new VueRouter({
  routes: [
    {
      path: '/about',
      component:About
    },
     {
      path: '/home',
       component: Home,
       children: [
         {
           path: 'news',
           component:News
         },
         {
           path: 'message',
           component:Message,
         }
       ]
    },
    ]
})

效果:

总结:

1. 配置路由规则,使用 children 配置项:

routes:[
	{
		path:'/about',
		component:About,
	},
	{
		path:'/home',
		component:Home,
		children:[ //通过children配置子级路由
			{
				path:'news', //此处一定不要写:/news
				component:News
			},
			{
				path:'message',//此处一定不要写:/message
				component:Message
			}
		]
	}
]

2. 跳转(要写完整路径):

<router-link to="/home/news">News</router-link>

6.5  路由的 query 参数

  • src/router.index.js
// 该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router"
// 引入组件
import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'


//创建并暴露一个路由器
export default new VueRouter({
  routes: [
    {
      path: '/about',
      component:About
    },
     {
      path: '/home',
       component: Home,
       children: [
         {
           path: 'news',
           component:News
         },
         {
           path: 'message',
           component: Message,
           children: [
             {
               path: 'detail',
               component: Detail,
             }
           ]
         }
       ]
    },
    ]
})
  • src/pages/Detail.vue
<template>
  <ul>
    <li>消息编号:{
   
   { $route.query.id }}</li>
    <li>消息标题:{
   
   { $route.query.title }}</li>
  </ul>
</template>

<script>
export default {
  name: "Detail",
}
</script>
  • src/pages/Message.vue
<template>
  <div>
    <ul>
      <li v-for="m in messageList" :key="m.id">
        <!-- 跳转路由并携带query参数,to的字符串写法 -->
        <!-- <router-link
          :to="`/home/message / detail ? id = ${m.id}& title=${m.title}`"
          >{
   
   { m.title }}</router-link
        >&nbsp;&nbsp; -->

        <!-- 跳转路由并携带query参数,to的对象写法 -->
        <router-link
          :to="{
            path: '/home/message/detail',
            query: {
              id: m.id,
              title: m.title,
            },
          }"
        >
          {
   
   { m.title }}
        </router-link>
      </li>
    </ul>
    <hr />
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: "Message",
  data() {
    return {
      messageList: [
        { id: "001", title: "消息001" },
        { id: "002", title: "消息002" },
        { id: "003", title: "消息003" },
      ],
    }
  },
}
</script>

<style></style>

效果:

总结:

1. 传递参数 

<!-- 跳转并携带query参数,to的字符串写法 -->
<router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link>
				
<!-- 跳转并携带query参数,to的对象写法 -->
<router-link 
	:to="{
		path:'/home/message/detail',
		query:{
		   id:666,
            title:'你好'
		}
	}"
>跳转</router-link>

 2. 接收参数:

$route.query.id
$route.query.title

6.6  命名路由

  • src/router/index.js
// 该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router"
// 引入组件
import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'


//创建并暴露一个路由器
export default new VueRouter({
  routes: [
    {
      name:'guanyu',
      path: '/about',
      component:About
    },
     {
      path: '/home',
       component: Home,
       children: [
         {
           path: 'news',
           component:News
         },
         {
           path: 'message',
           component: Message,
           children: [
             {
               name:'xiangqing',
               path: 'detail',
               component: Detail,
             }
           ]
         }
       ]
    },
    ]
})
  • src/pages/Message.vue
<template>
  <div>
    <ul>
      <li v-for="m in messageList" :key="m.id">
        <!-- 跳转路由并携带query参数,to的字符串写法 -->
        <!-- <router-link
          :to="`/home/message / detail ? id = ${m.id}& title=${m.title}`"
          >{
   
   { m.title }}</router-link
        >&nbsp;&nbsp; -->

        <!-- 跳转路由并携带query参数,to的对象写法 -->
        <router-link
          :to="{
            name: 'xiangqing',
            query: {
              id: m.id,
              title: m.title,
            },
          }"
        >
          {
   
   { m.title }}
        </router-link>
      </li>
    </ul>
    <hr />
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: "Message",
  data() {
    return {
      messageList: [
        { id: "001", title: "消息001" },
        { id: "002", title: "消息002" },
        { id: "003", title: "消息003" },
      ],
    }
  },
}
</script>

效果:

总结:

1. 作用:可以简化路由的跳转。

2. 如何使用

  ①  给路由命名:

{
	path:'/demo',
	component:Demo,
	children:[
		{
			path:'test',
			component:Test,
			children:[
				{
                      name:'hello' //给路由命名
					path:'welcome',
					component:Hello,
				}
			]
		}
	]
}

  ②  简化跳转:

<!--简化前,需要写完整的路径 -->
<router-link to="/demo/test/welcome">跳转</router-link>

<!--简化后,直接通过名字跳转 -->
<router-link :to="{name:'hello'}">跳转</router-link>

<!--简化写法配合传递参数 -->
<router-link 
	:to="{
		name:'hello',
		query:{
		   id:666,
            title:'你好'
		}
	}"
>跳转</router-link>

6.7  路由的 params 参数

  • src/router/index.js
// 该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router"
// 引入组件
import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'


//创建并暴露一个路由器
export default new VueRouter({
  routes: [
    {
      name:'guanyu',
      path: '/about',
      component:About
    },
     {
      path: '/home',
       component: Home,
       children: [
         {
           path: 'news',
           component:News
         },
         {
           path: 'message',
           component: Message,
           children: [
             {
               name:'xiangqing',
               path: 'detail/:id/:title',
               component: Detail,
             }
           ]
         }
       ]
    },
    ]
})
  • src/pages/Message.vue
<template>
  <div>
    <ul>
      <li v-for="m in messageList" :key="m.id">
        <!-- 跳转路由并携带params参数,to的字符串写法 -->
        <!-- <router-link :to="`/home/message/detail/${m.id}/${m.title}`">{
   
   {
          m.title
        }}</router-link
        >&nbsp;&nbsp; -->

        <!-- 跳转路由并携带params参数,to的对象写法 -->
        <router-link
          :to="{
            name: 'xiangqing',
            params: {
              id: m.id,
              title: m.title,
            },
          }"
        >
          {
   
   { m.title }}
        </router-link>
      </li>
    </ul>
    <hr />
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: "Message",
  data() {
    return {
      messageList: [
        { id: "001", title: "消息001" },
        { id: "002", title: "消息002" },
        { id: "003", title: "消息003" },
      ],
    }
  },
}
</script>
  • src/pages/Detail.vue
<template>
  <ul>
    <li>消息编号:{
   
   { $route.params.id }}</li>
    <li>消息标题:{
   
   { $route.params.title }}</li>
  </ul>
</template>

<script>
export default {
  name: "Detail",
}
</script>

效果:

总结:

1. 配置路由,声明接收 params 参数 

{
	path:'/home',
	component:Home,
	children:[
		{
			path:'news',
			component:News
		},
		{
			component:Message,
			children:[
				{
					name:'xiangqing',
					path:'detail/:id/:title', //使用占位符声明接收params参数
					component:Detail
				}
			]
		}
	]
}

2. 传递参数

<!-- 跳转并携带params参数,to的字符串写法 -->
<router-link :to="/home/message/detail/666/你好">跳转</router-link>
				
<!-- 跳转并携带params参数,to的对象写法 -->
<router-link 
	:to="{
		name:'xiangqing',
		params:{
		   id:666,
            title:'你好'
		}
	}"
>跳转</router-link>

特别注意:路由携带 params 参数时,若使用 to 的对象写法,则不能使用 path 配置项,必须使用 name 配置!

3. 接收参数:

$route.params.id
$route.params.title

6.8  路由的 props 配置

  • src/pages/Message.vue
<template>
  <div>
    <ul>
      <li v-for="m in messageList" :key="m.id">
        <!-- 跳转路由并携带params参数,to的字符串写法 -->
        <!-- <router-link :to="`/home/message/detail/${m.id}/${m.title}`">{
   
   {
          m.title
        }}</router-link
        >&nbsp;&nbsp; -->

        <!-- 跳转路由并携带query参数,to的对象写法 -->
        <router-link
          :to="{
            name: 'xiangqing',
            query: {
              id: m.id,
              title: m.title,
            },
          }"
        >
          {
   
   { m.title }}
        </router-link>
      </li>
    </ul>
    <hr />
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: "Message",
  data() {
    return {
      messageList: [
        { id: "001", title: "消息001" },
        { id: "002", title: "消息002" },
        { id: "003", title: "消息003" },
      ],
    }
  },
}
</script>
  • src/router/index.js
// 该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router"
// 引入组件
import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'


//创建并暴露一个路由器
export default new VueRouter({
  routes: [
    {
      name:'guanyu',
      path: '/about',
      component:About
    },
     {
      path: '/home',
       component: Home,
       children: [
         {
           path: 'news',
           component:News
         },
         {
           path: 'message',
           component: Message,
           children: [
             {
               name: 'xiangqing',
               path: 'detail',
               component: Detail,

               //props的第一种写法,值为对象,该对象中的所有key-value都会以props的形式传给Detail组件。
               //  props: { a: 1, b: 'hello' }

               //props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件
               //  props: true

               //props的第三种写法,值为函数,
               props($route) {
                 return { id: $route.query.id, title: $route.query.title }

                // 解构赋值写法
                //  props({ query }) {
                //    return { id: query.id, title: query.title }

                // 连续解构赋值写法(语义化不明确,不推荐)
              //  props({ query: { id,title} }) {
              //      return { id, title }
               }
             }
           ]
         }
       ]
    },
    ]
})
  • src/pages/Detail.vue
<template>
  <ul>
    <li>消息编号:{
   
   { id }}</li>
    <li>消息标题:{
   
   { title }}</li>
  </ul>
</template>

<script>
export default {
  name: "Detail",
  props: ["id", "title"],
}
</script>

总结:

  • 作用:让路由组件更方便的收到参数
{
	name:'xiangqing',
	path:'detail/:id',
	component:Detail,

	//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
	// props:{a:900}

	//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
	// props:true
	
	//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
	props(route){
		return {
			id:route.query.id,
			title:route.query.title
		}
	}
}

6.9  <router-link> 的 replace 属性

  • src/pages/Home.vue
<template>
  <div>
    <h2>Home组件内容</h2>
    <div>
      <ul class="nav nav-tabs">
        <li>
          <router-link
            class="list-group-item"
            active-class="active"
            to="/home/news"
            >News</router-link
          >
        </li>
        <li>
          <router-link
            class="list-group-item"
            active-class="active"
            to="/home/message"
            >Message</router-link
          >
        </li>
      </ul>
      <router-view></router-view>
    </div>
  </div>
</template>

<script>
export default {
  name: "Home",
}
</script>

总结:

1. 作用:控制路由跳转时操作浏览器历史记录的模式

2. 浏览器的历史记录有两种写入方式:分别为 pushreplacepush 是追加历史记录,replace 是替换当前记录。路由跳转时候默认为 push

3. 如何开启 replace 模式:<router-link replace .......>News</router-link>

6.10  编程式路由导航

  • src/components/Banner.vue
<template>
  <div class="col-xs-offset-2 col-xs-8">
    <div class="page-header">
      <h2>Vue Router Demo</h2>
      <button @click="back">后退</button>
      <button @click="forward">前进</button>
      <button @click="test">测试一下</button>
    </div>
  </div>
</template>

<script>
export default {
  name: "Banner",
  methods: {
    back() {
      // this.$router.back()
    },
    forward() {
      this.$router.forward()
    },
    test() {
      this.$router.go(3)
    },
  },
}
</script>
  •  src/pages/Message.vue
<template>
  <div>
    <ul>
      <li v-for="m in messageList" :key="m.id">
        <!-- 跳转路由并携带params参数,to的字符串写法 -->
        <!-- <router-link :to="`/home/message/detail/${m.id}/${m.title}`">{
   
   {
          m.title
        }}</router-link
        >&nbsp;&nbsp; -->

        <!-- 跳转路由并携带query参数,to的对象写法 -->
        <router-link
          :to="{
            name: 'xiangqing',
            query: {
              id: m.id,
              title: m.title,
            },
          }"
        >
          {
   
   { m.title }}
        </router-link>
        <button @click="pushShow(m)">push查看</button>
        <button @click="replaceShow(m)">replace查看</button>
      </li>
    </ul>
    <hr />
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: "Message",
  data() {
    return {
      messageList: [
        { id: "001", title: "消息001" },
        { id: "002", title: "消息002" },
        { id: "003", title: "消息003" },
      ],
    }
  },
  methods: {
    pushShow(m) {
      this.$router.push({
        name: "xiangqing",
        query: {
          id: m.id,
          title: m.title,
        },
      })
    },
    replaceShow(m) {
      this.$router.replace({
        name: "xiangqing",
        query: {
          id: m.id,
          title: m.title,
        },
      })
    },
  },
}
</script>
  • src/pages/Detail.vue
<template>
  <ul>
    <li>消息编号:{
   
   { id }}</li>
    <li>消息标题:{
   
   { title }}</li>
  </ul>
</template>

<script>
export default {
  name: "Detail",
  props: ["id", "title"],
}
</script>
  • src/router/index.js
// 该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router"
// 引入组件
import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'


//创建并暴露一个路由器
export default new VueRouter({
  routes: [
    {
      name:'guanyu',
      path: '/about',
      component:About
    },
     {
      path: '/home',
       component: Home,
       children: [
         {
           path: 'news',
           component:News
         },
         {
           path: 'message',
           component: Message,
           children: [
             {
               name: 'xiangqing',
               path: 'detail',
               component: Detail,

               //props的第一种写法,值为对象,该对象中的所有key-value都会以props的形式传给Detail组件。
               //  props: { a: 1, b: 'hello' }

               //props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件
               //  props: true

               //props的第三种写法,值为函数,
               props($route) {
                 return { id: $route.query.id, title: $route.query.title }

                // 解构赋值写法
                //  props({ query }) {
                //    return { id: query.id, title: query.title }

                // 连续解构赋值写法(语义化不明确,不推荐)
              //  props({ query: { id,title} }) {
              //      return { id, title }
               }
             }
           ]
         }
       ]
    },
    ]
})

效果:

总结 :

1. 作用:不借助 <router-link>  实现路由跳转,让路由跳转更加灵活。

2. 具体编码:

//$router的两个API
this.$router.push({
	name:'xiangqing',
		params:{
			id:xxx,
			title:xxx
		}
})

this.$router.replace({
	name:'xiangqing',
		params:{
			id:xxx,
			title:xxx
		}
})
this.$router.forward() //前进
this.$router.back() //后退
this.$router.go() //可前进也可后退

3. 相关 API:

①. this.$router.push(path): 相当于点击路由链接(可以返回到当前路由界面)

②. this.$router.replace(path): 用新路由替换当前路由(不可以返回到当前路由界面)

③. this.$router.back(): 请求(返回)上一个记录路由

④. this.$router.go(-1): 请求(返回)上一个记录路由

⑤. this.$router.go(1): 请求下一个记录路由

6.11  缓存路由组件

  • src/pages/News.vue
<template>
  <ul>
    <li>news001 <input type="text" /></li>
    <li>news002 <input type="text" /></li>
    <li>news003 <input type="text" /></li>
  </ul>
</template>

<script>
export default {
  name: "News",
}
</script>
  • src/pages/Home.vue
<template>
  <div>
    <h2>Home组件内容</h2>
    <div>
      <ul class="nav nav-tabs">
        <li>
          <router-link
            class="list-group-item"
            active-class="active"
            to="/home/news"
            >News</router-link
          >
        </li>
        <li>
          <router-link
            class="list-group-item"
            active-class="active"
            to="/home/message"
            >Message</router-link
          >
        </li>
      </ul>
      <!-- 缓存多个路由组件 -->
      <keep-alive :include="['News', 'Message']">
        <router-view></router-view>
      </keep-alive>

      <!-- 缓存一个路由组件 -->
      <!-- <keep-alive include="News">
        <router-view></router-view>
      </keep-alive> -->
    </div>
  </div>
</template>

<script>
export default {
  name: "Home",
}
</script>

效果:

总结:

1. 作用:让不展示的路由组件保持挂载,不被销毁。

2. 具体编码:

<keep-alive include="News"> 
    <router-view></router-view>
</keep-alive>

6.12  两个新的生命周期钩子:activated 和 deactivated

  • src/pages/News.vue
<template>
  <ul>
    <li :style="{ opacity }">欢迎学习Vue</li>
    <li>news001 <input type="text" /></li>
    <li>news002 <input type="text" /></li>
    <li>news003 <input type="text" /></li>
  </ul>
</template>

<script>
export default {
  name: "News",
  data() {
    return {
      opacity: 1,
    }
  },
  activated() {
    this.timer = setInterval(() => {
      console.log("@")
      this.opacity -= 0.01
      if (this.opacity <= 0) this.opacity = 1
    }, 16)
  },
  deactivated() {
    console.log("News组件即将被销毁率了")
    clearInterval(this.timer)
  },
}
</script>

效果:

总结:

1. 作用:activateddeactivated 是路由组件所独有的两个钩子,用于捕获路由组件的激活状态。

2. 具体名字:

①  activated 路由组件被激活时触发。

②  deactivated 路由组件失活时触发。

6.13  路由守卫

6.13.1  全局路由守卫

  • src/router/index.js
// 该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router"
// 引入组件
import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'


//创建并暴露一个路由器
const router = new VueRouter({
  routes: [
    {
      name:'guanyu',
      path: '/about',
      component: About,
      meta: {title:'关于'}
    },
    {
      name:'zhuye',
      path: '/home',
      component: Home,
      meta: {title:'主页'},
      children: [
         {
           name:'xinwen',
           path: 'news',
           component: News,
           meta: {isAuth:true,title:'新闻'}
         },
         {
           name:'xiaoxi',
           path: 'message',
           component: Message,
           meta: {isAuth:true,title:'消息'},
           children: [
             {
               name: 'xiangqing',
               path: 'detail',
               component: Detail,
               meta: {isAuth:true,title:'详情'},
               props($route) {
                 return { id: $route.query.id, title: $route.query.title }
               }
             }
           ]
         }
       ]
    },
    ]
})

// 全局前置路由守卫——初始化的时候被调用、每次路由切换之前被调用
router.beforeEach((to,from,next) => {
  console.log('前置路由守卫',to, from)
  if (to.meta.isAuth) { //判断是否需要鉴权
    if (localStorage.getItem('school') === 'atguigu') {
      next()
    }
    else {
      alert('学校名不对,无权限查看!')
    }
  } else {
     next()
  }
})

// 全局后置路由守卫——初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to,from) => {
  console.log('后置路由守卫', to, from)
  document.title = to.meta.title || '硅谷系统'
})

export default router

效果:

6.13.2  独享路由守卫

  • src/router/index.js
// 该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router"
// 引入组件
import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'


//创建并暴露一个路由器
const router = new VueRouter({
  routes: [
    {
      name:'guanyu',
      path: '/about',
      component: About,
      meta: {title:'关于'}
    },
    {
      name:'zhuye',
      path: '/home',
      component: Home,
      meta: {title:'主页'},
      children: [
         {
           name:'xinwen',
           path: 'news',
           component: News,
          meta: { isAuth: true, title: '新闻' },
           beforeEnter: (to, from, next) => {
            console.log('独享路由守卫',to, from)
            if (to.meta.isAuth) { //判断是否需要鉴权
            if (localStorage.getItem('school') === 'atguigu') {
            next()
            }
            else {
            alert('学校名不对,无权限查看!')
            }
          } else {
           next()
          }
          }
         },
         {
           name:'xiaoxi',
           path: 'message',
           component: Message,
           meta: {isAuth:true,title:'消息'},
           children: [
             {
               name: 'xiangqing',
               path: 'detail',
               component: Detail,
               meta: { isAuth: true, title: '详情' },
               props($route) {
                 return { id: $route.query.id, title: $route.query.title }
                }
             }
           ]
         }
       ]
    },
    ]
})

// 全局后置路由守卫——初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to,from) => {
  console.log('后置路由守卫', to, from)
  document.title = to.meta.title || '硅谷系统'
})

export default router

效果:

6.13.3  组件内路由守卫

  • src/pages/About.vue
<template>
  <h2>我是About的内容</h2>
</template>

<script>
export default {
  name: "About",

  //通过路由规则,进入该组件时被调用
  beforeRouteEnter(to, from, next) {
    console.log("About---beforeRouteEnter", to, from)
    if (to.meta.isAuth) {
      //判断是否需要鉴权
      if (localStorage.getItem("school") === "atguigu") {
        next()
      } else {
        alert("学校名不对,无权限查看!")
      }
    } else {
      next()
    }
  },

  //通过路由规则,离开该组件时被调用
  beforeRouteLeave(to, from, next) {
    console.log("About---beforeRouteLeave", to, from)
    next()
  },
}
</script>

效果:

总结:

路由守卫:

1. 作用:对路由进行权限控制

2. 分类:全局守卫、独享守卫、组件内守卫

3. 全局守卫:

//全局前置守卫:初始化时执行、每次路由切换前执行
router.beforeEach((to,from,next)=>{
	console.log('beforeEach',to,from)
	if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
		if(localStorage.getItem('school') === 'atguigu'){ //权限控制的具体规则
			next() //放行
		}else{
			alert('暂无权限查看')
			// next({name:'guanyu'})
		}
	}else{
		next() //放行
	}
})

//全局后置守卫:初始化时执行、每次路由切换后执行
router.afterEach((to,from)=>{
	console.log('afterEach',to,from)
	if(to.meta.title){ 
		document.title = to.meta.title //修改网页的title
	}else{
		document.title = 'vue_test'
	}
})

4. 独享守卫:

beforeEnter(to,from,next){
	console.log('beforeEnter',to,from)
	if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
		if(localStorage.getItem('school') === 'atguigu'){
			next()
		}else{
			alert('暂无权限查看')
			// next({name:'guanyu'})
		}
	}else{
		next()
	}
}

5. 组件内守卫:

//进入守卫:通过路由规则,进入该组件时被调用
beforeRouteEnter (to, from, next) {
},
//离开守卫:通过路由规则,离开该组件时被调用
beforeRouteLeave (to, from, next) {
}

6.14  路由的两种工作模式:history 模式和 hash 模式

1. 对于一个 url 来说,什么是 hash 值?—— # 及其后面的内容就是 hash 值。

2. hash 值不会包含在 HTTP 请求中,即:hash 值不会带给服务器

3. hash 模式:

  ① 地址中永远带着 # 号,不美观 。

  ② 若以后将地址通过第三方手机 app 分享,若 app 校验严格,则地址会被标记为不合法。

  ③ 兼容性较好。

4. history 模式:

   ① 地址干净,美观 。

   ② 兼容性和 hash 模式相比略差。

   ③ 应用部署上线时需要后端人员支持,解决刷新页面服务端 404 的问题

前端打包项目并上线全过程:

⑴  第一步:打包静态资源

npm run build

 构建好生产环境后,会出现一个文件名叫 “dist” 文件夹,此时文件夹中就包含了打包出来的 css文件、js 文件、html 文件以及页签图标。

⑵  第二步:在服务器上部署

新建一个服务器:利用 node.jsexpress 框架搭建一个服务器

◐  新建文件夹 demo,利用 VSCode 打开文件夹,安装 express

   ◆  先使 express 变为一个合法的包: 

npm init

  ◆  取名 atguigu_test_server ,后一直不停的回车。

  ◆  安装 express

npm i express

◐  新建服务器主文件 server.js 

const express = require('express')

const app = express()

app.get('/person', (req,res) => {
  res.send({
    name: 'tom',
    age:18
  })
})

app.listen(5005, (err) => {
  if(!err)console.log('服务器启动成功了!');
})

 至此,一个微型服务器搭建完毕。

◐  启动服务器

node server

⑶  第三步:部署静态资源(html/css/js……) 

将静态资源复制到文件夹 static(有时候也叫 public) ,并重启服务器,效果如下:

在服务器上即可运行项目,不需要脚手架了。

【注】但此时,若刷新页面(即发送网络请求),会出现问题:

原因在于将 home/message/...... 当成资源请求服务器,而服务器并不存在这些资源。

这是 路由 history 模式的一个弊端 ,当我们在脚手架中将路由改成 hash 模式,上述页面 404 的问题即能解决。(修改路由模式后必须重新打包和启动服务器)

★★★ 若执意想用路由的 history 模式 ,解决方法如下:

与后端开发工程师协商配合,分配服务器的资源和前端传递过去的,区别哪些是前端路由的,哪些是后端路由的。这里推荐一个中间件,可省去自己写正则匹配去区分。

① 打开 npm 网站 搜索 connect-history-api-fallback ,找到

② 复制 save connect-history-api-fallback ,回到服务器执行

npm i save connect-history-api-fallback

 ③ 引入中间件 var history = require('connect-history-api-fallback'); 

     这里定义就改成 :

const history = require('connect-history-api-fallback');

④ 应用这个中间件,注意必须在静态资源应用之前

app.use(history())
app.use(express.static(__dirname+'/static'))

引入后完整的 server.js 代码如下:

const express = require('express')
const history = require('connect-history-api-fallback');

const app = express()
app.use(history())
app.use(express.static(__dirname+'/static'))

app.get('/person', (req,res) => {
  res.send({
    name: 'tom',
    age:18
  })
})

app.listen(5005, (err) => {
  if(!err)console.log('服务器启动成功了!');
})

 由此就能解决在 history 模式下也能发送网络请求了。

第七章:Vue UI 组件库

7.1  常用 UI 组件库

7.1.1  移动端常用 UI 组件库

    1. Vant

    2. Cube UI

    3. Mint UI 

7.1.2  PC 端常用 UI 组件库

    1. Element UI

    2. IView UI 

7.2  element-ui 基本使用

    1. 安装 element-ui: npm i element-ui -S

    2. src/main.js

// 引入 vue
import Vue from 'vue'
// 引入App
import App from './App.vue'

//完整引入
//引入ElementUI组件库
import ElementUI from 'element-ui';
// 引入ElementUI全部样式
import 'element-ui/lib/theme-chalk/index.css';

// 关闭Vue的生产提示
Vue.config.productionTip = false
// 应用ElementUI
Vue.use(ElementUI);

//创建vm
new Vue({
    el: '#app',
    render: h => h(App),
})

     3. src/App.vue

<template>
  <div>
   <br />
    <el-row>
      <el-button icon="el-icon-search" circle></el-button>
      <el-button type="primary" icon="el-icon-edit" circle></el-button>
      <el-button type="success" icon="el-icon-check" circle></el-button>
      <el-button type="info" icon="el-icon-message" circle></el-button>
      <el-button type="warning" icon="el-icon-star-off" circle></el-button>
      <el-button type="danger" icon="el-icon-delete" circle></el-button>
    </el-row>
  </div>
</template>

<script>
export default {
  name: "App",
}
</script>

效果:

7.3. element-ui 按需引入

    1. 安装 babel-plugin-componentnpm install babel-plugin-component -D

    2. 修改 babel-config-js : 

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset',
    ["@babel/preset-env", { "modules": false }]
  ],
  plugins: [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

    3. src/main.js

// 引入 vue
import Vue from 'vue'
// 引入App
import App from './App.vue'

//完整引入
//引入ElementUI组件库
import ElementUI from 'element-ui';

//按需引入
import { Button, Row,DatePicker } from 'element-ui';

// 关闭Vue的生产提示
Vue.config.productionTip = false
// 应用ElementUI
Vue.use(ElementUI);
Vue.component('atguigu-button', Button);
Vue.component('atguigu-row', Row);
Vue.component('atguigu-data-picker', DatePicker);


//创建vm
new Vue({
    el: '#app',
    render: h => h(App),
})

     4. src/App.vue

<template>
  <div>
    <br />
    <button>原生的按钮</button>
    <input type="text" />
    <atguigu-row>
      <atguigu-button>默认按钮</atguigu-button>
      <atguigu-button type="primary">主要按钮</atguigu-button>
      <atguigu-button type="success">成功按钮</atguigu-button>
      <atguigu-button type="info">信息按钮</atguigu-button>
      <atguigu-button type="warning">警告按钮</atguigu-button>
      <atguigu-button type="danger">危险按钮</atguigu-button>
    </atguigu-row>
    <atguigu-data-picker type="date" placeholder="选择日期">
    </atguigu-data-picker>
    <atguigu-row>
      <atguigu-button icon="el-icon-search" circle></atguigu-button>
      <atguigu-button
        type="primary"
        icon="el-icon-edit"
        circle
      ></atguigu-button>
      <atguigu-button
        type="success"
        icon="el-icon-check"
        circle
      ></atguigu-button>
      <atguigu-button
        type="info"
        icon="el-icon-message"
        circle
      ></atguigu-button>
      <atguigu-button
        type="warning"
        icon="el-icon-star-off"
        circle
      ></atguigu-button>
      <atguigu-button
        type="danger"
        icon="el-icon-delete"
        circle
      ></atguigu-button>
    </atguigu-row>
  </div>
</template>

<script>
export default {
  name: "App",
}
</script>

效果:

 ★★★ 欢迎批评指正!

参考:http://t.csdn.cn/j9260

猜你喜欢

转载自blog.csdn.net/weixin_44566194/article/details/128632799