第10章 Vue項(xiàng)目開發(fā)之城市

10-1.city頁面路由配置

1.添加路由配置

// router/index.js文件
import City from '@/pages/city/City'
export default new Router({
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    },
    {
      path: '/city',
      name: 'City',
      component: City
    }
  ]
})

2.添加相對(duì)應(yīng)的頁面
在pages文件下面添加city文件夾和City.vue文件


效果圖

3.初始化City.vue頁面

<template>
  <div>
    city
  </div>
</template>

<script>
export default {
  name: 'City'
}
</script>
<style lang="stylus" scoped>

</style>
10-2.city-header部分制作
//city/City.vue
<template>
  <div>
    <city-header></city-header>
  </div>
</template>

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

</style>


//city/components/header.vue
<template>
  <div class="header">
    城市選擇
    <router-link to="/">
      <div class="iconfont back-city">&#xe696;</div>
    </router-link>
  </div>
</template>

<script>
export default {
  name: 'CityHeader'
}
</script>
<style lang="stylus" scoped>
@import '~styles/varibles.styl'
.header
  position relative
  height $headHeight
  line-height $headHeight
  background $bgColor
  text-align center
  color #ffffff
  .back-city
    position absolute
    left 0
    top 0
    width .64rem
    text-align center
    padding 0 .1rem
    font-size .48rem
    color #fff
</style>

效果圖
10-3.city-search部分制作

上面咱們已經(jīng)完成了頭部的制作,這一節(jié)咱們來city-search的ui部分制作颓哮,隨后等咱們把city列表制作完成后窄陡,咱們?cè)賮碇谱鱟ity-search相關(guān)的邏輯部分入愧,代碼如下

//city/components/Search.vue
<template>
  <div class="search">
    <input class="search-input" type="text" placeholder="輸入城市名稱或者拼音" />
  </div>
</template>

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

city/City.vue,在city的主頁面引入我們制作好的city-search模塊


image.png
10-4 city-list互站、city-ajax 、city-vuex此蜈、city-search-logic 部分的制作
城市整體效果圖

Ui上面的制作堰氓,直接從github下載下來,git checkout 到不同的分支现柠,就能看到代碼了院领,總結(jié)嘛,不能能把所有的項(xiàng)目中的代碼都展示出來够吩,更多的是展示難點(diǎn)比然、思路、注意事項(xiàng)等等一些小細(xì)節(jié)地方周循。
city-ajax部分和index-ajax 方式是一樣强法,在這里咱們就不再次贅述了

知識(shí)點(diǎn)1:BetterScroll 的使用,讓城市列表可以滾動(dòng)起來

//安裝better-scroll
npm install better-scroll -S

在這個(gè)使用better-scroll的時(shí)候我們需要注意三點(diǎn)

  • dom結(jié)構(gòu)(要符合這種結(jié)構(gòu))
<div class="wrapper">
  <ul class="content">
    <li>...</li>
    <li>...</li>
    ...
  </ul>
  <!-- you can put some other DOMs here, it won't affect the scrolling
</div>
  • 樣式(要滾動(dòng)的list 要脫離文檔流)
.list 
  overflow: hidden;
  position: absolute;
  top: 1.6rem;
  left: 0;
  right: 0;
  bottom: 0;
  • 在vue中的調(diào)用和使用方法
//dom部分
<div class="list" ref="wrapper">
.....
</div>

//js部分
import BScroll from 'better-scroll'
mounted () {
    this.scroll = new BScroll(this.$refs.wrapper)
}

知識(shí)點(diǎn)2兄弟組件數(shù)據(jù)傳遞
我們知道:
City.vue是父組件
components/List.vue是一個(gè)子組件
components/Alphabet.vue也是一個(gè)子組件

那么子組件(Alphabet.vue)如何和子組件(List.vue)進(jìn)行通信呢?
現(xiàn)在有這樣的一個(gè)需求湾笛,就是當(dāng)我們點(diǎn)擊右側(cè)的字母(代碼在Alphabet.vue中)饮怯,列表(List.vue)能自動(dòng)滾動(dòng)相對(duì)應(yīng)的列表字母模塊部分,那么這個(gè)過程就是一個(gè)子組件和子組件的通信(兄弟組件數(shù)據(jù)傳遞)

