vue07-路由 vue-router、keep-alive、tab-bar

九、路由 vue-router

详情

一般使用vue的插件都要用Vue.use(插件)

  • 介绍:
    • 互联的网络将信息传输到目标地址的活动
    • 路由器提供两种机制:
      1. 路由:决定数据包从源到目的地的路径
      2. 将输入端的数据转送到合适的输出端
    • 路由表:是一个映射表,决定了数据包的指向
  • 后端路由--前端路由
    • 后端处理url和页面的映射,jsp是后端渲染,到前端的时候页面就确认好了
    • 前端处理url和页面的跳转映射

改编url不刷新页面

  • 改location.hash='aaa';
  • history:
    • 改history.pushState({},'','aaa');类似压栈,history.back()类似弹栈
    • 改history.replaceState({},'','aaa'),不能back()
    • 改history.go(-1) = history.back(),前进或者后退
    • 改history.forword()=history.go(1)
  1. 安装路由:npm install vue-router --save 因为生产也需要路由

  2. 导入:

    • router/index.js
    import Vue from 'vue'
    //1. 导入插件
    import Router from 'vue-router'
    import HelloWorld from '@/components/HelloWorld'
    
    //2. 使用插件
    Vue.use(Router)
    
    //3. 创建路由配置
    const routes = [
      {
        path: '/',
        name: 'HelloWorld',
        component: HelloWorld
      }
    ];
    
    //4. 传入路由配置,导出路由对象
    export default new Router({
      routes
    })
    
    
    • main.js
    import Vue from 'vue'
    import App from './App'
    //只写目录默认会找  index.js
    import router from './router'
    
    Vue.config.productionTip = false
    
    new Vue({
      el: '#app',
      router,
      render: h => h(App)
    })
    
    
  • 替换a标签
<div id="app">
    <router-link to="/home">首页</router-link>
    <!-- 相当于占位符 -->
    <router-view></router-view>
    <router-link to="/about">详情</router-link>
  </div>
  • 常用属性

    • tag 、replace

      <!-- tag设置替换成什么标签 -->
          <!-- replace表示禁用了返回前进按钮,是使用了history.replaceState() -->
          <router-link to="/home" tag='button' replace>首页</router-link>
      
    • 配置默认的active的样式

      .router-link-active{
        color: #f00
      }
      
      
    • 自定义样式:手动一个一个标签的写

      <!--active-class 自定义点击后的样式 -->
          <router-link to="/home" tag='button' replace active-class="active">首页</router-link>
      
    • 配置全局的active-class

    export default new Router({
      routes,
      mode:'history',
      linkActiveClass:'active'
    })
    

默认重定向

const routes = [
  {
    path:'/',
    redirect:'/home'
  },
  {
    path: '/home',
    name: 'Home',
    component: Home
  },
  {
    path:'/about',
    name:'About',
    component:About
  }
];

设置router的默认方式为history

  • 本身默认hash
  • history:url不会显示#号
//4. 传入路由配置,导出路由对象
export default new Router({
  routes,
  mode:'history'
})

手动写路由跳转

  • router会给每个组件传$router
<template>
  <div id="app">
    <button @click="homeClick">首页</button>
    <button @click="aboutClick">详细</button>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'App',
  methods:{
    //router会给每个组件传$router
    homeClick(){
      // this.$router.push('/home');
      this.$router.replace('/home');
    },
    aboutClick(){
      // this.$router.push('/about');
      this.$router.replace('/about');
    }
  }
}
</script>

<style>
#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;
}
</style>

动态路由

01动态路由
  • 需要调用$route.params来获取参数
  1. 创建一个vue组件:User.vue

    <template>
      <div>
          <h2>个人信心</h2>
          <h3></h3>
      </div>
    </template>
    
    <script>
    export default {
        name:'User',
    }
    </script>
    
    <style>
    
    </style>
    
  2. 配置路由:index.js

    import Vue from 'vue'
    import User from '../components/User.vue'
    
    //1. 导入插件
    import Router from 'vue-router'
    
    //2. 使用插件
    Vue.use(Router)
    
    //3. 创建路由配置
    const routes = [
      {
        path:'/user',
        component:User
      }
    ];
    
    //4. 传入路由配置,导出路由对象
    export default new Router({
      routes,
      mode:'history',
      linkActiveClass:'active'
    })
    
    
  3. 加入路由到目标组件:Vue.vue

    <template>
      <div id="app">
        <router-link to="/user" replace>用户</router-link>
        <router-view></router-view>
      </div>
    </template>
    
    <script>
    export default {
      name: 'App',
    }
    </script>
    
    <style>
    .active{
      color: rgb(209, 15, 25)
    }
    </style>
    
    
    
  4. 导入组件到入口 : main.js

    import Vue from 'vue'
    import App from './App'
    //只写目录默认会找  index.js
    import router from './router'
    
    Vue.config.productionTip = false
    
    /* eslint-disable no-new */
    new Vue({
      el: '#app',
      router,
      render: h => h(App)
    })
    
    
    
  5. 设置动态路由:index.js

    import Vue from 'vue'
    import User from '../components/User.vue'
    
    //1. 导入插件
    import Router from 'vue-router'
    
    //2. 使用插件
    Vue.use(Router)
    
    //3. 创建路由配置
    const routes = [
      {
        path:'/user/:userName',
        component:User
      }
    ];
    
    //4. 传入路由配置,导出路由对象
    export default new Router({
      routes,
      mode:'history',
      linkActiveClass:'active'
    })
    
  6. 配置页面的url: Vue.vue

    <template>
      <div id="app">
        <router-link v-bind:to="'/user/'+userName" replace>用户</router-link>
        <router-view></router-view>
      </div>
    </template>
    
    <script>
    export default {
      name: 'App',
      data(){
          return {
              userName:'xiaoming'
          }
      }
    }
    </script>
    
    <style>
    .active{
      color: rgb(209, 15, 25)
    }
    </style>
    
    
  7. 获取动态路由中的参数:User.vue

    • $route是当前活跃的路由
    <template>
      <div>
          <h2>个人信心</h2>
          <h3>{{userName}}</h3>
      </div>
    </template>
    
    <script>
    export default {
        name:'User',
        computed:{
            userName(){
                return this.$route.params.userName;
            }
        }
    }
    </script>
    
    <style>
    
    </style>
    
    
