(18)城市选择页开发——⑧ 使用 keep-alive 优化网页性能 | Vue.js 项目实战: 移动端“旅游网站”开发

205 阅读4分钟
转载请注明出处,未经同意,不可修改文章内容。

🔥🔥🔥“前端一万小时”两大明星专栏——“从零基础到轻松就业”、“前端面试刷题”,已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。

涉及面试题:
keep-alive 标签的目的是什么?

[编号:travel_18]

1 问题分析

我们的项目开发到这里,“首页”和“城市选择页”好像都已经完成了,整个开发过程中也进行过多次代码的优化、性能的优化,看起来并没有什么问题。

但实际上,就整个网页性能上来说,它依然存在问题。

我们打开控制台的 Network,选中 XHR 查看请求。当在首页点击城市,切换到城市选择页后,会请求城市的数据 city.json ;从城市选择页跳转回首页时,又会请求一次首页的数据 index.json 。即,在首页与城市选择页间切换时,每次都会重新发送请求:

视频01.gif

❓为什么会重复发送请求呢?

答:因为每次路由重新从城市选择页 /city 切换到首页 / 时,首页 Home.vue 就会被重新渲染,然后 mounted 这个生命周期函数就会重新执行,去发送请求、获取数据(首页切换至城市选择页同理)。

2 使用 <keep-alive> 优化网页性能

❓重复发送请求,性能上就会较低,有什么办法可以解决这个问题呢?

答:使用 内置组件,可以解决这个问题。

1️⃣程序的入口组件是 App 这个组件,所以我们打开 App.vue

<template>
  <div id="app">
    <keep-alive> <!-- ❗️使用 keep-alive 标签包裹 router-view 标签(这是指:当这个路由被加载
								 过一次后,就把路由中的内容进行缓存,下次再进这个路由时,不需要再重新渲染、执行生命
								 周期函数,只需要从缓存中把之前的内容再显示出来即可。) -->
      <router-view/>
    </keep-alive>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>

</style>

保存后,返回页面查看。当在首页刷新页面时,请求一次首页数据 index.json ;进入城市选择页时,请求一次城市数据 city.json ,之后切换路由都不再重复发送请求:

视频02.gif

此时我们已经对性能上进行了优化,项目代码是否已经完美了呢?

其实还没有。

实际上,这里面还隐藏了一个问题。在实际的项目中,当我们切换“当前城市”后,首页的相关数据,都应该展示“当前城市”所对应的数据(即“当前城市”改变时,还应该发送一次请求,获取“新城市”的数据):

这就需要我们在发送 AJAX 请求时,带上“城市”的参数,去请求对应城市的数据。

2️⃣打开 home 下的 Home.vue

<template>
  <div>
    <home-header></home-header>
    <home-swiper :list="swiperList"></home-swiper>
    <home-icons :list="iconList"></home-icons>
    <home-recommend :list="recommendList"></home-recommend>
    <home-weekend :list="weekendList"></home-weekend>
  </div>
</template>

<script>
import HomeHeader from './components/Header'
import HomeSwiper from './components/Swiper'
import HomeIcons from './components/Icons'
import HomeRecommend from './components/Recommend'
import HomeWeekend from './components/Weekend'
import axios from 'axios'

import { mapState } from 'vuex' // 2️⃣-①:引入 mapState;

export default {
  name: 'Home',
  components: {
    HomeHeader,
    HomeSwiper,
    HomeIcons,
    HomeRecommend,
    HomeWeekend
  },
  data () {
    return {
      swiperList: [],
      iconList: [],
      recommendList: [],
      weekendList: []
    }
  },
  computed: { // 2️⃣-②:添加一个计算属性,使用 mapState,获取到城市对应的内容;
    ...mapState(['city'])
  },
  methods: {
    getHomeInfo () {
      axios.get('/api/index.json?city=' + this.city) /*
      																							 2️⃣-③:发送 AJAX 请求时带上参数
                                                     city;
                                                      */
        .then(this.getHomeInfoSucc)
    },
    getHomeInfoSucc (res) {
      res = res.data
      if (res.ret && res.data) {
        const data = res.data
        this.swiperList = data.swiperList
        this.iconList = data.iconList
        this.recommendList = data.recommendList
        this.weekendList = data.weekendList
      }
    }
  },
  mounted () {
    this.getHomeInfo()
  }
}
</script>

