【Vue.js】Vue.js中常用的UI组件库和Vue Router

时间:2022-07-26
本文章向大家介绍【Vue.js】Vue.js中常用的UI组件库和Vue Router,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

1、Vue生态中常用的UI组件库

1. vant

介绍

  • 轻量级、可靠的移动端 Vue 组件库
  • 有赞前端团队出品
  • GitHub地址:https://github.com/youzan/vant

特性

  • 拥有60+ 个组件
  • 90% 单元测试覆盖率
  • 完善的中英文文档和示例
  • 支持按需引入
  • 支持主题定制
  • 支持国际化
  • 支持 TypeScript
  • 支持 SSR

使用

  • 通过 npm 安装:
>> npm install vant --save
  • 通过 yarn 安装:
>> yarn add vant
  • 安装babel-plugin-import插件,babel-plugin-import 是一款 babel 插件,它会在编译过程中将 import 的写法自动转换为按需引入的方式:
>> npm install babel-plugin-import -D
  • 配置babel.config.js:
module.exports = {
  plugins: [
    ['import', {
      libraryName: 'vant',
      libraryDirectory: 'es',
      style: true
    }, 'vant']
  ]
};
  • 在代码中直接引入 Vant 组件,插件会自动将代码转化为按需引入形式:
import { Button } from 'vant';

代码示例

## App.vue

<template>
    <div id="app">
        <van-button class="btn" type="default">默认按钮</van-button>
        <van-button class="btn" type="primary">主要按钮</van-button>
        <van-button class="btn" type="info">信息按钮</van-button>
        <van-button disabled class="btn" type="warning">警告按钮</van-button>
        <van-button class="btn" type="danger">危险按钮</van-button>

        <p></p>

        <van-cell-group>
            <van-cell title="单元格" value="内容"></van-cell>
            <van-cell title="单元格" value="内容" label="描述信息"></van-cell>
        </van-cell-group>

        <p></p>

        <van-datetime-picker
                v-model="currentDate"
                type="datetime"
                :min-date="minDate"
                :max-date="maxDate"
        ></van-datetime-picker>
    </div>
</template>

<script>
    export default {
        name: 'app',
        components: {},
        data() {
            return {
                minHour: 10,
                maxHour: 20,
                minDate: new Date(),
                maxDate: new Date(2019, 10, 1),
                currentDate: new Date()
            };
        }
    }
</script>

<style>
    .btn {
         margin: 10px;
    }
</style>
## main.js

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

Vue.config.productionTip = false;

import { Button } from 'vant';
Vue.use(Button);
import { Cell, CellGroup } from 'vant';
Vue.use(Cell).use(CellGroup);
import { DatetimePicker } from 'vant';
Vue.use(DatetimePicker);

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

2. Ant Design Vue

介绍

  • 社区主导
  • 蚂蚁金服技术支持
  • https://github.com/vueComponent/ant-design-vue

特性

  • 55+ 个组件
  • 87% 单元测试覆盖率

3. Element UI

Mint UI

  • GitHub地址:http://mint-ui.github.io/#!/zh-cn
  • 饿了么开源的基于 vue 的移动端 UI 组件库

Elment UI

  • 官网地址:http://element-cn.eleme.io/#/zh-CN
  • 饿了么开源的基于 vue 的 PC 端 UI 组件库
  • vue-cli@3快速安装 Element 插件:
>> vue create my-app
>> cd my-app
>> vue add element

一般移动端建议使用vant,后台管理系统建议使用Ant Design Vue或Element UI。

## index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>lk-element-demo</title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but lk-element-demo doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>
## App.vue

