1.路由的概念
- 路由的本质,就是一种对应关系;
在url地址中,输入要访问的地址,浏览器去请求,地址对应的资源;那么url地址,和真实的资源之间,就有一种对应关系,这就是路由; - 后端路由:服务器端,根据不同的 URL请求,返回不同的内容;
本质:URL请求地址,与服务器资源,之间的对应关系;后端路由性能较低; - 前端路由:依靠 hash值 (锚链接) 的变化,实现的;根据不同的用户事件,通过事件函数,显示不同的内容;比如:点击页面中的菜单或按钮,改变URL的hash值,根据 hash值的变化,来控制组件的切换;
本质:用户事件与事件处理函数,之间的对应关系;
2.简易前端路由 切换tab栏
- 点击超链接时,改变url地址中的 hash值,hash值改变,就会触发 onhashchange事件;
根据 hash值,让不同的组件,进行显示;
//动态绑定 :is属性,把指定的组件,渲染到 component标签 所在的位置;
<component :is="comName"></component> //component标签,可当做【组件的占位符】
//window 的 onhashchange事件,监听 hash值的变化;
window.onhashchange = function(){
//location.hash 可获取到最新的 hash值
console.log(location.hash); // '#/keji'
location.hash.slice(1) //从第二个字符串开始切割;去掉前面的'#'号
........
}
// 手动形式,实现简易前端路由(实际开发中,使用Vue Router,管理vue项目中的路由,而不是自己写路由)
3.Vue Router简介
Vue Router:Vue.js 官方提供的,路由管理器;它依赖于Vue,所以需要先引入Vue.js,再引入Vue Router;
支持H5历史模式,或hash模式
支持嵌套路由
支持路由参数
支持编程式路由
支持命名路由
支持路由导航守卫
支持路由过渡动画
支持路由懒加载
支持路由滚动行为
4.Vue Router 使用步骤
//1.先引入Vue.js,再引入Vue-router.js
<script src="./lib/vue_2.5.22.js"></script>
<script src="./lib/vue-router_3.0.2.js"></script>
/*2.添加路由链接: router-link 是vue 中提供的标签,默认会被渲染为 a标签
to 属性会被渲染为 href属性;to属性的值,会被渲染为'#'开头的 hash地址*/
<router-link to="/user">User</router-link>
<router-link to="/register">Register</router-link>
//3.添加路由占位符: 将通过路由规则,匹配到的组件,渲染到 router-view 所在的位置
<router-view></router-view>
<script>
//4.定义路由组件
const User = {}
const Register = {}
//5.创建路由实例,并配置路由规则
const router = new VueRouter({ //创建路由实例对象
// routes:[] 路由规则数组,每个路由规则,都是一个配置对象;
routes: [
{path: '/', redirect: '/user'}, //路由重定向
{path: '/user', component: User},
{path: '/register', component: Register}
]
})
/*path: hash地址;component: 对应的组件;
路由重定向: 通过 redirect属性,指定一个新的路由地址,用户在访问,地址A时,强制跳转到地址C;
{path:'/', redirect: '/user'} //path 原路径,redirect重定向,到的新地址;*/
const vm = new Vue({
el: '#app',
data: {},
// 6.把路由对象,挂载到 vue根实例中
router: router
//router 属性名 属性值一样,es6简写
})
</script>
5. 嵌套路由
<div id='app'>
<router-view></router-view>
</div>
//Login组件模板里,包含了子路由链接,及子路由占位符;
const Login = {
template: `
<div>
<h1>Login 组件</h1>
<!-- 子路由链接 -->
<router-link to="/account">密码登录</router-link>
<router-link to="/phone">扫码登录</router-link>
<!-- 子路由占位符:子组件会在router-view中显示 -->
<router-view></router-view>
</div>`
}
//子级路由组件
const account = { };
const phone = { };
const myrouter = new VueRouter({
routes: [
//children[]数组,表示子路由规则;会在父组件的<router-view/>位置渲染
{ path: "/login", component: Login, children:[
{ path: "/account", component: account },
{ path: "/phone", component: phone },
]}
]
})
var vm = new Vue({
......
router:myrouter
});
6. 动态路由匹配
<div id="app">
<router-link to="/user/1">User1</router-link>
<router-link to="/user/2">User2</router-link>
<router-link to="/user/3">User3</router-link>
<router-view></router-view>
</div>
----------------------------------------------------------------
const User = {
//组件中,通过$route.params,获取传过来的参数
template: '<h1>用户id为: {{$route.params.id}}</h1>'
}
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User }
//动态路径参数,以':参数名'的形式,传递参数;User组件中,可以访问到,匹配到的id值
]
})
// 路由组件传递参数:props为布尔值
const User = {
props:["id"], //通过props接收路由传参
template:"<div> 用户id为: {{id}} </div>"
}
routes: [
{ path: '/user/:id', component: User, props: true }
//props:true 开启props传参,route.params将会被设置为组件属性
]
// bug --> props为静态数据对象,不能传递动态参数
const User = {
props: ['id', 'uname', 'age'],
template: '<h1>用户id为: {{id}} -- 姓名为:{{uname}} -- 年龄为:{{age}}</h1>'
# 此时id获取不到
}
routes: [ # 此时id不能用;props对象里有什么数据,组件中才能接收到什么数据
{ path: '/user/:id', component: User, props:{uname:'lisi', age:12} }
]
// props为函数类型
const User = {
props: ['id', 'uname', 'age'],
template: '<h1>用户id为: {{id}} -- 姓名为:{{uname}} -- 年龄为:{{age}}</h1>'
}
routes: [
{ path: '/user/:id', component: User,props: route => ({ uname: 'zs', age: 20, id: route.params.id }) }
]
//route对象,是路由中的动态参数对象,'/:id'有几个参数项,route中就有几个参数值;
//props 是一个函数,接收 route对象,为形参;获取路由对象,并通过路由对象的 params属性,获取传递的参数;
// props:(route)=>{
// return {username:"zs", age:20, id:route.params.id}
// }
7. 命名路由
//命名路由:通过 name属性,给路由规则,添加一个别名;更方便的,表示路由的路径;
{ path: "/user/:id", name: "user", component: User }
<router-link to="/user">User</router-link>
<router-link :to="{ name:'user', params: {id:123} }">User</router-link>
//添加别名后,可使用命名路由,跳转页面;还可以使用 params属性,传递参数
//:to 动态绑定跳转路径,params属性id,必须和 path:"/user/:id名" 保持一致
8. 编程式导航
页面导航的两种方式:
1.声明式导航:通过点击链接,实现导航;<a></a>、<router-link></router-link>
2.编程式导航:通过调用js的,API方法,实现导航;网页中的 location.href实现跳转
vue中常用的编程式导航 API :
this.$router.push('hash地址')
this.$router.go(n) // 1前进一步;-1后退一步;
const User = {
template:`<button @click="goRegister">跳转到注册页面</button>`,
methods: {
goRegister() {
this.$router.push('/register') //路由规则里的'path路径'
}
}
},
const Register = {
template: `<button @click="goBack">后退</button>`,
methods: {
goBack() {
this.$router.go(-1)
}
}
}
-------------------------------------------------------------------
//router.push() 方法的参数规则:
router.push('/home') // 字符串(路径名称)
router.push({ path: '/home' }) // 对象
router.push({ name: 'user', params: { id: 123 }}) //命名路由(传递参数)
router.push({ path: '/register', query: { uname: 'lisi' }})
//带查询参数,变成 /register?uname=lisi
9. 后台管理案例
1) 抽离APP根组件
<script src="./lib/vue_2.5.22.js"></script>
<script src="./lib/vue-router_3.0.2.js"></script>
<div id="app">
//路由占位符
<router-view></router-view>
</div>
<script>
//定义APP根组件
const APP = {}
//创建路由实例对象
const router = new VueRouter({
routes: [
{path: '/', component: APP}
]
})
const vm = new Vue({
el: '#app',
router //把路由对象挂载到 vue 根实例中
})
</script>
//通过组件的形式,展示页面的主体内容,而不是写死页面结构,可以定义一个根组件;
2) 创建左侧菜单
//将左侧菜单,改造为<router-link>路由链接;右侧主体区域,添加路由占位符;
const App = {
template: `
<div>
<!-- 头部区域 -->
<header class="header">后台管理系统</header>
<!--中间主体区域 -->
<div class="main">
<div class="content left"> //左侧菜单栏
<ul> //<li>用户管理</li> <li>权限管理</li> ... ...
<li><router-link to="/users">用户管理</router-link></li>
<li><router-link to="/rights">权限管理</router-link></li>
<li><router-link to="/goods">商品管理</router-link></li>
<li><router-link to="/orders">订单管理</router-link></li>
<li><router-link to="/settings">系统设置</router-link></li>
</ul>
</div>
// 右侧内容区域
<div class="content right"><div class="main-content">
<router-view />
</div></div>
</div>
<!-- 尾部区域 -->
<footer class="footer">版权信息</footer>
</div>`
}
3) 添加子路由规则
const router = new VueRouter({
routes: [
{ path: '/', component: App, redirect: '/users', children: [
{ path: '/users', component: Users },
{ path: '/userinfo/:id', component: UserInfo, props: true },
{ path: '/rights', component: Rights },
{ path: '/goods', component: Goods },
{ path: '/orders', component: Orders },
{ path: '/settings', component: Settings }
]}
]
})
/*先展示App根组件,再重定向到users子路由;在App组件的<router-view/>位置,渲染默认的子路由users;
*如果users不是子路由,则在App组件,外部的<router-view/>位置渲染,直接替换掉App组件;
4) 渲染用户列表管理区域
const Users = {
data() {
return {
userlist: [
{ id: 1, name: '张三', age: 10 },
{ id: 2, name: '李四', age: 20 },
{ id: 3, name: '王五', age: 30 },
{ id: 4, name: '赵六', age: 40 }
]
}
},
template: `<div>
<h3>用户管理区域</h3>
<table>
<thead>
<tr><th>编号</th><th>姓名</th><th>年龄</th><th>操作</th></tr>
</thead>
<tbody>
<tr v-for="item in userlist" :key="item.id">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.age}}</td>
<td> //编程式导航
<a href="javascript:;" @click="goDetail(item.id)">详情</a>
</td>
</tr>
</tbody>
</table>
</div>`,
methods: {
//把跳转的id传过来
goDetail(id) {
this.$router.push('/userinfo/' + id) //编程式导航传参
}
}//跳转路径中,包含动态参数id;路由规则中,把id的位置,标记为动态参数'/userinfo/:id'
}
//用户详情页组件
const UserInfo = {
props: ['id'],
template: `<div>
<h5>用户详情页 --- 用户Id为:{{id}}</h5>
<button @click="goback()">后退</button>
</div>`,
methods: {
goback() {
this.$router.go(-1)
}
}
}
//添加'/userinfo/:id'详情页,路由规则;
routes: [
{ path: '/', component: App, redirect: '/users', children: [
{ path: '/users', component: Users },
{ path: '/userinfo/:id', component: UserInfo, props: true },
...... //用户详情页获取传过来的id值,props: true;通过props 接收路由,传过来的参数
]}
]