一. 路由的概念与原理
路由的实质就是一种 对应关系 ,比方咱们在 url 地址中输出咱们要拜访的 url 地址之后,浏览器要去申请这个 url 地址对应的资源。
那么 url 地址和实在的资源之间就有一种对应的关系,就是路由。
路由分为 前端路由 和后端路由
1.1 后端路由
后端路由是依据不同的用户 URL 申请,返回不同的内容,实质就是 URL 申请地址与服务器资源之间的对应关系。
由服务器端进行实现,并实现资源的散发。
1.2 前端路由
前端路由依附 hash 值 (锚链接) 的变动进行实现。
后端路由性能绝对前端路由来说较低,所以,咱们接下来次要学习的是前端路由。
基本概念:依据不同的事件来显示不同的页面内容,即 用户事件 与事件处理函数 之间的对应关系。
前端路由次要做的事件就是监听事件并散发执行事件处理函数。
1.3 SPA(Single Page Application)
- 后端渲染(存在性能问题)
- Ajax 前端渲染(前端渲染进步性能,然而不反对浏览器的后退操作)
- SPA 单页面应用程序:整个网站只有一个页面,内容的变动通过 Ajax 部分更新实现,同时反对浏览器地址栏的后退和后退操作
- SPA 的实现原理之一:基于 URL 地址的 hash(hash 的变动会导致浏览器拜访历史记录的变动,但 hash 的变动不会触发新的 URL 申请)
- 在实现 SPA 的过程中,最外围的技术点就是前端路由
二、前端路由的初体验
前端路由是基于 hash 值的变动进行实现的(比方点击页面中的菜单或者按钮扭转 URL 的 hash 值,依据 hash 值的变动来管制组件的切换)
外围实现依附一个事件,即监听 hash 值变动的事件
window.onhashchange = function(){
//location.hash 能够获取到最新的 hash 值
location.hash
}
前端路由实现 tab 栏切换:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<!-- 导入 vue 文件 -->
<script src="./lib/vue_2.5.22.js"></script>
</head>
<body>
<!-- 被 vue 实例管制的 div 区域 -->
<div id="app">
<!-- 切换组件的超链接 -->
<a href="#/zhuye"> 主页 </a>
<a href="#/keji"> 科技 </a>
<a href="#/caijing"> 财经 </a>
<a href="#/yule"> 娱乐 </a>
<!-- 依据 :is 属性指定的组件名称,把对应的组件渲染到 component 标签所在的地位 -->
<!-- 能够把 component 标签当做是【组件的占位符】-->
<component :is="comName"></component>
</div>
<script>
// #region 定义须要被切换的 4 个组件
// 主页组件
const zhuye = {template: '<h1> 主页信息 </h1>'}
// 科技组件
const keji = {template: '<h1> 科技信息 </h1>'}
// 财经组件
const caijing = {template: '<h1> 财经信息 </h1>'}
// 娱乐组件
const yule = {template: '<h1> 娱乐信息 </h1>'}
// #endregion
// #region vue 实例对象
const vm = new Vue({
el: '#app',
data: {comName: 'zhuye'},
// 注册公有组件
components: {
zhuye,
keji,
caijing,
yule
}
})
// #endregion
// 监听 window 的 onhashchange 事件,依据获取到的最新的 hash 值,切换要显示的组件的名称
window.onhashchange = function() {
// 通过 location.hash 获取到最新的 hash 值
console.log(location.hash); // #/zhuye
vm.comName = location.hash.slice(2)
}
</script>
</body>
</html>
案例效果图:
点击每个超链接之后,会进行相应的内容切换,如下:
外围思路:
在页面中有一个 vue 实例对象,vue 实例对象中有四个组件,别离是 tab 栏切换须要显示的组件内容
在页面中有四个超链接,如下:
<a href="#/zhuye"> 主页 </a>
<a href="#/keji"> 科技 </a>
<a href="#/caijing"> 财经 </a>
<a href="#/yule"> 娱乐 </a>
当咱们点击这些超链接的时候,就会扭转 url 地址中的 hash 值,当 hash 值被扭转时,就会触发 onhashchange 事件,而后失去以后 hash 值,依据这个 hash 值来让不同的组件进行显示。
三、Vue Router 简介
它是一个 Vue.js 官网提供的 路由管理器。是一个性能更加弱小的前端路由器,举荐应用。
Vue Router 和 Vue.js 的外围深度集成,因而十分符合,能够一起不便的实现 SPA 单页应用程序的开发。
Vue Router 依赖于 Vue,所以须要先引入 Vue,再引入 Vue Router
Vue Router 的个性:
- 反对 H5 历史模式或者 hash 模式
- 反对嵌套路由
- 反对路由参数
- 反对编程式路由
- 反对命名路由
- 反对路由导航守卫
- 反对路由过渡动画特效
- 反对路由懒加载
- 反对路由滚动行为
四、Vue Router 的应用步骤(★★★)
A. 导入 js 文件 <script src="lib/vue_2.5.22.js"></script>
为全局 window 对象挂载 VueRouter 构造函数 <script src="lib/vue-router_3.0.2.js"></script>
B. 增加路由链接<router-link>
是 vue 中提供的标签,默认会被渲染为 a 标签,
to 属性默认被渲染为 href 属性,
to 属性的值会被渲染为 #结尾的 hash 地址 <router-link to="/user">User</router-link>
<router-link to="/login">Login</router-link>
C. 增加路由填充位(路由占位符)<router-view></router-view>
最初路由展现的组件就会在占位符的地位显示
D. 定义路由组件var User = {template:"<div>This is User</div>"}
var Login = {template:"<div>This is Login</div>"}
E. 配置路由规定并创立路由实例
var myRouter = new VueRouter({
//routes 是路由规定数组
routes:[
// 每一个路由规定都是一个对象,对象中至多蕴含 path 和 component 两个属性
//path 示意 路由匹配的 hash 地址,component 示意路由规定对应要展现的组件对象
{path:"/user",component:User},
{path:"/login",component:Login}
]
})
F. 将路由挂载到 Vue 实例中
new Vue({
el:"#app",
// 通过 router 属性挂载路由对象
router:myRouter
})
补充 :
路由重定向:能够通过路由重定向为页面设置默认展现的组件
在路由规定中增加一条路由规定即可,如下:
var myRouter = new VueRouter({
//routes 是路由规定数组
routes: [
//path 设置为 / 示意页面最初始的地址 / ,redirect 示意要被重定向的新地址,设置为一个路由即可
{path:"/", redirect:"/user"},
{path: "/user", component: User},
{path: "/login", component: Login}
]
})
五、嵌套路由,动静路由的实现形式
A. 嵌套路由的概念(★★★)
当咱们进行路由的时候显示的组件中还有新的子级路由链接以及内容。
嵌套路由最要害的代码在于了解子级路由的概念:
比方咱们有一个 /login 的路由
那么 /login 上面还能够增加子级路由,如:
/login/account
/login/phone
参考代码如下:
var User = {template: "<div>This is User</div>"}
//Login 组件中的模板代码外面蕴含了子级路由链接以及子级路由的占位符
var Login = {
template: `<div>
<h1>This is Login</h1>
<hr>
<router-link to="/login/account"> 账号密码登录 </router-link>
<router-link to="/login/phone"> 扫码登录 </router-link>
<router-view></router-view>
</div>`
}
// 定义两个子级路由组件
var account = {template: "<div> 账号:<input><br> 明码:<input></div>"};
var phone = {template: "<h1> 扫我二维码 </h1>"};
var myRouter = new VueRouter({
//routes 是路由规定数组
routes: [{path: "/", redirect: "/user"},
{path: "/user", component: User},
{
path: "/login",
component: Login,
// 通过 children 属性为 /login 增加子路由规定
children: [{path: "/login/account", component: account},
{path: "/login/phone", component: phone},
]
}
]
})
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router: myRouter
});
页面成果大抵如下:
B. 动静路由匹配(★★★)
<router-link to="/user/22">User</router-link>
var User = {template:"<div> 用户:{{$route.params.id}}</div>"}
var myRouter = new VueRouter({
//routes 是路由规定数组
routes: [
// 通过 /: 参数名 的模式传递参数
{path: "/user/:id", component: User},
]
})
能够在路由对应的组件中应用 $route.params.id
来获取门路传参的 id 参数值,然而这种形式不够灵便。今后能够尽量应用 props 将组件和路由解耦。
1. 通过 props 来接管参数
var User = {props:["id"], // 应用 props 接管 id 参数
template:"<div> 用户:{{id}}</div>"
}
var myRouter = new VueRouter({
//routes 是路由规定数组
routes: [
// 通过 /: 参数名 的模式传递参数
// 如果 props 设置为 true,route.params 将会被设置为组件属性
{path: "/user/:id", component: User, props:true},
]
})
2. 还有一种状况,咱们能够将 props 设置为对象,间接将静态数据传递给组件进行应用。
然而这样 id 的值就拜访不到了。
var User = {props:["username","pwd"],
template:"<div> 用户:{{username}}---{{pwd}}</div>"
}
var myRouter = new VueRouter({
//routes 是路由规定数组
routes: [
// 通过 /: 参数名 的模式传递参数
// 如果 props 设置为对象,则传递的是对象中的数据给组件
{path: "/user/:id", component: User, props:{username:"jack",pwd:123} },
]
})
3. 如果既想要获取路由传递的参数值,又想获取传递的对象数据,那么 props 应该设置为函数模式。
var User = {props:["username","pwd","id"],
template:"<div> 用户:{{id}} -> {{username}}---{{pwd}}</div>"
}
var myRouter = new VueRouter({
//routes 是路由规定数组
routes: [
// 通过 /: 参数名 的模式传递参数
// 如果 props 设置为函数,则通过函数的第一个参数获取路由对象
// 并能够通过路由对象的 params 属性获取传递的参数
//
{path: "/user/:id", component: User,props:(route)=>{return {username:"jack",pwd:123,id:route.params.id}
}
},
]
})
六、命名路由以及编程式导航
A. 命名路由:用 name 属性值给路由取别名
案例:
var User = {template:"<div> 用户:{{$route.params.id}}</div>"}
var myRouter = new VueRouter({
//routes 是路由规定数组
routes: [
// 通过 name 属性为路由增加一个别名
{path: "/user/:id", component: User, name:"user"},
]
})
增加了别名之后,能够应用别名进行跳转(给 to 属性绑定对象的模式)<router-link to="/user/123">User</router-link>
等价于<router-link :to="{name:'user', params: {id:123} }">User</router-link>
还能够编程式导航myRouter.push({ name:'user' , params: {id:123} } )
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router: myRouter,
mounted:function () {myRouter.push( { name:'user' , params: {id:123} } )
}
});
B. 编程式导航(★★★)
页面导航的两种形式:
A. 申明式导航:通过 点击链接 的形式实现的导航
B. 编程式导航:调用 js 的 api 办法实现导航,比方调用location.href
就是
Vue-Router 中常见的导航形式:this.$router.push("hash 地址");
this.$router.push("/login");
this.$router.push({name:'user' , params: {id:123} });
this.$router.push({path:"/login"});
this.$router.push({path:"/login",query:{username:"jack"} });
this.$router.go(n);
n 为数字,参考 history.gothis.$router.go(-1);
七、实现后盾治理案例(★★★)
案例成果:
点击左侧的 ” 用户治理 ”,” 权限治理 ”,” 商品治理 ”,” 订单治理 ”,” 零碎设置 ” 都会呈现对应的组件并展现内容
其中 ” 用户治理 ” 组件展现的成果如上图所示,在用户治理区域中的详情链接也是能够点击的,点击之后将会显示用户详情信息。
案例思路:
1). 先将以下代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title> 基于 vue-router 的案例 </title>
<style type="text/css">
html,
body,
#app {
margin: 0;
padding: 0px;
height: 100%;
}
.header {
height: 50px;
background-color: #545c64;
line-height: 50px;
text-align: center;
font-size: 24px;
color: #fff;
}
.footer {
height: 40px;
line-height: 40px;
background-color: #888;
position: absolute;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
}
.main {
display: flex;
position: absolute;
top: 50px;
bottom: 40px;
width: 100%;
}
.content {
flex: 1;
text-align: center;
height: 100%;
}
.left {
flex: 0 0 20%;
background-color: #545c64;
}
.left a {
color: white;
text-decoration: none;
}
.right {margin: 5px;}
.btns {
width: 100%;
height: 35px;
line-height: 35px;
background-color: #f5f5f5;
text-align: left;
padding-left: 10px;
box-sizing: border-box;
}
button {
height: 30px;
background-color: #ecf5ff;
border: 1px solid lightskyblue;
font-size: 12px;
padding: 0 20px;
}
.main-content {margin-top: 10px;}
ul {
margin: 0;
padding: 0;
list-style: none;
}
ul li {
height: 45px;
line-height: 45px;
background-color: #a0a0a0;
color: #fff;
cursor: pointer;
border-bottom: 1px solid #fff;
}
table {
width: 100%;
border-collapse: collapse;
}
td,
th {
border: 1px solid #eee;
line-height: 35px;
font-size: 12px;
}
th {background-color: #ddd;}
</style>
</head>
<body>
<div>
<!-- 头部区域 -->
<header class="header"> 后盾管理系统 </header>
<!-- 两头主体区域 -->
<div class="main">
<!-- 左侧菜单栏 -->
<div class="content left">
<ul>
<li> 用户治理 </li>
<li> 权限治理 </li>
<li> 商品治理 </li>
<li> 订单治理 </li>
<li> 零碎设置 </li>
</ul>
</div>
<!-- 右侧内容区域 -->
<div class="content right"><div class="main-content"> 增加用户表单 </div></div>
</div>
<!-- 尾部区域 -->
<footer class="footer"> 版权信息 </footer>
</div>
</body>
</html>
复制到咱们本人的文件夹中。
看一下这个文件中的代码编写了一些什么内容,
这个页面曾经把后盾治理页面的根本布局实现了
2). 在页面中引入 vue,vue-router
3). 创立 Vue 实例对象,筹备开始编写代码实现性能
4). 心愿是通过组件的模式展现页面的主体内容,而不是写死页面构造,所以咱们能够定义一个根组件:
// 只须要把本来页面中的 html 代码设置为组件中的模板内容即可
const app = {
template:`<div>
<!-- 头部区域 -->
<header class="header"> 后盾管理系统 </header>
<!-- 两头主体区域 -->
<div class="main">
<!-- 左侧菜单栏 -->
<div class="content left">
<ul>
<li> 用户治理 </li>
<li> 权限治理 </li>
<li> 商品治理 </li>
<li> 订单治理 </li>
<li> 零碎设置 </li>
</ul>
</div>
<!-- 右侧内容区域 -->
<div class="content right">
<div class="main-content"> 增加用户表单 </div>
</div>
</div>
<!-- 尾部区域 -->
<footer class="footer"> 版权信息 </footer>
</div>`
}
5). 当咱们拜访页面的时候,默认须要展现刚刚创立的 app 根组件,咱们能够
创立一个路由对象来实现这个事件, 而后将路由挂载到 Vue 实例对象中即可
const myRouter = new VueRouter({
routes:[{path:"/",component:app}
]
})
const vm = new Vue({
el:"#app",
data:{},
methods:{},
router:myRouter
})
补充:到此为止,根本的 js 代码都处理完毕了,咱们还须要设置一个路由占位符
<body>
<div id="app">
<router-view></router-view>
</div>
</body>
6). 此时咱们关上页面应该就能够失去一个 VueRouter 路由进去的根组件了
咱们须要在这个根组件中持续路由实现其余的性能子组件
先让咱们更改根组件中的模板:更改左侧 li 为子级路由链接,并在右侧内容区域增加子级组件占位符
const app = {
template:`<div>
........
<div class="main">
<!-- 左侧菜单栏 -->
<div class="content left">
<ul>
<!-- 留神:咱们把所有 li 都批改为了路由链接 -->
<li><router-link to="/users"> 用户治理 </router-link></li>
<li><router-link to="/accesses"> 权限治理 </router-link></li>
<li><router-link to="/goods"> 商品治理 </router-link></li>
<li><router-link to="/orders"> 订单治理 </router-link></li>
<li><router-link to="/systems"> 零碎设置 </router-link></li>
</ul>
</div>
<!-- 右侧内容区域 -->
<div class="content right">
<div class="main-content">
<!-- 在 -->
<router-view></router-view>
</div>
</div>
</div>
.......
</div>`
}
而后,咱们要为子级路由创立并设置须要显示的子级组件
// 倡议创立的组件首字母大写,和其余内容辨别
const Users = {template:`<div>
<h3> 用户治理 </h3>
</div>`}
const Access = {template:`<div>
<h3> 权限治理 </h3>
</div>`}
const Goods = {template:`<div>
<h3> 商品治理 </h3>
</div>`}
const Orders = {template:`<div>
<h3> 订单治理 </h3>
</div>`}
const Systems = {template:`<div>
<h3> 系统管理 </h3>
</div>`}
// 增加子组件的路由规定
const myRouter = new VueRouter({
routes:[
{path:"/",component:app , children:[{ path:"/users",component:Users},
{path:"/accesses",component:Access},
{path:"/goods",component:Goods},
{path:"/orders",component:Orders},
{path:"/systems",component:Systems},
]}
]
})
const vm = new Vue({
el:"#app",
data:{},
methods:{},
router:myRouter
})
7). 展现用户信息列表:
A. 为 Users 组件增加公有数据, 并在模板中循环展现公有数据
const Users = {data(){
return {
userList:[{id:1,name:"zs",age:18},
{id:2,name:"ls",age:19},
{id:3,name:"wang",age:20},
{id:4,name:"jack",age:21},
]
}
},
template:`<div>
<h3> 用户治理 </h3>
<table>
<thead>
<tr>
<th> 编号 </th>
<th> 姓名 </th>
<th> 年龄 </th>
<th> 操作 </th>
</tr>
</thead>
<tbody>
<tr :key="item.id" v-for="item in userList">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.age}}</td>
<td><a href="javascript:;"> 详情 </a></td>
</tr>
</tbody>
</table>
</div>`}
8. 当用户列表展现结束之后,咱们能够点击列表中的详情来显示用户详情信息,首先咱们须要创立一个组件,用来展现详情信息
const UserInfo = {props:["id"],
template:`<div>
<h5> 用户详情 </h5>
<p> 查看 {{id}} 号用户信息 </p>
<button @click="goBack"> 返回用户详情页 </button>
</div> `,
methods:{goBack(){
// 当用户点击按钮,后退一页
this.$router.go(-1);
}
}
}
而后咱们须要设置这个组件的路由规定
const myRouter = new VueRouter({
routes:[
{path:"/",component:app , children:[{ path:"/users",component:Users},
// 增加一个 /userinfo 的路由规定
{path:"/userinfo/:id",component:UserInfo,props:true},
{path:"/accesses",component:Access},
{path:"/goods",component:Goods},
{path:"/orders",component:Orders},
{path:"/systems",component:Systems},
]}
]
})
const vm = new Vue({
el:"#app",
data:{},
methods:{},
router:myRouter
})
再接着给用户列表中的详情 a 连贯增加事件
const Users = {data(){
return {
userList:[{id:1,name:"zs",age:18},
{id:2,name:"ls",age:19},
{id:3,name:"wang",age:20},
{id:4,name:"jack",age:21},
]
}
},
template:`<div>
<h3> 用户治理 </h3>
<table>
<thead>
<tr>
<th> 编号 </th>
<th> 姓名 </th>
<th> 年龄 </th>
<th> 操作 </th>
</tr>
</thead>
<tbody>
<tr :key="item.id" v-for="item in userList">
<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:{goDetail(id){this.$router.push("/userinfo/"+id);
}
}
}