<template>
    <div id="app">
        <div>
            <div class="block">
                <span class="demonstration">默认</span>
                <el-date-picker
                        v-model="value1"
                        type="date"
                        placeholder="选择日期">
                </el-date-picker>
            </div>
            <div class="block">
                <span class="demonstration">带快捷选项</span>
                <el-date-picker
                        v-model="value2"
                        align="right"
                        type="date"
                        placeholder="选择日期"
                        :picker-options="pickerOptions">
                </el-date-picker>
            </div>

            <el-container style="height: 500px; border: 1px solid #eee">
                <el-aside width="200px" style="background-color: rgb(238, 241, 246)">
                    <el-menu :default-openeds="['1', '3']">
                        <el-submenu index="1">
                            <template slot="title"><i class="el-icon-message"></i>导航一</template>
                            <el-menu-item-group>
                                <template slot="title">分组一</template>
                                <el-menu-item index="1-1">选项1</el-menu-item>
                                <el-menu-item index="1-2">选项2</el-menu-item>
                            </el-menu-item-group>
                            <el-menu-item-group title="分组2">
                                <el-menu-item index="1-3">选项3</el-menu-item>
                            </el-menu-item-group>
                            <el-submenu index="1-4">
                                <template slot="title">选项4</template>
                                <el-menu-item index="1-4-1">选项4-1</el-menu-item>
                            </el-submenu>
                        </el-submenu>
                        <el-submenu index="2">
                            <template slot="title"><i class="el-icon-menu"></i>导航二</template>
                            <el-menu-item-group>
                                <template slot="title">分组一</template>
                                <el-menu-item index="2-1">选项1</el-menu-item>
                                <el-menu-item index="2-2">选项2</el-menu-item>
                            </el-menu-item-group>
                            <el-menu-item-group title="分组2">
                                <el-menu-item index="2-3">选项3</el-menu-item>
                            </el-menu-item-group>
                            <el-submenu index="2-4">
                                <template slot="title">选项4</template>
                                <el-menu-item index="2-4-1">选项4-1</el-menu-item>
                            </el-submenu>
                        </el-submenu>
                        <el-submenu index="3">
                            <template slot="title"><i class="el-icon-setting"></i>导航三</template>
                            <el-menu-item-group>
                                <template slot="title">分组一</template>
                                <el-menu-item index="3-1">选项1</el-menu-item>
                                <el-menu-item index="3-2">选项2</el-menu-item>
                            </el-menu-item-group>
                            <el-menu-item-group title="分组2">
                                <el-menu-item index="3-3">选项3</el-menu-item>
                            </el-menu-item-group>
                            <el-submenu index="3-4">
                                <template slot="title">选项4</template>
                                <el-menu-item index="3-4-1">选项4-1</el-menu-item>
                            </el-submenu>
                        </el-submenu>
                    </el-menu>
                </el-aside>

                <el-container>
                    <el-header style="text-align: right; font-size: 12px">
                        <el-dropdown>
                            <i class="el-icon-setting" style="margin-right: 15px"></i>
                            <el-dropdown-menu slot="dropdown">
                                <el-dropdown-item>查看</el-dropdown-item>
                                <el-dropdown-item>新增</el-dropdown-item>
                                <el-dropdown-item>删除</el-dropdown-item>
                            </el-dropdown-menu>
                        </el-dropdown>
                        <span>王小虎</span>
                    </el-header>

                    <el-main>
                        <el-table :data="tableData">
                            <el-table-column prop="date" label="日期" width="140">
                            </el-table-column>
                            <el-table-column prop="name" label="姓名" width="120">
                            </el-table-column>
                            <el-table-column prop="address" label="地址">
                            </el-table-column>
                        </el-table>
                    </el-main>
                </el-container>
            </el-container>
        </div>
    </div>
</template>

<script>

    export default {
        name: 'app',
        data() {
            const item = {
                date: '2016-05-02',
                name: '王小虎',
                address: '上海市普陀区金沙江路 1518 弄'
            };
            return {
                tableData: Array(20).fill(item),
                value1: '',
                value2: ''
            }
        }
    }
</script>

<style>
    .el-header {
        background-color: #B3C0D1;
        color: #333;
        line-height: 60px;
    }

    .el-aside {
        color: #333;
    }
