使用Vue框架开发去哪儿旅游网移动端项目(七)

第七章 开发网站的城市列表页面

城市选择页面路由配置

先创建分支“city-router”,之后需要在pages文件夹之下新建一个city/city.vue。再切换到router文件夹之下的index.js。对新建city配置到之中。

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/pages/home/Home'
import City from '@/pages/city/City'

Vue.use(Router)

export default new Router({
     
  routes: [
    {
     
      path: '/',
      name: 'Home',
      component: Home
    },{
     
      path: '/city',
      name: 'City',
      component: City
    }]
})

对于City.vuerouter配置好之后,我们需要实现的是点击首页的右上角的城市就可以进入到City.vue的页面。

要实现该功能,需要使用标签(它包裹的内容被点击时,就会跳转到指定的页面之上)

Header.vue:

<router-link to="/city">
  <div class="header-right">{
     {
     this.city}}<span class="iconfont arrow-icon">&#xe64a;</span></div>
</router-link>

再到city文件夹中新建components文件夹,并且在components新建Header.vue组件。

Header.vue:

<template>
  <div class="header">城市选择</div>
</template>

<script>
export default {
     
  name: "CityHeader"
}
</script>

<style lang="stylus" scoped>
  @import '~styles/varibles.styl'
  .header
    overflow:hidden
    height:.86rem
    line-height:.86rem
    text-align:center
    color:#fff
    background:$bgColor
    font-size:.4rem
</style>

完成以上步骤,切换到city.vue文件中。对header.vue进行引入

City.vue:

<template>
  <city-header></city-header>
</template>

<script>
import CityHeader from './components/Header'
export default {
     
  name: "City",
  components:{
     
    CityHeader
  }
}
</script>

接下来,我们需要给当前城市页面添加一个返回主页的功能。这里我还是使用来完成就可以了。

<template>
  <div class="header">城市选择
    <router-link to="/">
      <div class="iconfont header-back">&#xe696;</div>
    </router-link>
  </div>
</template>
<style>
.header-back
  position:absolute
  top:0
  left:0
  width:.64rem
  text-align:center
  font-size:.4rem
  color:#fff
</style>

当前这个分支内容就写完了,就可以提交到仓库了。

添加搜索框

先新建一个分支“city-search”,在到city/components下新建Search.vue,代码如下:

<template>
  <div class="search">
    <input type="text" placeholder="输入城市名拼音" class="search-input" />
  </div>
</template>

<script>
export default {
     
  name: "CitySearch"
}
</script>

<style lang="stylus" scoped>
  @import '~styles/varibles.styl'
  .search
    height: .72rem
    background: $bgColor
    padding: 0 .1rem
    .search-input
      box-sizing: border-box
      height:.62rem
      width:100%
      text-align:center
      border-radius:.06rem
      color:#666
      padding: 0 .2rem
</style>

最后带city.vue文件引入search.vue就可以了,写完别忘了提交到仓库

列表布局

创建分支“city-list”,并新建List.vue

List.vue布局代码:

<template>
  <div class="list">
    <div class="area">
      <div class="title border-topbottom">您的位置</div>
      <div class="button-list">
        <div class="button-wrapper">
          <div class="button" style="border-color:#00bcd4">福州</div>
        </div>
      </div>
    </div>
    <div class="area">
      <div class="title border-topbottom">热门城市</div>
      <div class="button-list">
        <div class="button-wrapper">
          <div class="button">福州</div>
        </div>
        <div class="button-wrapper">
          <div class="button">福州</div>
        </div>
        <div class="button-wrapper">
          <div class="button">福州</div>
        </div>
        <div class="button-wrapper">
          <div class="button">福州</div>
        </div>
        <div class="button-wrapper">
          <div class="button">福州</div>
        </div>
        <div class="button-wrapper">
          <div class="button">福州</div>
        </div>
        <div class="button-wrapper">
          <div class="button">福州</div>
        </div>
        <div class="button-wrapper">
          <div class="button">福州</div>
        </div>
        <div class="button-wrapper">
          <div class="button">福州</div>
        </div>
      </div>
    </div>
    <div class="area">
      <div class="title border-topbottom">A</div>
      <div class="item-list">
        <div class="item border-topbottom">阿拉尔</div>
        <div class="item border-topbottom">阿拉尔</div>
        <div class="item border-topbottom">阿拉尔</div>
        <div class="item border-topbottom">阿拉尔</div>
      </div>
    </div>
    <div class="area">
      <div class="title border-topbottom">B</div>
      <div class="item-list">
        <div class="item border-topbottom">阿拉尔</div>
        <div class="item border-topbottom">阿拉尔</div>
        <div class="item border-topbottom">阿拉尔</div>
        <div class="item border-topbottom">阿拉尔</div>
      </div>
    </div>
    <div class="area">
      <div class="title border-topbottom">C</div>
      <div class="item-list">
        <div class="item border-topbottom">阿拉尔</div>
        <div class="item border-topbottom">阿拉尔</div>
        <div class="item border-topbottom">阿拉尔</div>
        <div class="item border-topbottom">阿拉尔</div>
      </div>
    </div>
    <div class="area">
      <div class="title border-topbottom">D</div>
      <div class="item-list">
        <div class="item border-topbottom">阿拉尔</div>
        <div class="item border-topbottom">阿拉尔</div>
        <div class="item border-topbottom">阿拉尔</div>
        <div class="item border-topbottom">阿拉尔</div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
     
  name: "CityList"
}
</script>

