美文网首页
vue(二):vue-router

vue(二):vue-router

作者: 林ze宏 | 来源:发表于2019-07-07 21:04 被阅读0次

    目录

    • 1 路由项目简介
    • 2 子路由
    • 3 路由中参数的传递
    • 4 路由表的组件群
    • 5 url 传值
    • 6 router-link 属性说明
    • 7 redirect 重定向
    • 8 alias 别名
    • 9 watch 监控动画
    • 10 404 错误页面处理
    • 11 路由生命钩子
    • 12 方法导航跳转
    • 13 补充
      13.1 路由配置为 history,页面刷新找不到路径问题
      13.2 路由切换简单动画效果
      13.3 组件获取 $route 对象,params 参数转为 props 配置
      13.4 路由生命周期补充(包括全局、路由配置、组件中路由生命钩子)
      13.5 组件异步加载,路由配置

    1 路由项目简介

    • 工程入口文件:

    • 路由配置:

      image.png
    • 说明:

    1:两种模式:hash 和 h5

    mode: 'history', // hash

    2:router-view,页面路由对应组件内容展示的位置

    <router-view/>

    3:router-link,页面路由跳转

    <router-link to="/">/</router-link>

    2 子路由

    配置 children 属性:

    {
      path: '/form',
      name: 'HelloForm',
      component: HelloForm, // 必须
      children: [
        {
          // path: '/form/first',
          path: 'first',
          name: 'FormFirst',
          component: FormFirst
        },
        {
          // path: '/form/second',
          path: 'second',
          name: 'FormFirst',
          component: FormSecond
        }
      ]
    },
    
    注意:这里 path 路径,上面两种写法都可以
    

    在根路径对应的组件中配置 router-view,用于显示子内容:

    HelloForm.js:
    
    <template>
      <div class="hello">
        <h1>{{ msg }}</h1>
        <h2>HelloForm</h2>
        <router-view/>
      </div>
    </template>
    
    

    页面 router-link 访问:

    <li>
      <router-link to="/form">from</router-link>
      <ol>
        <li>
          <router-link to="/form/first">
            from first
          </router-link>
        </li>
        <li>
          <router-link to="/form/second">
            from second
          </router-link>
        </li>
      </ol>
    </li>
    
    

    扩展:children 使用绑定方式

    children 使用绑定方式:与 path: '/users/id' 做区分:
    
    {
        path: '/users',
        name: 'HelloList',
        component: HelloForm,
        children: [
          { path: ':id', component: test }, 
          { path: 'user/:id', component: tt }
        ]
    },
    
    !!!记得要在父组件 HelloForm,路由为 users,
    展示对应的 children 子组件的内容,需要在父组件配置 <router-view/>
    
    
    访问:
    <router-link to="/users/11" exact>users</router-link>
    
    <router-link to="/users/user/1122" exact>users</router-link>
    
    

    3 路由中参数的传递

    • 都是获取 routes 中配置的 name 参数。
    • 项目入口文件、组件字符串模板、组件等都可以获取参数 name;

    1:router-link to 为 字符串时

    <router-link to="/form">from</router-link>

    router/index.js:
    
    import Vue from 'vue'
    import Router from 'vue-router'
    import HelloWorld from '@/components/HelloWorld'
    import HelloForm from '@/components/HelloForm'
    import HelloList from '@/components/HelloList'
    
    Vue.use(Router)
    
    const FormFirst = {
      template: `
        <div>
          {{$route.name}} // !!! 字符串组件模板获取 name 参数。
          <h1>FormFirst</h1>
        </div>
      `
    }
    const FormSecond = {
      template: `
        <h1>FormSecond</h1>
      `
    }
    
    export default new Router({
      mode: 'history', // hash
      base: __dirname,
      routes: [
        {
          path: '/',
          name: 'home',
          component: HelloWorld
        },
        {
          path: '/form',
          name: 'form00',
          component: HelloForm,
          children: [
            {
              // path: '/form/first',
              path: 'first',
              name: 'FormFirst111',
              component: FormFirst
            },
            {
              // path: '/form/second',
              path: 'second',
              name: 'FormSecond222',
              component: FormSecond
            }
          ]
        },
        {
          path: '/list',
          name: 'HelloList',
          component: HelloList
        }
      ]
    })
    
    
    App.vue:router-link to 为 字符串。
    
    <template>
      <div id="app">
        {{ $route.name }}
        <ol>
          <li>
            <router-link to="/">/</router-link>
          </li>
    
          <li>
            <router-link to="/form">from</router-link>
            <ol>
              <li>
                <router-link to="/form/first">
                  from first
                </router-link>
              </li>
              <li>
                <router-link to="/form/second">
                  from second
                </router-link>
              </li>
            </ol>
          </li>
    
          <li>
            <router-link to="/list" >list</router-link>
          </li>
        </ol>
    
        <router-view/>
      </div>
    </template>
    
    
    HelloWorld.vue:其中一个组件,可以获取参数。
    
    <template>
      <div class="hello">
        <h1>{{ msg }}</h1>
        <h2>Essential Links</h2>
        {{ $route.name }} // 获取参数
      </div>
    </template>
    
    

    2:router-link to 为 绑定参数

    <router-link :to="{name: 'home', params: {id: 321}}">/</router-link>

    注意:name 应该与 routes 中的 name 对应。

    App.vue:
    
    <template>
      <div id="app">
        <img src="./assets/logo.png">
        {{ $route.name }}
        {{ $route.params.id }} // 获取参数
    
        <ol>
          <li>
            <router-link :to="{name: 'home', params: {id: 321}}">/</router-link>
          </li>
    
          <li>
            <router-link :to="{name: 'form00', params: {id: 666}}">from</router-link>
            <ol>
              <li>
                <router-link :to="{name: 'FormFirst111', params: {id: 888}}">
                  from first
                </router-link>
              </li>
              <li>
                <router-link :to="{name: 'FormSecond222', params: {id: 777}}">
                  from second
                </router-link>
              </li>
            </ol>
          </li>
    
          <li>
            <router-link :to="{name: 'HelloList', params: {id: 456}}">list</router-link>
          </li>
        </ol>
        <router-view/>
      </div>
    </template>
    
    
    
    HelloWorld.js
    
    <template>
      <div class="hello">
        <h2>Essential Links</h2>
        {{ $route.name }}
        {{ $route.params.id }} // 其中一个组件获取参数
      </div>
    </template>
    
    
    字符串模板组件
    
    const FormFirst = {
      template: `
        <div>
          {{$route.name}}
          {{$route.params.id}} // 字符串模板获取参数
          <h1>FormFirst</h1>
        </div>
      `
    }
    
    
    图示说明

    4 路由表的组件群

    router-view 多个模板:如果没有指定 name,则为默认 default,如果有 name,需要和 components 对象中的 key 对应。

    {
      path: '/',
      name: 'home',
      components: {
        default: HelloWorld,
        left: FormFirst,
        right: FormSecond
      }
    },
    {
      path: '/list',
      name: 'HelloList',
      components: {
        default: FormFirst,
        left: FormFirst,
        right: FormSecond
      }
    },
    
    
    <template>
      <div id="app">
        <ol>
          <li>
            <router-link :to="{name: 'home', params: {id: 321}}">/</router-link>
          </li>
    
          <li>
            <router-link :to="{name: 'form00', params: {id: 666}}">from</router-link>
            <ol>
              <li>
                <router-link :to="{name: 'FormFirst111', params: {id: 888}}">
                  from first
                </router-link>
              </li>
              <li>
                <router-link :to="{name: 'FormSecond222', params: {id: 777}}">
                  from second
                </router-link>
              </li>
            </ol>
          </li>
    
          <li>
            <router-link :to="{name: 'HelloList', params: {id: 456}}">list</router-link>
          </li>
        </ol>
        <router-view/>
        <router-view name="left"/>
        <router-view name="right"/>
      </div>
    </template>
    
    
    图示

    5 url 传值

    5.2 params

    {
      path: '/:id?/', // id 有无都可以
      name: 'home',
      components: {
        default: HelloWorld,
        left: FormFirst,
        right: FormSecond
      }
    },
    {
      path: '/list/:id/:name',  // 需要 id 和 name
      name: 'HelloList',
      component: HelloList
    },
    {
      path: '/list/:id/:name',  // 正则表达式
      name: 'HelloList',
      component: HelloList
    },
    
    
    <router-link :to="{name: 'HelloList', params: {id: 1, name: 'xiaoming1'}}">list</router-link>
    
    <router-link to="/list/1/xiaoming">list2</router-link>
    
    
    组件获取对应的 url 参数:
    {{ $route.params.id }} - {{ $route.params.name }}
    
    

    注意:
    如果出现 Vue Router 跳转到页面后,点击当前的导航导致 URL 又在后面加了一段重复的当前路径的错误,原因如下:

    {
          path: '/list/:id/:name',
          name: 'HelloList',
          component: HelloList
    }
    
    <router-link to="list/1/xiaoming">list2 相对路由 错误!!!</router-link>
    <router-link to="/list/1/xiaoming">list3 绝对路由</router-link>
    
    
    图示

    5.2 query

    <router-link :to="{path: '/test', query: {id: 222, age: 122}}" >测试</router-link>
    
    

    获取参数:

    {{ $route.query.age }}

    说明:
    params 是和 name 配置使用的,而 query 是和 path 配置使用。获取参数为 {{route.params.xx}} 和 {{route.query.xx}}

    6 router-link 属性说明

    扩展:给 router-link 新增样式

    .router-link-exact-active,
    .router-link-active {
      color: red;
    }
    
    

    6.1 activeClass

    activeClass:选中状态,添加的 class

    <router-link to="/list" activeClass='myClass' >测试</router-link>

    6.2 append

    append:相对路径添加

    <router-link to="list" append>测试</router-link>

    如果为:绝对路径,则无效
    <router-link to="/list" append>测试</router-link>

    6.3 exact

    exact:精准匹配

    如果没有 exact,则访问路径为 /test/tt,也会匹配 /test。如下:

    <router-link to="/test/tt" exact>测试1</router-link>

    <router-link to="/test" >测试2</router-link>

    如果使用 exact,则为精准匹配, /test/tt,不会匹配 /test。

    <router-link to="/test/tt" exact>测试1</router-link>

    <router-link to="/test" exact>测试2</router-link>

    7 redirect 重定向

    方式一:简单跳转

    {
      path: '/cdx',
      redirect: '/test'
    },
    {
      path: '/test',
      name: 'HelloList',
      component: test
    },
    
    页面访问:
    <router-link to="/cdx">测试重定向</router-link>
    

    方式二:带参数

    {
      path: '/cdx/:id',
      redirect: '/users/:id'
    },
    {
      path: '/users',
      name: 'HelloList',
      component: HelloForm,
      children: [
        { path: ':id', component: test }, // 记得要在父组件 HelloForm,路由为 users,展示对应的 children 子组件的内容,需要在父组件配置 <router-view/>
        { path: 'user/:id', component: tt }
      ]
    },
    
    
    页面访问:
    <router-link to="/cdx/111">测试重定向</router-link>
    
    

    方式三:函数处理

    {
      path: '/cdx/:id',
      redirect: param => {
        console.log(param) // 经常使用 hash、query、params 等参数
        return '/'
      }
    },
    
    页面访问:
    <router-link to="/cdx/111">测试重定向</router-link>
    
    
    param

    8 alias 别名

    {
      path: '/test',
      name: 'HelloList',
      component: test,
      alias: ['/tttt', '/gg']
    },  
    
    
    <router-link to="/gg"  exact>别名1</router-link>
    
    <router-link :to="{path: '/tttt', query: {id: 222}}" >别名2</router-link>
    
    

    9 watch 监控动画

    watch 监听动画在 App.vue 文件。

      watch: {
        $route(to, from) {
          console.log(to, from);
          if (to.path === '/users/11') {
            this.name = 'fade1';
          } else {
            this.name = 'fade';
          }
        }
      }
    
    
    <template>
      <div id="app">
        <ol>
          <li>
            <router-link :to="{name: 'home', params: {id: 321}}" exact>/</router-link>
          </li>
     
          <li>
            <router-link to="/users/user/1122" exact>users</router-link>
          </li>
    
          <li>
            <router-link :to="{path: '/test', query: {id: 222, age: 122}}" >测试2</router-link>
          </li>
    
          <li>
            <router-link to="/cdx/111">测试重定向</router-link>
          </li>
        </ol>
    
        <transition :name="name" mode="out-in">
          <router-view/>
        </transition>
    
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          name: 'fade'
        };
      },
      watch: {
        $route(to, from) {
          console.log(to, from);
          if (to.path === '/users/11') {
            this.name = 'fade1';
          } else {
            this.name = 'fade';
          }
        }
      }
    };
    </script>
    
    <style>
    /* scoped */
    #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;
    }
    ol {
      width: 144px;
      text-align: left;
    }
    
    .router-link-exact-active {
      color: red;
    }
    
    .fade-enter,
    .fade-leave-active {
      opacity: 0;
    }
    .fade-enter-active,
    .fade-leave-active {
      transition: opacity 0.5s;
    }
    </style>
    
    
    

    10 404 错误页面处理

    import Vue from 'vue'
    import Router from 'vue-router'
    import HelloWorld from '@/components/HelloWorld'
    
    Vue.use(Router)
    
    export default new Router({
      mode: 'hash', // hash history
      base: __dirname,
      routes: [
        {
          path: '/',
          name: 'home',
          components: {
            default: HelloWorld
          }
        },
        {
          path: '/test',
          name: 'HelloList',
          component: test
        },
        { path: '*', component: Page404 }
      ]
    })
    
    
    

    11 路由生命钩子

    import Vue from 'vue'
    import Router from 'vue-router'
    import HelloWorld from '@/components/HelloWorld'
    
    Vue.use(Router)
    
    const test = {
      template: `
        <h1>test</h1>
      `,
      beforeRouteEnter(to, from, next) {
        console.log('beforeRouteEnter', to, from)
        next()
      },
      beforeRouteLeave(to, from, next) {
        console.log('beforeRouteLeave', to, from)
        next()
      }
    }
    
    const Page404 = {
      template: `
        <h1>Page404 error</h1>
      `
    }
    
    export default new Router({
      mode: 'hash', // hash history
      base: __dirname,
      routes: [
        {
          path: '/',
          name: 'home',
          components: {
            default: HelloWorld
          }
        },
        {
          path: '/test',
          name: 'HelloList',
          component: test,
          beforeEnter: (to, from, next) => {
            console.log('beforeEnter', to, from);
            // next(false); // 不允许进入,或者不写
            // next({ path: '/dsds' }) // 重定向
            next() // 允许
          }
        },
        { path: '*', component: Page404 }
      ]
    })
    
    
    

    注意:beforeEnter 是在 routes 路由里面配置的,而 beforeRouteEnter 和 beforeRouteLeave 是在对应的组件中。

    参数说明:

    • 如果没有写 next ,或者 next(false) 表示不跳转;
    • 而 next() 表示默认跳转;
    • next({ path: '/dsds' }) 也可以对象相关配置,重定向等。

    12 方法导航跳转

    <template>
      <div id="app">
        <button @click="qianjin">前进</button>
        <button @click="houtui">后退</button>
        <button @click="home">home</button>
        <button @click="query">query</button>
        <ol>
          <li>
            <router-link :to="{name: 'home', params: {id: 321}}" exact>/</router-link>
          </li>
          <li>
            <router-link to="/test">test</router-link>
          </li>
    
        </ol>
    
        <transition :name="name" mode="out-in">
          <router-view/>
        </transition>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          name: 'fade'
        };
      },
      methods: {
        qianjin: function() {
          this.$router.go(1);
        },
        houtui: function() {
          this.$router.go(-1);
        },
        home: function() {
          this.$router.push('/');
        },
        query: function() {
          this.$router.push({ path: '/test', query: { plan: 'private' } });
        }
      }
    };
    </script>
    
    <style>
    /* scoped */
    #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;
    }
    ol {
      width: 144px;
      text-align: left;
    }
    
    .router-link-exact-active {
      color: red;
    }
    
    .fade-enter,
    .fade-leave-active {
      opacity: 0;
    }
    .fade-enter-active,
    .fade-leave-active {
      transition: opacity 0.5s;
    }
    </style>
    
    
    

    13 补充

    13.1 路由配置为 history,页面刷新找不到路径问题

    当设置路由为 history 路由时,没有配置 nginx 重定向,当页面刷新的时候,会根据路由路径请求后台资源,这时候会报路径错误,因为不会重定向到路由配置页;所以,解决方法也可以通过配置 webpack 解决。

    • 在配置 webpack-dev-server 的地方新增 historyApiFallBack 配置:
    const devServer = {
      port: 8888,
      host: '0.0.0.0',
      ...
      historyApiFallBack : {
        index: '/index.html'
      }
    }
    
    • 注意:配置的路径跟 output 路径有关系,如果有配置 output 中 有配置 publicPath,那也需要在 historyApiFallBack 中的 index 路径前面配置。

    如:output 配置:

    output: {
      filename: 'bundle.[hash:8].js',
      path: path.join(__dirname, '../dist'),
      publicPath: '/public/'
    },
    
    

    则 historyApiFallBack 中的 index 路径配置为:

      historyApiFallBack : {
        index: '/public/index.html'
      }
    

    13.2 路由切换简单动画效果

    <transition name='fade'>
      <router-view />
    </transition>
    
    
    .fade-enter-active, .fade-leave-active {
      transition: opacity .5s
    }
    .fade-enter, .fade-leave-to {
      opacity: 0
    }
    
    

    13.3 组件获取 $route 对象,params 参数转为 props 配置

    方式一,前面介绍可以通过 this.$route 对象获取:

    mounted () {
      console.log(this.$route)
    }
    
    

    方式二:在配置路由组件, 利用 props (布尔、对象、函数)传递对应的配置路由参数,把参数转为 props

    {
      path: '/app/:id',
      props: true, // 把 path: '/app/:id' 中的 id 参数,转化为 props 属性传递给组件 Todo,Todo 可以通过 props 获取到 id,不用通过 this.$route.params.id 获取 。
      component: Todo,
      name: 'app',
      meta: {
        title: 'this is app',
        description: 'xxxx'
      }
    }
    
    

    props 也可以为对象或者函数,如:

    ...
    props: {
      id: '111'
    },
    ...
    
    ...
    props: (route) => ({id: route.query.xx})
    ...
    

    13.4 路由生命周期补充(包括全局、路由配置、组件中路由生命钩子)

    • 1 全局导航钩子(全局路由)
      beforeEach、beforeResolve、afterEach
    cosnt router = createRouter();
    
    router.beforeEach((to, from, next) => {
      console.log('before each invoked');
      if (to.fullPath === '/login') {
        next();
      } 
    })
    
    router.beforeResolve((to, from, next) => {
      console.log('before resolve invoked');
      if (to.fullPath === '/login') {
        next();
      } 
    })
    
    router.afterEach((to, from) => {
      console.log('after each invoked');
    })
    
    

    例子:验证用户登录,才显示的路由路径

    router.beforeEach((to, from, next) => {
      console.log('before each invoked');
      if (to.fullPath === '/app') {
        next({path: '/login'});
      } else {
        next();
      }
    })
    
    
    • 2 App 路由配置中的钩子:
      beforeEnter
    {
      path: '/app',
      name: 'app',
      ...
      beforeEnter (to, from, next) {
         next()
      }
    }
    
    
    • 3 组件内路由钩子
      beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
    export default{
      data () {
        return {
          id: xxx
        }
      },
      beforeRouteEnter (to, from, next) {
        next();
      },
      beforeRouteUpdate(to, from, next) {
        next();
      },
      beforeRouteLeave(to, from, next) {
        next();
      }
    }
    
    

    说明:
    1:beforeRouteRupdate 触发的时候,需要路由加载的是同一个,例如根据参数 id 的不同,加载的组件还是一样的,这时候 beforeRouteRupdate 钩子就会触发。

      {
        path: '/app/:id',
        component: Todo,
        name: 'app',
        ...
      }
    
    组件是一样的 Todo,但是 id 参数不一样的时候,就会触发 beforeRouteRupdate 钩子
    

    2:进入页面之前的验证,因为在 beforeRouteEnter 钩子,页面还没有加载,所以,不能获取该页面的数据,可以通过 next 回调方法;

    beforeRouteEnter (to, from, next) {
      console.log(' 组件进入之前', this); // undefined
      next(vm => {
        console.log('组件已经进入', vm.id)
      })
    }
    
    

    3:通过 beforeRouteLeave 钩子,控制页面离开行为,例如表单很多的时候,提示是否离开

    beforeRouteLeave  (to, from, next) {
      if (global,confirm('确定离开该页面吗?')) {
        next();
      }
    }
    
    

    13.5 组件异步加载,路由配置

    异步加载对应路由的代码,而不是一次性加载所有页面代码。优化加快首屏加载的速度。

    1:component 写法,通过函数 import 对应的组件:

    {
      path: '/app/:id',
      props: true,
      component: () => import('../views/todo.vue'), // !!!
      name: 'app',
      ...
    }
    
    

    2:安装 babel-plugin-syntax-dynamic-import 包:

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

    3:配置 babel:syntax-dynamic-import

      {
        "plugins": {
          "tansform-vue-jsx",
          "syntax-dynamic-import"
        }
      }
    
    

    相关文章

      网友评论

          本文标题:vue(二):vue-router

          本文链接:https://www.haomeiwen.com/subject/dnbihctx.html