</style>
## element.js

import Vue from 'vue'
import Element from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(Element)
## main.js

import Vue from 'vue'
import App from './App.vue'
import './plugins/element.js'

Vue.config.productionTip = false

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

2、Vue Router

1. 概念

  • Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得更加轻松

Vue Router主要功能

  • 嵌套的路由/视图表
  • 模块化的、基于组件的路由配置
  • HTML5 历史模式或 hash 模式
  • 路由参数
  • 基于 Vue.js 过渡系统的视图过渡效果
  • 细粒度的导航控制
  • 带有自动激活的 CSS class 的链接
  • 将组件(components)映射到路由(routes),然后告诉 vue-router 在哪里渲染它们
  • 组件与组件之间可以通过路由进行灵活切换
  • 在切换过程中可以进行各种参数传递、权限控制等

2. 基本配置

初始化工程项目

>> vue create lk-vue-router
>> npm install vue-router --save 			# 安装Vue-Router
>> npm run serve

路由默认配置

# main.js

import router from './router'

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

import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
import About from './views/About.vue'

Vue.use(Router);

export default new Router({
    routes: [
        {path: '/', name: 'home', component: Home},
        {path: '/about', name: 'about', component: About}
    ]
})

路由导航

<div id="nav">
       <router-link to="/">首页</router-link>|
       <router-link to="/about">关于</router-link>
</div>

路由出口

<router-view/>

3. history模式

概念

  • vue-router 默认 hash 模式 ,url使用#后面定位路由,对seo不利,设置history,就可以使用普通的url模式
  • history 模式即普通url模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面
  • 修改的只是URL中的hash,则不会导致页面被刷新

使用

const router = new VueRouter({
  	mode: 'history',
  	routes: [...]
})

hash和history区别

  • hash模式url带#号,history模式不带#号
  • 如果考虑url的规范,那么就需要使用history模式,因为history模式没有#号,是个正常的url,适合开发习惯
  • 把用Vue或者React做的页面分享至三方app,有的app里面url是不允许带有#号的,所以要将#号去除那么就要使用history模式
  • 使用history模式还有一个问题就是,在访问二级页面的时候,做刷新操作,会出现404错误,那么就需要和后端人配合让他配置一下apache或是nginx的url重定向,重定向到你的首页路由

hash

history

url显示

有#,不好看

无#,好看

回车刷新

可以加载到hash值对应页面

一般就是404了

支持版本

支持低版本浏览器和IE浏览器

HTML5新推出的API

代码示例

## router.js

import Vue from 'vue'
import Router from 'vue-router'

// 引入页面
import Home from './views/Home'
import About from './views/About'

Vue.use(Router);

export default new Router({
    // mode: 'history',
    routes: [
        { path: '/', redirect: '/home' },
        // { path: '/', redirect: {name: 'about'} },
        // { path: '/', redirect: to => { return '/home'}},
        {path: '/home', name: 'home', component: Home},
        {path: '/about', name: 'about', component: About},
    ]
})
## main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false;

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

<template>
    <div id="app">
         <!--设置路由导航-->
         <div id="nav">
             <router-link to="/home">首页</router-link>
             <router-link to="/about">关于</router-link>
         </div>
         <!--设置路由出口-->
         <router-view></router-view>
    </div>
</template>

<script>
    export default {
        name: 'app',
        components: {}
    }
</script>

<style>
    #app {
        font-family: 'Avenir', Helvetica, Arial, sans-serif;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
        text-align: center;
        color: #2c3e50;
        margin-top: 60px;
    }

    #nav{
        padding: 30px;
    }
    #nav a{
        font-size: 18px;
        color: #484848;
        margin: 0 10px;
    }

    #nav a.router-link-exact-active{
        color: #e9232c;
    }
</style>
## Home.vue

<template>
    <div id="home">
        <h2>首页</h2>
    </div>
</template>

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

<style scoped>
    #home{
        width: 300px;
        height: 500px;
        background-color: skyblue;
        margin: 0 auto;
    }
    h2{
        color: red;
    }