02传参

路由配置中props 被设置为 trueroute.params 将会被设置为组件属性。

路由方式

编程式路由

// 字符串
router.push('home')

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

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

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

注意: path和params 不共存params会被忽略,path和query 可以。name和params也可以

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

同样的规则也适用于 router-link 组件的 to 属性

route 、router 、$router 、$route

  • $router:路由组件对象 配置的路由对象
  • $route:当前活跃路由

匹配优先级

有时候,同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:谁先定义的,谁的优先级就最高。

懒加载

  • 如果把所有的js都打包到app中,js将会很大,访问的时候会有等待时间,所以把不同的路由对应的组件分割成不同的代码块,然后当路由被访问的时候加载对应的资源,就更加高效了

    import Vue from 'vue'
    
    //替换成懒加载
    // import Home from '../components/Home.vue'
    // import About from '../components/About.vue'
    // import User from '../components/User.vue'
    
    //懒加载:
    const Home = ()=>import('../components/Home.vue')
    const About = ()=>import('../components/About.vue')
    const User = ()=>import('../components/User.vue')
    
    
    //1. 导入插件
    import Router from 'vue-router'
    
    //2. 使用插件
    Vue.use(Router)
    
    //3. 创建路由配置
    const routes = [
      {
        path:'/',
        redirect:'/home'
      },
      {
        path: '/home',
        name: 'Home',
        component: Home
      },
      {
        path:'/about',
        name:'About',
        component:About
      },
      {
        path:'/user/:userName',
        component:User
      }
    ];
    
    //4. 传入路由配置,导出路由对象
    export default new Router({
      routes,
      mode:'history',
      linkActiveClass:'active'
    })
    
    

子路由

index.js
import Vue from 'vue'

//替换成懒加载
// import Home from '../components/Home.vue'
// import About from '../components/About.vue'
// import User from '../components/User.vue'

//懒加载:
const Home = () => import('../components/Home.vue')
const About = () => import('../components/About.vue')
const User = () => import('../components/User.vue')
const HomeChild = () => import ('../components/HomeChild.vue')


//1. 导入插件
import Router from 'vue-router'

//2. 使用插件
Vue.use(Router)

//3. 创建路由配置
const routes = [
  {
    path: '/',
    redirect: '/home'
  },
  {
    path: '/home',
    name: 'Home',
    component: Home,
    children: [
      {
        path: '',
        // redirect:'child'
      },
      {
        //这里不能同/开头,会自动加上
        path: 'child',
        name: 'HomeChild',
        component: HomeChild
      }]
  },
  {
    path: '/about',
    name: 'About',
    component: About
  },
  {
    path: '/user/:userName',
    component: User
  }
];

//4. 传入路由配置,导出路由对象
export default new Router({
  routes,
  mode: 'history',
  linkActiveClass: 'active'
})

Home.vue
<template>
  <div>
      <h2>首页11</h2>
      <router-link to="/home/child">child</router-link>
      <router-view></router-view>
  </div>
</template>

<script>
export default {
    name:'Home'
}
</script>

<style>

</style>


传参到另一个组件

profile.vue
<template>
  <div><span>个人档案</span>
    <span>{{$route.query}}</span><br>
    <span>query.name: {{$route.query.name}}</span>

  </div>
</template>

<script>
  export default {
    name: "Profile"
  }
</script>

<style scoped>

</style>

配置路由:index.js
const Profile = () => import('../components/Profile') 

{
    path: '/profile',
    component: Profile
  }
显示位置的路由传参
<template>
  <div id="app">
    <router-link to="/home" tag='button' replace >首页</router-link>
    <router-link to="/about" replace>详情</router-link>
    <router-link :to="'/user/'+userName" replace>用户</router-link>
    <router-link :to="{path:'/profile',query:{name:'lisa',age:18},fragment:'4d5as46s'}" replace>档案</router-link>

    <!-- <button @click="homeClick">首页</button>
    <button @click="aboutClick">详细</button> -->
    <router-view></router-view>
  </div>
</template>

为什么这样传参:

  • 符合url的规范:

  • 所以可以用query对象传参

导航守卫

注意导航守卫并没有应用在跳转(redirect)路由上,而仅仅应用在其目标上。为redirect的路由添加一个 beforeEachbeforeLeave 守卫并不会有任何效果