<style lang="stylus" scoped>
  .border-topbottom
    &:before
      border-color: #ccc
    &:after
      border-color: #ccc
  //加了list的样式 网页无法滑动  为什么这样写?是为了内容不被撑开
  .list
    overflow: hidden
    position: absolute
    top:1.58rem
    left:0
    right:0
    bottom:0
    .title
      line-height: .44rem
      background: #eee
      padding-left: .2rem
      color: #666
      font-size: .26rem
    .button-list
      padding:.1rem .6rem .1rem .1rem
      overflow:hidden
      .button-wrapper
        float:left
        width:33.33%
        .button
          margin: .1rem
          padding: .1rem 0
          border-radius:.06rem
          text-align:center
          border: .02rem solid #CCC
    .item-list
      .item
        line-height:.76rem
        color:#666
        padding-left:.2rem
</style>

Better-scroll的使用及字母表布局

在前面的一节,我们给页面的多余的代码给隐藏了,就导致了网页无法上下滑动。这节就需要用到第三发库Better-scroll,它可以帮助我们实现同样的上下滑动的效果。

# 安装better-scroll
npm install better-scroll --save

安装好之后,要使用该插件,就需要按照一定布局格式来使用,我们需要把HTML的布局改一下:

<template>
  //ref是用于接收DOM元素的
  <div class="list" ref="wrapper">
    <div> //这里额外的添加一个DIV标签
      <div class="area">
        <div class="title border-topbottom">您的位置</div>
        <div class="button-list">
          <div class="button-wrapper">
            <div class="button" style="border-color:#00bcd4">福州</div>
          </div>
        </div>
      </div>
      //...
    </div>
  </div>
</template>

布局已经改好了,我们直接按照以下的方式就用用了。实现后,发现顶部的Header不会再随着下滑而消失了。

<script>
import Bscroll from 'better-scroll'
export default {
     
  name: "CityList",
  mounted (){
     
    this.scroll = new Bscroll(this.$refs.wrapper)
  }
}
</script>

接下来我们要实现的是,右侧的字母导航功能。实现这个功能,我们需要单独的创建一个组件“Alphabet.vue”。

右侧的字母导航布局的代码:

<template>
  <ul class="list">
    <li class="item">A</li>
    <li class="item">B</li>
    <li class="item">C</li>
    <li class="item">D</li>
    <li class="item">E</li>
    <li class="item">F</li>
    <li class="item">G</li>
  </ul>
</template>

<script>
export default {
     
  name: "CityAlphabet"
}
</script>

<style lang="stylus" scoped>
  @import '~styles/varibles.styl'
  .list
    display:flex
    flex-direction:column
    justify-content:center
    position: absolute
    top: 1.58rem
    right:0
    bottom:0
    width:.4rem
    .item
      text-align:center
      line-height:.4rem
      color:$bgColor
</style>

动态渲染页面的数据

这里我们还是选择使用ajax来渲染。先创建分支“city-ajax”。json数据下载

有了城市json数据之后我们将它放到mock文件夹下。随后我们在city.vue组件中引入axios插件。

<template>
  <div>
    <city-header></city-header>
    <city-search></city-search>
    //给该组件传参
    <city-list :cities="cities" :hot="hotCities"></city-list>
    <city-alphabet></city-alphabet>
  </div>
</template>

