当用户在浏览器端进行路由导航时,有些目标路由的组件需要从服务器端抓取数据,再把这些数据显示到网页上。抓取数据有以下两种方式。
(1)导航后抓取:在导航完成后,在目标路由的组件的生命周期函数中抓取数据。在抓取的过程中,可以在网页上显示“正在加载中...”的提示信息。
(2)导航前抓取:先在导航守卫函数beforeRouteEnter()和beforeRouteUpdate()中抓取数据,接下来再进行导航。
以上两种方式都能完成抓取任务,到底选用哪一种,取决于开发人员的喜好及开发团队的要求。
1、导航后抓取
例程1定义了ItemPostFetch组件,在它的created()钩子函数中,调用$watch()函数监听$route.params变量,如果该变量发生更新,就会执行fetchData()方法。该$watch()函数的第三个参数{ immediate: true }确保在ItemPostFetch组件的初始化阶段也会执行一次fetchData()方法。
fetchData()方法负责抓取数据,在实际应用中,会通过Ajax请求到服务器端抓取数据,本方法做了简化,通过setTimeOut()函数模拟耗时的抓取数据的行为。
■ 例程1 ItemPostFetch.vue
<template>
<div>
<div v-if="isLoading" >商品数据加载中...</div>
<div v-if="isError" >商品数据加载失败</div>
<div v-if="isReady">
<p>商品ID: {{item.id}}</p>
<p>商品名字: {{item.title }} </p>
<p>商品描述: {{item.desc}}</p>
</div>
</div>
</template>
<script>
import Items from '@/assets/items' //引入Item数据
export default {
data() {
return {
item: {},
isLoading: false,
isReady: null,
isError: null
}
},
created() {
//监听$route.params,如果发生更新,就调用fetchData()方法
this.$watch(
() => this.$route.params,
() => {
this.fetchData()
},
//确保在初始化组件时也调用一次fetchData()方法
{ immediate: true }
)
},
methods: {
fetchData() {
this.isReady = null
this.isError=null
this.isLoading = true
//模拟耗时的抓取数据行为,在实际应用中会到服务器端抓取数据
setTimeout(
()=>{
this.item=Items.find(
(item)=>item.id==this.$route.params.id
)
if(this.item){
//如果存在与id匹配的商品数据,就显示商品数据
this.isLoading=false
this.isReady=true
}else{
//如果不存在与id匹配的商品数据,就显示错误信息
this.isLoading=false
this.isError=true
}
},2000) //延迟2秒后执行数据抓取
}
}
}
</script>
在index.js中,为ItemPostFetch组件设置如下路由:
{
path: '/postfetch/:id',
component: ItemPostFetch
}
通过浏览器访问http://localhost:8080/#/postfetch/1,会看到网页上首先显示“商品数据加载中...”,接下来再显示id为1的商品信息。
通过浏览器访问http://localhost:8080/#/postfetch/5,会看到网页上首先显示“商品数据加载中...”,接下来再显示“商品数据加载失败”。
2、导航前抓取
在例程2定义了ItemPreFetch组件。在beforeRouteEnter()和beforeRouteUpdate()导航守卫函数中都会通过fetchData()函数抓取数据。fetchData()是一个独立的函数,不属于ItemPreFetch组件。fetchData()函数有一个作为回调函数的callback参数,当抓取数据完毕后,callback回调函数会把item变量和isError变量赋值给ItemPreFetch组件的item变量和isError变量。
由于在beforeRouteEnter()函数中不能通过this关键字访问ItemPreFetch组件,因此通过next()函数来为ItemPreFetch组件的item变量和isError变量赋值。
■ 例程2 ItemPreFetch.vue
<template>
<div>
<div v-if="isError" >商品数据加载失败</div>
<div v-if="! isError">
<p>商品ID: {{item.id}}</p>
<p>商品名字: {{item.title }} </p>
<p>商品描述: {{item.desc}}</p>
</div>
</div>
</template>
<script>
import Items from '@/assets/items' //引入Item数据
function fetchData(id,callback) {
let isError=null
let item=null
//模拟耗时的抓取数据行为,在实际应用中会到服务器端抓取数据
setTimeout(
()=>{
item=Items.find(
(item)=>item.id==id
)
if(item){
isError=false
}else{
isError=true
}
callback(item,isError)
},2000) //延迟2秒后执行数据抓取
}
export default {
data() {
return {
item: {},
isError: null
}
},
beforeRouteEnter(to, from, next) {
fetchData(to.params.id,
(item, isError) => {
next(vm => {
vm.item=item
vm.isError=isError
})
}
)
},
beforeRouteUpdate(to) {
fetchData(to.params.id,
(item, isError) => {
this.item=item
this.isError=isError
}
)
}
}
</script>
beforeRouteEnter()函数如果不使用next参数,还可以改写为:
beforeRouteEnter(to) {
fetchData(to.params.id,
(item, isError) => {
return vm => {
vm.item=item
vm.isError=isError
}
}
)
}
在index.js中,为ItemPreFetch组件设置如下路由:
{
path: '/prefetch/:id',
component: ItemPreFetch
}
通过浏览器访问http://localhost:8080/#/prefetch/1,会看到网页首先停留在原来的页面,接下来再显示id为1的商品信息。
通过浏览器访问http://localhost:8080/#/prefetch/5,会看到网页首先停留在原来的页面,接下来再显示“商品数据加载失败”。