vue2.5快速入门(二)

Vue核心插件之路由模块

路由的跳转原理(哈希模式)

单页应用的路由模式有两种

  • 哈希模式(利用hashchange 事件监听 url的hash 的改变)
  • history模式(使用此模式需要后台配合把接口都打到我们打包后的index.html上)

哈希模式原理,哈希就是锚点

window.addEventListener('hashchange', function(e) {
console.log(e)
})

核心是锚点值的改变,我们监听到锚点值改变了就去局部改变页面数据,不做跳转。跟传统开发模式url改变后立刻发起请求,响应整个页面,渲染整个页面比路由的跳转用户体验更好

示例代码如下,哈希(锚点)就是链接后面的#/XXX

<!DOCTYPE html>
<html>
<head>
	<title></title>
</head>
<body>
	<a href="#/login">登录</a>
	|
	<a href="#/register">注册</a>
    <div id="app"></div>
    
    <script type="text/javascript">
        var appdiv = document.getElementById('app')
        // 监听哈希改变事件
        window.addEventListener('hashchange', function(e) {
            console.log(location.hash)
            switch(location.hash) {
                case "#/login":
                    appdiv.innerHTML = "我是登录页面"
                    break
                case "#/register":
                    appdiv.innerHTML = "我是注册页面"
                    break
            }
        })
</script>
</body>
</html>

点击后的页面内容分别如下

安装和使用路由

路由是以插件的形式引入到我们的vue项目中来的

vue-router是vue的核心插件

  • 1:下载 npm i vue-router -S
  • 2:安装插件Vue.use(VueRouter);
  • 3:创建路由对象 var router = new VueRouter();
  • 4:配置路由规则 router.addRoutes([路由对象]);
    路由对象{path:‘锚点值’,component:要(填坑)显示的组件}
  • 5:将配置好的路由对象交给Vue
    • 在options中传递-> key叫做 router
  • 6:留坑(使用组件)

从vue-router模块下取出来vue-router.js,在html中直接引入

测试代码如下

<!DOCTYPE html>
<html>
<head>
	<title>路由的安装和使用</title>
</head>
<body>
	<div id="app">
	</div>

	<script type="text/javascript" src="vue.js"></script>
	<!-- 引入路由插件 -->
	<script type="text/javascript" src="vue-router.js"></script>
	<script type="text/javascript">
        var login = {
            template:`
                <div>我是登录页面</div>
            `
        }
        // 安装路由插件
        Vue.use(VueRouter);
        // 创建路由对象
        var router = new VueRouter ({
            // 配置路由对象
            routes:[
                {path: '/login', name:'login', component:login}
            ]
        })
		new Vue({
            el:'#app',
            router,
            template:`
                <div>
					<p>请在链接上加上login测试路由功能</p>
					<router-view></router-view>
				</div>
            `,
		})
	</script>
</body>
</html>

这是为匹配路由的

匹配路由后,router-view会直接被组件取代

路由的跳转

路由的跳转方式有主要有以下两种形式

  • 通过标签:
<router-link to='/login'></router-link>
  • 通过js控制跳转
this.$router.push({path:'/login'})

通过标签跳转示例代码

<!DOCTYPE html>
<html>
<head>
	<title>路由的安装和使用</title>
</head>
<body>
	<div id="app">
		
	</div>

	<script type="text/javascript" src="vue.js"></script>
	<!-- 引入路由插件 -->
	<script type="text/javascript" src="vue-router.js"></script>
	<script type="text/javascript">
        var login = {
            template:`
                <div>我是登录页面</div>
            `
        }
        var register = {
            template:`
                <div>我是注册页面</div>
            `
        }
        // 安装路由插件
        Vue.use(VueRouter);
        // 创建路由对象
        var router = new VueRouter ({
            // 配置路由对象
            routes:[
                {path: '/login', name:'login', component:login},
                {path: '/register', name:'register', component:register}
            ]
        })
		new Vue({
            el:'#app',
            router,
            template:`
                <div>
                    <router-link to="/login">去登陆</router-link>
                    |
					<router-link to="/register">去注册</router-link>
					<router-view></router-view>
				</div>
            `,
		})
	</script>
