底层原理是MVVM(Model 数据源,view 视图,model view Vue实例)
在MVVM概念中:
<script>
//创建 vue 的实例对象
new Vue({
//el 属性是固定写法,表示 vm 实例要控制哪个区域 ,接受的值是一个选择器
//注意:el实例只控制第一个符合条件的标签
el:'#name',
//dta 对象就是要渲染到页面的数据
data:{ name:'wukl',
username:'11',
gender:'男',
info:"你们好啊! "
}
})
script>
概念:vue提供的模板语法,辅助开发者渲染页面基本结构
vue中按照不同用途指令分为六大类:
渲染DOM元素的文本内容
vue提供的模板渲染语法中,除了支持绑定简单的数据值,还支持Javascript表达式的运算
<div>1+2 的结果是 {{1+2}} div>
<div>{{ tips}} 反转的结果是:{{tips.split('').reverse().join()}}div>
<!--在使用v-bind绑定属性期间,如果绑定内容需动态拼接,则字符串外面应该包裹单引号--!>
<div :title="'box'+index">只是一个divdiv>
<p v-text="username">p>
<p v-text="gender">性别p>
<!--一定要放在vue作用域内--!>
插值表达式,专门解决 v-text 会覆盖默认文本内容的问题
<p>姓名:{{username}}p>
v-text只能渲染纯文本内容,若要把包含HTML标签的字符串渲染到页面内,则使用v-html
注意:插值表达式只能用在元素的内容节点中,不能用在属性节点中
解决方案: v-blind可以为属性节点绑定值
vue规定 v-bind: 可以简写为 :
<div id="i">
<input type="text" v-bind:placeholder="username" >
div>
vue提供了v-on 事件绑定指令
<p>count的值是{{count}}p>
<button v-on:click="addCount">+1button>
***************************************************************
<button @click="count +=1" > +1button>
在Vue实例中,methods定义了时间的处理函数
const vm=new Vue({
el:'#i',
methods:{
addCount:function(){}
// 简写为addCount(){}
}
})
//vm对象是Vue的实例对象,自带data中的数据,可以通过this(vm.count)调用并修改
再绑定事件处理函数的时候,可以用小括号传递参数:
v-on:click="addCount(1)"
v-on可以被简写成@
@click="addCount(1)"
注意:原生DOM对象 onclick、oninput、onkeyup等原生对象,替换成 vue 的事件绑定形式后分别为v-on:click、v-on:input、v-on:keyup
<button @click="addCount(1,$event)">+Nbutton>
为应对事件处理函数中 event.preventDefault() 或event.stopPropagation()等需求,vue提出了事件修饰符的概念,辅助开发者对事件的触发控制。
<a href='http://' @click="show()">a>
methods:{
show(e){
e.preventDefault();
//原生javascript:阻止末尾行为
}
}
//事件修饰符,加载在事件绑定后
<a href="" @click.prevent="show()">
常见的事件修饰符:
冒泡:当外层与内层部件同时绑定相同事件,触发内部事件时,会冒泡至外层部件。
监听键盘事件时,可以为键盘相关的事件添加键盘修饰符
<input @keyup.enter="vm.submit()">
v-model:双向绑定指令
只能用于表单元素(能和用户产生交互)
input
type=“radio”
type=“checkbox”
type=“text”
textarea
select
<p>{{username}}p>
<input type="text" v-model="username">
<input type="text" :value="username">
<select v-model="city">
<option value="">请选择城市option>
<option value="1">北京option>
<option value="2">上海option>
select>
.unmber :对于 input 中的数据,当内容仅为一位数字时,才会被当成number类型,多位数字默认为字符串。
.tirm : 绑定数据时自动去除两端字符串。
.lazy : 懒惰模式,忽略变化的中间过程。
辅助开开发者按需控制DOM的显示与隐藏。
<p v-if="flag">被 v-if 控制p>
<p v-show="flag">被 v-show 控制p>
v-if可以配合v-else-if、v-else使用
<div v-if="type === 'A'">优秀div>
<div v-else-if="type === 'B'">良好div>
<div v-else="type === 'c'">一般div>
vue提供了循环v-for指令,辅助开发者基于一个数组来循环渲染一个列表结构,v-for使用的是 item in items 形式的特殊语法。
还有第二个可选参数,代表当前索引**(item,index) in items**
data:{
items:[
{id:1,username:'kl'},
{id:2,username:'wu'}
]
}
-----------------------------------------------------------
<table class="table table-bordered table-hover table-striped">
<thead>
<th>索引th>
<th>名称th>
thead>
<tbody v-for="item in items":key="item.id">
<tr>
<td>{{item.id}}td>
<td>{{item.username}}td>
tr>
tbody>
table>
key的注意事项
使标签的状态和数据对应起来,防止标签状态紊乱
过滤器功能:文本的格式化,常用于:插值表达式和v-bind属性绑定
<p>{{ message | capitalize }}p>
过滤器本质是个函数,定义到filters:{} Vue实例属性中
而且一定要有返回值,message的值可以被过滤器函数直接接收到
**********************************************************
new Vue({
filter:{
//val接收到的就是message的值
capitable(val){
const first=val.charAt(0).toUpperCase //charAt接受一个索引,表示从字符串把索引对应的字符获取过来
const other = val.slice(1) //slice方法可以截取字符串,从索引位置开始
return first+other
}
}
})
!!!!!全局过滤器应绑定在Vue实例之前!!!!!
定义在filter中的是私有过滤器,不能被其他区域的 Vue 实例访问
在多个 vue 实例之间共享过滤器,要定义为全局过滤器
//第一个参数是全局过滤器的“名字”
//第二个参数是全局过滤器的“处理函数”
//当全局过滤器和私有过滤器重名时,会优先调用私有过滤器(就近原则)
Vue.filter('capitalize',(str) => {
const first=val.charAt(0).toUpperCase
const other = val.slice(1)
return first+other
})
1.过滤器可以连续调用
<p>
{{ data | filter_1 | filter_2}}
p>
2.过滤器函数可以传递参数(因为其本质是函数)
<p> {{ message | filter(arg_1,arg_2)}}p>
****************************************************
Vue.filter('filter',(val,arg_1,arg_2){})
Watch侦听器:监测数据变化,依据数据变化做出反应
new Vue({
//所有的侦听器都应该被定义到 watch 节点下
watch:{
//侦听器本质是个函数,要监听哪个数据的变化,就把哪个数据名作为方法名
//第一个是newVal 新值 后面是 oldVal 旧值
username(newval,oldval){
}
}
})
方法格式的侦听器:因为如果值没有被改变,侦听器不会立即执行
对象格式的侦听器:可以通过 immediate 选项,让侦听器自动触发
watch:{
//定义对象格式的侦听器
username:{
handler:function(newVal,oldVal){},
//true代表一进入页面就会触发,默认值是false,控制侦听器是否会自动触发一次
immediate:true
}
}
data:{
info:{
username:5
}
}
此时username不直接挂载在data中,不能通过info属性侦听到其值的改变
解决方法:在对象类型侦听器中,设置 deep:true ,只要对象中任何数据变化,就会导致侦听方法被调用
watch:{
//定义对象格式的侦听器
username:{
handler:function(newVal,oldVal){},
//默认为false
deep:true
}
}
**********************************************************
//如果要侦听对象的子属性的变化,则必须包裹一层单引号
'info.username'(){
}
通过一系列运算最终得到一个属性值,这个属性值可以直接被模板结构或methods 方法使用
<div class="box" :style="{ backgroundColor :`rgb(${r},${g},${b})`}">
div>
**************************************************************
computed:{
//这个方法要返回一个生成好的rgb字符串
rgb:function(){
return `rgb($(this.r),$(this.g),$(this.b))`
}
}
优点:
axios 只专注于网络请求。
基本语法(axios 在导入后就会在创建一个全局可用的函数,用来发起网络请求)
axios({
method:'请求类型',
url:'URL地址',
//params:{}, GET传参
data:{} //POST传参
}).then((result) => {
//.then 用来指定请求成功后的回调函数
})
//result 拿到的数据中的result.data 才是服务器真实的数据
// 因为axios 在真正的数据外,套了一层壳
axios 在真正的数据外,套了一层壳
{
config:{},
data:{真实的数据},
headers:{},
request:{},
status:xxx,
statusText:""
}
document.querySelector('#btn').addEventListener('click',async function(){
//如果调用某个方法的返回值时 Promise 实例,则前面可以添加 await !
// await 只能用在被 async “修饰”的方法中
// 加await 后,result从一个Promise对象变成数据对象
await axios({
method:'GET',
url:'http://www.liulongbin.top:3006/api/getbooks',
params:{
id:2
}
}).then(function(result){
console.log(result)
})
})
//结合上层代码result 对象中有 config、data、status等属性
// 如果我们只关心 data 类型,可以使用解构赋值,提取我们期许的数据
// 解构赋值中使用冒号进行重命名
const { data:res }=await axios()
const {data:res}=await axios.get('URL'
(,{
//get参数
params:{}
})
)
***************************************************************
const {data:res}=await axios.post('URL',
(,{
//直接在花括号里写数据即可
})
)
单页面应用程序(Single Page Application)简称 SPA,即一个Web网站中只有一个HTML页面。
vue-cli 是Vue.js开发的标准工具,简化了Webpack创建工程化Vue项目的过程。
安装
npm i -g @vue/cli
创建项目
vue create 项目名称
vue项目中 src 目录的构成
assets 文件夹:存放项目中用到的静态资源,eg:css样式,图片资源
compoents 文件夹:程序员封装的、可复用的组件,都要放到 conponents 目录下
mian.js 是项目的入口文件,整个项目的运行,s要执行 main.js
App.vue 是项目的根组件
vue项目运行逻辑
main.js把app.vue渲染到index.html的页面中
//导入vue 这个包,得到vue 构造函数
import Vue from 'vue'
//导入 app.vue 根组件,将来要把 app.vue 中的模板结构,渲染到 html 页面中
import App from './App.vue'
Vue.config.productionTip = false
//创建 Vue 的实例对象
new Vue({
//把render 函数指定组件,渲染到 html 页面中
render: h => h(App),
//.$mount 或者 el 都可以指定 Vue 的作用区域
//el:'#app' div#app 就是个占位符,把其替换为模板内容
//.$mount 与el 作用完全一样
}).$mount('#app')
就是对UI结构的封装和复用
App.vue本质都是就是一个vue的组件
<template>
<div>
<h1>test {{username}}</h1>
</div>
</template>
<script>
export default ({
//data信号源
//注意:vue组件中的 data 不能像之前一样,不能指向对象
//注意:组件中data 必须是一个函数
data(){
//这个 return 出去的{ },可以定义数据
return {
username:'keli'
}
}
})
</script>
<style>
h1{
background:pink
}
</style>
template只能包含一个根节点
解决方案:模板整体使用一个
整体包裹
//1.使用import 语法导入需要的组件
import Left from "./components/Left.vue"
//2.使用 components 节点注册组件
export default{
components:{
Left
}
}
//3.以标签形式使用刚才注册的组件
<div>
<Left></Left>
</div>
私有组件只能使用在已在 components 注册过的组件内,未声明则无法使用。
全局注册一次,不需重复注册
方法:在vue项目的 main.js 入口文件中,通过 Vue.comonent()方法,可以注册全局组件。
//导入需要全局注册的组件
import Count from'@/components/Count.vue'
//参数一:字符串格式,表示组件的“注册名称”
//参数二:需要被全局注册的组件
Vue.component('MyCount',Count)
对于全局组件,可能有不同的初始值需求,而props 作为自定义属性,在封装组件时,可以极大的提高组件的复用性!
//这里是全局声明组件Count 中的vue.component 对象挂载的内容
export default{
//这里是数组
//自定义的属性的名字,是封装者自定义的(只要名称合法即可)
props:['init_vue1','init_vue2']
data(){
return count=init_vue1+init_vue2
}
}
***************************************************************
//在使用组件时,需要传递props 中声明的属性值
//这里的 9 是字符串
<count init_vue1='9'></count>
//这里的 9 是数字类型,因为 :(v-bind) 默认括号中的为表达式
<count :init_vue1='9'></count>
这时 init 值可以结合 v-bind 使用,传递javascript 中的属性值.
props中的数据,可以直接在模板结构中被使用,但是,props中的值是只读的,不能直接修改props 的值
解决方案:可以把 props 的值转存在 data 中,因为 data 中的数据都是可读可写的
用户有可能不传入props中要求属性的默认值,所以要设置初始值。
//注意:数组格式的props不能定义初始值,所以要使用对象格式的 props
export default{
props:{
init:{
//如果外界使用 Count 组件的时候,没有传递 init 属性,初始值就会生效
default:0
}
}
}
在声明自定义属性时,可以通过 type 来定义属性的值类型。
export default{
props:{
init:{
//用 default 属性定义属性的默认值
default:0,
//用 type 属性定义属性的值类型
//如果传递过来的值不符合此类型,则会在终端里报错
type:Number
}
}
}
export default{
props:{
init:{
//当调用该组件时,如果没有传递init 属性值,则会强制报错
required:true
}
}
}
写在.vue 组件中的样式会全局生效,所以容易造成样式冲突(因为样式都会在一个 html 页面中呈现,样式会共用)
使用 css 中的属性选择器 [ ],为组件添加统一的自定义属性(不同属性之间应该不同)
高级解决方法
在 style 标签中 添加 scoped属性,vue中自动生成并填充自定义属性。
要在父组件修改子组件中的值,而父组件已添加 scoped 属性,所以不能直接选中子属性,需要加 /deep/ 使用了后代选择器。
//样式不加 /deep/ 时: h5[data-v-3c83f0b7]
//样式修改为: [data-v-3c83f0b7] h5 后代选择器
//可以选中子元素中的 h5 标签
使用外部 UI 库时,不应修改 UI 库的源码,可以使用 /deep/ 选择子代组件,并修改样式。
生命周期:创建、运行、销毁的过程
为了在组件生命周期中关键的时间点,准确地执行某些操作,vue提供了生命周期函数,这些函数会被依次执行。
vue官方给出的生命周期流程图:
因为此时 vue 实例中的,peops、methods、data已经初始化,但是没有渲染,所以经常在此发送 ajax 请求(调用methods 方法),添加到 data 中,供模板使用。
注意:此时模板结构尚未生成到网页中,所以不能调用DOM操作
将要把生成好的模板结构渲染到 html 页面中,这时还不能操作DOM结构
这时 el 结构已被模板结构替换,成功渲染到 html 页面中,完成了DOM结构的渲染,可以获取并且操作DOM。
将要根据数据变化后、最新的数据重新渲染组建的模板结构
此时,数据是最新的,UI是旧的
document.elementSelect.innerhtml
数据与UI 结构都是最新的
组件之间的关系
父 -> 子: 自定义属性 props
子 -> 父:子组件向父组件共享数据使用自定义事件。
//子组件
methods:{
add(){
this.count+=1
this.$emit('numchange',this.count)
}
}
***************************************************************
//父组件
//只要 $emit 被调用,numChange就会被触发
<Son @numchange='getNewCount'></son>
export default{
data(){
return {this.countFromSon}
}
methods:{
// val 即子组件传来的参数值
getNewCount(val){
this.countFromSon = val
}
}
}
vue2.x 中,兄弟组件之间数据共享方案是EventBus。
EventBus的使用步骤
在不依赖于 jQuery 的情况下,获取 DOM 元素或组件的引用
在 Vue 组件实例对象中都有一个 refs空对象。
可以在组件中不同的标签内添加不同的 ref ,这个属性值会被添加到 refs 中,通过 this.refs.ref 值,便可以直接拿到这个 DOM 元素。
组件的 $nextTick(cb) 方法,把回调函数中的内容延迟执行,等DOM渲染完毕后执行
this.$nextTick(() =>{
this.$refs.btnref.focus()
})
***************************************************************
//不能代替this.$nextTick() 因为一旦数据改变就会调用该函数
//而功能要求是: 每次 input 出现时调用,这样会导致按钮出现时也会调用 focus功能 ,导致报错
updated(){
this.$refs.btnref.focus()
}
为了实现动态组件渲染:vue 提供了一个内置的 组件,专门用来实现动态组件的渲染。
//变量 left_val 用来存储组件名称
<component :is="left_val"></components>
data(){
return {
left_val:'left'
}
}
因为在使用 component 标签动态创建、销毁组件时,其中的data 数据会被重置,所以要使用 keep-alive 组件保持数据状态。
被keep-alive 包裹的组件不会被销毁,只会被隐藏。( inactive 被缓存状态)
当组件被缓存时,会自动触发组件的 deactived 生命周期,(一开始会触发created,之后不会触发,因为之后都是被隐藏)
当组件被激活时,会自动触发组件的 activated 生命周期
include:只有名称匹配的组件会被缓存,多个组件间用英文的逗号分隔。
<keep-alive include="MyLeft,MyRight>
<component :is="comName"></component>
</keep-alive>
exclude: 只有名称匹配的组件不被缓存,它和 include 只能存在一个
如果在“声明组件”的时候,没有为组件指定 name 名称,则组件的名称就是“注册时候的名称”。
而当声明过 name 之后,就会把组件的注册名称覆盖。(include 、exclude 等属性中要使用 name 的名称。)
1.组件中的“注册名称”的主要应用场景:以标签的形式,把注册好的组件,渲染和使用到页面结构中
2.组件声明的时候,“name” 名称的主要应用:结合 标签实现组件缓存功能;以及在调试工具中看到组件的 name 名称。
插槽(slot )是vue 为组件封装者提供的能力。允许开发者在封装组件时,把不确定、希望由用户指定的部分定义为插槽
// change.vue
//vue 官方规定:每一个 slot 插槽都有一个 name 名称
//如果忽略了 solt 的 name 属性,则有一个默认的名称叫做 default
<slot name="default"> </slot>
//此时引用该组件时:会将内容渲染到插槽中
<change>
//默认渲染到 default 中,而要指定插槽,需要用 template 包裹,然后用 v-slot 指定插槽, v-slot 不能直接用在元素标签身上。
<template v-slot:default>
<p>这是插槽的内容</p>
<template>
</change>
***************************************************************
<template #default>
v-slot 简写是 #
在 标签中声明一些内容,如果用户没有传入,则插槽部分会被后备内容所填充。
{{obj}} //obj={ 'msg':'sss'} 传过来 slot 中的属性值
***************************************************************
这样可以实现数据之间的传递
directives 节点声明私有自定义属性。
//调用时,使用 v-color 来调用自定义属性。
directives:{
color:{
bind(el){
el.style.clor = 'red'
}
}
}
//当指令第一次被绑定到元素上的时候,会立即触发 bind 指令,形参中的el 表示绑定到的那个 DOM 对象
<p v-color="'red'"></p>
directives:{
color(){
bind(el,binding)
//obj 或者其他名字都可以
//binding.value 对象中包含了自定义属性中传递的值
//binding.expression 是表达式的值 "'red'"
el.style.color = binding.value
}
}
bind 函数只会在创建时调用一次,当数据更新时,不会被触发。而 update 函数会在每次数据更新时调用。
directives:{
color:{
update(el,binding){
el.style.color=binding.value
}
}
}
bind 和 update 都要设置,bind在第一次绑定时被执行, update 在数据刷新时被执行。
如果 bind 和 update 函数中的逻辑完全形同,则对象格式可以写为函数格式。
directives:{
color(el,binding){
el.style.color = binding.value
}
}
//相当于在 bind 和 update 中都写了一份
全局自定义指令需要通过“Vue.directive()”声明(放到 main.js 中):
Vue.directive('color',(el,binding)=>{
el.style.color=binding.value
}
})
把 axios 挂载到 vue 组件 原型对象上,这样不需要组件重复导入。同时,可以为 axios 对象设置 defaults.baseURL 属性,确立默认根目录地址。
// 全局配置 axios 的请求根路径
axios.defaults.baseURL = 'http://www.liulongbin.top:3006'
// 把请求根路径挂载到 axios中
Vue.prototype.$http = axios
// 今后在每个 .vue组件中发起请求,只需要 this.$http.get()即可
但是,这种方法不利于实现 api 的复用,不建议使用
前端路由:Hash 地址和组件之间的对应关系
工作方式:
可以结合动态组件使用
// 为了监听 hash值的变化
window.onHashChange = () => {
// 当hash 值变化时,便会调用该函数
//location.hash 可以获取当前的hash 值
switch (locatin.hash){
case '#/home':
this.comName = 'Home'
break
case...
...
}
}
vue-router 是 vue.js 官方给出的路由解决方案。
// 注意,由于版本之间兼容问题,vue@2.需要安装 vue-router 的@3.系列版本
npm i vue-router
在 src 源代码目录下,新建 router/inex.js 路由模块:
// src/router/index.js 就是到项目的路由模块
// 导入 VUE 和vue-router 的包
import Vue from 'vue'
import VueRouter from 'vue-router'
// 使用 Vue.use() 函数,把VueRouter 安装为 Vue 的插件
Vue.use(VueRouter)
// 创建路由的实例对象
const router = new VueRouter()
export default router
在main.js 中挂载路由模块;
import router from './router/index.js'
new Vue({
render: (h) => h(App),
// 在Vue 项目中,想要把路由用起来,必须把路由实例对象,通过以下方式挂载
// router: router 属性名和属性值相同,可以简写
router
}).$mount('#app')
在进行模块化导入时,如果给定的是文件夹,则默认导入这个文件夹下,名字叫做 index.js 的文件
***************************************************************
const router = new VueRouter({
// routes 是一个数组,定义“hash 地址”和“组件”之间的对应关系
routes: [
// 这里要省略‘#’
{ path: '/left', component: left },
{ path: '/right', component: right }
]
})
//#在 router-link中不需要添加
路由重定向:用户在访问地址 A 时,强制用户跳转到地址C
{ path:'/',redirect:'/home'}
通过路由实现组件的嵌套展示,叫做嵌套路由
// 在子组件 left 中嵌套声明 router-link ,接下来只剩下 router/index.js 中的路径配置了
<router-link to="/right/tab1"> tab1 </router-link>
<router-link to="/right/tab2"> tab2 </router-link>
<hr />
<router-view></router-view>
注意:子路由规则不要加斜线
const router = new VueRouter({
// routes 是一个数组,定义“hash 地址”和“组件”之间的对应关系
routes: [
// 这里要省略‘#’
{
path: '/left',
component: left
},
{
path: '/right',
component: right,
//重定向为 /right/tab1 使切换到 right 时,就会默认出现 tab1 组件
redirect: '/right/tab1'
children: [
{ path: 'tab1', component: Tab1 },
{ path: 'tab2', component: Tab2 }
]
},
// redirect 重定向
{ path: '/', redirect: '/left' }
]
{
path: '/right',
component: right,
// redirect: '/right/tab1',
children: [
// 默认子路由:如果 children 数组中,某个路由规则的 path 值为
// 空字符串,则这条路由规则,叫做“ 默认子路由”
{ path: '', component: Tab1 },
{ path: 'tab2', component: Tab2 }
]
},
***************************************************************
//此时要在默认组件对应的 router-link 中
把 Hash 地址中的可变的部分定义为参数项,从而提高路由规则的复用性。
在 vue-router 中使用英文的冒号 (:)来定义路由的参数项。
//动态路由以 : 进行声明,冒号后面是动态参数的名称
{ path:'/movie/:id',component : Movie}
现在的需求是,希望根据 id 的值来展示对应电影的详情信息。
解决方法一:
在组件实例对象中,有一个 router 属性,里面的 params 记录了路径中的 id 值
this.$route.params.id //取值即可
this.$route 是路由的“参数对象”
this.$router 是路由的“导航对象”
解决方法二
为当前路由开启 props 传参
//在当前路由中开启 props 传参
{ path: ':id', component: movie, props: true }
***************************************************************
//在组件中接收
//在数组中,属性名都以字符串的形式表示
props:['id']
eg:
/right/:id
eg:
/right?id='1'&age=20
在 this.$route.fullpath 中,包括了之后的查询参数,而同级的 path 属性不包括查询参数。
在浏览器中,点击链接实现导航的方式,叫做声明式导航。
eg:
在浏览器中,调用 API 方法实现导航的方式,叫做编程式导航。
eg:
跳转到指定的 hash 地址,并创造一条历史记录。
跳转到指定的 hash 地址,并替换到当前的历史记录
调用 $router.go() 方法,可以在浏览历史中前进和后退。
// go(-1)
//表示后退一层,如果后退的层数超过上限,则原地不动
this.$router.go(-1) //后退到之前的组件页面
在实际开发过程中,一般只会用到前进和后退一层页面,所以 vue-router 提供了如下两个方法:
导航守卫可以控制路由的访问权限。
每次发生路由的导航跳转时,都会触发全局前置守卫,从而实现对每个路由进行访问权限的控制。
// 创建路由实例对象
const router = new VueRouter({ ... })
// 调用路由实例对象的 beforeEach 方法,即可声明“全局前置守卫”
// 每次发生路由导航跳转的时候,都会自动触发 fn 这个“回调函数”
router.beforeEach(fn)
全局前置守卫的回调函数中接收 3 个形参,格式为:
const router = new VueRouter({ ... })
router.beforeEach((to,from,next) =>{
// to 时即将要访问的路由信息对象
// from 时将要离开的路由信息对象
// next 是一个函数,调用 next() 表示放行,允许此次导航
})
控制后台主页的访问权限
router.beforeEach((to,from,next) =>{
if(to.path === '/main'){
//获取本地储存的 token 值
const token = localStorage.getItem('token')
if(token) {
next
}else {
next('/login')
}
} else {
next()
}
})
在浏览器中,调用 API 方法实现导航的方式,叫做编程式导航。
eg:
跳转到指定的 hash 地址,并创造一条历史记录。
跳转到指定的 hash 地址,并替换到当前的历史记录
调用 $router.go() 方法,可以在浏览历史中前进和后退。
// go(-1)
//表示后退一层,如果后退的层数超过上限,则原地不动
this.$router.go(-1) //后退到之前的组件页面
在实际开发过程中,一般只会用到前进和后退一层页面,所以 vue-router 提供了如下两个方法:
导航守卫可以控制路由的访问权限。
[外链图片转存中…(img-58R2B2lg-1665064366052)]
每次发生路由的导航跳转时,都会触发全局前置守卫,从而实现对每个路由进行访问权限的控制。
// 创建路由实例对象
const router = new VueRouter({ ... })
// 调用路由实例对象的 beforeEach 方法,即可声明“全局前置守卫”
// 每次发生路由导航跳转的时候,都会自动触发 fn 这个“回调函数”
router.beforeEach(fn)
全局前置守卫的回调函数中接收 3 个形参,格式为:
const router = new VueRouter({ ... })
router.beforeEach((to,from,next) =>{
// to 时即将要访问的路由信息对象
// from 时将要离开的路由信息对象
// next 是一个函数,调用 next() 表示放行,允许此次导航
})
控制后台主页的访问权限
router.beforeEach((to,from,next) =>{
if(to.path === '/main'){
//获取本地储存的 token 值
const token = localStorage.getItem('token')
if(token) {
next
}else {
next('/login')
}
} else {
next()
}
})