<style>
</style>

保存后,返回页面查看,当刷新页面时,发送的请求带上了当前城市“北京”:

但还有一个问题,在使用 <keep-alive> 标签后,只有在首次进入页面需要发送一次请求,之后切换页面时不再发送请求,而是使用缓存中的数据。

❓那么改变城市后,如何发送请求,再次获取对应城市的数据呢?

答:当我们使用 <keep-alive> 时,在组件中会有一个新的生命周期函数可以调用——activated,它会在切换组件(即切换页面)时执行。

我们在它执行前,判断“当前城市”是否与“最后选择的城市”不同。如果不同就在 activated 中再次发送请求,如果相同就依然使用缓存中的数据,不用发送请求。

3️⃣回到 home 下的 Home.vue

<template>
  <div>
    <home-header></home-header>
    <home-swiper :list="swiperList"></home-swiper>
    <home-icons :list="iconList"></home-icons>
    <home-recommend :list="recommendList"></home-recommend>
    <home-weekend :list="weekendList"></home-weekend>
  </div>
</template>

<script>
import HomeHeader from './components/Header'
import HomeSwiper from './components/Swiper'
import HomeIcons from './components/Icons'
import HomeRecommend from './components/Recommend'
import HomeWeekend from './components/Weekend'
import axios from 'axios'
import { mapState } from 'vuex'
export default {
  name: 'Home',
  components: {
    HomeHeader,
    HomeSwiper,
    HomeIcons,
    HomeRecommend,
    HomeWeekend
  },
  data () {
    return {
      lastCity: '', /*
      							3️⃣-①:在 data 中定义一个变量 lastCity,初始化为空,
      							它表示最后一次选择的城市;
                     */
      swiperList: [],
      iconList: [],
      recommendList: [],
      weekendList: []
    }
  },
  computed: {
    ...mapState(['city'])
  },
  methods: {
    getHomeInfo () {
      axios.get('/api/index.json?city=' + this.city)
        .then(this.getHomeInfoSucc)
    },
    getHomeInfoSucc (res) {
      res = res.data
      if (res.ret && res.data) {
        const data = res.data
        this.swiperList = data.swiperList
        this.iconList = data.iconList
        this.recommendList = data.recommendList
        this.weekendList = data.weekendList
      }
    }
  },
  mounted () {
    this.lastCity = this.city // 3️⃣-②:当页面被挂载后,让 lastCity 等于当前的 city;
    this.getHomeInfo()
  },
  activated () { // 3️⃣-③:添加 activated 生命周期函数;
    
    if (this.lastCity !== this.city) { // 3️⃣-④:如果 lastCity 不等于 city;

      this.lastCity = this.city /*
      													3️⃣-⑤:就让 lastCity 等于 city(即,最后一次选择的城市不等于
                                当前城市时,让当前城市作为最后一次选择的城市);
                                 */
      
      this.getHomeInfo() // 3️⃣-⑥:然后调用 getHomeInfo 重新发送请求。
    }
  }
}
</script>

<style>
</style>

保存后,返回页面查看。当首次进入首页时,请求一次数据;首次进入城市选择页时,请求一次城市数据。当在城市选择页选择相同城市时,不会发送请求;当切换为不同城市后,才再次发送请求、获取对应城市的数据:

视频03.gif

以上,我们就完成了“首页”和“城市选择页”所有的功能。

祝好,qdywxs ♥ you!