思路:
第一步:子組件(Alphabet.vue)點(diǎn)擊字母的時(shí)候嚎研,通過$emit發(fā)送一個(gè)'change'的方法硕淑,并且把攜帶的點(diǎn)擊入?yún)鬟f給父組(City.vue)

//dom部分
<li
      class="item"
      v-for="item of letters"
      :key="item"
      @click="handleLetterClick" //觸發(fā)點(diǎn)擊事件
    >{{item}}</li>

//js部分
methods: {
    handleLetterClick (e) {
      this.$emit('change', e.target.innerText)
    }
}

第二步:父組件(City.vue)通過屬性來監(jiān)聽‘change’事件,同時(shí)創(chuàng)建一個(gè)新的方法嘉赎,在此方法中來接受子組件傳遞過來的參數(shù)置媳,隨后把入?yún)⒎湃氲絛ata初始化的letter中,再然后公条,把letter獲得入?yún)⒁詫傩缘姆绞絺鬟f給city-list組件

//1)dom 來監(jiān)聽子組件發(fā)出來的change
<city-alphabet :cities="cities" @change="handleLetterClick"></city-alphabet>

//4)dom 父組件從子組件那拿來的數(shù)據(jù)(letter)傳遞給新的子組件
<city-list :cities="cities" :hotCities="hotCities" :letter="letter"></city-list>

//2)初始化data中的letter值 用來存儲(chǔ)子組件出來的入?yún)?data () {
    return {
      letter: ''
    }
},

//3)js change 創(chuàng)建的方法 來接受子組件傳遞過來的值拇囊,并把它存儲(chǔ)到data里面
handleLetterClick (letter) {
      this.letter = letter
}

第三步:子組件(List.vue)通過屬性props來接受父組件傳過來的值

//js
props: {
    letter: String//接受父組件傳遞過來的值
},

//js 監(jiān)聽傳過來值的變化
watch: {
    letter () {
      if (this.letter) {
        const element = this.$refs[this.letter][0]  //通過獲取字母的值
        this.scroll.scrollToElement(element) //滾動(dòng)到指定元素模塊
      }
    }
  }

//dom 需要在字母模塊添加ref屬性
<div
  class="area"
  v-for="(item,key) of cities"
  :key="key" 
  :ref="key"http://這個(gè)key值剛好和兄弟組件傳過來的值相同
>
  <div class="title border-topbottom">{{key}}</div>
  <div class="item-list">
    <div class="item border-bottom" v-for="innerItem of item" :key="innerItem.id">{{innerItem.name}}</div>
  </div>
</div>

知識(shí)點(diǎn)3 完成一個(gè)手指滑動(dòng)右側(cè)字母,左側(cè)區(qū)域跟著滾動(dòng)
這部分咱們需要給右側(cè)的字母綁定上三個(gè)事件:

@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"

為了只讓在touchmove里面去觸發(fā)這些操作靶橱,所以我們需要定義個(gè)開關(guān)(標(biāo)示位),我們把這個(gè)標(biāo)示位放在了data里面

touchStatus: false //設(shè)置為false

所以當(dāng)我們開始滑動(dòng)的時(shí)候我們把touchStatus設(shè)置為true

handleTouchStart () {
  this.touchStatus = true
}

當(dāng)我們手指劃出觸發(fā)操作區(qū)域的時(shí)候寥袭,我們需要把標(biāo)示為設(shè)置為false

handleTouchEnd () {
  this.touchStatus = false
}

所以只有當(dāng)標(biāo)示位為true的這種情況,我們采取進(jìn)滑動(dòng)字母相對(duì)應(yīng)的操作

handleTouchMove () {
  if (this.touchStatus) {
  //滑動(dòng)過程中所對(duì)應(yīng)的邏輯
  }
}