<script>
import axios from "axios"
import CityHeader from './components/Header'
import CitySearch from './components/Search'
import CityList from './components/List'
import CityAlphabet from './components/Alphabet'
export default {
     
  name: "City",
  components:{
     
    CityHeader,
    CitySearch,
    CityList,
    CityAlphabet
  },
  //定义返回给组件的数据
  data(){
     
    return {
     
      cities:{
     },
      hotCities:[]
    }
  },
  methods:{
     
    getCityInfo(){
     
      axios.get("/api/city.json").then(this.handleGetCityInfoSucc)
    },
    //给data方法中的变量进行赋值
    handleGetCityInfoSucc(res){
     
      res = res.data
      if(res.ret && res.data){
     
        const data = res.data
        this.cities = data.cities
        this.hotCities = data.hotCities
      }
    }
  },
  mounted(){
     
    this.getCityInfo()
  }
}
</script>

<style lang="stylus" scoped>
  
</style>

这时我们把目光切换到list.vue,做出以下的修改:

<template>
  <div class="list" ref="wrapper">
    <div>
      //省略前面部分代码
      <div class="area">
        <div class="title border-topbottom">热门城市</div>
        <div class="button-list">
          <div class="button-wrapper" v-for="item of hot" :key="item.id">
            <div class="button">{
     {
     item.name}}</div>
          </div>
        </div>
      </div>
      <div class="area" v-for="item,key of cities" :key="key">
        <div class="title border-topbottom">{
     {
     key}}</div>
        <div class="item-list">
          <div class="item border-topbottom" v-for="innerItem of item" :key="innerItem.id">{
     {
     innerItem.name}}</div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
//省略前面部分代码
  props:{
     
    hot:Array,
    cities:Object
  },
//省略后面部分代码
}
</script>

接下来我们继续渲染右侧字母导航:对Alphabet.vue组件如下的修改:

<template>
  <ul class="list">
    <li class="item" v-for="item,key of cities" :key="key">{
     {
     key}}</li>
  </ul>
</template>

<script>
export default {
     
  name: "CityAlphabet",
  props:{
     
    cities:Object
  }
}
</script>

最后别忘记把代码提交到线上仓库。

兄弟组件间联动

我们需要实现的就是点击字母导航就可以跳转到对于的城市区域。创建分支“city-components”。

兄弟组件间的传值,前面说到的是使用“总线”的方式来实现。所以这里我们实现的思路就是由Alphabet.vue先给City.vue传值,再有它分发给List.vue组件。

Alphabet.vue:

<template>
  <ul class="list">
    //这里添加点击事件
    <li class="item" v-for="item,key of cities" :key="key" @click="letterClick">{
     {
     key}}</li>
  </ul>
</template>
<script>
methods:{
     
  letterClick(e){
     
    // 被点击的时候向外触发一个事件并携带被点击的数值
    this.$emit('change',e.target.innerText)
  }
}
</script>

City.vue:

<template>
  <div>
    //省略部分代码
    <city-alphabet :cities="cities" @change="letterClick"></city-alphabet>
  </div>
</template>

<script>
data(){
     
  return {
     
    cities:{
     },
    hotCities:[],
    letter:""
  }
},
methods:{
     
    //省略部分代码....
    //监听Alphabet.vue的change点击事件
    letterClick(letter){
     
      this.letter = letter
    }
  }
</script>

List.vue:

<template>
  <div class="list" ref="wrapper">
    <div>
      //省略部分代码   添加了ref用户获取DOM元素
      <div class="area" v-for="item,key of cities" :key="key" :ref="key">
        //.....
      </div>
    </div>
  </div>
</template>

<script>
import Bscroll from 'better-scroll'
export default {
     
  //省略部分代码....
  // 监听letter的变化
  watch:{
     
    letter(){
     
      if (this.letter) {
     
        // 由于获取到的是数组,所以需要加[0]
        const element = this.$refs[this.letter][0]
        // scrollToElement是由better scroll提供
        this.scroll.scrollToElement(element)
      }
    }
  }
}
</script>

完成以上步骤,就可以实现了点击字母就会跳转到对于的区域。现在需要给它做的是当滑动页面的时候,字母导航也会显示滑动的效果。要完成该功能只需对Alphabet.vue做出修改就可以了。

完整代码:

<template>
  <ul class="list">
    <li 
      class="item" 
      v-for="item of letters" 
      :key="item" 
      :ref="item"
      @click="letterClick" 
      @touchstart="handletouchStart" 
      @touchmove="handletouchMove" 
      @touchend="handletouchEnd"
    >
      {
     {
     item}}
    </li>
  </ul>