全局守卫

所有的路由都会被过滤,也可以在特定的组件内创建局部守卫

  • 主要监听页面的跳转

  • from从哪个组件来的

  • to去跳转到哪个组件

  • next()

    • next(false)中断路由
    • next(path)跳转到哪个页面,可用来做一些条件判断的跳转,比如login
    • 其他的用的时候查官网
    import Vue from 'vue'
    
    //替换成懒加载
    // import Home from '../components/Home.vue'
    // import About from '../components/About.vue'
    // import User from '../components/User.vue'
    
    //懒加载:
    const Home = () => import('../components/Home.vue')
    const About = () => import('../components/About.vue')
    const User = () => import('../components/User.vue')
    const HomeChild = () => import('../components/HomeChild.vue')
    const Profile = () => import('../components/Profile')
    
    
    //1. 导入插件
    import Router from 'vue-router'
    
    //2. 使用插件
    Vue.use(Router)
    
    //3. 创建路由配置
    const routes = [
      {
        path: '/',
        redirect: '/home'
      },
      {
        path: '/home',
        name: 'Home',
        component: Home,
        meta: {
          title: '首页'
        },
        children: [
          {
            path: '',
            // redirect:'child'
          },
          {
            //这里不能同/开头,会自动加上
            path: 'child',
            name: 'HomeChild',
            component: HomeChild,
          }]
      },
      {
        path: '/about',
        name: 'About',
        component: About,
        meta: {
          title: '详情'
        },
      },
      {
        path: '/user/:userName',
        component: User,
        meta: {
          title: '用户'
        },
      },
      {
        path: '/profile',
        component: Profile,
        meta: {
          title: '档案'
        },
      }
    ];
    const router = new Router({
      routes,
      mode: 'history',
      linkActiveClass: 'active'
    })
    
    router.beforeEach((to, from, next) => {
      next()
      //匹配path中的meta对象的title
      document.title = to.matched[0].meta.title
      console.log(to);
      // console.log(from);
      // console.log("next: "+next);
    })
    
    //4. 传入路由配置,导出路由对象
    export default router
    
    
独享守卫
import Vue from 'vue'

//懒加载:
const Home = () => import('../components/Home.vue')

//1. 导入插件
import Router from 'vue-router'

//2. 使用插件
Vue.use(Router)

//3. 创建路由配置
const routes = [
  {
    path: '/',
    redirect: '/home'
  },
  {
    path: '/home',
    name: 'Home',
    component: Home,
    meta: {
      title: '首页'
    },
    children: [
      {
        path: '',
        // redirect:'child'
      },
      {
        //这里不能同/开头,会自动加上
        path: 'child',
        name: 'HomeChild',
        component: HomeChild,
        beforeEnter: (to, from, next) => {
          console.log("独享守卫");
            next()
        }
      }]
  }
];
const router = new Router({
  routes,
  mode: 'history',
  linkActiveClass: 'active'
})

//4. 传入路由配置,导出路由对象
export default router

前置钩子和后置钩子
  import Vue from 'vue'
  
  //懒加载:
  const Home = () => import('../components/Home.vue')
  
  //1. 导入插件
  import Router from 'vue-router'
  
  //2. 使用插件
  Vue.use(Router)
  
  //3. 创建路由配置
  const routes = [
    {
      path: '/',
      redirect: '/home'
    },
    {
      path: '/home',
      name: 'Home',
      component: Home,
      meta: {
        title: '首页'
      }
    },
    
  ];
  const router = new Router({
    routes,
    mode: 'history',
    linkActiveClass: 'active'
  })
  
  //前置钩子 hook,像filter一样
  router.beforeEach((to, from, next) => {
    next()
    //匹配path中的meta对象的title
    document.title = to.matched[0].meta.title
    console.log(to);
  })
  
  //后置钩子
  router.afterEach((to,from)=>{
    console.log("在跳转之后调用");
  })
  
  //4. 传入路由配置,导出路由对象
  export default router
  

十、打包js的结构图

  • app*.js所有的业务代码
  • mainifest*.js代码转换的依赖的底层支持
  • vendor*.js第三方插件
  • .map文件:项目打包后,代码都是经过压缩加密的,如果运行时报错,输出的错误信息无法准确得知是哪里的代码报错。有了map就可以像未加密的代码一样,准确的输出是哪一行哪一列有错,可以设置:config/index.js productionSourceMap:false

