目录
Vue框架入门系列(二)
/    

Vue框架入门系列(二)

路由的学习

vue-router的安装和配置

npm install vue-router --save

vue-router是一个插件,所以可以通过Vue.use()来安装路由功能

一般我们手动安装的时候,可以先在src目录下创建router
然后创建在此文件夹中创建index.js文件

// 配置路由相关信息
import Vue from 'vue'
import Router from 'vue-router'
import contentCpn from '@/components/contentCpn'

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

// 2. 创建VueRouter对象
// 3. 将router对象传入到vue实例
export default new Router({
  // 配置路由和组件之间的映射关系
  routes: [
    {
      path: '/',
      name: 'contentCpn', 
      component: contentCpn
    }
  ]
})

  1. 导入路由对象,并且调用Vue.use(VueRouter)
  2. 创建路由实例,并且传入路由映射配置
  3. 在vue实例中挂载创建的路由器

使用vue-router的步骤
第一步:创建路由组件
第二步:配置路由映射:组件和路径映射关系
第三步:使用路由:通过<router-link?>和<router-view?>

一个链接跳转到路由,一个是路由的显示

动态路由

使用$route.params.参数名

<template>
    <div>
        <h3>动态路由</h3>
        <p>{{$route.params.name}}</p>
    </div>
</template>

<script>
export default {
    name: 'dynamicCpn',
    data () {
        return {

        }
    }
}

</script>

<style scoped>  /* scoped 表示 仅在当前组件生效。 */

</style>

App.vue

<template>
  <div id="app">
      <h2>你好,世界。。。</h2>
      <router-link to="/hello">哈喽</router-link>  
      <router-link v-bind:to="'/user/' + name">动态路由</router-link>
      <router-view></router-view>
  </div>
</template>

index.js

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '../components/HelloWorld.vue'
import dynamicCpn from '../components/dynamicCpn.vue'

Vue.use(Router)

export default new Router({
    routes: [
        {
            path: '/hello',
            component: HelloWorld
        },
        {
            path: '/user/:name',
            component: dynamicCpn
        }
    ],
    mode: 'history'  // html5中的history模式
})

路由的懒加载

  • 当打包构建应用时,JavaScript包会变得非常大,影响页面加载。
  • 如果我们能把不同路由对应的组件分割不同的代码块,然后当路由被访问的时候才加载对应组件,
    这样就更加高效了。
  • 修改index.js
import Vue from 'vue'
import Router from 'vue-router'
// import HelloWorld from '../components/HelloWorld.vue'
// import dynamicCpn from '../components/dynamicCpn.vue'


/* 路由 懒加载 */
const HelloWorld = () => import('../components/HelloWorld')
const dynamicCpn = () => import('../components/dynamicCpn')

Vue.use(Router)

export default new Router({
    routes: [
        {
            path: '/hello',
            component: HelloWorld
        },
        {
            path: '/user/:name',
            component: dynamicCpn
        }
    ],
    mode: 'history'  // html5中的history模式
})

嵌套路由

  • 创建两个子组件
  • 修改router中index.js文件
import Vue from 'vue'
import Router from 'vue-router'
// import HelloWorld from '../components/HelloWorld.vue'
// import dynamicCpn from '../components/dynamicCpn.vue'


/* 路由 懒加载 */
const HelloWorld = () => import('../components/HelloWorld')
/* 嵌套子路由 */
const HelloAAA = () => import('../components/HelloAAA')
const HelloBBB = () => import('../components/HelloBBB')

const dynamicCpn = () => import('../components/dynamicCpn')


Vue.use(Router)

export default new Router({
    routes: [
        {
            path: '',
            redirect: '/hello'
        },
        {
            path: '/hello',
            component: HelloWorld,
            children: [
                {
                    path: '',
                    redirect: 'HelloAAA'
                },
                {
                    path: 'HelloAAA',
                    component: HelloAAA
                },
                {
                    path: 'HelloBBB',
                    component: HelloBBB
                }
            ]
        },
        {
            path: '/user/:name',
            component: dynamicCpn
        }
  
    ],
    mode: 'history',  // html5中的history模式
    linkActiveClass: 'active'
})
  • 然后在父路由中修改
<template>
  <div>
    <p>你好,helloworld</p>

    <router-link to="/hello/HelloAAA">AAA</router-link>  
    <router-link to="/hello/HelloBBB">BBB</router-link>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

</style>