</body>
</html>

通过js跳转示例代码

<!DOCTYPE html>
<html>
<head>
	<title>路由的安装和使用</title>
</head>
<body>
	<div id="app">
		
	</div>

	<script type="text/javascript" src="vue.js"></script>
	<!-- 引入路由插件 -->
	<script type="text/javascript" src="vue-router.js"></script>
	<script type="text/javascript">
        var login = {
            template:`
                <div>我是登录页面</div>
            `
        }
        var register = {
            template:`
                <div>我是注册页面</div>
            `
        }
        var buy = {
            template:`
                <div>我是购物页面</div>
            `
        }
        // 安装路由插件
        Vue.use(VueRouter);
        // 创建路由对象
        var router = new VueRouter ({
            // 配置路由对象
            routes:[
                {path: '/login', name:'login', component:login},
                {path: '/register', name:'register', component:register},
                {path: '/buy', name:'buy', component:buy}
            ]
        })
		new Vue({
            el:'#app',
            router,
            template:`
                <div>
                    <router-link to="/login">去登陆</router-link>
                    |
                    <router-link to="/register">去注册</router-link><br>
                    <button @click="gotoBuyPage">我要去买东西</button>
                    <button @click="back">返回上一页</button>
					<router-view></router-view>
				</div>
            `,
            methods:{
                gotoBuyPage() {
                    // push跟replace是达到同样效果,但是replace是不会向history插入记录
                    // this.$router.push({path:'/buy'})
                    this.$router.replace({path:'/buy'})
                },
                back() {
                    this.$router.go(-1)
                }
            }
		})
	</script>
</body>
</html>

区别:

  • this.$router.push() 跳转到指定的url,会向history插入新记录
  • this.$router.replace()同样是跳转到指定的url,但是这个方法不会向history里面添加新的记录,点击返回,会跳转到上上一个页面。上一个记录是不存在的
  • this.$router.go(-1) 常用来做返回,读history里面的记录后退一个

vue-router中的对象(很容易混淆):

  • $route 路由信息对象,只读对象
  • $router 路由操作对象,只写对象

路由的传参和取参

查询参

  • 配置(传参)
:to="{name:'login',query:{id:loginid}}"
  • 获取(取参)
this.$route.query.id

路由参数

  • 配置(传参)
 :to="{name:'register',params:{id:registerid} }"
  • 配置路由的规则
 { name:'detail',path:'/detail/:id'}

获取

this.$route.params.id

总结:

  • :to传参的属性里 params是和name配对的 query和name或path都可以
  • 使用路由参数必须要配置路由规则里面配置好参数名,否则刷新页面参数会丢失

示例代码如下,:key="$route.fullPath"比较关键,能解决只有查询参数表,路径不变而造成页面不重新渲染的问题

<!DOCTYPE html>
<html>
<head>
	<title>路由的跳转</title>