十一、keep-alive组件

  1. 是vue的一个组件:保证一些组件进入缓存不用你每次请求解析资源,提高效率,在显示的地方配置

    <template>
      <div id="app">
        <router-link to="/home" tag="button" replace>首页</router-link>
        <router-link to="/about" replace>详情</router-link>
        <router-link :to="'/user/'+userName" replace>用户</router-link>
        <router-link :to="{path:'/profile',query:{name:'lisa',age:18},fragment:'4d5as46s'}" replace>档案</router-link>
        <button @click="toProfile">档案2</button>
        <!-- <button @click="homeClick">首页</button>
        <button @click="aboutClick">详细</button>-->
        <!-- <router-view></router-view> -->
    
        <!-- 保存到缓存中 -->
        <keep-alive>
          <router-view></router-view>
        </keep-alive>
      </div>
    </template>
    
  2. keep-alive的组件才可以使用activated()、deactivated()

    <template>
      <div>
        <h2>首页11</h2>
        <router-link :to="{path:'/home/child',query:{content:'child1'}}">child</router-link>
        <router-link :to="toChild2">child2</router-link>
        <router-view></router-view>
      </div>
    </template>
    
    <script>
    export default {
      name: "Home",
      data() {
        return {
          toChild2: {
            path: "/home/child2",
            query: {
              content: "child2"
            }
          },
          path: "/home/child",
          query:{
            childContent:'child1'
          }
        };
      },
      methods: {},
      created() {
        console.log("Home组件被创建成功");
      },
      mounted() {
        console.log("组件被挂载成功");
      },
      updated() {
        console.log("组件中发生改变时");
      },
      destroyed() {
        console.log("home destroyed");
      },
      activated() {
        console.log("home 激活");
        this.$router.push(this.path)
      },
      deactivated() {
        console.log("home 离开");
      },
      beforeRouteLeave(to, from, next) {
        console.log('before leave home');
        this.path = this.$route.path;
        console.log(this.path);
        next();
      }
    };
    </script>
    
    <style>
    </style>
    
    
  3. keep-alive 的exclude、include属性

    1. exclude=“componentName,componentName...”,被排除在缓存之外,不能加空格
    <keep-alive exclude="Profile">
          <router-view></router-view>
        </keep-alive>
    
    
    export default {
      name: "Profile",
      created() {
        console.log("profile created");
      },
      destroyed() {
        console.log("profile destroyed");
      }
    };
    

十二、自定义tab-bar

  1. /*style中引用要用@import */

    准备好tabbar.vue,调好样式,预留出来一个插槽,用来放具体的tabbar的item

    <template>
      <div id="tab-bar">
        <slot></slot>
      </div>
    </template>
    
    <script>
    
      export default {
        name: "TabBar",
      }
    </script>
    
    <style scoped>
    
      #tab-bar {
        display: flex;
        background-color: #fdfdff;
    
        /*显示在最下面和屏幕等宽*/
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
    
        /*阴影  fgba(最后是0.1表示透明度)*/
        box-shadow: 0 -1px 1px rgba(100, 100, 100, .1);
      }
    
    </style>
    
    
  2. 封装tab-bar-item

    <template>
      <div class="tab-bar-item" @click="itemClick">
        <div v-if="!isActive">
          <slot name="item-icon"></slot>
        </div>
        <div v-else>
          <slot name="item-icon-active"></slot>
        </div>
        <div :class="{active:isActive}">
          <slot name="item-text"></slot>
        </div>
    
      </div>
    </template>
    
    <script>
      export default {
        name: "TabBarItem",
        props:{
          path:{
            type:String
          }
        },
        data() {
          return {
            // isActive: true
          }
        },
        computed:{
          isActive(){
            return this.$route.path.indexOf(this.path) !== -1
          }
        },
        methods:{
          itemClick(e){
            this.$router.replace(this.path)
          }
        }
      }
    </script>
    
    <style scoped>
    
      .tab-bar-item {
        flex: 1;
        text-align: center;
        /*一般移动端的tabbar都是49px*/
        height: 49px;
        font-size: 14px;
      }
    
      .tab-bar-item img {
         24px;
        height: 24px;
        margin-top: 3px;
        margin-bottom: 2px;
        /*可以去掉图片下面的三个像素*/
        vertical-align: bottom;
      }
    
      .active {
        color: red;
      }
    </style>
    
    
  3. 注册到app.vue中

    <template>
      <div id="app">
        <router-view></router-view>
        <tab-bar>
          <tab-bar-item path="/home">
            <img slot="item-icon" src="./assets/images/tabbar/home.png" alt="首页">
            <img slot="item-icon-active" src="./assets/images/tabbar/home_active.png" alt="">
            <div slot="item-text">首页</div>
          </tab-bar-item>
          <tab-bar-item path="/category">
            <img slot="item-icon" src="./assets/images/tabbar/category.png" alt="">
            <img slot="item-icon-active" src="./assets/images/tabbar/category_active.png" alt="">
            <div slot="item-text">分类</div>
          </tab-bar-item>
          <tab-bar-item path="/cart">
            <img slot="item-icon" src="./assets/images/tabbar/cart.png" alt="">
            <img slot="item-icon-active" src="./assets/images/tabbar/cart_active.png" alt="">
            <div slot="item-text">购物车</div>
          </tab-bar-item>
          <tab-bar-item path="/profile">
            <img slot="item-icon" src="./assets/images/tabbar/profile.png" alt="">
            <img slot="item-icon-active" src="./assets/images/tabbar/profile_active.png" alt="">
            <div slot="item-text">我的</div>
          </tab-bar-item>
        </tab-bar>
      </div>
    </template>
    
    <script>
      import TabBar from "./components/tabbar/TabBar";
      import TabBarItem from "./components/tabbar/TabBarItem";
    
      export default {
        name: 'App',
        components: {
          TabBar,
          TabBarItem
        }
      }
    </script>
    
    <style>
      /*style中引用要用@*/
      @import "./assets/css/base.css";
    </style>
    
    

    可以优化class,颜色直接写死不合适

    还可以从父组件传过来,然后绑定style来设置------------恢复内容开始------------

