Vue常见考点以及容易混淆的知识点----Day05

目录

第五章

一、路由机制

二、后端路由阶段

1、后端路由

2、后端路由的缺点

三、前端路由阶段

 1、前后端分离阶段︰

2、单页面富应用阶段:

3、前端路由的核心

四、Vue-Router的基本使用

1.路由的安装

 2.路由的使用

 3.动态路由的使用

 4.嵌套路由

五、编程式导航

 六、路由组件传参

(1)path-query传参

(2)name-params传参 

七、路由模式

(1)hash模式

(2)history模式

(3)vue-router使用的模式

八、导航守卫--路由的改变会触发导航守卫

(1)全局守卫

 (2)全局解析守卫

(3)全局后置钩子 

 (4)路由独享的守卫

(5)组件内的守卫:

5.1可用的配置 API​

5.2使用组合 API​


第五章

一、路由机制

vue-router是vue的一个插件,用来提供路由功能。通过路由的改变可以动态加载组件,达到开发单页面程序的目的

二、后端路由阶段

早期的网站开发整个HTML页面是由服务器来渲染的。服务器直接生产渲染好对应的HTML页面,返回给客户端进行展示.

1、后端路由

  • 一个页面有自己对应的网址,也就是URL.
  • URL会发送到服务器,服务器会通过正则对该URL进行匹配,并且最后交给一个Controller进行处理。
  • Controller进行各种处理,最终生成HTML或者数据,返回给前端.

当我们页面中需要请求不同的路径内容时,交给服务器来进行处理,服务器渲染好整个页面,并且将页面返回给客户端.
这种情况下渲染好的页面,不需要单独加载任何的js和css,可以直接交给浏览器展示,这样也有利于SEO的优化.

2、后端路由的缺点

  • —种情况是整个页面的模块由后端人员来编写和维护的.
  • 另一种情况是前端开发人员如果要开发页面,需要通过PHP和Java等语言来编写页面代码.
  • 通常情况下HTML代码和数据以及对应的逻辑会混在一起,编写和维护都是非常糟糕的事情.

三、前端路由阶段

 1、前后端分离阶段︰

随着Ajax的出现,有了前后端分离的开发模式.
后端只提供API来返回数据,前端通过Ajax获取数据,并且可以通JavaScript将数据渲染到页面中.
这样做最大的优点就是前后端责任的清晰,后端专注于数据上,前端专注于交互和可视化上.
并且当移动端(iOS/Android)出现后,后端不需要进行任何处理,依然使用之前的一套API即可.

2、单页面富应用阶段:

其实SPA最主要的特点就是在前后端分离的基础上加了一层前端路由.也就是前端来维护下套路由规则.

3、前端路由的核心

改变URL,但是页面不进行整体的刷新。

四、Vue-Router的基本使用

vue-router是基于路由和组件的

  • 路由用于设定访问路径,将路径和组件映射起来.
  • 在vue-router的单页面应用中,页面的路径的改变就是组件的切换.

1.路由的安装

见:安装 | Vue Router 

 2.路由的使用

在html文件中使用时需要引入vueRouter(先引入vue.js,在引入vueRouter)

### js代码
    <script>
      // 声明组件
    let myA = {
      template: `
        <div>A组件</div>
      `
    };
    let myB = {
      template: `
        <div>B组件</div>
      `
    };
    // 1.定义路由对象数组 route路由对象  router路由器对象  routes路由对象组
    let routes = [{
      path: '/a',
      component: myA
    }, {
      path: '/b',
      component: myB
    }];
    // 2.创建路由器对象  声明路由器实例对象
    let router = new VueRouter({
      // 声明配置路由对象
      routes: routes
    })
    // 3.注册路由器对象
    new Vue({
      el: '#app',
      // 将路由实例对象导入vue实例,相当于router:router,在此使用简写形式
      router,
      components: {
        'my-a': myA,
        'my-b': myB
      },
      data: {
        msg: 'hello'
      },
    
    })
	</script>