</style>
## About.vue

<template>
    <div id="about">
        <h2>关于我们</h2>
    </div>
</template>

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

<style scoped>
   #about{
       width: 300px;
       height: 500px;
       background-color: red;
       margin: 0 auto;
   }

   h2{
       color: green;
   }
</style>

4. 动态路由

概念

  • 动态路由指路由可以携带一些参数,使用this.$router获取

使用

{path: '/mine/:name', name: 'mine', component: Mine}
export default {
    name: "Mine",
    created() {
        // 输出当前路由
        console.log(this.$route);
    }
}

参数属性传递

  • 设置props属性,获取路由的变量就和普通的属性传递没什么区别
  • 参数属性传递方式:
  1. 对象模式:如果 props 是一个对象,它会被按原样设置为组件属性。当 props 是静态的时候有用
  2. 布尔模式:如果 props 被设置为 true,route.params 将会被设置为组件属性
  3. 函数模式:可以创建一个函数返回 props。这样你便可以将参数转换成另一种类型,将静态值与基于路由的值结合等等

代码示例

## router.js

import Vue from 'vue'
import Router from 'vue-router'

// 引入页面
import Home from './views/Home'
import About from './views/About'
import Mine from './views/Mine'

Vue.use(Router);

/*
let func = ({params, query})=>{
    return {
        name: params.name,
        sex: params.sex,
        height: query.height,
        dog: query.dog,
    }
};
*/

let func = (route)=>{
    return {
        name: route.params.name,
        sex: route.params.sex,
        height: route.query.height,
        dog: route.query.dog,
    }
};

export default new Router({
    routes: [
        { path: '/', redirect: '/home' },
        { path: '/home', name: 'home', component: Home },
        { path: '/about', name: 'about', component: About },
        // { path: '/mine/:name/:sex', name: 'mine', component: Mine }
        // { path: '/mine', name: 'mine', component: Mine, props: {name: '小撩'} }
        // { path: '/mine/:name/:sex', name: 'mine', component: Mine, props: true }
        { path: '/mine/:name/:sex', name: 'mine', component: Mine, props: func }
    ]
})
## main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false;

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

<template>
    <div id="app">
         <!--设置路由导航-->
         <div id="nav">
             <router-link to="/home">首页</router-link>
             <router-link to="/about">关于</router-link>
             <router-link to="/mine">我的</router-link>
         </div>
         <!--设置路由出口-->
         <router-view></router-view>
    </div>
</template>

<script>
    export default {
        name: 'app',
        components: {}
    }
</script>

<style>
    #app {
        font-family: 'Avenir', Helvetica, Arial, sans-serif;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
        text-align: center;
        color: #2c3e50;
        margin-top: 60px;
    }

    #nav{
        padding: 30px;
    }
    #nav a{
        font-size: 18px;
        color: #484848;
        margin: 0 10px;
    }

    #nav a.router-link-exact-active{
        color: #e9232c;
    }
</style>
## Home.vue

<template>
    <div id="home">
        <h2>首页</h2>
    </div>
</template>

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

<style scoped>
    #home{
        width: 300px;
        height: 500px;
        background-color: skyblue;
        margin: 0 auto;
    }
    h2{
        color: red;
    }
</style>
## About.vue

<template>
    <div id="about">
        <h2>关于我们</h2>
    </div>
</template>

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

<style scoped>
   #about{
       width: 300px;
       height: 500px;
       background-color: red;
       margin: 0 auto;
   }

   h2{
       color: green;
   }
</style>
## Mine.vue

<template>
    <div id="mine">
        <h2>个人中心</h2>
        <p>------------------------------------------</p>

        <h2>根据路由对象获取的路径参数</h2>
        <p>姓名:{{$route.params.name}}</p>
        <p>性别:{{$route.params.sex}}</p>
        <p>身高:{{$route.query.height}}</p>
        <p>小狗:{{$route.query.dog}}</p>

        <h2>根据属性对象获取的路径参数</h2>
        <p>姓名:{{name}}</p>
        <p>性别:{{sex}}</p>
        <p>身高:{{height}}</p>
        <p>小狗:{{dog}}</p>
    </div>