</template>

<script>
export default {
     
  name: "CityAlphabet",
  props:{
     
    cities:Object
  },
  // 当触发touchstart之后才执行touchmove 所以定义该标识位
  data (){
     
    return {
     
      touchStatus:false
    }
  },
  // 计算出当前所在字母的位置
  computed:{
     
    letters (){
     
      const letters = []
      for (let i in this.cities) {
     
        letters.push(i)
      }
      return letters
    }
  },
  methods:{
     
    letterClick(e){
     
      // 被点击的时候向外触发一个事件并携带被点击的数值
      this.$emit('change',e.target.innerText)
    },
    handletouchStart(){
     
      this.touchStatus = true
    },
    // 获取手指移动到的地方并计算所接触的字母
    handletouchMove(e){
     
      if (this.touchStatus) {
     
        const startY = this.$refs['A'][0].offsetTop
        const touchY = e.touches[0].clientY - 79
        const index = Math.floor((touchY - startY) / 20)
        if(index >= 0 && index < this.letters.length){
     
          this.$emit('change',this.letters[index])
        }
      }
    },
    handletouchEnd(){
     
      this.touchStatus = false
    }
  }
}
</script>

<style lang="stylus" scoped>
  @import '~styles/varibles.styl'
  .list
    display:flex
    flex-direction:column
    justify-content:center
    position: absolute
    top: 1.58rem
    right:0
    bottom:0
    width:.4rem
    .item
      text-align:center
      line-height:.4rem
      color:$bgColor
</style>

优化列表代码性能

去除重复性计算的代码:

<script>
data (){
     
  return {
     
    touchStatus:false,
    // 添加了初始startY变量
    startY:0
  }
},
//....
// 当ajax获取到数据的时候开始计算
update(){
     
  this.startY = this.$refs['A'][0].offsetTop
},
//...
handletouchMove(e){
     
  if (this.touchStatus) {
     
    //与前面比较已经把第一句删了
    const touchY = e.touches[0].clientY - 79
    //注意这里的startY是data中的。
    const index = Math.floor((touchY - this.startY) / 20)
    if(index >= 0 && index < this.letters.length){
     
      this.$emit('change',this.letters[index])
    }
  }
}
</script>

给touchmove函数添加一个函数节流。由于前面的写法切换的台频繁:

<script>
data (){
     
  return {
     
    touchStatus:false,
    startY:0,
    timer:null
  }
},
// 获取手指移动到的地方并计算所接触的字母
handletouchMove(e){
     
  if (this.touchStatus) {
     
    if (this.timer) {
     
      clearTimeout(this.timer)
    }
    this.timer = setTimeout(() => {
     
      const touchY = e.touches[0].clientY - 79
      const index = Math.floor((touchY - this.startY) / 20)
      if(index >= 0 && index < this.letters.length){
     
        this.$emit('change',this.letters[index])
      }
    },16)
  }
}
</script>

搜索功能的实现

完整代码:

<template>
  <div>
    <div class="search">
      <input v-model="keyword" type="text" placeholder="输入城市名拼音" class="search-input" />
    </div>
    <div class="search-content" ref="search" v-show="keyword">
      <ul>
        <li class="search-item border-bottom" v-for="item of list" :key="item.id">{
     {
     item.name}}</li>
        <li class="search-item border-bottom" v-show="hasData">未找到匹配数据</li>
      </ul>
    </div>
  </div>
</template>

<script>
import Bscroll from "better-scroll"
export default {
     
  name: "CitySearch",
  props: {
     
    cities: Object
  },
  data (){
     
    return {
     
      keyword: "",
      list: [],
      timer:null  //用于节流声明
    }
  },
  // 计算是否匹配到数据
  computed:{
     
    hasData (){
     
      return !this.list.length
    }
  },
  //监听搜索栏keyword的变化
  watch:{
     
    keyword (){
     
      if (this.timer) {
     
        clearTimeout(this.timer)
      }
      if (!this.keyword) {
     
        this.list = []
        return
      }
      this.timer = setTimeout(() => {
     
        const result = []
        for(let i in this.cities){
     
          this.cities[i].forEach((value) => {
     
            if(value.spell.indexOf(this.keyword) > -1 || value.name.indexOf(this.keyword) > -1) {
     
              result.push(value)
            }
          })
        }
        this.list = result
      },100)
    }
  },
  mounted () {
     
    // 实现搜索结果页面的滑动
    this.scroll = new Bscroll(this.$refs.search)
  }
}
</script>

