跟我一起做一个vue的小项目(十)

接下来我们对城市列表页面进行优化,除了对数据优化,也会进行节流处理

//srcpagescitycomponentsAlphabet.vue
<template>
   <ul class="list">
       <li class="item"
        v-for="item of letters"
        @click="handleLetterClick"
        @touchstart="handleTouchStart"
        @touchmove="handleTouchMove"
        @touchend="handleTouchEnd"
        :key="item"
        :ref="item"
        >{{item}}</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>
import { clearTimeout, setTimeout } from 'timers'
export default {
  name: 'CityAlphabet',
  props: {
    cities: Object
  },
  computed: {
    letters () {
      const letters = []
      for (let i in this.cities) {
        letters.push(i)
      }
      return letters
    }
  },
  data () {
    return {
      touchStatus: false,
      startY: 0,
      timer: null
    }
  },
  updated () {
    this.startY = this.$refs['A'][0].offsetTop
  },
  methods: {
    handleLetterClick (e) {
      this.$emit('change', e.target.innerText)
      // console.log('e.target.innerText', e.target.innerText)
    },
    handleTouchStart () {
      this.touchStatus = true
    },
    handleTouchMove (e) {
      if (this.touchStatus) {
        // const startY = this.$refs['A'][0].offsetTop
        // console.log(startY)
        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])
          }
          console.log(touchY)
        }, 16)
      }
    },
    handleTouchEnd () {
      this.touchStatus = false
    }
  }
}
</script>
<style lang="stylus" scoped>
@import '~styles/varibles.styl';
.list
    display:flex
    flex-direction:column
    justify-content:center
    top:1.58rem
    right:0
    bottom:0
    .4rem
    position:absolute
    .item
        text-align:center
        line-height:.4rem
        text-align:center
        color:$bgColor
</style>

接下来我们来进行搜索列表的实现

<template>
<div>
    <div class="search">
        <input type="text"
        v-model="keyword"
        class="search-input"
        placeholder="请输入城市名或拼音">
    </div>
    <div class="search-content"
    ref="search"
    v-show="keyword"
    >
        <ul>
            <li
            :key="item.id"
            v-for="item of list"
            class="search-item border-bottom">
                {{item.name}}
            </li>
            <li
             class="search-item border-bottom"
             v-show="!list.length"
            >
            没有找到匹配数据
            </li>
        </ul>
    </div>