</head>
<body>
	<div id="app">
	</div>
	<script type="text/javascript" src="vue.js"></script>
	<!-- 引入路由插件 -->
	<script type="text/javascript" src="vue-router.js"></script>
	<script type="text/javascript">
		var login={
			template:`
				<div>我是登录页面 
					<span>这是我获取到的参数: {{ msg }}</span>
				</div>
			`,
			data(){
				return {
					msg:''
				}
			},
			created(){
				this.msg=this.$route.query.id
			}
		}
		var restiger={
			template:`
				<div>我是注册页面
					<span>这是我获取到的路由参数:{{ foo }}</span>
				</div>
			`,
			data() {
				return {
					foo:''
				}
			},
			created(){
				this.foo=this.$route.params.foo
			}
		}
		//安装路由插件
		Vue.use(VueRouter);
		//创建路由对象
		var router= new VueRouter({
			//配置路由对象
			routes:[
				{path:'/login',name:'login',component:login},
				{path:'/restiger/:foo',name:'restiger', component:restiger},
			]
		})
		new Vue({
			el:'#app',
			router,
			template:`
				<div>
					<router-link :to="{name:'login',query:{id:'123'}}">去登录</router-link>
					|
					<router-link :to="{name:'restiger',params:{foo:'bar'}}">去注册</router-link>
					<button @click='jslink'>js跳转去登录</button>
					<router-view :key="$route.fullPath"></router-view>
				</div>
			`,
			data(){
				return {}
			},
			methods:{
				// js跳转传参是一样的
				jslink(){
					this.$router.push({name:'login',query:{id:'456'}})
				}
			}
		})
	</script>
</body>
</html>

restiger中的参数,如果定义成props就更简单了,连data都不用了

<!DOCTYPE html>
...
		var restiger={
			template:`
				<div>我是注册页面
					<span>这是我获取到的路由参数:{{ foo }}</span>
				</div>
			`,
			props:['foo']
		}
...
...
		})
	</script>
</body>
</html>

嵌套路由

补充上一节知识点:js跳转路由传参和标签传参,路由相同而参数不同时页面不做刷新的问题—解决方案:

<router-view :key="$route.fullPath"></router-view>

代码思想

  • 1:router-view的细分
    • router-view第一层中,包含一个router-view
  • 2:每一个坑挖好了,要对应单独的组件
  • 路由配置
routes: [
    {
        path:'/nav',
        name:'nav',
        component:Nav,
        //路由嵌套增加此属性
        children:[
            //在这里配置嵌套的子路由
        ]
    }
]

案例

  • 进入首页下面会有导航,个人中心、首页、资讯、我的之类的

案例代码如下,需要留意的是nav的命名问题

<!DOCTYPE html>
<html>
<head>
	<title>路由的跳转</title>
</head>
<body>
	<div id="app">
	</div>

	<script type="text/javascript" src="vue.js"></script>
	<!-- 引入路由插件 -->
	<script type="text/javascript" src="vue-router.js"></script>
	<script type="text/javascript">
		var Nav={
			template:`
				<div>
					<router-link :to="{name:'nav.index'}">首页</router-link>
					|
					<router-link :to="{name:'nav.pensonal'}">个人中心</router-link>
					|
					<router-link :to="{name:'nav.message'}">资讯</router-link>
					|
					<router-link :to="{name:'nav.mine'}">我的</router-link>
					<router-view></router-view>
				</div>
			`,
		}
		var index={
			template:`
				<div>首页</div>
			`,
		}
		var pensonal={
			template:`
				<div>个人中心</div>
			`,
		}
		var message={
			template:`
				<div>资讯</div>
			`,
		}
		var mine={
			template:`
				<div>我的</div>
			`,
		}
		//安装路由插件
		Vue.use(VueRouter);
		//创建路由对象
		var router= new VueRouter({
			//配置路由对象
			routes:[
				{
					path:'',
					redirect:'/nav'
				},
				{
					path:'/nav',
					name:'nav',
					component:Nav,
					//嵌套路由增加这个属性
					children:[
						//配置我们的嵌套路由
						{path:'',redirect:'/nav/index'},
						{path:'index',name:'nav.index',component:index},
						{path:'pensonal',name:'nav.pensonal',component:pensonal},
						{path:'message',name:'nav.message',component:message},
						{path:'mine',name:'nav.mine',component:mine},
					]
				}
			]
		})
		new Vue({
			el:'#app',
			router,
			template:`
				<div>
					<router-view></router-view>
				</div>
			`,
		})
	</script>
</body>
</html>

路由守卫