九、路由 vue-router

详情

一般使用vue的插件都要用Vue.use(插件)

  • 介绍:
    • 互联的网络将信息传输到目标地址的活动
    • 路由器提供两种机制:
      1. 路由:决定数据包从源到目的地的路径
      2. 将输入端的数据转送到合适的输出端
    • 路由表:是一个映射表,决定了数据包的指向
  • 后端路由--前端路由
    • 后端处理url和页面的映射,jsp是后端渲染,到前端的时候页面就确认好了
    • 前端处理url和页面的跳转映射

改编url不刷新页面

  • 改location.hash='aaa';
  • history:
    • 改history.pushState({},'','aaa');类似压栈,history.back()类似弹栈
    • 改history.replaceState({},'','aaa'),不能back()
    • 改history.go(-1) = history.back(),前进或者后退
    • 改history.forword()=history.go(1)
  1. 安装路由:npm install vue-router --save 因为生产也需要路由

  2. 导入:

    • router/index.js
    import Vue from 'vue'
    //1. 导入插件
    import Router from 'vue-router'
    import HelloWorld from '@/components/HelloWorld'
    
    //2. 使用插件
    Vue.use(Router)
    
    //3. 创建路由配置
    const routes = [
      {
        path: '/',
        name: 'HelloWorld',
        component: HelloWorld
      }
    ];
    
    //4. 传入路由配置,导出路由对象
    export default new Router({
      routes
    })
    
    
    • main.js
    import Vue from 'vue'
    import App from './App'
    //只写目录默认会找  index.js
    import router from './router'
    
    Vue.config.productionTip = false
    
    new Vue({
      el: '#app',
      router,
      render: h => h(App)
    })
    
    
  • 替换a标签
<div id="app">
    <router-link to="/home">首页</router-link>
    <!-- 相当于占位符 -->
    <router-view></router-view>
    <router-link to="/about">详情</router-link>
  </div>
  • 常用属性

    • tag 、replace

      <!-- tag设置替换成什么标签 -->
          <!-- replace表示禁用了返回前进按钮,是使用了history.replaceState() -->
          <router-link to="/home" tag='button' replace>首页</router-link>
      
    • 配置默认的active的样式

      .router-link-active{
        color: #f00
      }
      
      
    • 自定义样式:手动一个一个标签的写

      <!--active-class 自定义点击后的样式 -->
          <router-link to="/home" tag='button' replace active-class="active">首页</router-link>
      
    • 配置全局的active-class

    export default new Router({
      routes,
      mode:'history',
      linkActiveClass:'active'
    })
    

默认重定向

const routes = [
  {
    path:'/',
    redirect:'/home'
  },
  {
    path: '/home',
    name: 'Home',
    component: Home
  },
  {
    path:'/about',
    name:'About',
    component:About
  }
];

设置router的默认方式为history

  • 本身默认hash
  • history:url不会显示#号
//4. 传入路由配置,导出路由对象
export default new Router({
  routes,
  mode:'history'
})

手动写路由跳转

  • router会给每个组件传$router
<template>
  <div id="app">
    <button @click="homeClick">首页</button>
    <button @click="aboutClick">详细</button>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'App',
  methods:{
    //router会给每个组件传$router
    homeClick(){
      // this.$router.push('/home');
      this.$router.replace('/home');
    },
    aboutClick(){
      // this.$router.push('/about');
      this.$router.replace('/about');
    }
  }
}
</script>

<style>
#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;
}
</style>

动态路由

01动态路由
  • 需要调用$route.params来获取参数
  1. 创建一个vue组件:User.vue

    <template>
      <div>
          <h2>个人信心</h2>
          <h3></h3>
      </div>
    </template>
    
    <script>
    export default {
        name:'User',
    }
    </script>
    
    <style>
    
    </style>
    
  2. 配置路由:index.js

    import Vue from 'vue'
    import User from '../components/User.vue'
    
    //1. 导入插件
    import Router from 'vue-router'
    
    //2. 使用插件
    Vue.use(Router)
    
    //3. 创建路由配置
    const routes = [
      {
        path:'/user',
        component:User
      }
    ];
    
    //4. 传入路由配置,导出路由对象
    export default new Router({
      routes,
      mode:'history',
      linkActiveClass:'active'
    })
    
    
  3. 加入路由到目标组件:Vue.vue

    <template>
      <div id="app">
        <router-link to="/user" replace>用户</router-link>
        <router-view></router-view>
      </div>
    </template>
    
    <script>
    export default {
      name: 'App',
    }
    </script>
    
    <style>
    .active{
      color: rgb(209, 15, 25)
    }
    </style>
    
    
    
  4. 导入组件到入口 : main.js

    import Vue from 'vue'
    import App from './App'
    //只写目录默认会找  index.js
    import router from './router'
    
    Vue.config.productionTip = false
    
    /* eslint-disable no-new */
    new Vue({
      el: '#app',
      router,
      render: h => h(App)
    })
    
    
    
  5. 设置动态路由:index.js

    import Vue from 'vue'
    import User from '../components/User.vue'
    
    //1. 导入插件
    import Router from 'vue-router'
    
    //2. 使用插件
    Vue.use(Router)
    
    //3. 创建路由配置
    const routes = [
      {
        path:'/user/:userName',
        component:User
      }
    ];
    
    //4. 传入路由配置,导出路由对象
    export default new Router({
      routes,
      mode:'history',
      linkActiveClass:'active'
    })
    
  6. 配置页面的url: Vue.vue

    <template>
      <div id="app">
        <router-link v-bind:to="'/user/'+userName" replace>用户</router-link>
        <router-view></router-view>
      </div>
    </template>
    
    <script>
    export default {
      name: 'App',
      data(){
          return {
              userName:'xiaoming'
          }
      }
    }
    </script>
    
    <style>
    .active{
      color: rgb(209, 15, 25)
    }
    </style>
    
    
  7. 获取动态路由中的参数:User.vue

    • $route是当前活跃的路由
    <template>
      <div>
          <h2>个人信心</h2>
          <h3>{{userName}}</h3>
      </div>
    </template>
    
    <script>
    export default {
        name:'User',
        computed:{
            userName(){
                return this.$route.params.userName;
            }
        }
    }
    </script>
    
    <style>
    
    </style>
    
    