</template>

<script>
    export default {
        name: "Mine",
        props: ['name', 'sex', 'height', 'dog'],
        created() {
            console.log(this.$route);
           /*
            console.log(this.$route);
            console.log(this.$route.path);
            console.log(this.$route.params);
            console.log(this.$route.query);
            */
            // console.log(this.$router);
        }
    }
</script>

<style scoped>
    #mine{
        width: 300px;
        height: 500px;
        background-color: orange;
        margin: 0 auto;
    }
    h2{
        color: green;
    }
</style>

5. 嵌套路由

概念

  • 一级界面中可以通过嵌套路由配置二级界面切换

使用

{path: '/mine/:name', name: 'mine', component: Mine}
export default {
    name: "Mine",
    created() {
        // 输出当前路由
        console.log(this.$route);
    }
}

代码示例

## router.js

import Vue from 'vue'
import Router from 'vue-router'

// 一级界面
import Home from './views/Home'
import About from './views/About'
import Mine from './views/Mine'

// 二级界面
import News from './views/News'
import Shop from './views/Shop'

Vue.use(Router);

export default new Router({
    routes: [
        { path: '/', redirect: '/home' },
        {
            path: '/home',
            name: 'home',
            component: Home,
            children: [
                { path: '/home', redirect: '/home/news' },
                {path: 'news', name: 'news', component: News},
                {path: 'shop', name: 'shop', component: Shop},
            ]
        },
        {path: '/about', name: 'about', component: About},
        {path: '/mine', name: 'mine', component: Mine}
    ]
})
## main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false;

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

<template>
    <div id="app">
         <!--设置路由导航-->
         <div id="nav">
             <router-link to="/home">首页</router-link>
             <router-link to="/about">关于</router-link>
             <router-link to="/mine">我的</router-link>
         </div>
         <!--设置路由出口-->
         <router-view></router-view>
    </div>
</template>

<script>
    export default {
        name: 'app',
        components: {}
    }
</script>

<style>
    #app {
        font-family: 'Avenir', Helvetica, Arial, sans-serif;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
        text-align: center;
        color: #2c3e50;
        margin-top: 60px;
    }

    #nav{
        padding: 30px;
    }
    #nav a{
        font-size: 18px;
        color: #484848;
        margin: 0 10px;
    }

    #nav a.router-link-exact-active{
        color: #e9232c;
    }
</style>
## Home.vue

<template>
    <div id="home">
        <h2>首页</h2>
        <!--路由导航-->
        <ul>
           <li><router-link to="/home/news">新闻</router-link></li>
           <li><router-link to="/home/shop">商品</router-link></li>
        </ul>
        <!--路由出口-->
        <router-view></router-view>
    </div>
</template>

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

<style scoped>
    #home{
        width: 300px;
        height: 500px;
        background-color: skyblue;
        margin: 0 auto;
    }
    h2{
        color: red;
    }
</style>
## News.vue

<template>
    <div id="news">
        <h3>首页-新闻版块</h3>
    </div>
</template>

<script>
    export default {
        name: "News"
    }
</script>

<style scoped>
   #news{
       width: 100px;
       height: 100px;
       background-color: purple;
   }
</style>
## Shop.vue

<template>
    <div id="shop">
        <h3>首页-商品版块</h3>
    </div>
</template>

<script>
    export default {
        name: "Shop"
    }
</script>

<style scoped>
    #shop{
        width: 100px;
        height: 100px;
        background-color: greenyellow;
    }
</style>
## About.vue

<template>
    <div id="about">
        <h2>关于我们</h2>
    </div>
</template>

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

