项目地址:

https://github.com/caochangkui/vue-cli3

项目代码:

城市列表首页:

City.vue

<template>
<div id="city">
<!-- <img src="/logo.png" alt="" height="10px"> -->
<div class="word" v-show="showWord">
<span>{{letter}}</span>
</div>
<div class="title">城市选择</div>
<city-list
:cities="cities"
:hot="hotCities"
:letter="letter"
></city-list>
<city-alphabet
:cities="cities"
@change="handleLetterChange"
></city-alphabet>
</div>
</template> <script>
import axios from 'axios'
import CityList from './components/List'
import CityAlphabet from './components/Alphabet'
export default {
name: 'City',
components: {
CityList,
CityAlphabet
},
data () {
return {
showWord: false,
cities: {},
hotCities: [],
letter: ''
}
},
methods: {
getCityInfo () {
axios.get('/mock/city.json').then(this.handleGetCityInfoSucc)
},
handleGetCityInfoSucc (res) {
console.log(res.data)
res = res.data
if (res.ret && res.data) {
const data = res.data
this.cities = data.cities
this.hotCities = data.hotCities
}
},
handleLetterChange (letter) {
console.log(letter)
this.letter = letter
this.showWord = true
setTimeout(() => {
this.showWord = false
console.log(this.showWord)
}, 500)
}
},
mounted () {
this.getCityInfo()
}
}
</script> <style scoped>
.title {
line-height: 40px;
background: #10d1eb;
color: #fff;
}
.word {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
z-index: 99;
}
.word span {
display: inline-block;
height: 60px;
width: 60px;
background: rgba(0, 0, 0, .2);
display: flex;
justify-content: center;
align-items: center;
}
</style>

城市列表组件:

List.vue

<template>
<div class="list" ref="wrapper">
<div>
<div class="area">
<div class="title">当前城市</div>
<div class="button-list">
<div class="button-wrapper">
<div class="button">{{this.currentCity}}</div>
</div>
</div>
</div>
<div class="area">
<div class="title">热门城市</div>
<div class="button-list">
<div
class="button-wrapper"
v-for="item in hot"
:key="item.id"
@click="handleCityClick(item.name)"
>
<div class="button">{{item.name}}</div>
</div>
</div>
</div>
<div
class="area"
v-for="(item, index) in cities"
:key="index"
:ref="index"
>
<div class="title">{{index}}</div>
<div
class="item-list"
v-for="innerItem in item"
:key=innerItem.id
@click="handleCityClick(innerItem.name)"
>
<div class="item"> {{innerItem.name}} </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
},
data () {
return { }
},
computed: {
...mapState({
currentCity: 'city'
})
},
watch: {
// 监听 Alphabet 中传过来的letter,如有变化,则滚动区域自动滚动到对应元素上
letter () {
if (this.letter) {
const element = this.$refs[this.letter][0] // 获取对应字母的ref
this.scroll.scrollToElement(element) // 利用better-scroll插件 滚动到指定元素element
console.log(element)
}
}
},
methods: {
...mapMutations(['changeCity']),
handleCityClick (city) {
console.log(city)
// this.$store.commit('changeCity', city) // 将参数city传给vuex中的mutations中的changeCity函数
this.changeCity(city)
this.$router.push('/') // 页面跳转 参考
}
},
mounted () {
this.scroll = new Bscroll(this.$refs.wrapper, {
click: true
})
}, }
</script> <style scoped>
.list {
position: absolute;
top: 40px;
left: 0;
right: 0;
bottom: 0;
overflow: hidden;
}
.title {
line-height: 40px;
background: #eee;
padding-left: 10px;
color: #666;
font-size: 14px;
text-align: left;
}
.button-list {
overflow: hidden;
padding: 10px 30px 10px 10px;
}
.button-wrapper {
float: left;
width: 33.33%;
}
.button {
margin: 4px;
padding: 4px 0;
text-align: center;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 14px;
color: #555;
}
.item {
line-height: 40px;
padding-left: 16px;
text-align: left;
border-bottom: 1px solid #eee;
}
</style>