vue-router参数传递

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

  • params的类型:

    1. 配置路由格式:/router/:id
    2. 传递的方式:在path后面跟上对应的值
    3. 传递后形成的路径:/router/123, /router/abc
    • 获取参数的值使用 $route.params.abc
  • query的类型

    1. 配置路由格式:/router, 也就是普通配置
    2. 传递的方式:对象中使用query 的key作为传递方式
    3. 传递后形成的路径:/router?id=123, /router?id=abc
    • App.vue
        <template>
        <div id="app">
            <h2>你好,世界。。。</h2>
            <router-link to="/hello">哈喽</router-link>  
            <router-link v-bind:to="'/user/' + name">动态路由</router-link>  
            <router-link :to="profile">档案</router-link>  
            <button @click="profileClick">档案按钮测试</button>
            <router-view></router-view>
        </div>
        </template>
    
        <script>
        // import HelloWorld from './components/HelloWorld.vue'
    
        export default {
        name: 'App',
        data () {
            return {
            name: '张三',
            profile: {
                path: '/profile',
                query: {
                    name: '张三',
                    age: 18,
                    height: '176cm'
                }
            }
            }
        },
        methods: {
            profileClick () {
            this.$router.push(this.profile)
            }
        }
        }
        </script>
    
        <style>
        .active {
            color: red;
        }
        </style>
    
    
    • 组件profile.vue
        <template>
            <div>
                <h2>我是 profile 组件</h2>
                <h2>{{$route.query}}</h2>
            </div>
        </template>
    
        <script>
    
        export default {
            name: 'profile'
        }
    
        </script>
    
    

$route 和 $router是有区别的

  • $router为VueRouter实例,想要导航到不同URL,则使用$router.push方法
  • $route为当前router跳转对象里面可以获取name、path、query、params等。

导航守卫

在router文件夹下的index.js中

const router = new Router({
    routes: [
        {
            path: '',
            redirect: '/hello'
        },
        {
            path: '/hello',
            component: HelloWorld,
            meta: {
                title: '首页'
            },
            children: [
                {
                    path: '',
                    redirect: 'HelloAAA'
                },
                {
                    path: 'HelloAAA',
                    component: HelloAAA
                },
                {
                    path: 'HelloBBB',
                    component: HelloBBB
                }
            ],
            // 元 数据

        },
        {
            path: '/user/:name',
            component: dynamicCpn,
            meta: {
                title: '动态路由'
            }
        },
        {
            path: '/profile',
            component: profile,
            meta: {
                title: '关于'
            }
        }
  
    ],
    mode: 'history',  // html5中的history模式
    linkActiveClass: 'active'
})
// 前置钩子  (hook) 或者 前置守卫
router.beforeEach((to, from, next) => {
    // 从from跳转到to
    document.title = to.matched[0].meta.title
    // next是必须要执行的
    next()
})

// 如果是后置钩子,也就是afterEach, 不需要主动调用next()函数
router.afterEach((to, from) => {   
    console.log('当前页面: ' + to.matched[0].meta.title);
    console.log('上一次页面:', from.matched[0] === undefined ? '为空' : from.matched[0].meta.title);
})
// 上面使用的守卫是 全局 守卫

export default router
  • 导航守卫的补充
    • 路由独享的守卫
    • 组件内的守卫

路由独享的守卫

我们可以在路由配置上直接定义 beforeEnter 守卫

    const router = new VueRouter({
        routers: [
            {
                path: '/foo',
                component: Foo,
                beforeEnter: (to, from, next) => {
                    // ............
                }
            }
        ]
    })

组件内的守卫

组件中的js代码

export default {
    name: 'dynamicCpn',
    data () {
        return {
  
        }
    },
    beforeRouteEnter: (to, from, next) => {
        console.log('组件内的守卫')
        next()
    }
}

keep-alive 和 vue-router

  • keep-alive 是 vue 内置的一个组件,可以被包含的组件保留状态,或避免重新渲染
  • router-view也是一个组件,如果直接被包在keep-alive里面,所有路径匹配到的视图组件都会被缓存.

例如在 profile.vue中

<template>
    <div>
        <h2>我是 profile 组件</h2>
        <h2>{{$route.query}}</h2>
    </div>
</template>

<script>

export default {
    name: 'profile',
  created () {
    console.log('profile created')
  },
  destroyed () {
    console.log('profile destroyed')
  }
}

</script>

当我们在App.vue中 使用keep-alive标签包裹

<template>
  <div id="app">
      <h2>你好,世界。。。</h2>
      <router-link to="/hello">哈喽</router-link>  
      <router-link v-bind:to="'/user/' + name">动态路由</router-link>  
      <router-link :to="profile">档案</router-link>  
      <button @click="profileClick">档案按钮测试</button>
      <keep-alive>
        <router-view></router-view>
      </keep-alive>
  </div>
</template>

运行的时候, profile组件的生命周期, 最开始进行 created, 之后就不再销毁 和 创建

使用keep-alive标签包裹之后, 会有 执行两个函数 activated 和 disactivated

export default {
    name: 'profile',
  created () {
    console.log('profile created')
  },
  destroyed () {
    console.log('profile destroyed')
  },
  activated () {
      console.log('activated')
  },
  deactivated () {
      console.log('deactivated')
  }
}

