九、路由 vue-router
一般使用vue的插件都要用Vue.use(插件)
- 介绍:
- 互联的网络将信息传输到目标地址的活动
- 路由器提供两种机制:
- 路由:决定数据包从源到目的地的路径
- 将输入端的数据转送到合适的输出端
- 路由表:是一个映射表,决定了数据包的指向
- 后端路由--前端路由
- 后端处理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)
-
安装路由:npm install vue-router --save 因为生产也需要路由
-
导入:
- 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) })
router-link
- 替换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来获取参数
-
创建一个vue组件:User.vue
<template> <div> <h2>个人信心</h2> <h3></h3> </div> </template> <script> export default { name:'User', } </script> <style> </style>
-
配置路由: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' })
-
加入路由到目标组件: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>
-
导入组件到入口 : 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) })
-
设置动态路由: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' })
-
配置页面的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>
-
获取动态路由中的参数: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
被设置为 true
,route.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的路由添加一个 beforeEach
或 beforeLeave
守卫并不会有任何效果
全局守卫
所有的路由都会被过滤,也可以在特定的组件内创建局部守卫
-
主要监听页面的跳转
-
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组件
-
是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>
-
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>
-
keep-alive 的exclude、include属性
- 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
-
/*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>
-
封装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>
-
注册到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(插件)
- 介绍:
- 互联的网络将信息传输到目标地址的活动
- 路由器提供两种机制:
- 路由:决定数据包从源到目的地的路径
- 将输入端的数据转送到合适的输出端
- 路由表:是一个映射表,决定了数据包的指向
- 后端路由--前端路由
- 后端处理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)
-
安装路由:npm install vue-router --save 因为生产也需要路由
-
导入:
- 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) })
router-link
- 替换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来获取参数
-
创建一个vue组件:User.vue
<template> <div> <h2>个人信心</h2> <h3></h3> </div> </template> <script> export default { name:'User', } </script> <style> </style>
-
配置路由: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' })
-
加入路由到目标组件: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>
-
导入组件到入口 : 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) })
-
设置动态路由: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' })
-
配置页面的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>
-
获取动态路由中的参数: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
被设置为 true
,route.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的路由添加一个 beforeEach
或 beforeLeave
守卫并不会有任何效果
全局守卫
所有的路由都会被过滤,也可以在特定的组件内创建局部守卫
-
主要监听页面的跳转
-
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组件
-
是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>
-
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>
-
keep-alive 的exclude、include属性
- 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
-
/*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>
-
封装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>
-
注册到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来设置
------------恢复内容结束------------