1 vue-router 之集成

import Router from 'vue-router';

import routes from './routes';

// const router = new Router({
//   routes
// })

export default () => {
  return new Router({
    routes,
    mode: 'history' // history路由形式,seo友好
  });
};

这里为什么要 export 出去一个函数。因为在每次服务端渲染都会新生成一个 app,router 只有一个对象,就会缓存每次新建的 app,导致服务端渲染流程结束后,app 并没有被释放掉,造成内存溢出。

路由要使用<router-view />来渲染

1.1 路由参数

export default () => {
  return new Router({
    routes,
    mode: 'history', // history路由形式,seo友好
    base: '/base/', // 应用基路径,所有路径前面都会有base
    linkActiveClass: '',
    linkExactActiveClass: '',
    scrollBehavior: (to, from, savedPosition){ // 页面路径进行跳转的时候页面要不要滚动
      // to,路由跳转要去的路由
      // from,从哪个路由跳转到下一个路由
      // savedPosition,记录滚动条位置
    },
    parseQuery(query){ // 把url参数字符串转obj

    },
    stringifyQuery(obj){ // 把obj转字符串

    },
    fallback: true // 不支持前端路由情况下,vue会自动fallback成哈希的模式,如果设成false,单页就变成了多页应用,每次路由跳转都会到后端再去返回新的内容,一般为true
  })
}

vue 中可点击的内容一般用<router-link />来做

linkActiveClass: '',
linkExactActiveClass: ''
// 就是用来配置全局样式,两者区别linkExactActiveClass是linkActiveClass子集
// scrollBehavior
scrollBehavior: (to, from, savedPosition){
  if(savedPosition){ // 如果在app下产生过滚动行为,下一次回来还会在这个位置
    return savedPosition
  } else {
    return { x: 0, y: 0 }
  }
}

浏览器会默认帮助跳转到默认位置,我们可以根据需求自定义

1.2 路由配置及参数传递

export default [
  {
    path: '/',
    redirect: '/app'
  },
  {
    path: '/app',
    component: app,
    name: 'app',
    meta: {},
    children: [
      //子路由
      {
        path: 'test',
        component: Test
      }
    ]
  },
  {
    path: '/login',
    component: Login
  }
];
<router-link to="/login">login</router-link>

//通过name去解析路由,而不是直接解析字符串
<router-link :to="{name: 'app'}">login</router-link>
// 关键字。搜索引擎优化
meta: {
  title: 'this is app',
  description: 'xxxx'
}

1.3 路由动画

<transition name="fade">
  <router-view></router-view>
</transition>

<style lang="stylus">
  .fade-enter-active, .fade-leave-active
    transition: opacity .5s
  .fade-enter, .fade-leave-to
    opacity: 0
</style>

1.4 路由传参

export default [
  {
    path: '/',
    redirect: '/app'
  },
  {
    path: '/app:id', // /app/xxx, xxx会变成id的变量传到组件内部
    props: true, // 会把:id传入到App组件里
    component: App,
    name: 'app',
    meta: {}
  }
];

可以通过 this.$route 取到路由相关参数

通过 url 后?加参数可以取到 query

props: true 这种方式可以更方便,同时达到组件与路由的解耦效果,尽量不要在组件里取$route

url: localhost:8080/app/123?a=123&b=456
// 同时也可以自定义props
{
  path: '/app:id',
  props: {
    id: 123
  }
}

// 根据query进行传递
{
  path: '/app:id',
  props: (route) => ({
    id: route.query.b  // 456
  })
}

1.5 路由高级用法-命名视图

<template>
  <div id="app">
    <router-view name="a" />
    <router-view />
  </div>
</template>
{
  path: '/app,
  component: {
    default: Todo,
    a: Login
  }
}

1.6 路由高级用法-导航守卫

// 导航钩子

import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './app.vue';

import './assets/styles/global.styl';
import routes from './config/router';

Vue.use(VueRouter);

var router = routes();

router.beforeEach((to, from, next) => {
  // 进行数据校验,比如验证用户界面是需要用户登录才能显示
  if (to.fullPath === '/app') {
    next('/login');
  } else {
    next();
  }
});
router.beforeResolve((to, from, next) => {
  console.log('before resolve invoked');
  next();
});
router.afterEach((to, from) => {
  console.log('before each invoked');
});

new Vue({
  router,
  render: h => h(App)
}).$mount('#root');
// 路由配置也可以增加钩子

{
  path: '/app,
  component: {
    default: Todo,
    a: Login
  },
  beforeEnter (to, from, next) { //在beforeEach和beforeResolve之间调用
    //执行逻辑
    next()
  }
}
// 在组件里增加钩子

export default {
  beforeRouteEnter(to, from, next) {
    next()
  },
  beforeRouteUpdate(to, from, next) { // 只有在使用param路由才会触发
    next()
  },
  beforeRouteLeave(to, from, next) {
    next()
  },
  data () {
    return {

  }
}
// beforeRouteLeave最先触发
// 整个触发顺序

beforeEach();

beforeRouteEnter();

beforeResolve();

afterEach();

在做路由跳转数据监听的时候可以用 beforeRouteEnter 代替 watch,并且 beforeRouteEnter 要通过 next 传递参数,因为在这之前它并没有被创建,取不到值。

export default {
  beforeRouteEnter(to, from, next) {
    console.log(this.id); // undifined
    next(vm => {
      console.log(vm.id);
    });
  }
};

beforeRouteEnter 路由钩子一般用来做数据获取插入到对象当中,这样页面进来时数据就已经获取好了

beforeRouteLeave 可以做一些确认,比如表单提交离开时,判断表单是否做了修改,然后弹出提示要不要离开,确认离开就执行 next,不确认就把数据保存下来。

beforeRouteLeave(to, from, next){
  if(global.confirm('are you sure?')) {
    next()
  }
}

1.7 路由高级用法-异步组件

{
  path: '/app,
  component: () => import('../views/todo/todo.vue')
}

可能会提示不正确语法 import

// 安装插件

npm i babel-plugin-syntax-dynamic-import -D

// 修改下.babelrc

{
  "presets": [
    "env"
  ],
  "plugins": [
    "transform-vue-jsx",
    "syntax-dynamic-import"
  ]
}

// 同时把app.vue里需要异步加载的组件import去掉
<template>
  <div id="root">
    <div id="cover"></div>
    <Header></Header>
    <router-link to="/login">login</router-link>
    <!-- <todo></todo> -->
    <router-view />
    <Footer></Footer>
  </div>
</template>

<script>
import Header from './layout/header.vue'
import Footer from './layout/footer.jsx'
// import Todo from './views/todo/todo.vue'

export default {
  components: {
    Header,
    Footer,
    // Todo
  }
}
</script>