Vue从零开始之VueRouter

VueRouter路由

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。

安装vue-router插件

vue-router 是一个插件包,所以我们还是需要用 npm/cnpm 来进行安装的。打开命令行工具,进入你的项目目录,输入下面命令。

npm install vue-router --save --registry=https://registry.npm.taobao.org

VueRouter+ElementUI基本使用

ElementUI,下面是根据vuecli2安装的ElementUI.vuecli3可使用插件安装

创建项目,安装依赖

# 使用 webpack 打包工具初始化一个名为 hello-vue-element 的工程
vue init webpack hello-vue-element
# 进入工程目录
cd hello-vue-element
# 安装 vue-router
npm install vue-router --save --registry=https://registry.npm.taobao.org
# 安装 element-ui
npm i element-ui -S --registry=https://registry.npm.taobao.org
# 安装 SASS 加载器,运行时如果报如下错误: Module build failed: TypeError: this.getResolve is not a function 原因是当前sass的版本太高
npm install sass-loader@7.3.1 node-sass --save-dev --registry=https://registry.npm.taobao.org
# 安装依赖初始化
npm install --registry=https://registry.npm.taobao.org
#启动
npm run dev

修改目录结构

在源码目录中创建如下结构:

  • assets:用于存放资源文件
  • components:用于存放 Vue 功能组件
  • views:用于存放 Vue 视图组件
  • router:用于存放 vue-router 配置

创建首页视图

在 views 目录下创建一个名为 Main.vue 的视图组件;该组件在当前章节无任何作用,主要用于登录后展示登录成功的跳转效果;

<template>
    <div>
      首页
    </div>
</template>
<script>
    export default {
        name: "Main"
    }
</script>
<style scoped>
</style>

一个组件页面里只能有一个根元素

创建登录页视图

在 views 目录下创建一个名为 Login.vue 的视图组件,其中 el-* 的元素为 ElementUI 组件;

<template>
  <div>
    <el-form ref="loginForm" :model="form" :rules="rules" label-width="80px" class="login-box">
      <h3 class="login-title">欢迎登录</h3>
      <el-form-item label="账号" prop="username">
        <el-input type="text" placeholder="请输入账号" v-model="form.username"/>
      </el-form-item>
      <el-form-item label="密码" prop="password">
        <el-input type="password" placeholder="请输入密码" v-model="form.password"/>
      </el-form-item>
      <el-form-item>
                                                <!--提交的loginForm为表单的 ref-->
        <el-button type="primary" v-on:click="onSubmit('loginForm')">登录</el-button>
      </el-form-item>
    </el-form>
    <el-dialog
      title="温馨提示"
      :visible.sync="dialogVisible"
      width="30%"
      :before-close="handleClose">
      <span>请输入账号和密码</span>
      <span slot="footer" class="dialog-footer">
        <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
  export default {
    name: "Login",
    data() {
      return {
        form: {
          username: '',
          password: ''
        },
        // 表单验证,需要在 el-form-item 元素中增加 prop 属性
        rules: {
          username: [
            {required: true, message: '账号不可为空', trigger: 'blur'}
          ],
          password: [
            {required: true, message: '密码不可为空', trigger: 'blur'}
          ]
        },
        // 对话框显示和隐藏
        dialogVisible: false
      }
    },
    methods: {
      onSubmit(formName) {
        // 为表单绑定验证功能
        this.$refs[formName].validate((valid) => {
          if (valid) {
            // 使用 vue-router 路由到指定页面,该方式称之为编程式导航
            this.$router.push("/main");
          } else {
            this.dialogVisible = true;
            return false;
          }
        });
      }
    }
  }
</script>
<style lang="scss" scoped>
  .login-box {
    border: 1px solid #DCDFE6;
    width: 350px;
    margin: 180px auto;
    padding: 35px 35px 15px 35px;
    //圆角
    border-radius: 5px;
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    //阴影
    box-shadow: 0 0 25px #909399;
  }
  .login-title {
    text-align: center;
    margin: 0 auto 40px auto;
    color: #303133;
  }
</style>

创建路由配置

在 router 目录下创建一个名为 index.js 的 vue-router 路由配置文件

import Vue from 'vue'
import Router from 'vue-router'
import Login from "@/views/Login"
import Main from '@/views/Main'

// 通过Vue.use(插件),安装插件,默认执行插件的install方法
Vue.use(Router);