思路
在滑動(dòng)這個(gè)過程中关霸,最終我們?cè)谶@個(gè)頁面上下滑動(dòng)的時(shí)候传黄,我們需要知道你滑動(dòng)的位置是第幾個(gè)字母
1、我們需要知道A字母距離頂部的距離
2队寇、我們需要知道手指滑動(dòng)到當(dāng)前字母距離頂部的的距離
3膘掰、把上面兩個(gè)做一個(gè)差值,那么我們就可以得到當(dāng)前位置距離A字母之間的高度
4、我們把得到這個(gè)差值高度除以每個(gè)字母的高度识埋,那么我們就得到了是第幾個(gè)字母了
根據(jù)上面這個(gè)思路凡伊,我們需要得到這個(gè)字母的數(shù)組:

computed: {
    letters () {
       const letters = []
       for (let i in this.cities) {
          letters.push(i)
       }
       return letters
    }
}

通過計(jì)算屬性,我們就可以把dom上的數(shù)據(jù)獲取從父組件傳遞過來的cities改為letters

<li
  class="item"
  v-for="item of letters" //通過計(jì)算屬性來獲得字母值
  :key="item"
  :ref="item"
  @click="handleLetterClick"
  @touchstart="handleTouchStart"
  @touchmove="handleTouchMove"
  @touchend="handleTouchEnd"
>
{{item}}
</li>

根據(jù)上面的思路咱們開始來編寫相對(duì)應(yīng)邏輯

handleTouchMove (e) {
    //標(biāo)示位開始
    if (this.touchStart) {
      const startY = this.$refs['A'].offsetTop //獲取字母A距離頂部的距離
      const touchY = e.touches[0].clientY - 79 //獲取手機(jī)滑動(dòng)當(dāng)前字母距離頂部距離(79是header和搜索框的高度)
      const index = Math.floor((touchY-startY) / 20) //獲得是第幾個(gè)字母

     if (index >= 0 && index < this.letters.length) {
        this.$emit('change', this.letters[index]) //在有效的索引里面去 查找是第幾個(gè)字母
     }
    }
}

其實(shí)寫到這塊我們的功能是完成了的窒舟,但是細(xì)想還有一些地方需要優(yōu)化?
初始化

data () {
  return {
    startY: 0,
    timer: null
  }
},

優(yōu)化一:每次都去求獲取字母A距離頂部的距離系忙?

updated () {
    this.startY = this.$refs['A'][0].offsetTop
},

優(yōu)化二:滑動(dòng)字母的時(shí)候,需要做一下事件節(jié)流(通過一個(gè)定時(shí)器timer)

handleTouchMove (e) {
  if (this.touchStatus) {
    if (this.timer) {
      clearTimeout(this.timer)
    }
    this.timer = setTimeout(() => {
      const startY = this.startY
      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])
      }
    }, 16)
  }
},

知識(shí)點(diǎn)4 實(shí)現(xiàn)一個(gè)城市搜索功能
需求
1.根據(jù)字母或者漢字可以進(jìn)行檢索想要的內(nèi)容
2.當(dāng)搜索框沒數(shù)據(jù)的時(shí)候惠豺,不顯示搜索區(qū)域內(nèi)容
3.當(dāng)搜索框有數(shù)據(jù)且數(shù)據(jù)不在搜索內(nèi)容時(shí)银还,顯示暫無搜索內(nèi)容
4.當(dāng)搜索出來的內(nèi)容比較多的時(shí)候,搜索內(nèi)容可以進(jìn)行滾動(dòng)(better-scroll)

第一步:獲取從父組件傳遞過來的cities值

props: {
    cities: Object
},

第二步:data里面初始化keyword洁墙、list蛹疯、timer

data () {
  return {
    keyword: '',
    list: [],
    timer: null
  }
},

第三步:watch方法監(jiān)聽keyword的更改、其中這里面包含timer優(yōu)化扫俺、list數(shù)據(jù)獲取苍苞、檢索操作的邏輯

watch: {
  keyword () {
    if (this.timer) {
      clearTimeout(this.timer)
    }
    if (!this.keyword) {
      this.list = []
      return false
    }
    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)
  }
},