<style lang="stylus" scoped>
  @import '~styles/varibles.styl'
  .search
    height: .72rem
    background: $bgColor
    padding: 0 .1rem
    .search-input
      box-sizing: border-box
      height:.62rem
      width:100%
      text-align:center
      border-radius:.06rem
      color:#666
      padding: 0 .2rem
  .search-content
    position:absolute
    top:1.58rem
    overflow:hidden
    left:0
    right:0
    bottom:0
    background:#eee
    z-index:1
    .search-item
      line-height:.62rem
      padding-left:.2rem
      color:#666
      background:#fff
</style>

使用Vuex实现数据共享

这节课要实现的是首页与城市列表进行数据共享,意思就是点击城市,该城市传递给首页。首先先创建分支“city-vuex”。

再来介绍一个Vuex是由官网提供的大型数据框架,可以对数据进行共享、交互。

安装vuex:

npm install vuex --save

由于后期使用vuex开发数据还是很复杂的,所以便于后期维护,我们在src下新建一个文件夹store,在该文件夹之下再创建一个index.js。具体内容如下:

import Vue from 'vue'
import Vuex from 'vuex'

// 让vue使用vuex插件
Vue.use(Vuex)

// 导出的是vuex创建的一个仓库
export default new Vuex.Store({
     
	// 公用的数据存储在state之中
	state: {
     
		city: "福州"
	}
})

之后再将它引入到main.js中使用。

import store from './store'

new Vue({
     
//....
  store,
//...
})

https://vuex.vuejs.org/flow.png

通过前面的代码实现,我们已经完成了state的数据内容,根据这张图,接下来我们就应把数据共享到视图层(首页)。

因为前面开发的首页,右上角的城市是通过json直接传的,这样根本无法实现城市列表与首页进行数据共享,所以我们需要在home/Home.vue组件中将相关的city代码删除。在components/Header.vue也用相关的代码,也要删除,对做出以下的修改:

<router-link to="/city">
			<div class="header-right">{
     {
     this.$store.state.city}}<span class="iconfont arrow-icon">&#xe64a;</span></div>
</router-link>

做到这里就已经成功的完成了首页的城市关联。接下来我们要对城市列表中的当前位置进行关联。代码如下:

<div class="area">
    <div class="title border-topbottom">您的位置</div>
	<div class="button-list">
    	<div class="button-wrapper">
        	<div class="button" style="border-color:#00bcd4">{
     {
     this.$store.state.city}}</div>
		</div>
	</div>
</div>

接下来,我们需要点击城市列表中的任意一个城市都能更改当前的城市。所以就需要为列表中的每个城市选项添加一个点击事件并且传入当前所点击的城市名,并且在逻辑区下事件的执行内容。代码如下:

<div class="item-list">
  <div class="item border-topbottom" v-for="innerItem of item" :key="innerItem.id" @click="handleCityClick(innerItem.name)">{
     {
     innerItem.name}}</div>
</div>

methods: {
     
  handleCityClick (city) {
     
    // this.$store.dispatch('changeCity',city)
    // 组件可以直接调用mutations
    this.$store.commit('changeCity',city)
  }
}

接下来我们回到state/index.js添加以下代码:

import Vue from 'vue'
import Vuex from 'vuex'

// 让vue使用vuex插件
Vue.use(Vuex)

// 导出的是vuex创建的一个仓库
export default new Vuex.Store({
     
  // 公用的数据存储在state之中
  state: {
     
    city: "厦门"
  },
  // 整个执行流程是:组件调用actions,actions调用mutations,mutations再改变state的数据
  // actions: {
     
  //  // 接收页面传过来的参数并处理
  //  changeCity(ctx,city) {
     
  //    ctx.commit('changeCity',city)
  //  }
  // },
  mutations: {
     
    changeCity (state,city) {
     
      state.city = city
    }
  }
})

除了上面做出的修改,也要需要到search.vue中做出同样的修改。

完成以上代码,最后我们需要点击某个城市之后,马上就跳转到首页,这里需要用到vue router路由的知识点-编程式导航。具体实现代码如下:

methods: {
     
    handleCityClick (city) {
     
        // this.$store.dispatch('changeCity',city)
        // 组件可以直接调用mutations
        this.$store.commit('changeCity',city)
        // 使用vue-router 跳转到首页
        this.$router.push('/')
    }
}

