目介绍
本项目是通过慕课网来学习的vue项目,因为公司比较忙,所以一段时间只能停下来。现在也算是终于写完了,因为没有本地服务器和后台支持,现在用的json文件调用。
项目引用插件
fastclick:处理移动端click事件300毫秒延迟 引用方式:main.js fastClick.attach(document.body)
babel-polyfill:es6转es5的转换器
vue-awesome-swiper:vue的swiper插件 引用方式:main.js Vue.use(VueAwesomeSwiper)
项目中vue-router&vuex,都是分别单独放在router和store文件夹下
项目组成
项目中分为首页,城市列表页,以及旅游项目详情页。
分别对应Home.vue city.vue detail.vue
-
首页 home.vue
构成:基本组件构建加vue-awesome-swiper 实现轮播。
(list.vue包含Recommend.vue和Weekend.vue。因为都是v-for循环出来的数据,很基础 这里就不做总结了)
home.vue 中的一个组件为icon.vue
这个组件每一个icon是一条数据,对于这个分页 ,同样采用swiper插件,那么第一页显示8条,剩余第二页就需要计算,在这里采用计算属性computed 定一个page(),创建一个pages变量,把父组件传来的值iconlist进行分组,8个一组,
进行分页展示
computed: { pages () { const pages = [] this.iconlist.forEach((item, index) => { const page = Math.floor(index / 8) if (!pages[page]) { pages[page] = [] } pages[page].push(item) }) return pages } }
home.vue其他的组件还是比较简单的,基本就是v-for对数据的循环。这里就不总结了。
-
城市列表页 city.vue
首先显示头部组件,当前城市和热门城市组件,城市搜索组件
头部组件:页面标题加返回按钮 这个没什么说的。
搜索组件:一个input框,这里用padding撑开(兼容),在页面上有一个灰色的不透明遮罩。v-show='hasNoData'来判断是否有数据来进行数据展示和友情提示。HasNoData是通过计算属性,把父组件传来的list的的长度作为判断条件
computed: {
hasNoData () {
return !this.list.length
}
}
在输入框搜索,进行匹配的可以是文字也可以是拼音,通过父组件传来的citylist循环遍历,再把每个citylist[i]遍历出来,就是每个数据的对象,进行匹配的文字和拼音就是name字段和spell字段,然后添加到result,然后再赋值给list,在模板中循环就ok。
(部分数据展示)
<script type="es6"> import Bscroll from 'better-scroll' import { mapMutations } from 'vuex' export default { name: 'CitySearch', props: { citylist: Object }, data () { return { keyword: '', list: [], times: null } }, methods: { handleCityClick (city) { // this.$store.commit('changeCity', city) this.changeCity(city) this.$router.push('/') }, ...mapMutations(['changeCity']) }, computed: { hasNoData () { return !this.list.length } }, watch: { keyword () { if (this.times) { clearTimeout(this.times) } if (!this.keyword) { this.list = [] return } this.times = setTimeout(() => { const result = [] for (let i in this.citylist) { this.citylist[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>
Alphabet.vue组件 ,根据字母滑动迅速定位到该字母的城市。
<template> <div> <ul class="list"> <li class="item" v-for="item of letters" :key="item" :ref="item" @click="handleLetterClick" @touchstart.prevent="handleTouchStart" @touchmove="handleTouchMove" @touchend="handleTouchEnd" > {{item}} </li> </ul> </div> </template>
updated () { this.startY = this.$refs['A'][0].offsetTop }, computed: { letters () { const letters = [] for (let i in this.citylist) { letters.push(i) } return letters } }, methods: { handleLetterClick (e) { this.$emit('change', e.target.innerText) }, handleTouchStart () { this.touchStatus = true }, 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) } }, handleTouchEnd () { this.touchStatus = false } }
通过计算属性把父组件传来的值进行循环,取出key值(A,B,C...),v-for循环key值,展示在页面。
滑动定位当前字母位置:首先三个事件,touchStart(开启滚动),touchMove(手指移动),touchEnd(停止滚动),
touchMove:touchY(手指滑动的位置),startY(首字母A的位置),因为css设计每个字母的宽高均为20,也就是说计算下标只需要Math.floor((touchY - this.startY) / 20),这样算出来的就是每个字母对应的下标,这样我们就能得到letters里面的数据,再传给父类,
父类再传给子组件CityList组件,再利用better-scroll提供的this.scroll.scrollToElement(element)方法,把对应的对象传进去就会自定滑到对应位置,所以在页面上直接通过父组件传来的litter就可以迅速定位到自己滑动的字母对应的位置。