</div>
</template>
<script>
import { clearTimeout, setTimeout } from 'timers'
// 解决搜索框内容不能滚动
import Bscroll from 'better-scroll'
export default {
  name: 'CitySearch',
  props: {
    cities: Object
  },
  data () {
    return {
      keyword: '',
      list: [],
      timer: null
    }
  },
  computed: {
    hasNoData () {
      return !this.list.length
    }
  },
  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
        100%
        line-height:.62rem
        text-align:center
        border-radius:.06rem
        color:#666
.search-content
    z-index:1
    overflow:hidden
    position:absolute
    top:1.58rem
    left:0
    right:0
    bottom:0
    background:#eee
    .search-item
        line-height:.62rem
        padding-left:.2rem
        background:#fff
        color:#666

</style>

我们看下效果

接下来我们使用vuex进行城市定位选择,也就是城市选择页面的数据要传递给首页,也就是City组件中的数据要传递给home组件中
安装vuex

 cnpm install vuex --save

先看下实现的效果

代码如下

<template>
    <div class="list" ref="wrapper">
       <div>
            <div class="area">
            <div class="title border-topbottom">
                当前城市
            </div>
            <div class="button-list">
                <div class="button-wrapper">
                    <div class="button">{{this.$store.state.city}}</div>
                </div>
            </div>
        </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"
                    @click="handleCityClick(item.name)"
                >
                    <div class="button">{{item.name}}</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"
            v-for="(item,key) of cities"
            :key="key"
            :ref="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"
                     @click="handleCityClick(innerItem.name)"
                >
                    {{innerItem.name}}
                </div>
                <!-- <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div> -->
            </div>
        </div>
        <!-- <div class="area">
            <div class="title border-topbottom">
                B
            </div>
            <div class="item-list">
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
            </div>
        </div> -->
        <!-- <div class="area">
            <div class="title border-topbottom">
                C
            </div>
            <div class="item-list">
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
            </div>
        </div> -->
       </div>
    </div>
</template>
<script>
import Bscroll from 'better-scroll'
export default {
  name: 'CityList',
  props: {
    hot: Array,
    cities: Object,
    letter: String
  },
  methods: {
    handleCityClick (city) {
    //   this.$store.dispatch('changeCity', city)
      this.$store.commit('changeCity', city)
      this.$router.push('/')
    //   alert(city)
    }
  },
  watch: {
    letter () {
    //   console.log('this.letter', this.letter)
      if (this.letter) {
        const element = this.$refs[this.letter][0]
        console.log('element', element)
        this.scroll.scrollToElement(element)
      }
    }
  },
  mounted () {
    this.scroll = new Bscroll(this.$refs.wrapper)
  }
}
</script>
<style lang="stylus" scoped>
@import '~styles/varibles.styl';
.border-topbottom
    &:before
        border-color:#ccc
    &:after
        border-color:#ccc
.list
    overflow:hidden
    position:absolute
    top:1.58rem
    left:0
    right:0
    bottom:0
    .title
        line-height:.54rem
        background:#eee
        padding-left:.2rem
        color:#666
        font-size:.26rem
    .button-list
        padding:.1rem .6rem .1rem .1rem
        overflow:hidden
        .button-wrapper
            33.33%
            float:left
            .button
                margin:.1rem
                text-align:center
                border:.02rem solid #ccc
                border-radius:.06rem
                padding:.1rem 0
    .item-list
        .item
            line-height:.76rem
            color:#666
            padding-left:.2rem
</style>

接下来我们使用localstorage存储数据,使刷新的时候,也能记住我们选择的城市,另外代码还做了隐身模式或者浏览器不能保存数据的处理

//index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
let defaultCity = '上海'
try {
  if (localStorage.city) {
    defaultCity = localStorage.city
  }
} catch (e) {

}

export default new Vuex.Store({
  state: {
    // city: localStorage.city || '上海'
    city: defaultCity
  },
  //   actions: {
  //     changeCity (ctx, city) {
  //       ctx.commit('changeCity', city)
  //     }
  //   },
  mutations: {
    changeCity (state, city) {
      state.city = city
      try {
        localStorage.city = city
      } catch (e) {

      }
    //   localStorage.city = city
    }
  }
})

接下来我们来拆分index.js文件,将store中的内容按照state,mutation等进行处理

//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) {

    }
    //   localStorage.city = city
  }
}
//index.js
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
Vue.use(Vuex)
// let defaultCity = '上海'
// try {
//   if (localStorage.city) {
//     defaultCity = localStorage.city
//   }
// } catch (e) {

// }

export default new Vuex.Store({
  state,
  //   actions: {
  //     changeCity (ctx, city) {
  //       ctx.commit('changeCity', city)
  //     }
  //   },
  mutations
})
//header.vue
<template>
  <div class="header">
    <div class="header-left">
      <div class="iconfont back-icon">&#xe624;</div>
    </div>
    <div class="header-input">
      <span class="iconfont">&#xe632;</span>
      输入城市/游玩主题</div>
      <router-link to="/city">
        <div class="header-right">
          {{this.city}}
            <span class="iconfont arrow-icon">&#xe600;</span>
        </div>
      </router-link>
  </div>
</template>
<script>
import {mapState} from 'vuex'
export default {
  // 1rem = html font-size=50px
  name: 'HomeHeader',
  computed: {
    ...mapState(
      [
        'city'
      ]
    )
  },
  props: {
    // city: String
  }
}
</script>
<style lang="stylus" scoped>
@import '~styles/varibles.styl'
  .header
    line-height:$headerHeight
    background:$bgColor
    color:#fff
    display:flex
    .header-left
      0.64rem
      float:left
      .back-icon
        text-align:center
        font-size:0.4rem
    .header-input
      margin-top: 0.12rem;
      line-height: 0.64rem;
      -webkit-box-flex: 1;
      -ms-flex: 1;
      margin-bottom: 0.12rem;
      flex: 1;
      background: #fff;
      padding-left: 0.1rem;
      border-radius: 0.1rem;
      color: #ccc;
    .header-right
      min-1.04rem
      padding:0 .1rem
      float:right
      text-align:center
      color:#fff
      .arrow-icon
        margin-left:-.04rem
        font-size:.24rem