<style scoped>
   #about{
       width: 300px;
       height: 500px;
       background-color: red;
       margin: 0 auto;
   }

   h2{
       color: green;
   }
</style>
## Mine.vue

<template>
    <div id="mine">
        <h2>个人中心</h2>
    </div>
</template>

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

<style scoped>
    #mine{
        width: 300px;
        height: 500px;
        background-color: orange;
        margin: 0 auto;
    }
    h2{
        color: green;
    }
</style>

6. 路由(导航)守卫

概念

  • 通过路由守卫可以对每次刷新或进入的路由界面进行权限验证,相当于Vue中的全局中间件

全局守卫

  • router.beforeEach 注册一个全局前置守卫
  • 参数
  1. to:Route: 即将要进入的目标 路由对象
  2. from:Route: 当前导航正要离开的路由
  3. next:Function: 一定要调用该方法来 resolve 这个钩子
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
     // ...
})

router.beforeEach((to,from,next)=>{
    if (to.path !== '/login') { 			// 要求登录
      if (window.isLogin) {
        next();
      } else {
        next('/login?redirect='+to.path);
      }
    } else {
      next();
    }
    next();
});

全局后置钩子

  • 可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身
router.afterEach((to, from) => {
  // ...
})

路由独享守卫

  • 可以在路由配置上直接定义 beforeEnter 守卫
const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})
  • 这些守卫与全局前置守卫的方法参数是一样的

7. 组件内的守卫

概念

  • 可以在组件内部实现相应钩子,在组件内部进行相应的守卫

方法

  • beforeRouteEnter
  • beforeRouteUpdate
  • beforeRouteLeave

使用

const Foo = {
  template: `...`,
  beforeRouteEnter (to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用,不能获取组件实例 `this`,因为当守卫执行前,组件实例还没被创建
  },
  beforeRouteUpdate (to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用,举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。可以访问组件实例 `this`
  },
  beforeRouteLeave (to, from, next) {
    // 导航离开该组件的对应路由时调用,可以访问组件实例 `this`
  }
}
beforeRouteEnter(to, from, next) {
   console.log("Mine路由进入前调用");
   next();
},
beforeRouteUpdate(to, from, next) {
   console.log("Mine路由,但是参数变了");
   next();
},
beforeRouteLeave(to, from, next) {
   console.log("Mine路由离开前");
   next();
}

路由守卫流程

  • 导航被触发
  • 在失活的组件里调用离开守卫
  • 调用全局的 beforeEach 守卫
  • 在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)
  • 在路由配置里调用 beforeEnter
  • 解析异步路由组件
  • 在被激活的组件里调用 beforeRouteEnter
  • 调用全局的 beforeResolve 守卫(2.5+)
  • 导航被确认
  • 调用全局的 afterEach 钩子
  • 触发 DOM 更新
  • 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数

8. 异步组件

  • 按需加载,用到时加载
{
  	path:'/about',
 	component: () => import('./views/About.vue')
}

9. 相关API

  • this.$router.push(path):相当于点击路由链接(可以返回到当前路由界面)
  • this.$router.replace(path):用新路由替换当前路由(不可以返回到当前路由界面)
  • this.$router.back():请求(返回)上一个记录路由
  • this.$router.go(-1):请求(返回)上一个记录路由
  • this.$router.go(1):请求下一个记录路由

10. $router 和 $route的区别

router

  • router是VueRouter的一个对象,通过Vue.use(VueRouter)和VueRouter构造函数得到一个router的实例对象
  • 这个对象中是一个全局的对象,他包含了所有的路由包含了许多关键的对象和属性

route

  • route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象
  • 可以获取对应的name,path,params,query等

代码示例

## router.js

import Vue from 'vue'
import Router from 'vue-router'

// 一级界面
import Login from './views/Login'
import DashBoard from './views/DashBoard'

// 二级界面
import Home from './views/Home'
// import About from './views/About'
import Mine from './views/Mine'

const About = ()=> import('./views/About');

Vue.use(Router);