Vuex的高级使用及localStorage

前面一节把store/index.js中的city值给固定死了,所以当我们更改城市的时候,当刷新后,显示又是默认的城市。所以我们需要解决的是记住前面你所更改的城市。这里我们使用localStore来解决这个问题。

export default new Vuex.Store({
     
	// 公用的数据存储在state之中
	state: {
     
		city: localStorage.city || "厦门"
	},
	mutations: {
     
		changeCity (state,city) {
     
			state.city = city
			localStorage.city = city
		}
	}
})

这里建议使用localStorage的时候添加异常捕获,因为有些用的使用浏览器的时候,使用的是隐身模式,如果没有就报错。

import Vue from 'vue'
import Vuex from 'vuex'

// 让vue使用vuex插件
Vue.use(Vuex)

let defaultCity = "厦门"
try{
     
	if (localStorage.city) {
     
		defaultCity = localStorage.city
	}
}catch (e) {
     }

// 导出的是vuex创建的一个仓库
export default new Vuex.Store({
     
	// 公用的数据存储在state之中
	state: {
     
		city: defaultCity
	},
	mutations: {
     
		changeCity (state,city) {
     
			state.city = city
			try{
     
				localStorage.city = city
			}catch (e) {
     }
		}
	}
})

我们会看到上面的代码,越来复杂,所以在实际的开发过程中呢,都会对代码进行拆分。我们分别在store文件夹下新建state.jsmutations.js文件。最后我们再到主文件中引入即可。

state.js代码如下:

let defaultCity = "厦门"
try{
     
	if (localStorage.city) {
     
		defaultCity = localStorage.city
	}
}catch (e) {
     }

export default {
     
	city: defaultCity
}

mutations.js代码如下:

export default {
     
	changeCity (state,city) {
     
		state.city = city
		try{
     
			localStorage.city = city
		}catch (e) {
     }
	}
}

index.js代码:

import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
// 让vue使用vuex插件
Vue.use(Vuex)
// 导出的是vuex创建的一个仓库
export default new Vuex.Store({
     
	// 公用的数据存储在state之中
	state,
	mutations
})

接下来,再介绍一个关于vuex的映射的知识点,具体使用看以下代码:

// 使用前需要先引入
import {
      mapState,mapMutations } from 'vuex'

// 通过计算属性将state/index中的city内容映射到mapSate之中
computed: {
     
  ...mapState({
     
    currentCity:'city'
  })
},
methods: {
     
  handleCityClick (city) {
     
    //最后直接使用映射的函数
    this.changeCity(city)
    // 使用vue-router 跳转到首页
    this.$router.push('/')
  },
  // 将state/index中的changeCity内容映射到mapMutations之中
  ...mapMutations (['changeCity'])
}

更多相关的内容可以去官方学习。

使用keep-alive优化网页性能

现在的问题是,当我们运行网页的时候,我们会发现每次在首页与城市列表两个页面来回切换的时候,每一次都会请求响应的json数据,这样就会造成过多的性能消耗的问题。

那么使用keep-alive就会有效的解决这个问题,keep-alive是vue官方提供的组件,它的意思是当我们切换路由时所加载的数据,会将所加载的数据文件存储到缓存中,这样就会避免多次加载的情况。

所以我们只需要在App.vue文件中做出以下修改:

<template>
  <div id="app">
    <keep-alive>
      <router-view/>
  </keep-alive>
  </div>
</template>

当我们切换城市的时候,希望在首页显示对应城市的数据。但是现在切换后首页的数据并没有重新获取,所以我们在Home.vue组件中做出以下修改:

<script>

export default {
     
  data (){
     
    return {
     
      lastCity: '',
      //...
  },
  computed:{
     
    ...mapState(['city'])
  },
  methods:{
     
    getHomeInfo (){
     
      // 虽然这里我们写的是api的开头的地址,但是vue已经帮我们跳转到了我们本地的json文件
      axios.get('/api/index.json?city=' + this.city)
        .then(this.getHomeInfoSucc)
    },
    //...
  },
  mounted (){
     
    this.lastCity = this.city
    this.getHomeInfo()
  },
  // 当使用keep-alive的时,会多出该周期函数
  activated () {
     
    if (this.lastCity !== this.city) {
     
      this.lastCity = this.city
      this.getHomeInfo()
    }
  }
}
</script>

你可能感兴趣的:(前端)