02传参

路由配置中props 被设置为 trueroute.params 将会被设置为组件属性。

路由方式

编程式路由

// 字符串
router.push('home')

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

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

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

注意: path和params 不共存params会被忽略,path和query 可以。name和params也可以

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

同样的规则也适用于 router-link 组件的 to 属性

route 、router 、$router 、$route

  • $router:路由组件对象 配置的路由对象
  • $route:当前活跃路由

匹配优先级

有时候,同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:谁先定义的,谁的优先级就最高。

懒加载

  • 如果把所有的js都打包到app中,js将会很大,访问的时候会有等待时间,所以把不同的路由对应的组件分割成不同的代码块,然后当路由被访问的时候加载对应的资源,就更加高效了

    import Vue from 'vue'
    
    //替换成懒加载
    // import Home from '../components/Home.vue'
    // import About from '../components/About.vue'
    // import User from '../components/User.vue'
    
    //懒加载:
    const Home = ()=>import('../components/Home.vue')
    const About = ()=>import('../components/About.vue')
    const User = ()=>import('../components/User.vue')
    
    
    //1. 导入插件
    import Router from 'vue-router'
    
    //2. 使用插件
    Vue.use(Router)
    
    //3. 创建路由配置
    const routes = [
      {
        path:'/',
        redirect:'/home'
      },
      {
        path: '/home',
        name: 'Home',
        component: Home
      },
      {
        path:'/about',
        name:'About',
        component:About
      },
      {
        path:'/user/:userName',
        component:User
      }
    ];
    
    //4. 传入路由配置,导出路由对象
    export default new Router({
      routes,
      mode:'history',
      linkActiveClass:'active'
    })
    
    

子路由

index.js
import Vue from 'vue'

//替换成懒加载
// import Home from '../components/Home.vue'
// import About from '../components/About.vue'
// import User from '../components/User.vue'

//懒加载:
const Home = () => import('../components/Home.vue')
const About = () => import('../components/About.vue')
const User = () => import('../components/User.vue')
const HomeChild = () => import ('../components/HomeChild.vue')


//1. 导入插件
import Router from 'vue-router'

//2. 使用插件
Vue.use(Router)

//3. 创建路由配置
const routes = [
  {
    path: '/',
    redirect: '/home'
  },
  {
    path: '/home',
    name: 'Home',
    component: Home,
    children: [
      {
        path: '',
        // redirect:'child'
      },
      {
        //这里不能同/开头,会自动加上
        path: 'child',
        name: 'HomeChild',
        component: HomeChild
      }]
  },
  {
    path: '/about',
    name: 'About',
    component: About
  },
  {
    path: '/user/:userName',
    component: User
  }
];

//4. 传入路由配置,导出路由对象
export default new Router({
  routes,
  mode: 'history',
  linkActiveClass: 'active'
})

Home.vue
<template>
  <div>
      <h2>首页11</h2>
      <router-link to="/home/child">child</router-link>
      <router-view></router-view>
  </div>
</template>

<script>
export default {
    name:'Home'
}
</script>

<style>

</style>


传参到另一个组件

profile.vue
<template>
  <div><span>个人档案</span>
    <span>{{$route.query}}</span><br>
    <span>query.name: {{$route.query.name}}</span>

  </div>
</template>

<script>
  export default {
    name: "Profile"
  }
</script>

<style scoped>

</style>

配置路由:index.js
const Profile = () => import('../components/Profile') 

{
    path: '/profile',
    component: Profile
  }
显示位置的路由传参
<template>
  <div id="app">
    <router-link to="/home" tag='button' replace >首页</router-link>
    <router-link to="/about" replace>详情</router-link>
    <router-link :to="'/user/'+userName" replace>用户</router-link>
    <router-link :to="{path:'/profile',query:{name:'lisa',age:18},fragment:'4d5as46s'}" replace>档案</router-link>

    <!-- <button @click="homeClick">首页</button>
    <button @click="aboutClick">详细</button> -->
    <router-view></router-view>
  </div>
</template>

为什么这样传参:

  • 符合url的规范:

  • 所以可以用query对象传参

导航守卫

注意导航守卫并没有应用在跳转(redirect)路由上,而仅仅应用在其目标上。为redirect的路由添加一个 beforeEachbeforeLeave 守卫并不会有任何效果

全局守卫