const router = new Router({
    routes: [
        { path: '/', redirect: '/dashboard' },
        {
            path: '/dashboard',
            name: 'dashboard',
            component: DashBoard,
            children: [
                { path: '/dashboard', redirect: '/dashboard/home' },
                { path: 'home', name: 'home', component: Home },
                { path: 'about', name: 'about', component: About },
                { path: 'mine', name: 'mine', component: Mine }
            ],
        },
        { path: '/login', name: 'login', component: Login }
    ]
});

// 全局路由前置守卫
router.beforeEach((to, from, next)=>{
    // console.log(to, from);
    if(to.path !== '/login'){ 		// 验证是否登录
        if(window.isLogin){ 		// 已经登录
            next();
        }else { 					// 没有登录
            // next('/login?redirect='+ to.path);
            // next('/login?redirect=/dashboard/mine');
            next('/login');
        }
    }else { 						// 不需要验证
        next();
    }
    // 放行
    next();
});

// 全局路由后置守卫
router.afterEach((to, from) => {
   // console.log('来了!');
});

export default router;
# main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false;

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

<template>
    <div id="app">
        <router-view></router-view>
    </div>
</template>

<script>
    export default {
        name: 'app',
        components: {}
    }
</script>

<style>
    #app {
        font-family: 'Avenir', Helvetica, Arial, sans-serif;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
        text-align: center;
        color: #2c3e50;
        margin-top: 60px;
    }
</style>
## Login.vue

<template>
    <div>
        <h2>登录界面</h2>
        <button @click="login">登录</button>
    </div>
</template>

<script>
    export default {
        name: "Login",
        methods: {
            login(){
                // 1. 登录成功
                window.isLogin = true;
                // 2. 获取回调地址
                const redirect = this.$route.query.redirect;
                if(redirect){ 						// 有回调地址
                    this.$router.push(redirect);
                }else { 							// 没有回调地址
                    // 去首页
                    this.$router.replace('/');
                }
            }
        }
    }
</script>

<style scoped>

</style>
## DashBoard.vue

<template>
    <div>
        <h3>主面板</h3>
        <!--设置路由导航-->
        <div id="nav">
            <router-link to="/dashboard/home">首页</router-link>
            <router-link to="/dashboard/about">关于</router-link>
            <router-link to="/dashboard/mine">我的</router-link>
        </div>
        <!--设置路由出口-->
        <router-view></router-view>
    </div>
</template>

<script>
    export default {
        name: "DashBoard"
    }
</script>

<style scoped>
    #nav{
        padding: 30px;
    }
    #nav a{
        font-size: 18px;
        color: #484848;
        margin: 0 10px;
    }

    #nav a.router-link-exact-active{
        color: #e9232c;
    }
</style>
## Home.vue

<template>
    <div id="home">
        <h2>首页</h2>
    </div>
</template>

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

<style scoped>
    #home{
        width: 300px;
        height: 500px;
        background-color: skyblue;
        margin: 0 auto;
    }
    h2{
        color: red;
    }
</style>
## About.vue

<template>
    <div id="about">
        <h2>关于我们</h2>
    </div>
</template>

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

<style scoped>
   #about{
       width: 300px;
       height: 500px;
       background-color: red;
       margin: 0 auto;
   }

   h2{
       color: green;
   }
</style>
## Mine.vue

<template>
    <div id="mine">
        <h2>个人中心</h2>
    </div>
</template>

<script>
    export default {
        name: "Mine",
        beforeRouteEnter(to, from, next){
            console.log('进入之前调用');
            next();
        },
        beforeRouteUpdate(to, from, next){
            console.log('路由的参数变了');
            next();
        },
        beforeRouteLeave(to, from, next){
            console.log('路由离开前调用');
            next();
        }
    }
</script>

<style scoped>
    #mine{
        width: 300px;
        height: 500px;
        background-color: orange;
        margin: 0 auto;
    }
    h2{
        color: green;
    }
</style>