</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">
                    <div class="button">{{this.currentCity}}</div>
                </div>
            </div>
        </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"
                    @click="handleCityClick(item.name)"
                >
                    <div class="button">{{item.name}}</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"
            v-for="(item,key) of cities"
            :key="key"
            :ref="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"
                     @click="handleCityClick(innerItem.name)"
                >
                    {{innerItem.name}}
                </div>
                <!-- <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div> -->
            </div>
        </div>
        <!-- <div class="area">
            <div class="title border-topbottom">
                B
            </div>
            <div class="item-list">
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
            </div>
        </div> -->
        <!-- <div class="area">
            <div class="title border-topbottom">
                C
            </div>
            <div class="item-list">
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
                <div class="item border-bottom">阿拉尔</div>
            </div>
        </div> -->
       </div>
    </div>
</template>
<script>
import Bscroll from 'better-scroll'
import {mapState, mapMutations} from 'vuex'

export default {
  name: 'CityList',
  props: {
    hot: Array,
    cities: Object,
    letter: String
  },
  computed: {
    ...mapState({
      currentCity: 'city'
    })
  },
  methods: {
    handleCityClick (city) {
    //   this.$store.dispatch('changeCity', city)
    //   this.$store.commit('changeCity', city)
      this.changeCity(city)
      this.$router.push('/')
    //   alert(city)
    },
    ...mapMutations(['changeCity'])
  },
  watch: {
    letter () {
    //   console.log('this.letter', this.letter)
      if (this.letter) {
        const element = this.$refs[this.letter][0]
        console.log('element', element)
        this.scroll.scrollToElement(element)
      }
    }
  },
  mounted () {
    this.scroll = new Bscroll(this.$refs.wrapper)
  }
}
</script>
<style lang="stylus" scoped>
@import '~styles/varibles.styl';
.border-topbottom
    &:before
        border-color:#ccc
    &:after
        border-color:#ccc
.list
    overflow:hidden
    position:absolute
    top:1.58rem
    left:0
    right:0
    bottom:0
    .title
        line-height:.54rem
        background:#eee
        padding-left:.2rem
        color:#666
        font-size:.26rem
    .button-list
        padding:.1rem .6rem .1rem .1rem
        overflow:hidden
        .button-wrapper
            33.33%
            float:left
            .button
                margin:.1rem
                text-align:center
                border:.02rem solid #ccc
                border-radius:.06rem
                padding:.1rem 0
    .item-list
        .item
            line-height:.76rem
            color:#666
            padding-left:.2rem
</style>

接下来我们使用keep-alive优化网页性能
路由发生改变,请求就会进行多次

keep-alive进行缓存

//app.vue 请求之后就放内存中    从内存中取数据,不用再去请求
<template>
  <div id="app">
    <!-- 当前路由地址所对应的内容 -->
  <keep-alive>
    <!-- 缓存 -->
      <router-view/>
  </keep-alive>
  </div>
</template>

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

<style>

</style>

使用keep-alive的时候,我们会增加生命周期函数activated

//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 {mapState} from 'vuex'
import axios from 'axios'
export default {
  name: 'Home',
  components: {
    HomeHeader,
    HomeSwiper,
    HomeIcons,
    HomeRecommend,
    HomeWeekend
  },
  computed: {
    ...mapState(['city'])
  },
  data () {
    return {
      swiperList: [],
      iconList: [],
      recommendList: [],
      weekendList: [],
      lastCity: null
    }
  },
  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
    this.getHomeInfo()
  },
  activated () {
    // 页面重新显示再执行
    if (this.lastCity !== this.city) {
      this.lastCity = this.city
      this.getHomeInfo()
    }
  }
}
</script>
<style>
</style>
原文地址:https://www.cnblogs.com/smart-girl/p/11185788.html