字母检索组件:

Alphabet.vue

<template>
<div class="list-wrapper">
<ul class="list">
<li class="item"
v-for="item of letters"
:key="item"
:ref="item"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
@click="handleLetterClick"
>{{item}}</li>
</ul>
</div>
</template> <script>
export default {
name: 'CityAlphabet',
props: {
cities: Object
},
data () {
return {
touchStatus: false,
startY: 0,
timeer: null
}
},
computed: {
letters () {
const letters = []
for (let i in this.cities) {
letters.push(i)
}
return letters
}
},
// 生命周期函数
updated () {
this.startY = this.$refs['A'][0].offsetTop // A字母距离滚动条顶部距离
console.log('updated---> ', this.startY)
},
methods: {
handleLetterClick (e) {
this.$emit('change', e.target.innerText)
console.log(1)
},
handleTouchStart () {
console.log('开始滑动')
this.touchStatus = true
},
handleTouchMove (e) {
if (this.touchStatus) {
if (this.timeer) {
clearTimeout(this.timeer)
}
this.timeer = setTimeout(() => {
console.log(e.touches[0])
const touchY = e.touches[0].clientY - 40 // 手指触摸当前位置距离视口顶部的距离减去40(40指滚动区域最上边和页面顶部之间的距离)
const index = Math.floor((touchY - this.startY) / 26) // 手指触摸当前位置所在的字母索引(26指单个字母的高度)
if (index >= 0 && index < this.letters.length) {
this.$emit('change', this.letters[index])
}
}, 16)
}
},
handleTouchEnd () {
this.touchStatus = false
}
}
}
</script> <style scoped>
.list {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: absolute;
right: 0;
top: 40px;
bottom: 0;
width: 30px;
list-style: none;
background: rgba(0, 0, 0, .2);
margin: 0;
padding: 0;
z-index: 999;
}
.item {
line-height: 24px;
color: #068b9c;
font-size: 14px;
text-align: center;
width: 100%;
} </style>

通过vuex管理已选城市:

import Vue from 'vue'
import Vuex from 'vuex' Vue.use(Vuex) let defaultCity = '北京' try {
if (localStorage.city) {
defaultCity = localStorage.city
}
} catch (e) {e} const state = {
count: 1,
city: defaultCity
} const mutations = {
changeCity (state, city) {
state.city = city
try {
localStorage.city = city
} catch (e) {e}
}
} const actions = { } export default new Vuex.Store({
state,
mutations,
actions
})