所有的路由都会被过滤,也可以在特定的组件内创建局部守卫

  • 主要监听页面的跳转

  • from从哪个组件来的

  • to去跳转到哪个组件

  • next()

    • next(false)中断路由
    • next(path)跳转到哪个页面,可用来做一些条件判断的跳转,比如login
    • 其他的用的时候查官网
    import Vue from 'vue'
    
    //替换成懒加载
    // import Home from '../components/Home.vue'
    // import About from '../components/About.vue'
    // import User from '../components/User.vue'
    
    //懒加载:
    const Home = () => import('../components/Home.vue')
    const About = () => import('../components/About.vue')
    const User = () => import('../components/User.vue')
    const HomeChild = () => import('../components/HomeChild.vue')
    const Profile = () => import('../components/Profile')
    
    
    //1. 导入插件
    import Router from 'vue-router'
    
    //2. 使用插件
    Vue.use(Router)
    
    //3. 创建路由配置
    const routes = [
      {
        path: '/',
        redirect: '/home'
      },
      {
        path: '/home',
        name: 'Home',
        component: Home,
        meta: {
          title: '首页'
        },
        children: [
          {
            path: '',
            // redirect:'child'
          },
          {
            //这里不能同/开头,会自动加上
            path: 'child',
            name: 'HomeChild',
            component: HomeChild,
          }]
      },
      {
        path: '/about',
        name: 'About',
        component: About,
        meta: {
          title: '详情'
        },
      },
      {
        path: '/user/:userName',
        component: User,
        meta: {
          title: '用户'
        },
      },
      {
        path: '/profile',
        component: Profile,
        meta: {
          title: '档案'
        },
      }
    ];
    const router = new Router({
      routes,
      mode: 'history',
      linkActiveClass: 'active'
    })
    
    router.beforeEach((to, from, next) => {
      next()
      //匹配path中的meta对象的title
      document.title = to.matched[0].meta.title
      console.log(to);
      // console.log(from);
      // console.log("next: "+next);
    })
    
    //4. 传入路由配置,导出路由对象
    export default router
    
    
独享守卫
import Vue from 'vue'

//懒加载:
const Home = () => import('../components/Home.vue')

//1. 导入插件
import Router from 'vue-router'

//2. 使用插件
Vue.use(Router)

//3. 创建路由配置
const routes = [
  {
    path: '/',
    redirect: '/home'
  },
  {
    path: '/home',
    name: 'Home',
    component: Home,
    meta: {
      title: '首页'
    },
    children: [
      {
        path: '',
        // redirect:'child'
      },
      {
        //这里不能同/开头,会自动加上
        path: 'child',
        name: 'HomeChild',
        component: HomeChild,
        beforeEnter: (to, from, next) => {
          console.log("独享守卫");
            next()
        }
      }]
  }
];
const router = new Router({
  routes,
  mode: 'history',
  linkActiveClass: 'active'
})

//4. 传入路由配置,导出路由对象
export default router

前置钩子和后置钩子
  import Vue from 'vue'
  
  //懒加载:
  const Home = () => import('../components/Home.vue')
  
  //1. 导入插件
  import Router from 'vue-router'
  
  //2. 使用插件
  Vue.use(Router)
  
  //3. 创建路由配置
  const routes = [
    {
      path: '/',
      redirect: '/home'
    },
    {
      path: '/home',
      name: 'Home',
      component: Home,
      meta: {
        title: '首页'
      }
    },
    
  ];
  const router = new Router({
    routes,
    mode: 'history',
    linkActiveClass: 'active'
  })
  
  //前置钩子 hook,像filter一样
  router.beforeEach((to, from, next) => {
    next()
    //匹配path中的meta对象的title
    document.title = to.matched[0].meta.title
    console.log(to);
  })
  
  //后置钩子
  router.afterEach((to,from)=>{
    console.log("在跳转之后调用");
  })
  
  //4. 传入路由配置,导出路由对象
  export default router
  

十、打包js的结构图

  • app*.js所有的业务代码
  • mainifest*.js代码转换的依赖的底层支持
  • vendor*.js第三方插件
  • .map文件:项目打包后,代码都是经过压缩加密的,如果运行时报错,输出的错误信息无法准确得知是哪里的代码报错。有了map就可以像未加密的代码一样,准确的输出是哪一行哪一列有错,可以设置:config/index.js productionSourceMap:false