export default new Router({
 // 注意拼写,不要写成routers
    // 匹配的优先级就按照路由的定义顺序
  routes: [
    {
      // 登录页
      path: '/login',
      // 命名路由,非必选项,跳转时与跳转方法的name属性匹配
      name: 'Login',
      component: Login
    },
    {
      // 首页
      path: '/main',
      name: 'Main',
      component: Main
    }
  ]
});

导入路由和ElementUI

修改 main.js 入口代码

import Vue from 'vue'
import App from './App'
//导入自定义路由配置, 如果/index.js前面是目录可省略不写
import router from './router'
// 导入 ElementUI
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

Vue.config.productionTip = false
// 安装 ElementUI 
Vue.use(ElementUI);
new Vue({
  el: '#app',
  components: { App },
  template: '<App/>',
  // 启用路由
  router,
  // 启用 ElementUI
  render: h => h(App)
});

模板中渲染组件

修改 App.vue 组件代码,渲染组件

<template>
  <div id="app">
    <router-link to="/main">跳转首页</router-link>
    <router-view/>
  </div>
</template>
<script>
  export default {
    name: 'App',
  }
</script>

VueRouter定义的两个全局标签:

  • router-link: 默认会被渲染成一个 a 标签,to 属性为指定链接
  • router-view: 会将url中路由匹配到的组件,在标签所在位置渲染

路由匹配规则

path: '/'  //根或缺省
path: ''   //根或缺省
path: '/params/:foo // :动态路由
path: '/optional-params/:foo?' // ?表示可选参数
path: '/params-with-regex/:id(\\d+)' // 参数后紧跟的括号里可以使用正则
path: '/asterisk/*' // *通配
path: '/optional-group/(foo/)?bar'  // ()? 表示路径中的一部分可选

路由跳转

标签

router-link标签的属性:

  • to: 指定跳转路径
    • to使用v-bind绑定后可以传对象,具体用法同router.push().
  • tag: 指定router-link会被渲染成什么标签
  • active-class: 当router-link对应的路由匹配成功时,会自动给当前元素添加一个名为router-link-active的class. 使用active-class修改添加的class的名字.(可以在路由配置中使用linkActiveClass属性统一修改)
  • replace: 表示跳转时使用replace函数,无法前进后退.(不添加时默认使用push函数)

当router-link对应的路由匹配成功时,会自动给当前元素添加一个名为router-link-active的class,可根据这个class修改标签路由匹配后的样式

 <router-link to="/main" tag='button' active-class='active' replace >跳转首页</router-link>
 
// 统一修改active-class
export default new Router({
  routes: [
    {
      // 登录页
      path: '/login',
      // 命名路由,非必选项
      name: 'Login',
      component: Login
    }
  ],
  linkActiveClass: 'active'
}); 

代码方式进行跳转

不要使用history绕过VueRouter修改路径

在 Vue 实例内部,你可以通过 this.$router 访问路由实例。进行路由跳转

  • router.push(location, onComplete?, onAbort?)
// 字符串
router.push('home')
// 字符串格式时传入data中的属性值
router.push('/home/'+ this.id)

// 对象
router.push({ path: 'home' })

// 命名的路由 , 变成 /user/123
router.push({ name: 'user', params: { userId: '123' }})

// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})

const userId = '123'
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// 这里的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user

注意:如果使用了 path,params 会被忽略,同样的规则也适用于 router-link 组件的 to 属性。

  • router.replace(location, onComplete?, onAbort?): 跟 router.push 很像,唯一的不同就是,它不会向 history 添加新记录.
  • router.go(n): 类似js的 history.go(n)。

VueRouter 动态路由

使用动态路径参数(以冒号开头)把某种模式匹配到的所有路由,全都映射到同个组件。

const router = new VueRouter({
  routes: [
    // 动态路径参数 以冒号开头
    { path: '/user/:id', component: User }
  ]
})

/user/foo 和 /user/bar 都将映射到User组件
但 /user 不会映射到User组件

跳转时传递参数

// 绑定data中的userId属性,单引号括起来的部分不会被Vue当做变量解析
<router-link :to="'/user/'+userId">个人信息</router-link>

在路由到的组件中接收传递的参数

<div>{{ $route.params.id }}</div>

或

new Vue({
    computed: {
        currentTime(){
            this.$route.params.id
        }
    }
})

r o u t e 路 由 记 录 和 route路由记录和 routerouter路由实例

  • $route: 路由记录,即路由配置中routes数组中的一个对象,可用来查看路径参数(params),请求参数(query),路由路径(path),hash等
  • $router: 路由实例,new Router创建的路由,用来进行路由跳转