第四步:數(shù)據(jù)處理好了固翰,要鋪到Ui上面
為了可以滾動(dòng):一定要符合better-scroll的dom結(jié)構(gòu)狼纬;search-content樣式要脫離文檔流。
只有當(dāng)有關(guān)鍵字才會(huì)顯示搜索內(nèi)容骂际;
當(dāng)關(guān)鍵字搜索沒有數(shù)據(jù)的時(shí)候疗琉,顯示”沒有搜索到匹配內(nèi)容“

<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="hasNoData">沒有搜索到匹配內(nèi)容</li>
  </ul>
</div>

第五步:搜索數(shù)據(jù)有了,但是過多的時(shí)候也要可以滾動(dòng)歉铝,better-scroll

mounted () {
  this.scroll = new Bscroll(this.$refs.search)
}

知識(shí)點(diǎn)5 vuex實(shí)現(xiàn)數(shù)據(jù)共享
如果學(xué)過react的同學(xué)肯定知道redux盈简,react是處理ui層的,那么數(shù)據(jù)層就是通過redux來完成太示,方便我們不同頁面之間的傳值柠贤,一直值的更改等等
同樣在vue中,vue也只負(fù)責(zé)ui部分类缤,vuex則是用來處理數(shù)據(jù)層的

vuex的原理圖

1.安裝vuex

npm install vuex -S

2.使用和調(diào)用vuex
因?yàn)関uex是處理數(shù)據(jù)模塊的臼勉,所以我們?cè)趕rc目錄下創(chuàng)建一個(gè)store目錄,在store目錄下面創(chuàng)建一個(gè)
index.js

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

export default new Vuex.Store({
  state: {
    city: '北京'
  }
})

創(chuàng)建好之后餐弱,我們?cè)趍ain.js文件中去調(diào)用這個(gè)文件

import store from './store'

new Vue({
  el: '#app',
  store,//根實(shí)例引入store
  router,
  components: { App },
  template: '<App/>'
})

3.應(yīng)用
在咱們這個(gè)項(xiàng)目中宴霸,首頁右上角的城市名稱是通過后端返給我們,那么我們可以通過vuex來初始化一個(gè)城市膏蚓,也可以通過vuex來更改城市這個(gè)值瓢谢。
在store/index.js 其實(shí)我們已經(jīng)做了city的初始化的值:北京
那么在首頁和城市頁面我們?nèi)绾潍@取vuex當(dāng)中這個(gè)值呢?

//pages/home/components/Header.vue
{{this.$store.state.city}}

//pages/city/components/List.vue  當(dāng)前城市
{{this.$store.state.city}}

點(diǎn)擊熱門城市或者點(diǎn)擊城市搜索出來列表切換城市的顯示驮瞧,那么我們?nèi)ト绾胃膕tate這個(gè)值呢氓扛?

//點(diǎn)擊熱門城市事件
@click="handleCityClick(item.name)"

methods: {
  handleCityClick (city) {
      //要調(diào)用store里面的dispatch方法
      this.$store.dispatch('changeCity', city)
  }
}

上面我們已經(jīng)觸發(fā)了一個(gè)dispatch的方法,那么我們通過actions來接受這個(gè)方法
store/index.js

export default new Vuex.Store({
  state: {
    city: '上海'
  },
 actions: {
    changeCity(ctx, city) {
      //console.log(city)
      //那么action如何調(diào)用mutations呢论笔?通過commit方法
      ctx.commit('changeCity',city)
    }
  },
  mutations: {
    changeCity (state, city) {
      state.city = city
    }
  }
})

從上面可以看出在我們發(fā)送dispatch的時(shí)候幢尚,并沒有觸發(fā)異步請(qǐng)求破停,或者批量的數(shù)據(jù)操作,所以上面操作尉剩,我們可以直接跳過actions這部分真慢,不需要去觸發(fā)dispatch操作,而是直接調(diào)用commit對(duì)mutations的操作
所以上面的代碼就可以改為:

//點(diǎn)擊熱門城市事件
@click="handleCityClick(item.name)"

methods: {
  handleCityClick (city) {
      //要調(diào)用store里面的dispatch方法
      this.$store.commit('changeCity', city)  //將dispatch 改為commit
  }
}