vue-cli 3.0 实现A-Z字母滑动选择城市列表的更多相关文章

  1. VUE CLI 3.0 安装及创建项目

    一.安装 VUE CLI 3.0 官网: https://cli.vuejs.org/   详细资料可以自己先把官网过一遍. 1. 安装(默认你的电脑上已安装node及npm) npm install ...

  2. @vue/cli 3.0 使用 svg-sprite-loader 加载本地 SVG 文件

    目录 @vue/cli 3.0 使用 svg-sprite-loader 加载本地 SVG 文件 运行 使用 配置 svg-sprite-loader 调用当前环境下的颜色 props @vue/cl ...

  3. Vue CLI 3.0脚手架如何在本地配置mock数据

    前后端分离的开发模式已经是目前前端的主流模式,至于为什么会前后端分离的开发我们就不做过多的阐述,既然是前后端分离的模式开发肯定是离不开前端的数据模拟阶段. 我们在开发的过程中,由于后台接口的没有完成或 ...

  4. 如何使用@vue/cli 3.0在npm上创建,发布和使用你自己的Vue.js组件库

    译者按: 你可能npm人家的包过成千上万次,但你是否有创建,发布和使用过自己的npm包? 原文: How to create, publish and use your own VueJS Compo ...

  5. Django + Vue cli 3.0 访问静态资源问题

    [问题背景] 用Vue clie 3.0的搭建得框架把我坑死了,在打包后,调用不到静态资源js,css,mp3等 [问题原因] vue cli 3.0打包后,dist目录下没有static目录,而Dj ...

  6. 专访Vue作者尤雨溪:Vue CLI 3.0重构的原因

    1.为什么要对 Vue CLI 进行大规模修改? 尤雨溪认为旧版本的 Vue CLI 本质上只是从 GitHub 拉取模版,这种拉模版的方式有几个问题: (1) 在单个模版里面同时支持太多选项会导致模 ...

  7. vue cli 4.0.5 的使用

    vue cli 4.0.5 的使用 现在的 vue 脚手架已经升级到4.0的版本了,前两日vue 刚发布了3.0版本,我看了一下cli 4 和cli 3 没什么区别,既然这样,就只总结一下vue cl ...

  8. vue/cli 3.0脚手架搭建

    在vue 2.9.6中,搭建vue-cli脚手架的流程是这样的: 首先 全局安装vue-cli,在cmd中输入命令: npm install --global vue-cli  安装成功:  安装完成 ...

  9. @vue/cli 4.0+express 前后端分离实践

    之前总结过一篇vue-cli 2.x+express+json-server实现前后端分离的帖子,@vue/cli3.0及4.0搭建的项目与vue-cli2.x的项目结构有很大的不同.这里对@vue/ ...

随机推荐

  1. mysql Alter table设置default的问题,是bug么?

    不用不知道,用了没用? 昨天在线上创建了一个表,其中有两个列是timestamp类型的,创建语句假设是这样的: create table timetest(id int, createtime tim ...

  2. 在 Azure 中的 Windows 虚拟机上使用 SSL 证书保护 IIS Web 服务器

    若要保护 Web 服务器,可以使用安全套接字层 (SSL) 证书来加密 Web 流量. 这些 SSL 证书可存储在 Azure Key Vault 中,并可安全部署到 Azure 中的 Windows ...

  3. MySQL基础之 LIKE操作符

    LIKE操作符 作用:用于在WHERE子句中搜索列中的指定模式. 语法:SELECT  COLUMN_NAME  FROM  TABLE_NAME  WHERE  COLUMN_NAME  LIKE ...

  4. 乘风破浪:LeetCode真题_041_First Missing Positive

    乘风破浪:LeetCode真题_041_First Missing Positive 一.前言 这次的题目之所以说是难,其实还是在于对于某些空间和时间的限制. 二.First Missing Posi ...

  5. 2.js深入(以通俗易懂的语言解释JavaScript)

    1.函数返回值: 即函数的执行结果 可以没有return 经验:一个函数应该只返回一种类型的值 2.函数传参 可变参(不定参):arguments ——>(参数的个数可变,参数数组) 例子1:求 ...

  6. js节流

    function _throttling(fn,wait,mustRun){ var time=null; var startTime= new Date() return function(){ c ...

  7. 单一事件中心管理组件通信( vuex )

    有时候两个组件也需要通信(非父子关系).在简单的场景下,可以使用一个空的 Vue 实例作为中央事件总线: 补充$emit ,$on的讲解 代码: <!DOCTYPE html> <h ...

  8. MetaMask/zero-client

    https://github.com/MetaMask/zero-client MetaMask ZeroClient and backing iframe service architecture ...

  9. Pyspider抓取静态页面

    近期,我想爬一批新闻资讯的内容.新闻类型的网址很多,我想看看有没有一个网页上能包罗尽可能多的新闻网站呢,于是就发现了下面这个网页 http://news.hao123.com/wangzhi 这个页面 ...

  10. WorldWind源码剖析系列:地形瓦片类TerrainTile和地形瓦片服务类TerrainTileService

    地形瓦片类TerrainTile 用来抽象封装用户漫游中所请求的地形瓦片数据类型. 地形瓦片服务类TerrainTileService提供了从BIL(Binary Interleaved by Lin ...