VueRouter 参数传递

使用params的方式

修改路由配置,主要是在 path属性中增加了 :id 这样的占位符

{path: '/user/profile/:id', name:'UserProfile', component: UserProfile}

传递参数
  • router-link to方式

<router-link to="/user/profile/1">个人信息</router-link>

  • router-link :to方式

<router-link :to="{name: 'UserProfile', params: {id: 1}}">个人信息</router-link>

注意: 此时我们将 to 改为了 :to,是为了传对象参数,不然{}不会被解析. 注意 router-link 中的 name 属性名称 一定要和 路由中的 name 属性名称 匹配,因为这样 Vue 才能找到对应的路由路径;

  • 代码方式传递

this.$router.push({ name: 'UserProfile', params: {id: 1}});

接收参数
  • 在目标组件中接收路径参数:
    {{ $route.params.id }}

使用query方式

路由配置使用最普通的方式

{path: '/user/profile', name:'UserProfile', component: UserProfile}

传递参数

<router-link :to="{name: 'UserProfile', query: { plan: 'private'}}">query</router-link>

接收参数
  • 在目标组件中接收路径参数:
    {{ $route.query.plan }}

使用 props 的方式

在组件中使用 $route 会使之与其对应路由形成高度耦合,从而使组件只能在某些特定的 URL 上使用,限制了其灵活性。使用 props 将组件和路由解耦.

修改路由配置,主要增加了 props: true 属性

{path: '/user/profile/:id', name:'UserProfile', component: UserProfile, props: true}

传递参数
  • router-link to方式传递

<router-link to="/user/profile/2">个人信息</router-link>

  • router-link :to方式传递

<router-link :to="{name: 'UserProfile', params: {id: 1}}">个人信息</router-link>

  • 代码方式传递

this.$router.push({ name: 'UserProfile', params: {id: 1}});

接收参数
  • 为目标组件增加 props 属性,自动映射
  export default {
    //接收占位符id传递的值
    props: ['id'],
    name: "UserProfile"
  }
//模板中直接使用
{{ id }}

嵌套路由

嵌套路由又称子路由,在实际应用中,通常由多层嵌套的组件组合而成。

创建Profile.vue和List.vue 的视图组件,内容添加个根元素其他默认即可

修改 router 目录下的 index.js 路由配置文件,代码如下:

// 用于嵌套的路由组件
import UserProfile from '../views/user/Profile'
import UserList from '../views/user/List'

....  
    {
      path: '/main',
      name: 'Main',
      component: Main,
      // 配置嵌套路由
      children: [
        {
          // 默认重定向 /main/posts
          path: '',
          redirect: 'posts'
        },
        {
            // 当 /user/profile匹配成功
            // UserProfile会被渲染在 Main 组件的<router-view> 中
            path: '/user/profile', 
            component: UserProfile
        },
        {
          // 当 /main/posts 匹配成功
          // UserPosts 会被渲染在 Main 的 <router-view> 中
          path: 'posts',
          component: UserPosts
        }
      ]
    }
  • 以 / 开头的嵌套路径会被当作根路径。可以达到嵌套组件而无须设置嵌套的路径。
  • 非 / 开头的嵌套路径会被当做子路径,拼接在父路径之后进行匹配

Main.vue添加的内容

<template>
  <div id="app">
    <router-link to="/user/profile">跳转profile</router-link>
    <router-link to="/main/posts">跳转posts</router-link>
    <router-view/>
  </div>
</template>

Main.vue在App.vue渲染, profile和posts在Main.vue中渲染

VueRouter重定向

Vue 中的重定向是作用在路径不同但组件相同的情况下,或用于缺省时重定向到首页

修改路由配置(router/index.js)

    { // 缺省时重定向到/main
      path: '', // 与 path: '/' 等效
      redirect: '/main'
    },
    {
      path: '/main',
      name: 'Main',
      component: Main
    },
    { //将/goHome重定向到/main
      path: '/goHome',
      redirect: '/main'
    }

组件中使用
<router-link to="/goHome">回到首页</router-link>即可重定向到/main

VueRouter 路由模式与 404

路由模式

路由模式有两种

  • hash:路径带 # 符号(默认),如 http://localhost/#/login
  • html5的history:路径不带 # 符号,如 http://localhost/login

修改路由配置(/router/index.js文件),代码如下:

export default new Router({
  mode: 'history',
  routes: [
  ]
});

使用history模式用户直接访问或者刷新非index.html时,浏览器会绕过VueRouter直接请求后端服务,导致404.后端应进行相应设置

处理 404

创建一个视图组件,在路由配置文件(/router/index.js)导入并配置

    //该路由放到最后
   {
      path: '*',
      component: NotFound
    }

路由元信息

定义路由的时候可以配置 meta 字段:

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      meta: {
        title: '标题1'  
      },
      children: [
        {
          path: 'bar',
          component: Bar,
          // a meta field
          meta: { requiresAuth: true }
        }
      ]
    }
  ]
})

一个路由匹配到的所有路由记录都会保存在$route.matched 数组.我们可以遍历 $route.matched 来检查路由记录中的 meta 字段。

路由钩子(导航守卫)

“导航”表示路由正在发生改变。导航守卫主要用来通过跳转或取消的方式守卫导航。导航守卫就是路由的生命周期钩子函数.

全局钩子

  • beforeEach :全局前置钩子
  • afterEach: 全局后置钩子,不接受 next 函数
const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      meta: {
        title: '标题1'  
      }
    }
  ]
})

// 每个路由跳转前,将要跳转到的路由记录设置的元信息的title值,设置为网页的title
router.beforeEach((to,from,next)=>{
    document.title = to.mathed[0].meta.title
    next()
})

路由独享的守卫

  • beforeEnter: 进入路由之前
const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

组件内钩子

  • beforeRouteEnter:在进入路由前执行
  • beforeRouteLeave:在离开路由前执行
  export default {
    props: ['id'],
    name: "UserProfile",
    beforeRouteEnter: (to, from, next) => {
      console.log("准备进入个人信息页");
      next();
    },
    beforeRouteLeave: (to, from, next) => {
      console.log("准备离开个人信息页");
      // 当前页面路由的路径
      console.log(this.$route.path);
      next();
    }
  }

路由钩子中如果不使用next(),路由会一种被钩子劫持不能进行跳转.

参数说明:

  • to:路由将要跳转的路由记录,类型为route
  • from:路由跳转前的路由记录,类型为route
  • next:路由的控制参数
    • next() 路由继续执行,跳入下一个页面
    • next(’/path’) 改变路由的跳转方向,使其跳到另一个路由
    • next(false) 返回原来的页面
    • next((vm)=>{}) 仅在 beforeRouteEnter 中可用,vm 是组件实例

Axios异步请求

安装Axios

npm install axios -s --registry=https://registry.npm.taobao.org

main.js中引用Axios

import axios from 'axios'
/*原型链*/
Vue.prototype.axios = axios;

进行异步请求,要在进入路由前发送请求

  export default {
    props: ['id'],
    name: "UserProfile",
    beforeRouteEnter: (to, from, next) => {
      console.log("准备进入个人信息页");
      // 注意,一定要在 next 中请求,因为该方法调用时 Vue 实例还没有创建,此时无法获取到 this 对象,
     //在这里使用官方提供的回调函数拿到当前实例,再调用方法
      next(vm => {
        vm.getData();
      });
    },
    methods: {
      getData: function () {
        this.axios({
          method: 'get',
          url: 'http://localhost:8080/static/data.json'
        }).then(function (repos) {
          console.log('返回结果'+repos);
        }).catch(function (error) {
          console.log(error);
        });
      }
    }
  }
        .then(function (repos) {
          console.log('返回结果'+repos);
        })
        //可使用lambad
       .then(repos => {
          console.log('返回结果'+repos);
        }) 

路由懒加载

当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。

const Foo = () => import('./Foo.vue')

const router = new VueRouter({
  routes: [
    { 
        path: '/foo', 
        component: Foo
    }
  ]
})

打包时每个懒加载的组件会生成一个js文件,用到时按需加载.

按组分块

webpackChunkName相同的会打包在一个文件

const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')

keep-alive结合router-view

keep-alive可以使被包含的组件保留状态,或避免重新渲染

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

命名视图(一个路由同时渲染多个组件)

<router-view></router-view>
<router-view  name="a"></router-view>
<router-view  name="b"></router-view>

如果 没有设置名字,那么默认为 default。

const router = new VueRouter({
  routes: [
    {
      path: '/',
      // 注意多了个 s
      components: {
        default: Foo,
        a: Bar,
        b: Baz
      }
    }
  ]
})
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值