十一、keep-alive组件

  1. 是vue的一个组件:保证一些组件进入缓存不用你每次请求解析资源,提高效率,在显示的地方配置

    <template>
      <div id="app">
        <router-link to="/home" tag="button" replace>首页</router-link>
        <router-link to="/about" replace>详情</router-link>
        <router-link :to="'/user/'+userName" replace>用户</router-link>
        <router-link :to="{path:'/profile',query:{name:'lisa',age:18},fragment:'4d5as46s'}" replace>档案</router-link>
        <button @click="toProfile">档案2</button>
        <!-- <button @click="homeClick">首页</button>
        <button @click="aboutClick">详细</button>-->
        <!-- <router-view></router-view> -->
    
        <!-- 保存到缓存中 -->
        <keep-alive>
          <router-view></router-view>
        </keep-alive>
      </div>
    </template>
    
  2. keep-alive的组件才可以使用activated()、deactivated()

    <template>
      <div>
        <h2>首页11</h2>
        <router-link :to="{path:'/home/child',query:{content:'child1'}}">child</router-link>
        <router-link :to="toChild2">child2</router-link>
        <router-view></router-view>
      </div>
    </template>
    
    <script>
    export default {
      name: "Home",
      data() {
        return {
          toChild2: {
            path: "/home/child2",
            query: {
              content: "child2"
            }
          },
          path: "/home/child",
          query:{
            childContent:'child1'
          }
        };
      },
      methods: {},
      created() {
        console.log("Home组件被创建成功");
      },
      mounted() {
        console.log("组件被挂载成功");
      },
      updated() {
        console.log("组件中发生改变时");
      },
      destroyed() {
        console.log("home destroyed");
      },
      activated() {
        console.log("home 激活");
        this.$router.push(this.path)
      },
      deactivated() {
        console.log("home 离开");
      },
      beforeRouteLeave(to, from, next) {
        console.log('before leave home');
        this.path = this.$route.path;
        console.log(this.path);
        next();
      }
    };
    </script>
    
    <style>
    </style>
    
    
  3. keep-alive 的exclude、include属性

    1. exclude=“componentName,componentName...”,被排除在缓存之外,不能加空格
    <keep-alive exclude="Profile">
          <router-view></router-view>
        </keep-alive>
    
    
    export default {
      name: "Profile",
      created() {
        console.log("profile created");
      },
      destroyed() {
        console.log("profile destroyed");
      }
    };
    

十二、自定义tab-bar

  1. /*style中引用要用@import */

    准备好tabbar.vue,调好样式,预留出来一个插槽,用来放具体的tabbar的item

    <template>
      <div id="tab-bar">
        <slot></slot>
      </div>
    </template>
    
    <script>
    
      export default {
        name: "TabBar",
      }
    </script>
    
    <style scoped>
    
      #tab-bar {
        display: flex;
        background-color: #fdfdff;
    
        /*显示在最下面和屏幕等宽*/
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
    
        /*阴影  fgba(最后是0.1表示透明度)*/
        box-shadow: 0 -1px 1px rgba(100, 100, 100, .1);
      }
    
    </style>
    
    
  2. 封装tab-bar-item

    <template>
      <div class="tab-bar-item" @click="itemClick">
        <div v-if="!isActive">
          <slot name="item-icon"></slot>
        </div>
        <div v-else>
          <slot name="item-icon-active"></slot>
        </div>
        <div :class="{active:isActive}">
          <slot name="item-text"></slot>
        </div>
    
      </div>
    </template>
    
    <script>
      export default {
        name: "TabBarItem",
        props:{
          path:{
            type:String
          }
        },
        data() {
          return {
            // isActive: true
          }
        },
        computed:{
          isActive(){
            return this.$route.path.indexOf(this.path) !== -1
          }
        },
        methods:{
          itemClick(e){
            this.$router.replace(this.path)
          }
        }
      }
    </script>
    
    <style scoped>
    
      .tab-bar-item {
        flex: 1;
        text-align: center;
        /*一般移动端的tabbar都是49px*/
        height: 49px;
        font-size: 14px;
      }
    
      .tab-bar-item img {
         24px;
        height: 24px;
        margin-top: 3px;
        margin-bottom: 2px;
        /*可以去掉图片下面的三个像素*/
        vertical-align: bottom;
      }
    
      .active {
        color: red;
      }
    </style>
    
    
  3. 注册到app.vue中

    <template>
      <div id="app">
        <router-view></router-view>
        <tab-bar>
          <tab-bar-item path="/home">
            <img slot="item-icon" src="./assets/images/tabbar/home.png" alt="首页">
            <img slot="item-icon-active" src="./assets/images/tabbar/home_active.png" alt="">
            <div slot="item-text">首页</div>
          </tab-bar-item>
          <tab-bar-item path="/category">
            <img slot="item-icon" src="./assets/images/tabbar/category.png" alt="">
            <img slot="item-icon-active" src="./assets/images/tabbar/category_active.png" alt="">
            <div slot="item-text">分类</div>
          </tab-bar-item>
          <tab-bar-item path="/cart">
            <img slot="item-icon" src="./assets/images/tabbar/cart.png" alt="">
            <img slot="item-icon-active" src="./assets/images/tabbar/cart_active.png" alt="">
            <div slot="item-text">购物车</div>
          </tab-bar-item>
          <tab-bar-item path="/profile">
            <img slot="item-icon" src="./assets/images/tabbar/profile.png" alt="">
            <img slot="item-icon-active" src="./assets/images/tabbar/profile_active.png" alt="">
            <div slot="item-text">我的</div>
          </tab-bar-item>
        </tab-bar>
      </div>
    </template>
    
    <script>
      import TabBar from "./components/tabbar/TabBar";
      import TabBarItem from "./components/tabbar/TabBarItem";
    
      export default {
        name: 'App',
        components: {
          TabBar,
          TabBarItem
        }
      }
    </script>
    
    <style>
      /*style中引用要用@*/
      @import "./assets/css/base.css";
    </style>
    
    

    可以优化class,颜色直接写死不合适

    还可以从父组件传过来,然后绑定style来设置
    ------------恢复内容结束------------

原文地址:https://www.cnblogs.com/zpyu521/p/12394544.html