自定义 Vue 路由器

Flying
2020-05-28 / 0 评论 / 119 阅读 / 正在检测是否收录...

先前写过一篇为 material 组件自定义 AngularJS 路由器的文章。最近有一个为 Element UI 组件添加自定义路由器的需求,结合 vue-router 也不难实现。

lazy-load.svg

需求

  • 初始地址为 #city,不会选中区号按钮,面包屑 All;如果导航地址为 #city/0755,则选中0755,面包屑 All > 深圳
  • 点击区号按钮(021、0755)会相应修改访问地址(#city/021、#city/0755)
  • 点击区号按钮,面包屑会显示为 All > 城市名(广州、深圳)
  • 点击面包屑 All 跳转到初始地址 #city
  • 可以通过导航栏或浏览器的前进后退按钮导航
  • 同步修改浏览器标题栏为当前选择城市名

一句话,如何实现区号按钮组、导航栏、浏览器导航三者的同步更新?

实现区号按钮组

新建 Breadcrumb.vue, 这里我们用 el-radio-group 来渲染区号按钮

<el-radio-group v-model="selected" @change="handleChange">
  <el-radio-button
    v-for="item in cities"
    :label="item.code"
    :key="item.code"
  >
  </el-radio-button>
</el-radio-group>

以下是单选按钮组遍历要用到的数据:

const cities = [
  {
    city: "上海",
    code: "021",
    degree: 28,
  },
  {
    city: "北京",
    code: "010",
    degree: 24,
  },
  {
    city: "广州",
    code: "020",
    degree: 33,
  },
  {
    city: "深圳",
    code: "0755",
    degree: 32,
  },
];

我们为其绑定了 selected 保留,并声明了 handleChange 事件处理方法:

handleChange(value) {
 console.log(value)

可以简单测试以下,当切换单选按钮组,会打印不同的区号。

为方便,我们没有将这部分实现放到了 Breadcrum 组件中,并没有单独拆分成一个组件。

实现导航栏

Breadcrum 组件中:

<nav>
  <el-button class="el-icon-back" @click="back"></el-button>
  <el-button class="el-icon-right" @click="forward"></el-button>
  <router-link>All</router-link>
  <template v-if="selected">
    <i class="el-icon-arrow-right"></i>
    {{ currentCity }}
  </template>
</nav>

我们在这里添加了前进后退按钮和面包屑,下面我们来实现单选按钮组与面包屑的同步。添加以下计算属性:

computed: {
  currentCity() {
    const found = this.cities.find(item =>item.code === this.selected) 
    if (found) {
      return found.city
    }
    return 'All'
  }
}

测试以下,点击区号按钮,面包屑会显示为 All > 城市名,我们完成了第二个需求。要实现其他需求,着重看 Vue Router。

配置路由器

根据强两个需求,新建 router\index.js,配置如下路由对象后,导出自定义路由器:

export default new Router({
  routes: [
    {
      path: "/",
      redirect: "/city"
    },
    {
      path: "/city/:code",
      name: "Breadcrumb",
      component: Breadcrumb
    }
  ]
});

第一个路由默认会跳转到 #city,第二个路由地址使用了参数 code,参数为 0755 则会跳转到 #city/0755

注意,Vue Router 中路由地址传参方式 :paramName

添加路由器

App 组件中,引入之前的自定义路由器,将其最为插件添加 Vue 示例中。

import router from "./router";
//...
new Vue({
  // ...
  router,
  // ...
});

对照需求 1 测试一下, 没啥问题后来看需求 3:点击面包屑 All 跳转到初始地址 #city

修改面包屑

Breadcrumb 组件中做如下修改

<router-link exact exact-active-class="exact" :to="{ path: '/city' }">
All
</router-link>

<router-link> 组件支持用户在具有路由功能的应用中 (点击) 导航。

这里,我们做了两件事:

  • 配置了目标路由被精确匹配的时候应该激活的样式
  • 配置了表示目标路由的链接 '/city'

对照需求 1 测试一下。最后我们来看需求 4:通过导航栏或浏览器的前进后退导航

自定义前进后退导航

Breadcrumb 组件中,我们之前已经添加了前进后退按钮,现在需要实现交互:

  • 处理前进
forward() {
  this.$router.go(1);
}

router.go(n) 方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似 window.history.go(n)

  • 处理后退
back() {
  this.$router.go(-1);
}
  • 修改 handleChange
handleChange(value) {
  this.$router.push({ path: `/city/${value}` });
},
注意:在 Vue 实例内部,你可以通过 $router 访问路由实例。因此你可以调用 this.$router.push。

都是 Vue Router 编程式的导航,很简单。对照需求 1 测试一下。最后我们来看需求 4:通过导航栏或浏览器的前进后退导航

同步修改浏览器标题栏

这个操作需要直接修改 DOM,是一个副作用,需要监听$route.params.code

watch: {
  "$route.params.code": {
    handler(value) {
      document.title = this.currentCity
      this.selected = value;
    },
    immediate: true,
  },
},
注意,我们还同步修改了 selected ,并设置 immediatetrue,确保该回调将会在侦听开始之后被立即调用。

参考示例

1

评论 (0)

取消