当不再使用keep-alive标签包裹时,这两个函数不再生效.

需求: 记录之前访问的路径.

使用组件守卫进行实现
HelloWorld.vue

<template>
  <div>
    <p>你好,helloworld</p>

    <router-link to="/hello/HelloAAA">AAA</router-link>  
    <router-link to="/hello/HelloBBB">BBB</router-link>

    <keep-alive>
      <router-view></router-view>
    </keep-alive>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      path: '/hello/HelloAAA'
    }
  },
  props: {
    msg: String
  },
  activated () {
    // $router 为VueRouter实例对象
    this.$router.push (this.path).catch(err => err)
  },
  beforeRouteLeave (to, from, next) {
    console.log(this.path)
    // $route 为当前router跳转对象
    this.path = this.$route.path
    console.log('HelloWorld路由离开之前')
    next()
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

</style>

keep-alive是vue内置的一个组件, 可以使被包含的组件保留状态, 或者避免重新渲染
它们有两个非常重要的属性:

  • include 字符串或正则表达式,只有匹配的组件会被缓存
  • exclude 字符串或正则表达式,任何匹配的组件都不会被缓存.

router-view也是一个组件, 如果被包在keep-alive里面, 所有路径匹配到的视图组件都会被缓存

      <keep-alive exclude="profile"> <!-- 这里使用的是 组件中的 name  -->
        <router-view></router-view>
      </keep-alive>

axios网络请求


import axios from 'axios'

axios({
    url : '',
    params: {
        xxx : 'xxx'
    }
}).then(function (res) {
    console.log(res)
}).catch (function (err) {
    console.log(err)
})
// 或者
axios(...).then (res => {
    console.log(res)
}).catch (err => {
    console.log(err)
})

axios 的请求方式

axios (config)
axios.request (config)
axios.get (url[, cnofig])
axios.delete (url[, cnofig])
axios.head (url[, cnofig])
axios.post (url[, data[, cnofig]])
axios.put (url[, data[, cnofig]])
axios.patch (url[, data[, cnofig]])

发送post请求

request({
              url: '/api/login',
              method: 'POST',
              headers: {
                'content-type': 'application/json'
              },
              data: JSON.stringify(this.user)
            }).then (msg => {
              let status = msg.data.code
              this.$message(msg.data.msg)
              if (status === 200) {
          
                this.$router.push({path: '/chaoxing'})
              }
            }).catch(err => console.log(err))

axios 发送并发请求

    // 并发请求
    axios.all ([
        axios ({
            url: 'http://66.lacknb.cn/api/answer',
            params: {
                problem: '分时系统是什么'
            }
        }),
        axios ({
            url: 'http://66.lacknb.cn/test/api/jitang'
        })
    ]).then(results => {
        console.log(results[0])
        console.log(results[1])
    })

还可以使用axios.spread

    // 还可以这样写, 直接将结果分开
    axios.all ([
        axios ({
            url: 'http://66.lacknb.cn/api/answer',
            params: {
                problem: '分时系统是什么'
            }
        }),
        axios ({
            url: 'http://66.lacknb.cn/test/api/jitang'
        })
    ]).then(axios.spread ( (res1, res2) => {
        console.log(res1)
        console.log(res2)
    }))

axios配置信息相关

全局默认配置

axios.defaults.baseURL = 'http://66.lacknb.cn'
axios.defaults.timeout = 5000 // 设置超时时间 5 秒
// 自定义请求头
axios.defaults.headers = {
    'x-Requestd-With': 'XMLHttpRequest'
}

参数

url、method、params(get请求参数)
查询对象序列化函数 paramsSerializer: function (params) {}
data: {},post请求提供的参数 requestBody
跨域是否带token,withCredentials: false
响应数据格式:responseType: 'json'

axios的实例和模块封装

创建实例、并使用

    /* axios的实例 */
    const instance1 = axios.create({
        baseURL: 'http://66.lacknb.cn',
        timeout: 5000
    })

    instance1 ({
        url: '/test/api/jitang'
    }).then (res => {
        console.log(res)
    })

axios的封装

在src目录创建network文件夹,然后在这个文件夹中创建request.js


import axios from 'axios'

export function request (config) {

    // 1. 创建axios实例
    const instance = axios.create ({
        baseURL: 'http://66.lacknb.cn',
        timeout: 5000
    })

    // 2. 发送真正的网络请求
    return instance (config)

}

使用的时候,直接可以这样使用。

import {request } from './network/request'

request ({
  url: '/test/api/jitang'
}).then (res => {
  console.log(res)
})

axios 拦截器



标题:Vue框架入门系列(二)
作者:gitsilence
地址:http://blog.lacknb.cn/articles/2020/05/24/1590311956210.html