• 深入浅出的webpack构建工具--webpack4+vue+router项目架构(十四)


    阅读目录

    一:vue-router是什么?

    二:vue-router的实现原理

    三:vue-router使用及代码配置

    四:理解vue设置路由导航的两种方法。

    五:理解动态路由和命名视图

    六:理解嵌套路由

    七:在nginx上部署vue项目(history模式)

    八:vue-router 之 keep-alive

    一. vue-router是什么?

    vue-router是vue.js官方的路由插件,它和vue.js是集成的。它用于构建单页面应用,vue的单页面应用是基于路由和组件的,路由是用于设定访问路径的,并且路径和组件会产生映射起来。在vue-router单页面应用中,路径之间的切换,可以理解为组件的切换,路由模块的本质:是建立起url和页面之间的映射关系。

    二:vue-router的实现原理

    vue-router是用于构建单页面的,单页面的核心是更新视图而不会重新请求页面,这也就是为什么在页面中不用a标签的原因,因为页面只有一个index.html。那么它在实现单页面前端路由时,提供了两种模式,hash模式和History模式。默认情况下是使用hash模式。

    2.1 hash模式

    hash是URL的锚点(#), 代表网页中的一个位置,如果只改变#后的部分,浏览器会滚动到相应的位置,而不会重新加载网页,并且每次改变#后的部分,都会在浏览器的访问历史中增加一条记录,当我们使用后退按钮的时候,就可以返回到上一个位置。因此hash模式通过锚点值的改变,根据不同的值,渲染指定DOM位置的不同数据。

    2.2 history模式

    上面是通过hash模式的,页面的地址就会加上 # 号,比如我们的地址类似这样的:http://localhost:8080/#/,我们使用history的话,那么访问页面的时候就和平常一样,不带井号的;如下地址也可以访问 http://localhost:8080/ ,使用路由history模式的话,只需要在配置路由规则时,加入 'mode': 'history'即可,它是利用html5中的 history.pushState的API来完成的URL跳转,无需重新加载页面的。
    不过这种配置需要后台开发支持一下的,具体怎么配置,下面会详细讲到。

    三:vue-router使用及代码配置

    在vue-router中,定义了两个标签<router-link>和<router-view>来对应点击和显示,<router-link>是点击的部分,<router-view>是定义显示的部分,当我们点击之后,路由匹配组件的内容后会在<router-view>显示出来,<router-link>还需要一个属性 to, 它的含义就是到哪里去的意思。
    比如 <router-link to="/home">111</router-link> 的含义是当我们点击111的时候,它会找到home相对应的组件,然后会在 <router-view>中显示出来。

    理解配置路由

    路由一般使用两个部分组成,path和component,path指路径,component指的是组件,它是一个对象,比如 { path: '/home', component: home }

    比如我们这边定义两条路由,如下代码:

    const routes = [
      { path: '/home', component: Home },
      { path: '/xxx', component: XXX }
    ];

    2. 创建router管理
    创建router对路由进行管理,它是由构造函数 new vueRouter()创建,接收上面的routes参数。如下代码:

    const router = new vueRouter({
      routes: routes
    });

    3. 实列注入到vue根实列中

    我们接着把上面router实列注入待vue根实列中,我们就可以使用路由了。如下代码:

    new Vue({
      el: '#app',
      router: router,
      render: h => h(Index)
    });

    在配置代码之前,我们还是看看我们的项目整个目录结构如下:(基于第十三篇文章的基础之上再进行构建的)。

    ### 目录结构如下:
    demo1                                       # 工程名
    |   |--- dist                               # 打包后生成的目录文件             
    |   |--- node_modules                       # 所有的依赖包
    |   |--- app
    |   | |---index
    |   | | |-- views                           # 存放所有vue页面文件
    |   | | |-- components                      # 存放vue公用的组件
    |   | | |-- app.js                          # vue入口配置文件
    |   | | |-- router.js                       # 路由配置文件
    |   |--- views
    |   | |-- index.html                        # html文件
    |   |--- webpack.config.js                  # webpack配置文件 
    |   |--- .gitignore  
    |   |--- README.md
    |   |--- package.json
    |   |--- .babelrc                           # babel转码文件

    在app/index/views 新建home.vue 和 xxx.vue 文件。
    1. home.vue 代码如下:

    <style lang='stylus'>
      .home-container
        width 100%
    </style>
    <template>
      <div class="home-container">
        <h1>欢迎来到Home</h1>
        <p>{{msg}}</p>
      </div>
    </template>
    
    <script type="text/javascript">
      export default {
        data() {
          return {
            msg: '我是Home组件'
          }
        }
      }
    </script>

    xxx.vue 代码如下:

    <style lang='stylus'>
      .xxx-container
        width 100%
    </style>
    <template>
      <div class="xxx-container">
        <h1>欢迎来到xxx</h1>
        <p>{{msg}}</p>
      </div>
    </template>
    
    <script type="text/javascript">
      export default {
        data() {
          return {
            msg: '我是XXX组件'
          }
        }
      }
    </script>

    2. 接着在 app/index/views 新建index.vue, 代码如下:

    <style lang="stylus">
      
    </style>
    
    <template>
      <div id="app">
        <header>
          <router-link to='/home'>Home</router-link>
          <router-link to='/xxx'>XXX</router-link>
        </header>
        <!-- 对应组件的内容渲染到router-view中 -->
        <router-view></router-view>
      </div>
    </template>
    
    <script type="text/javascript">
      export default {
        data() {
          return {
            
          }
        }
      }
    </script>

    3. 在 app/index/router.js定义router,路径到组件的映射。 添加如下代码:

    import Vue from 'vue';
    import VueRouter from 'vue-router';
    
    // 引入组件 
    import home from './views/home';
    
    import xxx from './views/xxx';
    
    // 告诉 vue 使用 vueRouter
    
    Vue.use(VueRouter);
    
    const routes = [
      {
        path: '/home',
        component: home
      },
      {
        path: '/xxx',
        component: xxx
      },
      {
        path: '*', // 其他没有的页面都重定向到 home页面去
        redirect: '/home'
      }
    ]
    
    var router = new VueRouter({
      routes: routes
    });
    
    export default router;

    当然上面引入组件的方法,我们还可以懒加载的方式加载,懒加载引入的优点是:当我们访问页面的时候才会去加载相关的资源,这样的话,能提高页面的访问速度。
    比如如下这样:component: resolve => require(['@/views/HelloWorld'], resolve) // 使用懒加载

    因此我们可以把上面的代码写成如下:

    import Vue from 'vue';
    import VueRouter from 'vue-router';
    
    /*
    // 引入组件 
    import home from './views/home';
    
    import xxx from './views/xxx';
    
    */
    
    // 告诉 vue 使用 vueRouter
    Vue.use(VueRouter);
    
    const routes = [
      {
        path: '/home',
        component: resolve => require(['./views/home'], resolve)  // 使用懒加载
      },
      {
        path: '/xxx',
        component: resolve => require(['./views/xxx'], resolve)  // 使用懒加载
      },
      {
        path: '*', // 其他没有的页面都重定向到 home页面去
        redirect: '/home'
      }
    ]
    var router = new VueRouter({
      base: '/app/index', // 配置单页应用的基路径
      routes: routes
    });
    
    export default router;

    如上base的含义:应用的基路径,比如整个单页应用服务在 /app/index 下,那么base就应该设置为 /app/index.

    4. 实列注入到vue根实列中。
    把路由注入到根实列中,启动路由,我们在app/index/app.js 入口文件添加如下代码:

    import Vue from 'vue';
    
    import Index from './views/index';
    
    // 引入路由
    import router from './router';
    
    new Vue({
      el: '#app',
      router: router,
      render: h => h(Index)
    });

    因此要运行上面代码之前,我们先要 下载 vue-router 到我们项目中来,如下代码命令:

    npm i vue-router --save

    下载完成后,我们再来运行打包命令,npm run dev 后,就可以启动页面了。

    在页面访问如下

    四:理解vue设置路由导航的两种方法。

    vue设置路由导航的两种方法有 <router-link :to=''> 和 router.push().

    4.1 to的值可以是一个字符串路径,或者一个描述地址的对象。比如如下都是可以的。

    // 字符串
    <router-link to='/home'>Home</router-link>
    
    // 对象
    <router-link :to="{path: '/home'}">Home</router-link>
    
    // 命名路由
    <router-link :to="{name: 'home'}">Home</router-link>
    /*
     如果是命名路由的话,需要在router.js 加上name字段,如下代码:
     const routes = [
        {
          path: '/home',
          name: 'home',
          component: resolve => require(['./views/home'], resolve)  // 使用懒加载
        },
        {
          path: '/xxx',
          name: 'xxx',
          component: resolve => require(['./views/xxx'], resolve)  // 使用懒加载
        },
        {
          path: '*', // 其他没有的页面都重定向到 home页面去
          redirect: '/home'
        }
      ]
    */
    
    // 直接路由带查询参数query,地址栏就变成 /home?id=1
    <router-link :to="{path: 'home', query: {id: 1 }}">Home</router-link>
    
    // 如果是path的话,路由带参数params的话,params是不会生效的。如下代码 params的参数是不会在地址栏中显示的。
    <router-link :to="{path: 'home', params: {id: 1 }}">Home</router-link>
    
    // 命名路由带路由参数params,地址栏还是 /home, 但是可以通过 this.$route.params.id拿到值的
    <router-link :to="{name: 'home', params: {id: 1 }}">Home</router-link>

    4.2 router.push()方法

    // 支持字符串
    this.$router.push('xxx');
    
    // 支持对象
    this.$router.push({
      path: 'xxx'
    });
    
    // 支持命名路由方式
    this.$router.push({
      name: 'xxx'
    });
    
    // 直接路由带查询参数 query, 地址栏变成 /xxx?id=1
    this.$router.push({
      path: 'xxx',
      query: { id: 1 }
    });
    
    // 命名路由带查询参数query,地址栏变成 /xxx?id=1
    this.$router.push({
      name: 'xxx',
      query: { id: 1 }
    });
    
    // 如果提供了path,直接路由带参数params, params不会生效,在xxx页面通过 
    // console.log(this.$route.params.id) 是获取不到值的。
    this.$router.push({
      path: 'xxx',
      params: { id: 1 }
    });
    
    // 命名路由带路由参数params,地址栏是/xxx。在xxx页面通过 console.log(this.$route.params.id) 是可以获取到值的。
    this.$router.push({
      name: 'xxx',
      params: { id: 1 }
    });

    总结:1. 无论是直接路由path还是命名路由name,带查询参数query,地址栏会变成 /url?查询参数名=查询参数值

             2. 直接路由path带路由参数params,params不生效。在xxx页面通过 console.log(this.$route.params.id) 是获取不到值的。

             3. 命名路由name带路由参数params地址栏保持是 /url/路由参数值。在xxx页面通过 console.log(this.$route.params.id) 是可以获取到值的。

    五:理解动态路由和命名视图

    5.1 动态路由
    动态路由也可以叫做路由传参。
    在前面我们介绍了路由导航功能是不能传递参数的,我们可以叫他们静态路由,而能传递参数的路由模式,并且对应的路由数量是不确定的,因此我们可以叫他动态路由。

    应用场景:当我们的多个页面或组件都要被多次重复利用的时候,我们的路由都指向同一个组件,这时候从不同的地方进入相同的组件的时候,我们根据传递的参数不同,来渲染不同的数据。

    比如如下代码:

    const routes = [
      {
        path: '/xxx/:id',  // 动态路由信息
        name: 'xxx',
        component: resolve => require(['./views/xxx'], resolve)  // 使用懒加载
      }
    ];

    如上代码 path: /xxx/:id, 这种形式,这样定义之后,vue-router将会匹配所有的 /xxx/1, /xxx/2,.....

    比如我现在有多个页面需要进入xxx组件内,这时候我们可以在配置路由路径后加个:id。index.vue 改成如下代码:

    <template>
      <div id="app">
        <header>
          <router-link to="home">Home</router-link>
          <router-link to='xxx/on'>XXX</router-link>
        </header>
        <!-- 对应组件的内容渲染到router-view中 -->
        <router-view></router-view>
      </div>
    </template>

    当我点击 XXX 时候,会进入xxx组件内,那么在xxx.vue组件内,可以通过 this.$route.params.id 获取传的参数值了。

    如下图所示:

    5.2 理解命名视图

    有时候我们想同时显示多个视图,比如一个单页应用页面,有侧导航(sidebar) 和 头部(header) 和 main(主内容)等三个视图,这个时候命名视图就派上用场了。
    我们可以在页面中拥有多个单独命名的视图,而不是和我们上面一样只有一个单独的视图。如果 router-view 没有设置名字,那么默认为default。

    现在我们可以在 app/index/components 新建文件夹为sidebar, header, main, 及在各对应的目录下新建index.vue.

    现在我们的项目的目录结构变成如下了:

    ### 目录结构如下:
    demo1                                       # 工程名
    |   |--- dist                               # 打包后生成的目录文件             
    |   |--- node_modules                       # 所有的依赖包
    |   |--- app
    |   | |---index
    |   | | |-- views                           # 存放所有vue页面文件
    |   | | | |-- home.vue
    |   | | | |-- index.vue
    |   | | | |-- xxx.vue
    |   | | |-- components                      # 存放vue公用的组件
    |   | | | |--- header
    |   | | | | |-- index.vue                   # 公用的头部组件
    |   | | | |--- main
    |   | | | | |-- index.vue                   # 主体组件
    |   | | | |--- sidebar
    |   | | | | |-- index.vue                   # 侧导航公用的组件
    |   | | | |
    |   | | |-- app.js                          # vue入口配置文件
    |   | | |-- router.js                       # 路由配置文件
    |   |--- views
    |   | |-- index.html                        # html文件
    |   |--- webpack.config.js                  # webpack配置文件 
    |   |--- .gitignore  
    |   |--- README.md
    |   |--- package.json
    |   |--- .babelrc                           # babel转码文件

    app/index/components/header/index.vue 代码如下:

    <style lang="stylus">
      * {margin: 0; padding: 0}
      .header-container
        width 100%
        height 50px
        background #000
        div 
          font-size 16px
          color #fff
          text-align center
    </style>
    
    <template>
      <div class="header-container">
        <div>我的头部导航</div>
      </div>
    </template>
    
    <script type="text/javascript">
      export default {
        data() {
          return {
    
          }
        }
      }
    </script>

    app/index/components/sidebar/index.vue 代码如下:

    <style lang="stylus">
      .sidebar-container
        width 200px
        height 100%
        min-height 500px
        background red
        float left
        div 
          font-size 12px
          color #fff
          text-align center
    </style>
    
    <template>
      <div class="sidebar-container">
        <div>我的左侧导航</div>
      </div>
    </template>
    
    <script type="text/javascript">
      export default {
        data() {
          return {
    
          }
        }
      }
    </script>

    app/index/components/main/index.vue 代码如下:

    <style lang="stylus">
      .main-container
        margin-left 200px
        height 100%
        min-height 500px
        background green
        div 
          font-size 12px
          color #fff
          text-align center
    </style>
    
    <template>
      <div class="main-container">
        <div>我的主体部分</div>
      </div>
    </template>
    
    <script type="text/javascript">
      export default {
        data() {
          return {
    
          }
        }
      }
    </script>

    框架搭建完成后,我们需要在index.vue 代码变成如下:

    <style lang="stylus">
      
    </style>
    
    <template>
      <div id="app">
        <!--
        <header>
          <router-link to="/home">Home</router-link>
          <router-link to='/xxx/on'>XXX</router-link>
        </header>
      -->
        <router-view name="Header"></router-view>
        <router-view name="Sidebar"></router-view>
        <router-view name="Main"></router-view>
        <!-- 对应组件的内容渲染到router-view中 -->
        <router-view></router-view>
      </div>
    </template>
    
    <script type="text/javascript">
      export default {
        data() {
          return {
            
          }
        }
      }
    </script>

    接着我们需要在router.js下配置代码如下:

    import Vue from 'vue';
    import VueRouter from 'vue-router';
    
    // 引入组件 
    import home from './views/home';
    
    import xxx from './views/xxx';
    
    // 告诉 vue 使用 vueRouter
    Vue.use(VueRouter);
    
    const routes = [
      {
        path: '/home',
        name: 'home',
        components: {
          default: resolve => require(['./views/home'], resolve),  // 使用懒加载
          Header: resolve => require(['./components/header/index'], resolve),  // 使用懒加载
          Sidebar: resolve => require(['./components/sidebar/index'], resolve),  // 使用懒加载
          Main: resolve => require(['./components/main/index'], resolve)  // 使用懒加载
        }
      },
      {
        path: '/xxx/:id',
        name: 'xxx',
        components: {
          default: resolve => require(['./views/xxx'], resolve),  // 使用懒加载
          Header: resolve => require(['./components/header/index'], resolve),  // 使用懒加载
          Sidebar: resolve => require(['./components/sidebar/index'], resolve),  // 使用懒加载
          Main: resolve => require(['./components/main/index'], resolve)  // 使用懒加载
        } 
      },
      {
        path: '*', // 其他没有的页面都重定向到 home页面去
        redirect: '/home'
      }
    ]
    
    var router = new VueRouter({
      base: '/app/index', // 配置单页应用的基路径
      routes: routes
    });
    
    export default router;

    然后打包运行下,在浏览器上可以看到如下图所示的结构。

    如上可以看到,我们可以使用 命名视图 来搭建我们网站的框架,这可以理解命名视图的作用了。

    六:理解嵌套路由

    什么是嵌套路由?比如我们进入到我们home页面的时候,它下面还有分类,比如叫 java书籍,node书籍等,那么当我点击各个类目的时候,就对应到相应的组件。比如首先我进入的是 /home 这个路由,然后当我进入 /home下面的分类的 java书籍的话,那么我们的路由就是 /home/java, 如果进入分类的是 node书籍的话,那么路由就是 /home/node 了。因此 vue提供了 childrens这个属性来做这件事,它也是一组路由。

    首先我们在 app/index/views 下 新建 java.vue 和 node.vue.

    java.vue代码如下:

    <style lang='stylus'>
      .java-container
        width 100%
    </style>
    
    <template>
      <div class="java-container">
        <h1>欢迎来到java类书籍</h1>
        <p>{{msg}}</p>
      </div>
    </template>
    
    <script type="text/javascript">
      export default {
        data() {
          return {
            msg: '我是java组件'
          }
        },
        methods: {
          
        }
      }
    </script>

    node.vue 代码如下:

    <style lang='stylus'>
      .node-container
        width 100%
    </style>
    
    <template>
      <div class="node-container">
        <h1>欢迎来到node类书籍</h1>
        <p>{{msg}}</p>
      </div>
    </template>
    
    <script type="text/javascript">
      export default {
        data() {
          return {
            msg: '我是node组件'
          }
        },
        methods: {
          
        }
      }
    </script>

    app/index/router.js 代码就改成如下:

    import Vue from 'vue';
    import VueRouter from 'vue-router';
    
    // 引入组件 
    import home from './views/home';
    
    import xxx from './views/xxx';
    
    // 告诉 vue 使用 vueRouter
    Vue.use(VueRouter);
    
    const routes = [
      {
        path: '/home',
        name: 'home',
        component: resolve => require(['./views/home'], resolve),
        // 子路由
        children: [
          {
            path: 'java',
            component: resolve => require(['./views/java'], resolve)
          },
          {
            path: 'node',
            component: resolve => require(['./views/node'], resolve)
          }
        ]
      },
      {
        path: '/xxx/:id',
        name: 'xxx',
        component: resolve => require(['./views/xxx'], resolve)
      },
      {
        path: '*', // 其他没有的页面都重定向到 home页面去
        redirect: '/home'
      }
    ]
    
    var router = new VueRouter({
      base: '/app/index', // 配置单页应用的基路径
      routes: routes
    });
    
    export default router;

    app/index/views/index.vue 代码如下:

    <style lang="stylus">
      
    </style>
    
    <template>
      <div id="app">
        <header>
          <router-link to="/home" tag='li'>Home</router-link>
          <router-link to="/home/java">java</router-link>
          <router-link to="/home/node">node</router-link>
          <router-link to='/xxx/on'>XXX</router-link>
        </header>
      <!--
        <router-view name="Header"></router-view>
        <router-view name="Sidebar"></router-view>
        <router-view name="Main"></router-view>
      -->
        <!-- 对应组件的内容渲染到router-view中 -->
        <router-view></router-view>
      </div>
    </template>
    
    <script type="text/javascript">
      export default {
        data() {
          return {
            
          }
        }
      }
    </script>

    如上代码增加完成后,进行打包,编译都正常,但是点击java或node的时候,子路由一直没有渲染到对应的组件,网上很多资料说,子路由多写了 /, 但是我router.js里面也没有这些东西的,但是经过搜索,发现问题并不是在这里,而是说在嵌套的子模块里面引用子路由的时候,也需要加上 <router-view></router-view> 这句代码,如下是home.vue 代码:

    <template>
      <div class="home-container">
        <h1>欢迎来到Home</h1>
        <p>{{msg}}</p>
        <p @click="func">进入index页面</p>
        <router-view></router-view>
      </div>
    </template>

    注意:路由嵌套的真正的含义是:点击子路由的时候,父级组件还是会显示的,子组件也会显示的,这才是使用子路由嵌套的用途。
    如果仅仅想显示子组件的话,不想显示父组件的话,那就不要使用路由嵌套,直接使用兄弟路由,写死路径即可。

    比如

    const router = [
      {
        path: '/home',
        name: 'home',
        component: resolve => require(['./views/home'], resolve),
      },
      // 兄弟路由
      {
        path: '/home/java',
        name: 'home',
        component: resolve => require(['./views/java'], resolve),
      }
    ]

     github源码 webpack+vue+router

  • 相关阅读:
    SIFT四部曲之——高斯滤波
    Opencv模块功能介绍
    颜色空间那些事儿
    libSVM笔记之(一)在matlab环境下安装配置libSVM
    Debian7安装后的配置(英文环境chromium浏览器中汉字变成方块的问题)
    JAVA的编码转换测试
    Ubuntu普通用户使用串口设备
    RTSP流和USB摄像头转MJPEG使用VLC
    ubuntu 14.04安装右键打开终端功能
    学习的目的和方法论(实战主义)
  • 原文地址:https://www.cnblogs.com/tugenhua0707/p/9709579.html
Copyright © 2020-2023  润新知