还是照旧加前提:页面极丑!请忽略,咱们看功能就行,懒得写样式了
前提:安装vue-cli vuex axios
目标:
1、实现头部搜索城市功能(v-if判断input不为空时,searchaction搜索城市结果列表块元素为true,indexof查找数据中的关键字)
2、遍历数组找出hot为true的热门城市
3、遍历数据,charAt(0)获取城市名称拼音的首拼字母,转换为大写,去重赋值,A-Z排序。2个用途,1是定义子集,按首拼该字母首拼的城市,2是显示在页面右侧,点击页面滚动到该字母子集的位置
4、点击城市,该城市的id 、name等数据用vuex保存到全局中去供其他组件获取到值
上代码
html部分
<div class="city">
<header>
<input type="text" v-model="searchcity" class="input-clear" placeholder="城市/拼音">
<div class="over" v-if="searchaction">
<ul>
<li class="cityte" v-for="(item,index) in searcharr" :key="index" @click="choosecity(item.name,item.id)">{{item.name}}</li>
</ul>
</div>
</header>
<div class="mui-content">
<div class="hot-city">
<p>当前城市:{{this.$store.state.locatecityname}}</p>
<p style="padding:1rem 0 0 0;">热门城市</p>
<div class="hot-list">
<div class="item-box fl" @click="choosecity(item.name,item.id)" v-for="(item,index) in hotcity" :key="index">{{item.name}}</div>
</div>
</div>
<div class="city-main">
<div class="city-list">
<ul>
<li v-for="(item,index) in citymain" :key="index" class="cityli" :id="item.top">
<p class="cityle">{{item.top}}</p>
<ul>
<li v-for="(itemx,index) in item.citylist" :key="index" @click="choosecity(itemx.name,itemx.id)" class="cityte">{{itemx.name}}</li>
</ul>
</li>
</ul>
</div>
<div class="city-letter">
<ul>
<li v-for="(item,index) in letter" :key="index" @click="lettercity($event)">{{item}}</li>
</ul>
</div>
<div class="showletter" v-if='showx'>{{showletter}}</div>
</div>
</div>
</div>
js部分
import axios from 'axios'
export default {
name:'city',
data() {
return {
datalist:[],
letter:[], //城市首拼列表
hotcity:[], //热门城市列表
citymain:[], //首拼+该首拼下城市列表
showx:false,
showletter:'',
searchcity:[], //输入框输入的文字
searcharr:[], //输入查找的城市匹配结果数组
searchaction:false //搜索城市结果列表块元素
}
},
mounted () {
axios.get('../../static/city.json').then(response => {
const citydata = response.data.cities;
this.datalist = response.data.cities;
let cityhead = []; //首拼字母集合
let newcityhead = [];
for(let i = 0;i < citydata.length;i++){
let letteritem = citydata[i].pinyin.charAt(0).toUpperCase(); //获取城市拼音的首字母
cityhead.push(letteritem);
let ishot = citydata[i];
if(citydata[i].isHot){
this.hotcity.push(ishot);
}
}
console.log(this.hotcity)
cityhead = cityhead.sort(function compareFunction(item1,item2) { //字母按中文顺序排序
return item1.localeCompare(item2);
});
console.log(cityhead); //字母数组,按中文顺序排,但未去重
let headarr = [];
for(let i = 0; i <cityhead.length;i++){ //去重
if(!headarr.includes(cityhead[i])){
headarr.push(cityhead[i]);
}
}
console.log(headarr);
this.letter = headarr; //完成去重并赋值
for(let i = 0;i < headarr.length;i++){
let cityitem = new Object(); //自定义对象,城市列表下子集(包括首字母、该字母首拼的城市集合)
cityitem.top = headarr[i]; //首字母
cityitem.citylist = []; //该字母首拼的城市集合
for(let j = 0;j < citydata.length;j++){
if(headarr[i].toLowerCase() === citydata[j].pinyin.charAt(0)){
let citya = new Object();
citya.name = citydata[j].name;
citya.id = citydata[j].cityId;
cityitem.citylist.push(citya);
}
}
this.citymain.push(cityitem);
}
}).catch(error => {
console.log(error)
this.errored = true
}).finally(() => this.loading = false)
},
methods:{
choosecity(name,id) {
let cityid = id;
let cityname = name;
this.$store.commit("updatecityid",cityid)
this.$store.commit("updatecityname",cityname)
this.searchaction = false;
},
lettercity:function($event){
let citym = document.getElementsByClassName("city-main")[0];
let text = $event.currentTarget.innerText;
let item = document.getElementById(text);
this.showx = true;
this.showletter = text;
let that = this;
setTimeout(function(){
that.showx = false;
},2000);
citym.scrollTo(0,item.offsetTop - 350);
}
},
watch:{
searchcity:function(){
let searchcities = [];
if(this.searchcity != ""){
this.searchaction = true;
for(let i = 0;i < this.datalist.length;i++){
let str = this.datalist[i].name;
if(str.indexOf(this.searchcity) != -1){
let searchcityitem = new Object();
searchcityitem.id = this.datalist[i].cityId;
searchcityitem.name = this.datalist[i].name;
searchcities.push(searchcityitem);
}
}
}
this.searcharr = searchcities;
if(this.searchcity.length == 0){
this.searchaction = false;
}else{
this.searchaction = true;
}
}
}
}
使用vuex别忘了把它注入到main.js里,我就经常忘/(ㄒoㄒ)/~~
Vuex 主要有四部分:
state:包含了store中存储的各个状态。
getter: 类似于 Vue 中的计算属性,根据其他 getter 或 state 计算返回值。
mutation: 一组方法,是改变store中状态的执行者,只能是同步操作。
action: 一组方法,其中可以包含异步操作。
刚开始写在man.js里,但后续开发,用的越多越不方便,后来另外创了store目录存放
actions.js
const actions = {
ASYNC_SET_NAME({ state, commit, rootState }, payload) {
setTimeout(() => {
state.bName = 'asyncName'
}, 4000)
}
}
getter.js
const getter = {
doneTodos:(state,getter) => {
return state.todos.filter(todo => todo.done)
}
}
export default getter
index.js
import Vue from 'vue'
import Vuex from 'vuex'
import actions from './actions'
import getter from './getter'
import mutations from './mutations'
import state from './state'
Vue.use(Vuex)
export default new Vuex.Store({
state,
getter,
mutations,
actions,
})
mutations.js
const mutations = {
updatecityname(state,arg){
state.locatecityname = arg
},
updatecityid(state,arg){
state.locatecityid = arg
},
savetoken(state,arg){
state.token = arg;
sessionStorage.setItem('Author',arg);
},
}
export default mutations
state.js
const state = {
locatecityname:'',
locatecityid:'',
}
export default state
最后,差点忘了,mock的城市数据city.json,当时我随便搜搜就找到了,懒得搜的,直接去我git里面拿吧
https://github.com/czzxff/city