//store/index.js
export default new Vuex.Store({
  state: {
    city: '上海'
  },
  //刪除actions的相關(guān)操作
  mutations: {
    changeCity (state, city) {
      state.city = city
    }
  }
})

講到這里其實(shí)就實(shí)現(xiàn)了vuex的數(shù)據(jù)一個(gè)設(shè)置以及顯示的一些操作理茎,但是我們更具當(dāng)前的產(chǎn)品需求我們還是需要完善一下頁面跳轉(zhuǎn)黑界。
之前我們實(shí)現(xiàn)頁面跳轉(zhuǎn)是通過
1.router-link 的to屬性來實(shí)現(xiàn)
2.那么還有一種通過js 來實(shí)現(xiàn)頁面跳轉(zhuǎn)的$router.push
那么我們希望我們?cè)谶x擇完城市后,能自動(dòng)跳轉(zhuǎn)到首頁皂林,那么

this.$router.push('/')

知識(shí)點(diǎn)6 vuex的高級(jí)使用以及l(fā)ocalStorage

store/index.js文件的拆分和localStorage的應(yīng)用

在上面使用vuex中我們給city設(shè)置了一個(gè)初始值:'上海'朗鸠,但是當(dāng)我們切換完城市后,返回首頁础倍,如果我們刷新首頁烛占,那么我們選擇的城市就又變回為了默認(rèn)值:'上海',那么針對(duì)這種情況沟启,我們需要引入本地緩存localStorage忆家,但是呢,有些瀏覽器會(huì)屏蔽localStorage的一些東西德迹,為了程序的健壯性芽卿,減少?zèng)]必要的瀏覽器異常,所以在對(duì)localStorage進(jìn)行相關(guān)操作的時(shí)候胳搞,我們先進(jìn)行一層try catch的操作

//store/index.js
let defaultCity = '上海'
try {
  if (localStorage.city) {
    defaultCity = localStorage.city
  }
} catch (e) {}

export default new Vuex.Store({
  state: {
    city: defaultCity
  },
  mutations: {
    changeCity (state, city) {
      state.city = city
      try {
        localStorage.city = city
      } catch (e) {}
    }
  }
})

寫到這里我們發(fā)現(xiàn)卸例,將來如果我們業(yè)務(wù)比較復(fù)雜的話,store/index.js會(huì)變的越來越龐大肌毅,那么這不是我們希望看到的筷转,所以我們要對(duì)store/index.js進(jìn)行拆分。
那么如何進(jìn)行拆分呢悬而?
store/index.js 只是一個(gè)總文件呜舒,而這個(gè)總文件包含很多部分:state、actions摊滔、mutations等等阴绢,
那么我們將可以將這些模塊拆分成為:state.js、actions.js艰躺、mutations.js
最后再把他們引入到store/index.js文件中
那么呻袭,根據(jù)這個(gè)思路咱們接下來拆分一下store/index.js

//store/state.js

let defaultCity = '北京'
try {
  if (localStorage.city) {
    defaultCity = localStorage.city
  }
} catch (e) {

}

export default {
  city: defaultCity
}


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

那么store/index.js 就變?yōu)榱耍?/p>

import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
Vue.use(Vuex)

export default new Vuex.Store({
  state,
  mutations
})

vuex的高級(jí)應(yīng)用以及針對(duì)項(xiàng)目當(dāng)中的優(yōu)化

我們上面調(diào)用城市的時(shí)候是通過{{this.$store.state.city}}來實(shí)現(xiàn)的
如果這么寫的話,略顯頁面比較冗余腺兴。那么有沒有其他方法會(huì)比較簡(jiǎn)單一些呢左电?
vuex幫我們封裝了一些方法和aip有一個(gè)mapState的方法就可以幫我們實(shí)現(xiàn),那么應(yīng)該如何使用呢?

import { mapState } from 'vuex'

//第一種通過數(shù)組方法獲取
computed: {
    ...mapState(['city']) //這樣就把把store中的city值獲取到
}
//第二種通過對(duì)象方法獲嚷ㄗ恪(起一個(gè)別名)
computed: {
    ...mapState({
      currentCity: 'city'
    }) //這樣就把把store中的city值獲取到
}