const router = new VueRouter({ ... }
    // 前置的钩子函数 最后要执行next()才会跳转
    router.beforeEach((to, from, next) => {
    // ...
})

// 后置的钩子函数 已经跳转了不需要next
router.afterEach((to, from) => {
    // ...
})

路由守卫主要用于检验是否登录了,没登录就跳转到登录页面不让他在其他页面停留,但是现在这种处理主要的都用请求的全局拦截来做了。大致了解一下路由守卫即可

示例代码如下

<!DOCTYPE html>
<html>
<head>
	<title>路由守卫</title>
</head>
<body>
	<div id="app">
		
	</div>

	<script type="text/javascript" src="vue.js"></script>
	<!-- 引入路由插件 -->
	<script type="text/javascript" src="vue-router.js"></script>
	<script type="text/javascript">
		var Nav={
			template:`
				<div>
					<router-view></router-view>
					<router-link :to="{name:'nav.index'}">首页</router-link>
					|
					<router-link :to="{name:'nav.pensonal'}">个人中心</router-link>
					|
					<router-link :to="{name:'nav.message'}">资讯</router-link>
					|
					<router-link :to="{name:'nav.mine'}">我的</router-link>
				</div>
			`,
		}
		var Index={
			template:`
				<div>首页</div>
			`,
		}
		var Pensonal={
			template:`
				<div>个人中心</div>
			`,
		}
		var Message={
			template:`
				<div>资讯</div>
			`,
		}
		var Mine={
			template:`
				<div>我的</div>
			`,
		}
		//安装路由插件
		Vue.use(VueRouter);
		//创建路由对象
		var router= new VueRouter({
			//配置路由对象
			routes:[
				{
					path:'',
					redirect:'/nav'
				},
				{
					path:'/nav',
					name:'nav',
					component:Nav,
					//嵌套路由增加这个属性
					children:[
						//配置我们的嵌套路由
						{path:'',redirect:'/nav/index'},
						{path:'index',name:'nav.index',component:Index},
						{path:'pensonal',name:'nav.pensonal',component:Pensonal},
						{path:'message',name:'nav.message',component:Message},
						{path:'mine',name:'nav.mine',component:Mine},
					]
				}
			]
		})
		new Vue({
			el:'#app',
			router,
			template:`
				<div>
					<router-view></router-view>
				</div>
			`,
			data(){
				return {
					loginstate:true
				}
			},
			methods:{
			},
			mounted(){
				//利用路由守卫做当跳转首页时可直接跳转,跳转其他页面要等待两秒才可以跳转
				router.beforeEach((to,from,next)=>{
					console.log(to)
					if(to.path=='/nav/index'){
						next()
					}else{
						setTimeout(function(){
								next()
						},2000)
					}
				})
			}
			
		})
	</script>
</body>
</html>

购物车实战

下面的一个小例子是综合上面的所有知识点做的一个小demo

搭建一个显示内容的框架

在data数组中存放4个商品信息

{text:'springcloud',price:20},
{text:'vue',price:30},
{text:'js',price:40},
{text:'php',price:50},

在div中通过v-for显示出来

<ul>
	<li v-for='(list,index) in classlist'>
		课程名称:{{list.text}}---价格:{{list.price}}
		<button @click='addtochat(index)'>添加到购物车</button>
	</li>
</ul>

加入一个按钮,输入商品信息后点击,把输入的内容追加到classlist中,并清空输入的内容,整个部分代码如下

<!DOCTYPE html>
<html>
<head>
	<title>购物车</title>
	<style type="text/css">
		span{cursor: pointer;}
	</style>
</head>
<body>
	<div id="app">
		<div>
			课程:<input type="text" name="" v-model='course'>
			价钱:<input type="text" name="" v-model='price'>
			<button @click='addcourse'>添加商品</button>
		</div>
		<ul>
			<li v-for='(list,index) in classlist'>
				课程名称:{{list.text}}---价格:{{list.price}}
				<button @click=''>添加到购物车</button>
			</li>
		</ul>
	</div>
	<script type="text/javascript" src="vue.js"></script>
	<script type="text/javascript">
		new Vue({
			el:'#app',
			data(){
				return {
					classlist:[
						{text:'springcloud',price:20},
						{text:'vue',price:30},
						{text:'js',price:40},
						{text:'php',price:50},
					],
					course:'',
					price:'',
				}
			},
			methods:{
				//添加课程
				addcourse(){
					//插入数据到我们的商品库
					this.classlist.push({text:this.course,price:this.price})
					//清空我们刚输入的商品信息
					this.course=''
					this.price=''
				},
			},
		})
	</script>
</body>
</html>

完成购物车大体功能

在本小结中,加入购物车的table,在点击商品添加到购物车后,能在购物车显示出来,在购物车中还能对商品进行±操作,自动根据商品个数计算出商品价格

<!DOCTYPE html>
<html>
<head>
	<title>购物车</title>
	<style type="text/css">
		span{cursor: pointer;}
	</style>
</head>
<body>
	<div id="app">
		<div>
			课程:<input type="text" name="" v-model='course'>
			价钱:<input type="text" name="" v-model='price'>
			<button @click='addcourse'>添加商品</button>
		</div>
		<ul>
			<li v-for='(list,index) in classlist'>
				课程名称:{{list.text}}---价格:{{list.price}}
				<button @click='addtochat(index)'>添加到购物车</button>
			</li>
		</ul>
		<div>
			购物车
			<table border="1">
				<tr>
					<th>选中</th>
					<th>课程</th>
					<th>数量</th>
					<th>价格</th>
				</tr>
				<tr v-for="(chat,index) in chatarr">
					<td><input type="checkbox" name="" v-model='chat.active'></td>
					<td>{{chat.text}}</td>
					<td>
						<span @click='reducecount(index)'>-</span>
						{{chat.count}}
						<span @click='addcount(index)'>+</span>

					</td>
					<td>{{chat.count * chat.price}}</td>
				</tr>
			</table>
		</div>
	</div>
	<script type="text/javascript" src="vue.js"></script>
	<script type="text/javascript">
		new Vue({
			el:'#app',
			data(){
				return {
					classlist:[
						{text:'springcloud',price:20},
						{text:'vue',price:30},
						{text:'js',price:40},
						{text:'php',price:50},
					],
					course:'',
					price:'',
					chatarr:[], // 购物车数组
				}
			},
			methods:{
				//添加课程
				addcourse(){
					//插入数据到我们的商品库
					this.classlist.push({text:this.course,price:this.price})
					//清空我们刚输入的商品信息
					this.course=''
					this.price=''
				},
				// 添加到购物车
				addtochat(index){
					const goods=this.classlist[index]
					const result=this.chatarr.find(v=>v.text==goods.text)
					if(result){
						result.count+=1
					}else{
						this.chatarr.push({...goods,count:1,active:true}) // es6展开数组
					}
				},
				// 增加购物车商品数
				addcount(index){
					this.chatarr[index].count++
				},
				//减少购物车商品数量
				reducecount(index){
					if(this.chatarr[index].count>1){
						this.chatarr[index].count--
					}else{
						if(window.confirm(`是否删除${this.chatarr[index].text}?`)){
							this.chatarr.splice(index,1)
						}
					}
				}
			},
		})
	</script>
</body>
</html>

完成本地存储,重构做成组件的形式

本地存储采用,加入计算属性自动结算购物车,并把购物车的代码做成重构组件,方便后期进行维护;最后采用watch来实现将购物车信息保存到浏览器存储中,防止刷新页面丢失信息

<!DOCTYPE html>
<html>
<head>
	<title>购物车</title>
	<style type="text/css">
		span{cursor: pointer;}
	</style>
</head>
<body>
	<div id="app">
		<div>
			课程:<input type="text" name="" v-model='course'>
			价钱:<input type="text" name="" v-model='price'>
			<button @click='addcourse'>添加商品</button>
		</div>
		<ul>
			<li v-for='(list,index) in classlist'>
				课程名称:{{list.text}}---价格:{{list.price}}
				<button @click='addtochat(index)'>添加到购物车</button>
			</li>
		</ul>
		<Chat :chatarr='chatarr'></Chat>
	</div>
	<script type="text/javascript" src="vue.js"></script>
	<script type="text/javascript">
		var Chat = {
			props:['chatarr'],
			template:`
				<div>
					购物车
					<table border="1">
						<tr>
							<th>选中</th>
							<th>课程</th>
							<th>数量</th>
							<th>价格</th>
						</tr>
						<tr v-for="(chat,index) in chatarr">
							<td><input type="checkbox" name="" v-model='chat.active'></td>
							<td>{{chat.text}}</td>
							<td>
								<span @click='reducecount(index)'>-</span>
								{{chat.count}}
								<span @click='addcount(index)'>+</span>

							</td>
							<td>{{chat.count * chat.price}}</td>
						</tr>
						<tr>
							<td colspan='2'>选中的课程:{{activeCount}}/{{count}}</td>
							<td colspan='2'>需付金额:{{totalpirce}}</td>
						</tr>
					</table>
				</div>
			`,
			// 计算属性,实时计算需付金额
			computed:{
				//已选中课程
				activeCount(){
					return this.chatarr.filter(v=>v.active).length
				},
				//购物车存在多少项课程
				count(){
					return this.chatarr.length
				},
				//总价
				totalpirce(){
					let total=0
					this.chatarr.forEach(v=>{
						if(v.active){
							total+=v.price*v.count
						}
					})
					return total
				}
			},
			// 用watch来实现将购物车信息保存到浏览器存储中,防止刷新页面丢失信息
			watch: {
				// 监听购物车数组,每当监听到改变就存进本地存储做数据持久化
				chatarr:{
					handler(){
						window.localStorage.setItem('chat',JSON.stringify(this.chatarr)) // json序列号保存到浏览器缓存中
					},
					deep:true // chatarr是对象,所以需要深度监听
				}
			},
			methods:{
				// 增加购物车商品数
				addcount(index){
					this.chatarr[index].count++
				},
				//减少购物车商品数量
				reducecount(index){
					if(this.chatarr[index].count>1){
						this.chatarr[index].count--
					}else{
						if(window.confirm(`是否删除${this.chatarr[index].text}?`)){
							this.chatarr.splice(index,1)
						}
					}
				}
			}
		}
		new Vue({
			el:'#app',
			components:{
				Chat
			},
			data(){
				return {
					classlist:[
						{text:'springcloud',price:20},
						{text:'vue',price:30},
						{text:'js',price:40},
						{text:'php',price:50},
					],
					course:'',
					price:'',
					chatarr:[], // 购物车数组
				}
			},
			methods:{
				//添加课程
				addcourse(){
					//插入数据到我们的商品库
					this.classlist.push({text:this.course,price:this.price})
					//清空我们刚输入的商品信息
					this.course=''
					this.price=''
				},
				// 添加到购物车
				addtochat(index){
					const goods=this.classlist[index]
					const result=this.chatarr.find(v=>v.text==goods.text) // v=>v.text为es6的属性
					if(result){
						result.count+=1
					}else{
						this.chatarr.push({...goods,count:1,active:true}) // es6展开数组
					}
				},
			},
			created(){
				//利用本地存储做数据持久化 获取本地存储数据
				this.chatarr=JSON.parse(window.localStorage.getItem('chat')) 
			}
		})
	</script>
</body>
</html>

演示效果如下

查看浏览器的缓存可以看到如下信息

参考链接

全文所涉及的代码下载地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值