### html代码
	<div id="app">
    {{msg}}
    <!-- 4.实现路由切换,router-link的本质是创建a标签 -->
    <div>
      <router-link to="/a">去A路由</router-link>
      <router-link to="/b">去B路由</router-link>
      <a href="#/a">a标签路由去A</a>
    </div>
    <div>
      <!-- 路由组件显示的位置  路由出口,将匹配到的路由组件,渲染到此-->
      <router-view></router-view>
    </div>
  </div>
let routes=[
let routes=[
    {
        path:"/",
        //路由名称
        name:"aRoute",
        //别名 重命名
        alias:'/aa',
        //重定向 
        // redirect:'/a'
        redirect:{name:'aRoute'}
    }
]

 3.动态路由的使用

需要把某种模式匹配到的所有路由,全部映射到同一个组件。

例如 : 有一个user组件,对于所有id不同的用户,都要使用这个组件来渲染,那么可以在vue-router的路由路径中使用动态路径参数来达到这个效果。

复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch $route 对象,或者使用组件内部的导航守卫

<div id="app">
    {{msg}}
    <!-- 4.使用路由 -->
    <div>
      <router-link to="/user/id/1/username/zhangsan">去A路由</router-link>
    </div>
    <div>
      <!-- 路由组件显示的位置 -->
      <router-view></router-view>
    </div>
  </div>
 // 声明组件
    let myA = {
      data() {
        return {
          id: null,
          username: ''
        }
      },
      template: `
        <div>A组件{{id}}--{{username}}</div>
      `,
      /* created() {
        alert(1);
        // console.log(this.$route);
        this.id = this.$route.params.id;
        this.username = this.$route.params.username;
      } */
      //监听
      /* watch: {
        msg(newValue, oldValue) { },
        $route(to, from) {
          // to是新路由  from是旧路由
          // console.log(to, from);
          this.id = this.$route.params.id;
          this.username = this.$route.params.username;
        }
      } */
      // 监听路由发生变化 路由守卫
      beforeRouteUpdate(to, from, next) {
        // console.log(to.params);
        this.id = to.params.id;
        this.username = to.params.username;
        // 继续
        // next();
        // 阻断
        // next(false)
      }
    };
    let myB = {
      template: `
        <div>B组件</div>
      `
    };
    // 1.定义路由对象数组 route路由对象  router路由器对象  routes路由对象组
    let routes = [{
      // 动态路由
      //  /user/id/1/username/zhangsan  
      //  /user/id/2/username/lisi  
      path: '/user/id/:id/username/:username',
      component: myA
    }];
    // 2.创建路由器对象
    let router = new VueRouter({
      routes: routes
    })
    // 3.注册路由器对象
    new Vue({
      el: '#app',
      router: router,
      components: {
        'my-a': myA,
        'my-b': myB
      },
      data: {
        msg: 'hello'
      },
      methods: {}
    })

 4.嵌套路由

实际生活中的应用界面,通常由多层嵌套的组件组合而成。同样地,URL 中各段动态路径也按某种结构对应嵌套的各层组件 

## js代码
<script>
        // 创建一个组件
        let user={
            template:`
                <div>
                    <router-link to='/userChild1'>子组件1</router-link>
                    <router-link to='/userChild2'>子组件2</router-link>
                    <router-view ></router-view>
                </div>
            `
        }
        let manager={
            template:`
                <div>管理员</div>
            `
        }
        let userChild1={
            template:`
                <div>子组件1</div>
            `
        }
        let userChild2={
            template:`
                <div>子组件2</div>
            `
        }
        let routes=[{
            path:'/manager',
            component:manager
        },{
            path:'/user',
            component:user,
            redirect:'/userChild1',
            children:[{
                path:"/userChild1",
                component:userChild1
            },{
                path:"/userChild2",
                component:userChild2
            }]
        }];
        let router=new VueRouter({
            routes
        })
        new Vue({
            el:"#app",
            router,
            data:{

            }
        })
### html代码
  <div id="app">
       <router-link to='user'>去用户</router-link>
       <router-link to='manager'>去管理员</router-link>
       <router-view></router-view>
    </div>

五、编程式导航

除了使用 <router-link> 创建 a 标签来定义导航链接,还可以借助 router 的实例方法,通过编写代码来实现。this.$router.push()跳转到指定路由,会向history栈添加一个新的记录,当用户点击浏览器回退按钮的时候,可以回到跳转前的url。

### js代码
 <script>
         // 创建A B组件
    let myA={
        data(){
            return {

            }
        },
        template:`
            <div>
                A组件
            </div>
        `,
        created(){
            console.log(this.$route)
        },
        
    }
    let myB={
        data(){
            return {
                
            }
        },
        template:`
            <div>
                B组件
            </div>
        `
    };
    // 创建路由组件对象数组 routes router路由器对象 route路由对象
    let routes=[
        {
            path:"/a",
            component:myA,
            name:'mya'
        },
        {
            path:"/b",
            component:myB,
            
           
        }
    ];
    // 创建路由器对象实例
    let router=new VueRouter({
        // 配置路由对象组
        routes
    })
    
    new Vue({
        el:'#app',
        data:{

        },
        
        // 3.注册路由
        router,
        components:{
            'my-a':myA,
            'my-b':myB
        },
        methods:{
            toPath(){
                this.$router.push({
                    // 有效
                    path:"/a?id=1",
                    // 有效
                    // query:{id:1},
                    // // 无效
                    // params:{name:"terry"}
                })
            },
            toPath1(){
                this.$router.push({
                    name:'mya',
                    query:{id:1},
                    // 参数是一次性携带刷新页面 params失效
                    params:{
                        name:"terry"
                    }
                })
            }
        }
    })
    </script>
### html代码
<div id="app">
        <router-link to='/a'>去a路由</router-link>
        <router-link to='/b'>去b路由</router-link>
        <a href="#/a/2">去a路由</a>
        <button @click="$router.push('/a')">跳转到A路由</button>
        <button @click="$router.push('a')">跳转到A2路由</button>
        <button @click="toPath">跳转到A3路由</button>
        <button @click="toPath1">跳转到A4路由</button>
        <router-view></router-view>
        
    </div>
this.$router.repalce()这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步。
// 在浏览器记录中前进一步,等同于 history.forward()
router.go(1)
// 后退一步记录,等同于 history.back()
router.go(-1)
// 前进 3 步记录
router.go(3)
// 如果 history 记录不够用,则会报错
router.go(-100)
router.go(100)

 六、路由组件传参

路由传递是指,从A页面跳转到B页面时,将A页面中的变量传递给B页面使用,传递参数的方式有两种 :

(1)path-query传参

使用path与query结合的方式传递参数时,参数会被拼接在浏览器地址栏中,并且刷新页面后数据也不会丢失。

### js代码
<script>
let user = {
	template:`
		<div @click="userHandler">普通用户,点击此处可跳转至管理员页面</div>
	`,
	data() {
		return {
			list:"hello",
			obj:{
				name:'tom',
				age:3
			}
		}
	},
	methods: {
		userHandler() {
			// 跳转
			this.$router.push({
				path:'/manager',
				query:{
					list:this.list,
					obj:JSON.stringify(this.obj)
				}
			})
		}
	},
}
let manager = {
	template:`
		<div>管理员 {{$route.query.list}}  {{$route.query.obj}}</div>
	`
}
let router = new VueRouter({
	routes:[{
		path:'/user',
		component:user
	},{
		path:'/manager',
		component:manager
	}]
})
new Vue ({
	el:"#app",
	router
})
</script>
### html代码
<div id="app">
	<router-link to="/user">user</router-link>
	<router-link to="/manager">manager</router-link>
	<router-view></router-view>
</div>

(2)name-params传参 

name-params传参
### js代码
<script>
let user = {
	template:`
		<div @click="userHandler">普通用户,点击此处可跳转至管理员页面</div>
	`,
	data() {
		return {
			list:"hello",
			obj:{
				name:'tom',
				age:3
			}
		}
	},
	methods: {
		userHandler() {
			// 跳转
			this.$router.push({
				name:'manager',
				params:{
					list:this.list,
					obj:JSON.stringify(this.obj)
				}
			})
		}
	},
}
let manager = {
	template:`
		<div>管理员 {{$route.params.list}}  {{$route.params.obj}}</div>
	`
}
let router = new VueRouter({
	routes:[{
		path:'/user',
		component:user,
		name:'user'
	},{
		path:'/manager',
		component:manager,
		name:'manager'
	}]
})
new Vue ({
	el:"#app",
	router
})
</script>
### html代码
<div id="app">
	<router-link to="/user">user</router-link>
	<router-link to="/manager">manager</router-link>
	<router-view></router-view>
</div>

七、路由模式

(1)hash模式

hash模式的工作原理是hashchange事件,可以在window监听hash的变化。我们在url后面随便添加一个#xx触发这个事件。

window.onhashchange = function(event){ console.log(event); // 打印出一个HashChangeEvent事件对象,在该对象内有newURL和oldURL // location.hash中也有相关的信息 // 假设hash值是个颜色值,通过location.hash来获取到对应的hash值,然后设置页面中的某个元素的背景颜色来改变页面 }

(2)history模式

把window.history对象打印出来可以看到里边提供的方法和记录长度 history对象内有back(),forword(),go()等方法 前进,后退,跳转操作方法:

history.go(-3);//后退3次 history.go(2);//前进2次 history.go(0);//刷新当前页面 history.back(); //后退 history.forward(); //前进

(3)vue-router使用的模式

vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。如果不想要很丑的 hash,可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。不过这种模式要玩好,还需要后台配置支持。

hash路由和history路由的区别

  • hash路由在地址栏URL上有#,而history路由没有会好看一点
  • 进行回车刷新操作,hash路由会加载到地址栏对应的页面,而history路由一般就404报错了(刷新是网络请求,没有后端准备时会报错)。
  • hash路由支持低版本的浏览器,而history路由是HTML5新增的API。
  • hash的特点在于它虽然出现在了URL中,但是不包括在http请求中,所以对于后端是没有一点影响的,所以改变hash不会重新加载页面,所以这也是单页面应用的必备。
  • history运用了浏览器的历史记录栈,之前有back,forward,go方法,之后在HTML5中新增了pushState()和replaceState()方法(需要特定浏览器的支持),它们提供了对历史记录进行修改的功能,不过在进行修改时,虽然改变了当前的URL,但是浏览器不会马上向后端发送请求。

八、导航守卫--路由的改变会触发导航守卫

见: 导航守卫 | Vue Router

(1)全局守卫

全局守卫有全局前置守卫、全局后置守卫。

你可以使用 router.beforeEach 注册一个全局前置守卫:

const router = createRouter({ ... })

router.beforeEach((to, from) => {
  // ...
  // 返回 false 以取消导航
  return false
})

可以使用 router.afterEach注册一个全局后置守卫:

const router = new VueRouter({ ... }) router.afterEach((to, from) => { // ... })

 (2)全局解析守卫

你可以用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,因为它在每次导航时都会触发,不同的是,解析守卫刚好会在导航被确认之前、所有组件内守卫和异步路由组件被解析之后调用。这里有一个例子,确保用户可以访问自定义 meta 属性 requiresCamera 的路由:

router.beforeResolve(async to => {
  if (to.meta.requiresCamera) {
    try {
      await askForCameraPermission()
    } catch (error) {
      if (error instanceof NotAllowedError) {
        // ... 处理错误,然后取消导航
        return false
      } else {
        // 意料之外的错误,取消导航并把错误传给全局处理器
        throw error
      }
    }
  }
})

router.beforeResolve 是获取数据或执行任何其他操作(如果用户无法进入页面时你希望避免执行的操作)的理想位置。

(3)全局后置钩子 

你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:

router.afterEach((to, from) => {
  sendToAnalytics(to.fullPath)
})

它们对于分析、更改页面标题、声明页面等辅助功能以及许多其他事情都很有用。

它们也反映了 navigation failures 作为第三个参数:

router.afterEach((to, from, failure) => {
  if (!failure) sendToAnalytics(to.fullPath)
})

 (4)路由独享的守卫

你可以直接在路由配置上定义 beforeEnter 守卫:

const routes = [
  {
    path: '/users/:id',
    component: UserDetails,
    beforeEnter: (to, from) => {
      // reject the navigation
      return false
    },
  },
]

beforeEnter 守卫 只在进入路由时触发,不会在 paramsquery 或 hash 改变时触发。例如,从 /users/2 进入到 /users/3 或者从 /users/2#info 进入到 /users/2#projects。它们只有在 从一个不同的 路由导航时,才会被触发。

你也可以将一个函数数组传递给 beforeEnter,这在为不同的路由重用守卫时很有用:

function removeQueryParams(to) {
  if (Object.keys(to.query).length)
    return { path: to.path, query: {}, hash: to.hash }
}

function removeHash(to) {
  if (to.hash) return { path: to.path, query: to.query, hash: '' }
}

const routes = [
  {
    path: '/users/:id',
    component: UserDetails,
    beforeEnter: [removeQueryParams, removeHash],
  },
  {
    path: '/about',
    component: UserDetails,
    beforeEnter: [removeQueryParams],
  },
]

请注意,你也可以通过使用路径 meta 字段全局导航守卫来实现类似的行为。

(5)组件内的守卫:

最后,你可以在路由组件内直接定义路由导航守卫(传递给路由配置的)

5.1可用的配置 API

你可以为路由组件添加以下配置:

  • beforeRouteEnter
  • beforeRouteUpdate
  • beforeRouteLeave
const UserDetails = {
  template: `...`,
  beforeRouteEnter(to, from) {
    // 在渲染该组件的对应路由被验证前调用
    // 不能获取组件实例 `this` !
    // 因为当守卫执行时,组件实例还没被创建!
  },
  beforeRouteUpdate(to, from) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 `/users/:id`,在 `/users/1` 和 `/users/2` 之间跳转的时候,
    // 由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`
  },
  beforeRouteLeave(to, from) {
    // 在导航离开渲染该组件的对应路由时调用
    // 与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`
  },
}

beforeRouteEnter 守卫 不能 访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。

不过,你可以通过传一个回调给 next 来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数:

beforeRouteEnter (to, from, next) {
  next(vm => {
    // 通过 `vm` 访问组件实例
  })
}

注意 beforeRouteEnter 是支持给 next 传递回调的唯一守卫。对于 beforeRouteUpdate 和 beforeRouteLeave 来说,this 已经可用了,所以不支持 传递回调,因为没有必要了:

beforeRouteUpdate (to, from) {
  // just use `this`
  this.name = to.params.name
}

这个 离开守卫 通常用来预防用户在还未保存修改前突然离开。该导航可以通过返回 false 来取消。

beforeRouteLeave (to, from) {
  const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
  if (!answer) return false
}
5.2使用组合 API

如果你正在使用组合 API 和 setup 函数来编写组件,你可以通过 onBeforeRouteUpdate 和 onBeforeRouteLeave 分别添加 update 和 leave 守卫。 请参考组合 API 部分以获得更多细节。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值