//如果是第一種方法獲取的
將原來的 {{this.$store.state.city}} 改為 {{this.city}}

//如果是第二種方法獲取的
將原來的 {{this.$store.state.city}} 改為 {{this.currentCity}}

獲取vuex中store的數(shù)據(jù)我們可以通過mapState方法段誊,那么設(shè)置vuex數(shù)據(jù)呢?
我們可以通過vuex給我們提供的mapMutations方法栈拖,那么如何實(shí)現(xiàn)呢连舍?

import {mapMutations} from 'vuex'

methods: {
    handleCityClick (city) {
       //this.$store.commit('changeCity', city) 改為下面:
       this.changeCity(city)
       this.$router.push('/')
    },
    ...mapMutations(['changeCity'])
}

講的這里我們使用了vuex給我們提供的state、actions涩哟、mutations索赏,我們登錄vue官網(wǎng),我們發(fā)現(xiàn)vuex還給我們提供了兩個(gè)一個(gè)是getter贴彼、另一個(gè)是module
那么我們來看一下getter的使用

//store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
Vue.use(Vuex)

export default new Vuex.Store({
  state,
  mutations,
  getters: {
      doubleCity (state) {
          return state.city + ' ' + state.city
      }
  }
})

那么頁面上應(yīng)該如何使用或者調(diào)用呢潜腻?

import { mapGetters } from 'vuex'

computed: {
    ...mapGetters(['doubleCity'])
}

//頁面上調(diào)用
{{this.doubleCity}}

那么我們此時(shí)會(huì)想,這有什么用處呢器仗?因?yàn)閙apState就可以實(shí)現(xiàn)的方法融涣,我為什么還要使用mapGetters來實(shí)現(xiàn)呢?
其實(shí)呢精钮,我們發(fā)現(xiàn)getters方法有點(diǎn)類似vue組件當(dāng)中的computed方法威鹿,他可以把我們state值進(jìn)行處理后返給我們一個(gè)新值,從來來避免一些數(shù)據(jù)的冗余杂拨。
getter講完了专普,那么module我們?cè)谑裁辞闆r下去使用呢悯衬?
因?yàn)槲覀冊(cè)趕tore/index.js中 只寫了city相關(guān)的(state弹沽、actions、mutations)等等操作筋粗,當(dāng)我們?cè)趯?shí)際開發(fā)的過程中策橘,我們肯定不單單只有city這一個(gè)模塊的,如果有很多頁面的功能模塊的話娜亿,我們拆分的state.js丽已、actions.js、mutations.js會(huì)變得很臃腫的买决,這不是我們期盼看到的沛婴。
所以我們通過module模塊對(duì)我們的功能模塊進(jìn)行進(jìn)一步的拆分,每個(gè)功能模塊包含自己的(state、actions督赤、mutations等等)嘁灯。如下面例子:

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的狀態(tài)
store.state.b // -> moduleB 的狀態(tài)

知識(shí)點(diǎn)7 使用keep-alive優(yōu)化網(wǎng)頁
keep-alive是個(gè)抽象組件(或稱為功能型組件),實(shí)際上不會(huì)被渲染在DOM樹中躲舌。它的作用是在內(nèi)存中緩存組件(不讓組件銷毀)丑婿,等到下次再渲染的時(shí)候,還會(huì)保持其中的所有狀態(tài),并且會(huì)觸發(fā)activated鉤子函數(shù)羹奉。因?yàn)榫彺娴男枰ǔ3霈F(xiàn)在頁面切換時(shí)秒旋,所以常與router-view一起出現(xiàn):

//app.vue
 <keep-alive>
    <router-view/>
</keep-alive>

如此一來,每一個(gè)在router-view中渲染的組件诀拭,都會(huì)被緩存起來迁筛。
如果只想渲染某一些頁面/組件,可以使用keep-alive組件的include/exclude屬性耕挨。include屬性表示要緩存的組件名(即組件定義時(shí)的name屬性)瑰煎,接收的類型為string、RegExp或string數(shù)組俗孝;exclude屬性有著相反的作用酒甸,匹配到的組件不會(huì)被緩存。假如可能出現(xiàn)在同一router-view的N個(gè)頁面中赋铝,我只想緩存列表頁和詳情頁插勤,那么可以這樣寫:

<keep-alive :include="['Home', 'City']">
  <router-view />
</keep-alive>

那么針對(duì)咱們這個(gè)項(xiàng)目,當(dāng)我們?cè)黾由蟢eep-alive屬性后革骨,當(dāng)我們?cè)L問過的頁面請(qǐng)求過后农尖,再去請(qǐng)求的時(shí)候,那么就不會(huì)再去觸發(fā)ajax請(qǐng)求良哲,而在此項(xiàng)目中首頁的數(shù)據(jù)變更是需要我們切換不同的城市來實(shí)現(xiàn)變更的盛卡,也就是當(dāng)城市只要變更我們就需要對(duì)首頁數(shù)據(jù)進(jìn)行一次請(qǐng)求。那么我們應(yīng)該如何更新首頁的數(shù)據(jù)呢筑凫?

//通過vuex的mapState屬性我們可以獲取 city的值
import { mapState } from 'vuex'
 computed: {
    ...mapState(['city'])
  },

//通過ajax的入?yún)碚?qǐng)求不同城市的數(shù)據(jù)
getHomeInfo () {
      axios.get('/api/index.json?city=' + this.city).then(this.getHomeInfoSucc)
},

//當(dāng)我們觸發(fā)了keep-alive屬性后滑沧,那么就會(huì)多出一個(gè)activated的生命周期鉤子
//通過城市的變更,我們?cè)谶@個(gè)生命周期函數(shù)中再去請(qǐng)求接口巍实,入?yún)⒂米钚碌某鞘凶壹迹敲丛趺磥韰^(qū)分城市的變更呢?
//data里面定義一個(gè)新的字段lastCity
data () {
    return {
      lastCity: '',//定義
      swiperList: [],
      iconList: [],
      recommendList: [],
      weekendList: []
    }
  },


//如果當(dāng)前的city和最后一次請(qǐng)求的城市不一致棚潦,那么我們把最后一次請(qǐng)求的城市賦值為最新的城市令漂,且用最新的城市作為接口請(qǐng)求的入?yún)?activated () {
    if (this.lastCity !== this.city) {
      this.lastCity = this.city
      this.getHomeInfo()
    }
}

更多

上一篇:第9章 Vue項(xiàng)目開發(fā)之首頁
下一篇:第11章 Vue項(xiàng)目開發(fā)之詳情
全篇文章:Vue學(xué)習(xí)總結(jié)
所有章節(jié)目錄:Vue學(xué)習(xí)目錄

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市丸边,隨后出現(xiàn)的幾起案子叠必,更是在濱河造成了極大的恐慌,老刑警劉巖妹窖,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纬朝,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡嘱吗,警方通過查閱死者的電腦和手機(jī)玄组,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門滔驾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人俄讹,你說我怎么就攤上這事哆致。” “怎么了患膛?”我有些...
    開封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵摊阀,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我踪蹬,道長(zhǎng)胞此,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任跃捣,我火速辦了婚禮漱牵,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘疚漆。我一直安慰自己酣胀,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開白布娶聘。 她就那樣靜靜地躺著闻镶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪丸升。 梳的紋絲不亂的頭發(fā)上铆农,一...
    開封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音狡耻,去河邊找鬼墩剖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛酝豪,可吹牛的內(nèi)容都是我干的涛碑。 我是一名探鬼主播精堕,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼孵淘,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了歹篓?” 一聲冷哼從身側(cè)響起瘫证,我...
    開封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎庄撮,沒想到半個(gè)月后背捌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡洞斯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年毡庆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了坑赡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡么抗,死狀恐怖毅否,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蝇刀,我是刑警寧澤螟加,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站吞琐,受9級(jí)特大地震影響捆探,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜站粟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一黍图、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧奴烙,春花似錦雌隅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至趾牧,卻和暖如春检盼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背翘单。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來泰國打工吨枉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人哄芜。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓貌亭,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親认臊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子圃庭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容