(最详细)VueApp项目实战3 - - 城市选择

一、路由配置

1.目的

为了实现从首页可以跳转到城市选择页面


2.编辑’index.js’文件(路径: fonfig/index.js) - - - 创建路由的路径

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/pages/home/Home'
// 引入city这个组件
import City from '@/pages/city/City'

Vue.use(Router)
export default new Router({
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    }, {
    // 创建一个路由
    // 路径也是根目录下的city
      path: '/city',
    // 路由的名字叫City
      name: 'City',
    // 创建一个city的组件
      component: City
    }
  ]
})



二、Ajax动态获取城市数据

1. 创建 'city.json’文件(路径: src/static/mock/city.json)

{
	"ret": true,
	"data":{
		"city": "北京",
		"hotCities": [{
			"id": 1,
			"spell": "beijing",
			"name": "北京"
		}, {
			"id": 3,
			"spell": "shanghai",
			"name": "上海"
		}, {
			"id": 47,
			"spell": "xian",
			"name": "西安"
		}, {
			"id": 239,
			"spell": "sanya",
			"name": "三亚"
		}, {
			"id": 188,
			"spell": "lijiang",
			"name": "丽江"
		}, {
			"id": 125,
			"spell": "guilin",
			"name": "桂林"
		}],
		"cities": {
			"A": [{
				"id": 56,
				"spell": "aba",
				"name": "阿坝"
			}, {
				"id": 57,
				"spell": "akesu",
				"name": "阿克苏"
			}, {
				"id": 58,
				"spell": "alashanmeng",
				"name": "阿拉善盟"
			}, {
				"id": 59,
				"spell": "aletai",
				"name": "阿勒泰"
			}, {
				"id": 60,
				"spell": "ali",
				"name": "阿里"
			}, {
				"id": 61,
				"spell": "ankang",
				"name": "安康"
			}, {
				"id": 62,
				"spell": "anqing",
				"name": "安庆"
			}, {
				"id": 63,
				"spell": "anshan",
				"name": "鞍山"
			}, {
				"id": 64,
				"spell": "anshun",
				"name": "安顺"
			}, {
				"id": 65,
				"spell": "anyang",
				"name": "安阳"
			}, {
				"id": 338,
				"spell": "acheng",
				"name": "阿城"
			}, {
				"id": 339,
				"spell": "anfu",
				"name": "安福"
			}, {
				"id": 340,
				"spell": "anji",
				"name": "安吉"
			}, {
				"id": 341,
				"spell": "anning",
				"name": "安宁"
			}, {
				"id": 342,
				"spell": "anqiu",
				"name": "安丘"
			}, {
				"id": 343,
				"spell": "anxi",
				"name": "安溪"
			}, {
				"id": 344,
				"spell": "anyi",
				"name": "安义"
			}, {
				"id": 345,
				"spell": "anyuan",
				"name": "安远"
			}],
			"B": [{
				"id": 1,
				"spell": "beijing",
				"name": "北京"
			}, {
				"id": 66,
				"spell": "baicheng",
				"name": "白城"
			}, {
				"id": 67,
				"spell": "baise",
				"name": "百色"
			}, {
				"id": 68,
				"spell": "baishan",
				"name": "白山"
			}, {
				"id": 69,
				"spell": "baiyin",
				"name": "白银"
			}, {
				"id": 70,
				"spell": "bangbu",
				"name": "蚌埠"
			}, {
				"id": 71,
				"spell": "baoding",
				"name": "保定"
			}, {
				"id": 72,
				"spell": "baoji",
				"name": "宝鸡"
			}, {
				"id": 73,
				"spell": "baoshan",
				"name": "保山"
			}, {
				"id": 74,
				"spell": "baotou",
				"name": "包头"
			}, {
				"id": 75,
				"spell": "bayannaoer",
				"name": "巴彦淖尔"
			}, {
				"id": 76,
				"spell": "bayinguoleng",
				"name": "巴音郭楞"
			}, {
				"id": 77,
				"spell": "bazhong",
				"name": "巴中"
			}, {
				"id": 78,
				"spell": "beihai",
				"name": "北海"
			}, {
				"id": 79,
				"spell": "benxi",
				"name": "本溪"
			}, {
				"id": 80,
				"spell": "bijie",
				"name": "毕节"
			}, {
				"id": 81,
				"spell": "binzhou",
				"name": "滨州"
			}, {
				"id": 82,
				"spell": "boertala",
				"name": "博尔塔拉"
			}, {
				"id": 83,
				"spell": "bozhou",
				"name": "亳州"
			}, {
				"id": 346,
				"spell": "baoying",
				"name": "宝应"
			}, {
				"id": 347,
				"spell": "bayan",
				"name": "巴彦"
			}, {
				"id": 348,
				"spell": "binhai",
				"name": "滨海"
			}, {
				"id": 349,
				"spell": "binxian",
				"name": "宾县"
			}, {
				"id": 350,
				"spell": "binyang",
				"name": "宾阳"
			}, {
				"id": 351,
				"spell": "bishan",
				"name": "璧山"
			}, {
				"id": 352,
				"spell": "boai",
				"name": "博爱"
			}, {
				"id": 353,
				"spell": "boluo",
				"name": "博罗"
			}, {
				"id": 354,
				"spell": "boxing",
				"name": "博兴"
			}],
			"C": [{
				"id": 2,
				"spell": "chongqing",
				"name": "重庆"
			}, {
				"id": 5,
				"spell": "changchun",
				"name": "长春"
			}, {
				"id": 6,
				"spell": "changsha",
				"name": "长沙"
			}, {
				"id": 7,
				"spell": "changzhou",
				"name": "常州"
			}, {
				"id": 8,
				"spell": "chengdu",
				"name": "成都"
			}, {
				"id": 84,
				"spell": "cangzhou",
				"name": "沧州"
			}, {
				"id": 85,
				"spell": "changde",
				"name": "常德"
			}, {
				"id": 86,
				"spell": "changdu",
				"name": "昌都"
			}, {
				"id": 87,
				"spell": "changji",
				"name": "昌吉"
			}, {
				"id": 88,
				"spell": "changzhi",
				"name": "长治"
			}, {
				"id": 89,
				"spell": "chaohu",
				"name": "巢湖"
			}, {
				"id": 90,
				"spell": "chaoyang",
				"name": "朝阳"
			}, {
				"id": 91,
				"spell": "chaozhou",
				"name": "潮州"
			}, {
				"id": 92,
				"spell": "chengde",
				"name": "承德"
			}, {
				"id": 93,
				"spell": "chenzhou",
				"name": "郴州"
			}, {
				"id": 94,
				"spell": "chifeng",
				"name": "赤峰"
			}, {
				"id": 95,
				"spell": "chizhou",
				"name": "池州"
			}, {
				"id": 96,
				"spell": "chongzuo",
				"name": "崇左"
			}, {
				"id": 97,
				"spell": "chuxiong",
				"name": "楚雄"
			}, {
				"id": 98,
				"spell": "chuzhou",
				"name": "滁州"
			}, {
				"id": 355,
				"spell": "cangnan",
				"name": "苍南"
			}, {
				"id": 356,
				"spell": "cangshan",
				"name": "苍山"
			}, {
				"id": 357,
				"spell": "caoxian",
				"name": "曹县"
			}, {
				"id": 358,
				"spell": "changdao",
				"name": "长岛"
			}, {
				"id": 359,
				"spell": "changfeng",
				"name": "长丰"
			}, {
				"id": 360,
				"spell": "changhai",
				"name": "长海"
			}, {
				"id": 361,
				"spell": "changle",
				"name": "长乐"
			}, {
				"id": 362,
				"spell": "changle",
				"name": "昌乐"
			}, {
				"id": 363,
				"spell": "changshan",
				"name": "常山"
			}, {
				"id": 364,
				"spell": "changshu",
				"name": "常熟"
			}, {
				"id": 365,
				"spell": "changtai",
				"name": "长泰"
			}, {
				"id": 366,
				"spell": "changting",
				"name": "长汀"
			}, {
				"id": 367,
				"spell": "changxing",
				"name": "长兴"
			}, {
				"id": 368,
				"spell": "changyi",
				"name": "昌邑"
			}, {
				"id": 369,
				"spell": "chaoan",
				"name": "潮安"
			}, {
				"id": 370,
				"spell": "chenggong",
				"name": "呈贡"
			}, {
				"id": 371,
				"spell": "chengkou",
				"name": "城口"
			}, {
				"id": 372,
				"spell": "chengwu",
				"name": "成武"
			}, {
				"id": 373,
				"spell": "chiping",
				"name": "茌平"
			}, {
				"id": 374,
				"spell": "chongren",
				"name": "崇仁"
			}, {
				"id": 375,
				"spell": "chongyi",
				"name": "崇义"
			}, {
				"id": 376,
				"spell": "chongzhou",
				"name": "崇州"
			}, {
				"id": 377,
				"spell": "chunan",
				"name": "淳安"
			}, {
				"id": 378,
				"spell": "cixi",
				"name": "慈溪"
			}, {
				"id": 379,
				"spell": "conghua",
				"name": "从化"
			}, {
				"id": 380,
				"spell": "congyang",
				"name": "枞阳"
			}],
			"D": [{
				"id": 9,
				"spell": "dalian",
				"name": "大连"
			}, {
				"id": 10,
				"spell": "dongguan",
				"name": "东莞"
			}, {
				"id": 99,
				"spell": "dali",
				"name": "大理"
			}, {
				"id": 100,
				"spell": "dandong",
				"name": "丹东"
			}, {
				"id": 101,
				"spell": "daqing",
				"name": "大庆"
			}, {
				"id": 102,
				"spell": "datong",
				"name": "大同"
			}, {
				"id": 103,
				"spell": "daxinganling",
				"name": "大兴安岭"
			}, {
				"id": 104,
				"spell": "dazhou",
				"name": "达州"
			}, {
				"id": 105,
				"spell": "dehong",
				"name": "德宏"
			}, {
				"id": 106,
				"spell": "deyang",
				"name": "德阳"
			}, {
				"id": 107,
				"spell": "dezhou",
				"name": "德州"
			}, {
				"id": 108,
				"spell": "dingxi",
				"name": "定西"
			}, {
				"id": 109,
				"spell": "diqing",
				"name": "迪庆"
			}, {
				"id": 110,
				"spell": "dongying",
				"name": "东营"
			}, {
				"id": 381,
				"spell": "dafeng",
				"name": "大丰"
			}, {
				"id": 382,
				"spell": "daishan",
				"name": "岱山"
			}, {
				"id": 383,
				"spell": "dangshan",
				"name": "砀山"
			}, {
				"id": 384,
				"spell": "dangtu",
				"name": "当涂"
			}, {
				"id": 385,
				"spell": "danxian",
				"name": "单县"
			}, {
				"id": 386,
				"spell": "danyang",
				"name": "丹阳"
			}, {
				"id": 387,
				"spell": "dapu",
				"name": "大埔"
			}, {
				"id": 388,
				"spell": "datian",
				"name": "大田"
			}, {
				"id": 389,
				"spell": "dayi",
				"name": "大邑"
			}, {
				"id": 390,
				"spell": "dayu",
				"name": "大余"
			}, {
				"id": 391,
				"spell": "dazu",
				"name": "大足"
			}, {
				"id": 392,
				"spell": "dean",
				"name": "德安"
			}, {
				"id": 393,
				"spell": "dehua",
				"name": "德化"
			}, {
				"id": 394,
				"spell": "dehui",
				"name": "德惠"
			}, {
				"id": 395,
				"spell": "dengfeng",
				"name": "登封"
			}, {
				"id": 396,
				"spell": "deqing",
				"name": "德清"
			}, {
				"id": 397,
				"spell": "deqing",
				"name": "德庆"
			}, {
				"id": 398,
				"spell": "dexing",
				"name": "德兴"
			}, {
				"id": 399,
				"spell": "dianbai",
				"name": "电白"
			}, {
				"id": 400,
				"spell": "dianjiang",
				"name": "垫江"
			}, {
				"id": 401,
				"spell": "dingnan",
				"name": "定南"
			}, {
				"id": 402,
				"spell": "dingtao",
				"name": "定陶"
			}, {
				"id": 403,
				"spell": "dingyuan",
				"name": "定远"
			}, {
				"id": 404,
				"spell": "donga",
				"name": "东阿"
			}, {
				"id": 405,
				"spell": "donghai",
				"name": "东海"
			}, {
				"id": 406,
				"spell": "dongming",
				"name": "东明"
			}, {
				"id": 407,
				"spell": "dongping",
				"name": "东平"
			}, {
				"id": 408,
				"spell": "dongshan",
				"name": "东山"
			}, {
				"id": 409,
				"spell": "dongtai",
				"name": "东台"
			}, {
				"id": 410,
				"spell": "dongtou",
				"name": "洞头"
			}, {
				"id": 411,
				"spell": "dongxiang",
				"name": "东乡"
			}, {
				"id": 412,
				"spell": "dongyang",
				"name": "东阳"
			}, {
				"id": 413,
				"spell": "dongyuan",
				"name": "东源"
			}, {
				"id": 414,
				"spell": "dongzhi",
				"name": "东至"
			}, {
				"id": 415,
				"spell": "duchang",
				"name": "都昌"
			}, {
				"id": 416,
				"spell": "dujiangyan",
				"name": "都江堰"
			}],
			"E": [{
				"id": 111,
				"spell": "eerduosi",
				"name": "鄂尔多斯"
			}, {
				"id": 112,
				"spell": "enshi",
				"name": "恩施"
			}, {
				"id": 113,
				"spell": "ezhou",
				"name": "鄂州"
			}, {
				"id": 417,
				"spell": "enping",
				"name": "恩平"
			}],
			"F": [{
				"id": 11,
				"spell": "foshan",
				"name": "佛山"
			}, {
				"id": 12,
				"spell": "fuzhou",
				"name": "福州"
			}, {
				"id": 114,
				"spell": "fangchenggang",
				"name": "防城港"
			}, {
				"id": 115,
				"spell": "fushun",
				"name": "抚顺"
			}, {
				"id": 116,
				"spell": "fuxin",
				"name": "阜新"
			}, {
				"id": 117,
				"spell": "fuyang",
				"name": "阜阳"
			}, {
				"id": 118,
				"spell": "fuzhou",
				"name": "抚州"
			}, {
				"id": 418,
				"spell": "faku",
				"name": "法库"
			}, {
				"id": 419,
				"spell": "fanchang",
				"name": "繁昌"
			}, {
				"id": 420,
				"spell": "fangzheng",
				"name": "方正"
			}, {
				"id": 421,
				"spell": "feicheng",
				"name": "肥城"
			}, {
				"id": 422,
				"spell": "feidong",
				"name": "肥东"
			}, {
				"id": 423,
				"spell": "feixi",
				"name": "肥西"
			}, {
				"id": 424,
				"spell": "feixian",
				"name": "费县"
			}, {
				"id": 425,
				"spell": "fengcheng",
				"name": "丰城"
			}, {
				"id": 426,
				"spell": "fengdu",
				"name": "丰都"
			}, {
				"id": 427,
				"spell": "fenghua",
				"name": "奉化"
			}, {
				"id": 428,
				"spell": "fengjie",
				"name": "奉节"
			}, {
				"id": 429,
				"spell": "fengkai",
				"name": "封开"
			}, {
				"id": 430,
				"spell": "fengshun",
				"name": "丰顺"
			}, {
				"id": 431,
				"spell": "fengtai",
				"name": "凤台"
			}, {
				"id": 432,
				"spell": "fengxian",
				"name": "丰县"
			}, {
				"id": 433,
				"spell": "fengxin",
				"name": "奉新"
			}, {
				"id": 434,
				"spell": "fengyang",
				"name": "凤阳"
			}, {
				"id": 435,
				"spell": "fenyi",
				"name": "分宜"
			}, {
				"id": 436,
				"spell": "fogang",
				"name": "佛冈"
			}, {
				"id": 437,
				"spell": "fuan",
				"name": "福安"
			}, {
				"id": 438,
				"spell": "fuding",
				"name": "福鼎"
			}, {
				"id": 439,
				"spell": "fuliang",
				"name": "浮梁"
			}, {
				"id": 440,
				"spell": "fumin",
				"name": "富民"
			}, {
				"id": 441,
				"spell": "funan",
				"name": "阜南"
			}, {
				"id": 442,
				"spell": "funing",
				"name": "阜宁"
			}, {
				"id": 443,
				"spell": "fuqing",
				"name": "福清"
			}, {
				"id": 444,
				"spell": "fuyang",
				"name": "富阳"
			}],
			"G": [{
				"id": 13,
				"spell": "guangzhou",
				"name": "广州"
			}, {
				"id": 14,
				"spell": "guiyang",
				"name": "贵阳"
			}, {
				"id": 119,
				"spell": "gannan",
				"name": "甘南"
			}, {
				"id": 120,
				"spell": "ganzhou",
				"name": "赣州"
			}, {
				"id": 121,
				"spell": "ganzi",
				"name": "甘孜"
			}, {
				"id": 122,
				"spell": "guangan",
				"name": "广安"
			}, {
				"id": 123,
				"spell": "guangyuan",
				"name": "广元"
			}, {
				"id": 124,
				"spell": "guigang",
				"name": "贵港"
			}, {
				"id": 125,
				"spell": "guilin",
				"name": "桂林"
			}, {
				"id": 126,
				"spell": "guoluo",
				"name": "果洛"
			}, {
				"id": 127,
				"spell": "guyuan",
				"name": "固原"
			}, {
				"id": 445,
				"spell": "ganxian",
				"name": "赣县"
			}, {
				"id": 446,
				"spell": "ganyu",
				"name": "赣榆"
			}, {
				"id": 447,
				"spell": "gaoan",
				"name": "高安"
			}, {
				"id": 448,
				"spell": "gaocheng",
				"name": "藁城"
			}, {
				"id": 449,
				"spell": "gaochun",
				"name": "高淳"
			}, {
				"id": 450,
				"spell": "gaolan",
				"name": "皋兰"
			}, {
				"id": 451,
				"spell": "gaoling",
				"name": "高陵"
			}, {
				"id": 452,
				"spell": "gaomi",
				"name": "高密"
			}, {
				"id": 453,
				"spell": "gaoqing",
				"name": "高青"
			}, {
				"id": 454,
				"spell": "gaotang",
				"name": "高唐"
			}, {
				"id": 455,
				"spell": "gaoyao",
				"name": "高要"
			}, {
				"id": 456,
				"spell": "gaoyi",
				"name": "高邑"
			}, {
				"id": 457,
				"spell": "gaoyou",
				"name": "高邮"
			}, {
				"id": 458,
				"spell": "gaozhou",
				"name": "高州"
			}, {
				"id": 459,
				"spell": "gongyi",
				"name": "巩义"
			}, {
				"id": 460,
				"spell": "guangchang",
				"name": "广昌"
			}, {
				"id": 461,
				"spell": "guangde",
				"name": "广德"
			}, {
				"id": 462,
				"spell": "guangfeng",
				"name": "广丰"
			}, {
				"id": 463,
				"spell": "guangning",
				"name": "广宁"
			}, {
				"id": 464,
				"spell": "guangrao",
				"name": "广饶"
			}, {
				"id": 465,
				"spell": "guangze",
				"name": "光泽"
			}, {
				"id": 466,
				"spell": "guannan",
				"name": "灌南"
			}, {
				"id": 467,
				"spell": "guanxian",
				"name": "冠县"
			}, {
				"id": 468,
				"spell": "guanyun",
				"name": "灌云"
			}, {
				"id": 469,
				"spell": "guixi",
				"name": "贵溪"
			}, {
				"id": 470,
				"spell": "gutian",
				"name": "古田"
			}, {
				"id": 471,
				"spell": "guzhen",
				"name": "固镇"
			}],
			"H": [{
				"id": 15,
				"spell": "haerbin",
				"name": "哈尔滨"
			}, {
				"id": 16,
				"spell": "haikou",
				"name": "海口"
			}, {
				"id": 17,
				"spell": "handan",
				"name": "邯郸"
			}, {
				"id": 18,
				"spell": "hangzhou",
				"name": "杭州"
			}, {
				"id": 19,
				"spell": "hefei",
				"name": "合肥"
			}, {
				"id": 20,
				"spell": "huizhou",
				"name": "惠州"
			}, {
				"id": 128,
				"spell": "haibei",
				"name": "海北"
			}, {
				"id": 129,
				"spell": "haidong",
				"name": "海东"
			}, {
				"id": 130,
				"spell": "hainan",
				"name": "海南"
			}, {
				"id": 131,
				"spell": "haixi",
				"name": "海西"
			}, {
				"id": 132,
				"spell": "hami",
				"name": "哈密"
			}, {
				"id": 133,
				"spell": "hanzhong",
				"name": "汉中"
			}, {
				"id": 134,
				"spell": "hebi",
				"name": "鹤壁"
			}, {
				"id": 135,
				"spell": "hechi",
				"name": "河池"
			}, {
				"id": 136,
				"spell": "hegang",
				"name": "鹤岗"
			}, {
				"id": 137,
				"spell": "heihe",
				"name": "黑河"
			}, {
				"id": 138,
				"spell": "hengshui",
				"name": "衡水"
			}, {
				"id": 139,
				"spell": "hengyang",
				"name": "衡阳"
			}, {
				"id": 140,
				"spell": "hetiandi",
				"name": "和田地"
			}, {
				"id": 141,
				"spell": "heyuan",
				"name": "河源"
			}, {
				"id": 142,
				"spell": "heze",
				"name": "菏泽"
			}, {
				"id": 143,
				"spell": "hezhou",
				"name": "贺州"
			}, {
				"id": 144,
				"spell": "honghe",
				"name": "红河"
			}, {
				"id": 145,
				"spell": "huaian",
				"name": "淮安"
			}, {
				"id": 146,
				"spell": "huaibei",
				"name": "淮北"
			}, {
				"id": 147,
				"spell": "huaihua",
				"name": "怀化"
			}, {
				"id": 148,
				"spell": "huainan",
				"name": "淮南"
			}, {
				"id": 149,
				"spell": "huanggang",
				"name": "黄冈"
			}, {
				"id": 150,
				"spell": "huangnan",
				"name": "黄南"
			}, {
				"id": 151,
				"spell": "huangshan",
				"name": "黄山"
			}, {
				"id": 152,
				"spell": "huangshi",
				"name": "黄石"
			}, {
				"id": 153,
				"spell": "huhehaote",
				"name": "呼和浩特"
			}, {
				"id": 154,
				"spell": "huludao",
				"name": "葫芦岛"
			}, {
				"id": 155,
				"spell": "hulunbeier",
				"name": "呼伦贝尔"
			}, {
				"id": 156,
				"spell": "huzhou",
				"name": "湖州"
			}, {
				"id": 472,
				"spell": "haian",
				"name": "海安"
			}, {
				"id": 473,
				"spell": "haifeng",
				"name": "海丰"
			}, {
				"id": 474,
				"spell": "haimen",
				"name": "海门"
			}, {
				"id": 475,
				"spell": "haining",
				"name": "海宁"
			}, {
				"id": 476,
				"spell": "haiyan",
				"name": "海盐"
			}, {
				"id": 477,
				"spell": "haiyang",
				"name": "海阳"
			}, {
				"id": 478,
				"spell": "hanshan",
				"name": "含山"
			}, {
				"id": 479,
				"spell": "hechuan",
				"name": "合川"
			}, {
				"id": 480,
				"spell": "hengfeng",
				"name": "横峰"
			}, {
				"id": 481,
				"spell": "hengxian",
				"name": "横县"
			}, {
				"id": 482,
				"spell": "heping",
				"name": "和平"
			}, {
				"id": 483,
				"spell": "heshan",
				"name": "鹤山"
			}, {
				"id": 484,
				"spell": "hexian",
				"name": "和县"
			}, {
				"id": 485,
				"spell": "hongze",
				"name": "洪泽"
			}, {
				"id": 486,
				"spell": "huaan",
				"name": "华安"
			}, {
				"id": 487,
				"spell": "huadian",
				"name": "桦甸"
			}, {
				"id": 488,
				"spell": "huaiji",
				"name": "怀集"
			}, {
				"id": 489,
				"spell": "huaining",
				"name": "怀宁"
			}, {
				"id": 490,
				"spell": "huaiyuan",
				"name": "怀远"
			}, {
				"id": 491,
				"spell": "huantai",
				"name": "桓台"
			}, {
				"id": 492,
				"spell": "huazhou",
				"name": "化州"
			}, {
				"id": 493,
				"spell": "huian",
				"name": "惠安"
			}, {
				"id": 494,
				"spell": "huichang",
				"name": "会昌"
			}, {
				"id": 495,
				"spell": "huidong",
				"name": "惠东"
			}, {
				"id": 496,
				"spell": "huilai",
				"name": "惠来"
			}, {
				"id": 497,
				"spell": "huimin",
				"name": "惠民"
			}, {
				"id": 498,
				"spell": "hukou",
				"name": "湖口"
			}, {
				"id": 499,
				"spell": "hulan",
				"name": "呼兰"
			}, {
				"id": 500,
				"spell": "huoqiu",
				"name": "霍邱"
			}, {
				"id": 501,
				"spell": "huoshan",
				"name": "霍山"
			}, {
				"id": 502,
				"spell": "huxian",
				"name": "户县"
			}],
			"J": [{
				"id": 21,
				"spell": "jiaozuo",
				"name": "焦作"
			}, {
				"id": 22,
				"spell": "jiaxing",
				"name": "嘉兴"
			}, {
				"id": 23,
				"spell": "jilin",
				"name": "吉林"
			}, {
				"id": 24,
				"spell": "jinan",
				"name": "济南"
			}, {
				"id": 157,
				"spell": "jiamusi",
				"name": "佳木斯"
			}, {
				"id": 158,
				"spell": "jiangmen",
				"name": "江门"
			}, {
				"id": 159,
				"spell": "jian",
				"name": "吉安"
			}, {
				"id": 160,
				"spell": "jiayuguan",
				"name": "嘉峪关"
			}, {
				"id": 161,
				"spell": "jieyang",
				"name": "揭阳"
			}, {
				"id": 162,
				"spell": "jinchang",
				"name": "金昌"
			}, {
				"id": 163,
				"spell": "jincheng",
				"name": "晋城"
			}, {
				"id": 164,
				"spell": "jingdezhen",
				"name": "景德镇"
			}, {
				"id": 165,
				"spell": "jingmen",
				"name": "荆门"
			}, {
				"id": 166,
				"spell": "jingzhou",
				"name": "荆州"
			}, {
				"id": 167,
				"spell": "jinhua",
				"name": "金华"
			}, {
				"id": 168,
				"spell": "jining",
				"name": "济宁"
			}, {
				"id": 169,
				"spell": "jinzhong",
				"name": "晋中"
			}, {
				"id": 170,
				"spell": "jinzhou",
				"name": "锦州"
			}, {
				"id": 171,
				"spell": "jiujiang",
				"name": "九江"
			}, {
				"id": 172,
				"spell": "jiuquan",
				"name": "酒泉"
			}, {
				"id": 173,
				"spell": "jixi",
				"name": "鸡西"
			}, {
				"id": 503,
				"spell": "jiande",
				"name": "建德"
			}, {
				"id": 504,
				"spell": "jiangdu",
				"name": "江都"
			}, {
				"id": 505,
				"spell": "jiangjin",
				"name": "江津"
			}, {
				"id": 506,
				"spell": "jiangle",
				"name": "将乐"
			}, {
				"id": 507,
				"spell": "jiangshan",
				"name": "江山"
			}, {
				"id": 508,
				"spell": "jiangyan",
				"name": "姜堰"
			}, {
				"id": 509,
				"spell": "jiangyin",
				"name": "江阴"
			}, {
				"id": 510,
				"spell": "jianhu",
				"name": "建湖"
			}, {
				"id": 511,
				"spell": "jianning",
				"name": "建宁"
			}, {
				"id": 512,
				"spell": "jianou",
				"name": "建瓯"
			}, {
				"id": 513,
				"spell": "jianyang",
				"name": "建阳"
			}, {
				"id": 514,
				"spell": "jian",
				"name": "吉安"
			}, {
				"id": 515,
				"spell": "jiaohe",
				"name": "蛟河"
			}, {
				"id": 516,
				"spell": "jiaoling",
				"name": "蕉岭"
			}, {
				"id": 517,
				"spell": "jiaonan",
				"name": "胶南"
			}, {
				"id": 518,
				"spell": "jiaozhou",
				"name": "胶州"
			}, {
				"id": 519,
				"spell": "jiashan",
				"name": "嘉善"
			}, {
				"id": 520,
				"spell": "jiaxiang",
				"name": "嘉祥"
			}, {
				"id": 521,
				"spell": "jiedong",
				"name": "揭东"
			}, {
				"id": 522,
				"spell": "jieshou",
				"name": "界首"
			}, {
				"id": 523,
				"spell": "jiexi",
				"name": "揭西"
			}, {
				"id": 524,
				"spell": "jimo",
				"name": "即墨"
			}, {
				"id": 525,
				"spell": "jingan",
				"name": "靖安"
			}, {
				"id": 526,
				"spell": "jingde",
				"name": "旌德"
			}, {
				"id": 527,
				"spell": "jinggangshan",
				"name": "井冈山"
			}, {
				"id": 528,
				"spell": "jingjiang",
				"name": "靖江"
			}, {
				"id": 529,
				"spell": "jingning",
				"name": "景宁"
			}, {
				"id": 530,
				"spell": "jingxian",
				"name": "泾县"
			}, {
				"id": 531,
				"spell": "jingxing",
				"name": "井陉"
			}, {
				"id": 532,
				"spell": "jinhu",
				"name": "金湖"
			}, {
				"id": 533,
				"spell": "jinjiang",
				"name": "晋江"
			}, {
				"id": 534,
				"spell": "jinmen",
				"name": "金门"
			}, {
				"id": 535,
				"spell": "jinning",
				"name": "晋宁"
			}, {
				"id": 536,
				"spell": "jintan",
				"name": "金坛"
			}, {
				"id": 537,
				"spell": "jintang",
				"name": "金堂"
			}, {
				"id": 538,
				"spell": "jinxian",
				"name": "进贤"
			}, {
				"id": 539,
				"spell": "jinxi",
				"name": "金溪"
			}, {
				"id": 540,
				"spell": "jinxiang",
				"name": "金乡"
			}, {
				"id": 541,
				"spell": "jinyun",
				"name": "缙云"
			}, {
				"id": 542,
				"spell": "jinzhai",
				"name": "金寨"
			}, {
				"id": 543,
				"spell": "jinzhou",
				"name": "晋州"
			}, {
				"id": 544,
				"spell": "jishui",
				"name": "吉水"
			}, {
				"id": 545,
				"spell": "jiujiang",
				"name": "九江"
			}, {
				"id": 546,
				"spell": "jiutai",
				"name": "九台"
			}, {
				"id": 547,
				"spell": "jixi",
				"name": "绩溪"
			}, {
				"id": 548,
				"spell": "jiyang",
				"name": "济阳"
			}, {
				"id": 549,
				"spell": "jiyuan",
				"name": "济源"
			}, {
				"id": 550,
				"spell": "juancheng",
				"name": "鄄城"
			}, {
				"id": 551,
				"spell": "junan",
				"name": "莒南"
			}, {
				"id": 552,
				"spell": "jurong",
				"name": "句容"
			}, {
				"id": 553,
				"spell": "juxian",
				"name": "莒县"
			}, {
				"id": 554,
				"spell": "juye",
				"name": "巨野"
			}],
			"K": [{
				"id": 25,
				"spell": "kunming",
				"name": "昆明"
			}, {
				"id": 174,
				"spell": "kaifeng",
				"name": "开封"
			}, {
				"id": 175,
				"spell": "kashidi",
				"name": "喀什地"
			}, {
				"id": 176,
				"spell": "kelamayi",
				"name": "克拉玛依"
			}, {
				"id": 177,
				"spell": "kezile",
				"name": "克孜勒"
			}, {
				"id": 555,
				"spell": "kaihua",
				"name": "开化"
			}, {
				"id": 556,
				"spell": "kaiping",
				"name": "开平"
			}, {
				"id": 557,
				"spell": "kaixian",
				"name": "开县"
			}, {
				"id": 558,
				"spell": "kaiyang",
				"name": "开阳"
			}, {
				"id": 559,
				"spell": "kangping",
				"name": "康平"
			}, {
				"id": 560,
				"spell": "kenli",
				"name": "垦利"
			}, {
				"id": 561,
				"spell": "kunshan",
				"name": "昆山"
			}],
			"L": [{
				"id": 26,
				"spell": "lanzhou",
				"name": "兰州"
			}, {
				"id": 27,
				"spell": "liuzhou",
				"name": "柳州"
			}, {
				"id": 28,
				"spell": "luoyang",
				"name": "洛阳"
			}, {
				"id": 178,
				"spell": "laibin",
				"name": "来宾"
			}, {
				"id": 179,
				"spell": "laiwu",
				"name": "莱芜"
			}, {
				"id": 180,
				"spell": "langfang",
				"name": "廊坊"
			}, {
				"id": 181,
				"spell": "lasa",
				"name": "拉萨"
			}, {
				"id": 182,
				"spell": "leshan",
				"name": "乐山"
			}, {
				"id": 183,
				"spell": "liangshan",
				"name": "凉山"
			}, {
				"id": 184,
				"spell": "lianyungang",
				"name": "连云港"
			}, {
				"id": 185,
				"spell": "liaocheng",
				"name": "聊城"
			}, {
				"id": 186,
				"spell": "liaoyang",
				"name": "辽阳"
			}, {
				"id": 187,
				"spell": "liaoyuan",
				"name": "辽源"
			}, {
				"id": 188,
				"spell": "lijiang",
				"name": "丽江"
			}, {
				"id": 189,
				"spell": "lincang",
				"name": "临沧"
			}, {
				"id": 190,
				"spell": "linfen",
				"name": "临汾"
			}, {
				"id": 191,
				"spell": "linxia",
				"name": "临夏"
			}, {
				"id": 192,
				"spell": "linyi",
				"name": "临沂"
			}, {
				"id": 193,
				"spell": "linzhi",
				"name": "林芝"
			}, {
				"id": 194,
				"spell": "lishui",
				"name": "丽水"
			}, {
				"id": 195,
				"spell": "liuan",
				"name": "六安"
			}, {
				"id": 196,
				"spell": "liupanshui",
				"name": "六盘水"
			}, {
				"id": 197,
				"spell": "longnan",
				"name": "陇南"
			}, {
				"id": 198,
				"spell": "longyan",
				"name": "龙岩"
			}, {
				"id": 199,
				"spell": "loudi",
				"name": "娄底"
			}, {
				"id": 200,
				"spell": "luohe",
				"name": "漯河"
			}, {
				"id": 201,
				"spell": "luzhou",
				"name": "泸州"
			}, {
				"id": 202,
				"spell": "lvliang",
				"name": "吕梁"
			}, {
				"id": 562,
				"spell": "laian",
				"name": "来安"
			}, {
				"id": 563,
				"spell": "laixi",
				"name": "莱西"
			}, {
				"id": 564,
				"spell": "laiyang",
				"name": "莱阳"
			}, {
				"id": 565,
				"spell": "laizhou",
				"name": "莱州"
			}, {
				"id": 566,
				"spell": "langxi",
				"name": "郎溪"
			}, {
				"id": 567,
				"spell": "lantian",
				"name": "蓝田"
			}, {
				"id": 568,
				"spell": "lanxi",
				"name": "兰溪"
			}, {
				"id": 569,
				"spell": "lean",
				"name": "乐安"
			}, {
				"id": 570,
				"spell": "lechang",
				"name": "乐昌"
			}, {
				"id": 571,
				"spell": "leizhou",
				"name": "雷州"
			}, {
				"id": 572,
				"spell": "leling",
				"name": "乐陵"
			}, {
				"id": 573,
				"spell": "leping",
				"name": "乐平"
			}, {
				"id": 574,
				"spell": "leqing",
				"name": "乐清"
			}, {
				"id": 575,
				"spell": "leting",
				"name": "乐亭"
			}, {
				"id": 576,
				"spell": "liancheng",
				"name": "连城"
			}, {
				"id": 577,
				"spell": "liangping",
				"name": "梁平"
			}, {
				"id": 578,
				"spell": "liangshan",
				"name": "梁山"
			}, {
				"id": 579,
				"spell": "lianhua",
				"name": "莲花"
			}, {
				"id": 580,
				"spell": "lianjiang",
				"name": "连江"
			}, {
				"id": 581,
				"spell": "lianjiang",
				"name": "廉江"
			}, {
				"id": 582,
				"spell": "liannan",
				"name": "连南"
			}, {
				"id": 583,
				"spell": "lianping",
				"name": "连平"
			}, {
				"id": 584,
				"spell": "lianshan",
				"name": "连山"
			}, {
				"id": 585,
				"spell": "lianshui",
				"name": "涟水"
			}, {
				"id": 586,
				"spell": "lianzhou",
				"name": "连州"
			}, {
				"id": 587,
				"spell": "liaozhong",
				"name": "辽中"
			}, {
				"id": 588,
				"spell": "lichuan",
				"name": "黎川"
			}, {
				"id": 589,
				"spell": "lijin",
				"name": "利津"
			}, {
				"id": 590,
				"spell": "linan",
				"name": "临安"
			}, {
				"id": 591,
				"spell": "lingbi",
				"name": "灵璧"
			}, {
				"id": 592,
				"spell": "lingshou",
				"name": "灵寿"
			}, {
				"id": 593,
				"spell": "lingxian",
				"name": "陵县"
			}, {
				"id": 594,
				"spell": "linhai",
				"name": "临海"
			}, {
				"id": 595,
				"spell": "linqing",
				"name": "临清"
			}, {
				"id": 596,
				"spell": "linquan",
				"name": "临泉"
			}, {
				"id": 597,
				"spell": "linqu",
				"name": "临朐"
			}, {
				"id": 598,
				"spell": "linshu",
				"name": "临沭"
			}, {
				"id": 599,
				"spell": "linyi",
				"name": "临邑"
			}, {
				"id": 600,
				"spell": "lishui",
				"name": "溧水"
			}, {
				"id": 601,
				"spell": "liucheng",
				"name": "柳城"
			}, {
				"id": 602,
				"spell": "liujiang",
				"name": "柳江"
			}, {
				"id": 603,
				"spell": "liuyang",
				"name": "浏阳"
			}, {
				"id": 604,
				"spell": "lixin",
				"name": "利辛"
			}, {
				"id": 605,
				"spell": "liyang",
				"name": "溧阳"
			}, {
				"id": 606,
				"spell": "longan",
				"name": "隆安"
			}, {
				"id": 607,
				"spell": "longchuan",
				"name": "龙川"
			}, {
				"id": 608,
				"spell": "longhai",
				"name": "龙海"
			}, {
				"id": 609,
				"spell": "longkou",
				"name": "龙口"
			}, {
				"id": 610,
				"spell": "longmen",
				"name": "龙门"
			}, {
				"id": 611,
				"spell": "longnan",
				"name": "龙南"
			}, {
				"id": 612,
				"spell": "longquan",
				"name": "龙泉"
			}, {
				"id": 613,
				"spell": "longyou",
				"name": "龙游"
			}, {
				"id": 614,
				"spell": "luancheng",
				"name": "栾城"
			}, {
				"id": 615,
				"spell": "luanchuan",
				"name": "栾川"
			}, {
				"id": 616,
				"spell": "luannan",
				"name": "滦南"
			}, {
				"id": 617,
				"spell": "luanxian",
				"name": "滦县"
			}, {
				"id": 618,
				"spell": "lufeng",
				"name": "陆丰"
			}, {
				"id": 619,
				"spell": "luhe",
				"name": "陆河"
			}, {
				"id": 620,
				"spell": "lujiang",
				"name": "庐江"
			}, {
				"id": 621,
				"spell": "luoding",
				"name": "罗定"
			}, {
				"id": 622,
				"spell": "luoning",
				"name": "洛宁"
			}, {
				"id": 623,
				"spell": "luoyuan",
				"name": "罗源"
			}, {
				"id": 624,
				"spell": "luquan",
				"name": "鹿泉"
			}, {
				"id": 625,
				"spell": "luquan",
				"name": "禄劝"
			}, {
				"id": 626,
				"spell": "luxi",
				"name": "芦溪"
			}, {
				"id": 627,
				"spell": "luzhai",
				"name": "鹿寨"
			}],
			"M": [{
				"id": 203,
				"spell": "maanshan",
				"name": "马鞍山"
			}, {
				"id": 204,
				"spell": "maoming",
				"name": "茂名"
			}, {
				"id": 205,
				"spell": "meishan",
				"name": "眉山"
			}, {
				"id": 206,
				"spell": "meizhou",
				"name": "梅州"
			}, {
				"id": 207,
				"spell": "mianyang",
				"name": "绵阳"
			}, {
				"id": 208,
				"spell": "mudanjiang",
				"name": "牡丹江"
			}, {
				"id": 628,
				"spell": "mashan",
				"name": "马山"
			}, {
				"id": 629,
				"spell": "meixian",
				"name": "梅县"
			}, {
				"id": 630,
				"spell": "mengcheng",
				"name": "蒙城"
			}, {
				"id": 631,
				"spell": "mengjin",
				"name": "孟津"
			}, {
				"id": 632,
				"spell": "mengyin",
				"name": "蒙阴"
			}, {
				"id": 633,
				"spell": "mengzhou",
				"name": "孟州"
			}, {
				"id": 634,
				"spell": "mingguang",
				"name": "明光"
			}, {
				"id": 635,
				"spell": "mingxi",
				"name": "明溪"
			}, {
				"id": 636,
				"spell": "minhou",
				"name": "闽侯"
			}, {
				"id": 637,
				"spell": "minqing",
				"name": "闽清"
			}, {
				"id": 638,
				"spell": "mulan",
				"name": "木兰"
			}],
			"N": [{
				"id": 29,
				"spell": "nanchang",
				"name": "南昌"
			}, {
				"id": 30,
				"spell": "nanjing",
				"name": "南京"
			}, {
				"id": 31,
				"spell": "nanning",
				"name": "南宁"
			}, {
				"id": 32,
				"spell": "nantong",
				"name": "南通"
			}, {
				"id": 33,
				"spell": "ningbo",
				"name": "宁波"
			}, {
				"id": 209,
				"spell": "nanchong",
				"name": "南充"
			}, {
				"id": 210,
				"spell": "nanping",
				"name": "南平"
			}, {
				"id": 211,
				"spell": "nanyang",
				"name": "南阳"
			}, {
				"id": 212,
				"spell": "naqu",
				"name": "那曲"
			}, {
				"id": 213,
				"spell": "neijiang",
				"name": "内江"
			}, {
				"id": 214,
				"spell": "ningde",
				"name": "宁德"
			}, {
				"id": 215,
				"spell": "nujiang",
				"name": "怒江"
			}, {
				"id": 639,
				"spell": "nanan",
				"name": "南安"
			}, {
				"id": 640,
				"spell": "nanao",
				"name": "南澳"
			}, {
				"id": 641,
				"spell": "nancheng",
				"name": "南城"
			}, {
				"id": 642,
				"spell": "nanchuan",
				"name": "南川"
			}, {
				"id": 643,
				"spell": "nanfeng",
				"name": "南丰"
			}, {
				"id": 644,
				"spell": "nanjing",
				"name": "南靖"
			}, {
				"id": 645,
				"spell": "nankang",
				"name": "南康"
			}, {
				"id": 646,
				"spell": "nanling",
				"name": "南陵"
			}, {
				"id": 647,
				"spell": "nanxiong",
				"name": "南雄"
			}, {
				"id": 648,
				"spell": "ningdu",
				"name": "宁都"
			}, {
				"id": 649,
				"spell": "ningguo",
				"name": "宁国"
			}, {
				"id": 650,
				"spell": "ninghai",
				"name": "宁海"
			}, {
				"id": 651,
				"spell": "ninghua",
				"name": "宁化"
			}, {
				"id": 652,
				"spell": "ningjin",
				"name": "宁津"
			}, {
				"id": 653,
				"spell": "ningxiang",
				"name": "宁乡"
			}, {
				"id": 654,
				"spell": "ningyang",
				"name": "宁阳"
			}, {
				"id": 655,
				"spell": "nongan",
				"name": "农安"
			}],
			"P": [{
				"id": 216,
				"spell": "panjin",
				"name": "盘锦"
			}, {
				"id": 217,
				"spell": "panzhihua",
				"name": "攀枝花"
			}, {
				"id": 218,
				"spell": "pingdingshan",
				"name": "平顶山"
			}, {
				"id": 219,
				"spell": "pingliang",
				"name": "平凉"
			}, {
				"id": 220,
				"spell": "pingxiang",
				"name": "萍乡"
			}, {
				"id": 221,
				"spell": "puer",
				"name": "普洱"
			}, {
				"id": 222,
				"spell": "putian",
				"name": "莆田"
			}, {
				"id": 223,
				"spell": "puyang",
				"name": "濮阳"
			}, {
				"id": 656,
				"spell": "panan",
				"name": "磐安"
			}, {
				"id": 657,
				"spell": "panshi",
				"name": "磐石"
			}, {
				"id": 658,
				"spell": "peixian",
				"name": "沛县"
			}, {
				"id": 659,
				"spell": "penglai",
				"name": "蓬莱"
			}, {
				"id": 660,
				"spell": "pengshui",
				"name": "彭水"
			}, {
				"id": 661,
				"spell": "pengze",
				"name": "彭泽"
			}, {
				"id": 662,
				"spell": "pengzhou",
				"name": "彭州"
			}, {
				"id": 663,
				"spell": "pingdu",
				"name": "平度"
			}, {
				"id": 664,
				"spell": "pinghe",
				"name": "平和"
			}, {
				"id": 665,
				"spell": "pinghu",
				"name": "平湖"
			}, {
				"id": 666,
				"spell": "pingnan",
				"name": "屏南"
			}, {
				"id": 667,
				"spell": "pingshan",
				"name": "平山"
			}, {
				"id": 668,
				"spell": "pingtan",
				"name": "平潭"
			}, {
				"id": 669,
				"spell": "pingyang",
				"name": "平阳"
			}, {
				"id": 670,
				"spell": "pingyin",
				"name": "平阴"
			}, {
				"id": 671,
				"spell": "pingyi",
				"name": "平邑"
			}, {
				"id": 672,
				"spell": "pingyuan",
				"name": "平原"
			}, {
				"id": 673,
				"spell": "pingyuan",
				"name": "平远"
			}, {
				"id": 674,
				"spell": "pixian",
				"name": "郫县"
			}, {
				"id": 675,
				"spell": "pizhou",
				"name": "邳州"
			}, {
				"id": 676,
				"spell": "poyang",
				"name": "鄱阳"
			}, {
				"id": 677,
				"spell": "pucheng",
				"name": "浦城"
			}, {
				"id": 678,
				"spell": "pujiang",
				"name": "浦江"
			}, {
				"id": 679,
				"spell": "pujiang",
				"name": "蒲江"
			}, {
				"id": 680,
				"spell": "pulandian",
				"name": "普兰店"
			}, {
				"id": 681,
				"spell": "puning",
				"name": "普宁"
			}],
			"Q": [{
				"id": 34,
				"spell": "qingdao",
				"name": "青岛"
			}, {
				"id": 35,
				"spell": "quanzhou",
				"name": "泉州"
			}, {
				"id": 224,
				"spell": "qiandong",
				"name": "黔东"
			}, {
				"id": 225,
				"spell": "qiannan",
				"name": "黔南"
			}, {
				"id": 226,
				"spell": "qianxinan",
				"name": "黔西南"
			}, {
				"id": 227,
				"spell": "qingyang",
				"name": "庆阳"
			}, {
				"id": 228,
				"spell": "qingyuan",
				"name": "清远"
			}, {
				"id": 229,
				"spell": "qinhuangdao",
				"name": "秦皇岛"
			}, {
				"id": 230,
				"spell": "qinzhou",
				"name": "钦州"
			}, {
				"id": 231,
				"spell": "qiqihaer",
				"name": "齐齐哈尔"
			}, {
				"id": 232,
				"spell": "qitaihe",
				"name": "七台河"
			}, {
				"id": 233,
				"spell": "qujing",
				"name": "曲靖"
			}, {
				"id": 234,
				"spell": "quzhou",
				"name": "衢州"
			}, {
				"id": 682,
				"spell": "qianan",
				"name": "迁安"
			}, {
				"id": 683,
				"spell": "qianshan",
				"name": "潜山"
			}, {
				"id": 684,
				"spell": "qianshan",
				"name": "铅山"
			}, {
				"id": 685,
				"spell": "qianxi",
				"name": "迁西"
			}, {
				"id": 686,
				"spell": "qidong",
				"name": "启东"
			}, {
				"id": 687,
				"spell": "qihe",
				"name": "齐河"
			}, {
				"id": 688,
				"spell": "qijiang",
				"name": "綦江"
			}, {
				"id": 689,
				"spell": "qimen",
				"name": "祁门"
			}, {
				"id": 690,
				"spell": "qingliu",
				"name": "清流"
			}, {
				"id": 691,
				"spell": "qingtian",
				"name": "青田"
			}, {
				"id": 692,
				"spell": "qingxin",
				"name": "清新"
			}, {
				"id": 693,
				"spell": "qingyang",
				"name": "青阳"
			}, {
				"id": 694,
				"spell": "qingyuan",
				"name": "庆元"
			}, {
				"id": 695,
				"spell": "qingyun",
				"name": "庆云"
			}, {
				"id": 696,
				"spell": "qingzhen",
				"name": "清镇"
			}, {
				"id": 697,
				"spell": "qingzhou",
				"name": "青州"
			}, {
				"id": 698,
				"spell": "qinyang",
				"name": "沁阳"
			}, {
				"id": 699,
				"spell": "qionglai",
				"name": "邛崃"
			}, {
				"id": 700,
				"spell": "qixia",
				"name": "栖霞"
			}, {
				"id": 701,
				"spell": "quanjiao",
				"name": "全椒"
			}, {
				"id": 702,
				"spell": "quannan",
				"name": "全南"
			}, {
				"id": 703,
				"spell": "qufu",
				"name": "曲阜"
			}, {
				"id": 704,
				"spell": "qujiang",
				"name": "曲江"
			}],
			"R": [{
				"id": 235,
				"spell": "rikaze",
				"name": "日喀则"
			}, {
				"id": 236,
				"spell": "rizhao",
				"name": "日照"
			}, {
				"id": 705,
				"spell": "raoping",
				"name": "饶平"
			}, {
				"id": 706,
				"spell": "renhua",
				"name": "仁化"
			}, {
				"id": 707,
				"spell": "rongan",
				"name": "融安"
			}, {
				"id": 708,
				"spell": "rongchang",
				"name": "荣昌"
			}, {
				"id": 709,
				"spell": "rongcheng",
				"name": "荣成"
			}, {
				"id": 710,
				"spell": "rongshui",
				"name": "融水"
			}, {
				"id": 711,
				"spell": "rudong",
				"name": "如东"
			}, {
				"id": 712,
				"spell": "rugao",
				"name": "如皋"
			}, {
				"id": 713,
				"spell": "ruian",
				"name": "瑞安"
			}, {
				"id": 714,
				"spell": "ruichang",
				"name": "瑞昌"
			}, {
				"id": 715,
				"spell": "ruijin",
				"name": "瑞金"
			}, {
				"id": 716,
				"spell": "rushan",
				"name": "乳山"
			}, {
				"id": 717,
				"spell": "ruyang",
				"name": "汝阳"
			}, {
				"id": 718,
				"spell": "ruyuan",
				"name": "乳源"
			}],
			"S": [{
				"id": 3,
				"spell": "shanghai",
				"name": "上海"
			}, {
				"id": 36,
				"spell": "shenyang",
				"name": "沈阳"
			}, {
				"id": 37,
				"spell": "shenzhen",
				"name": "深圳"
			}, {
				"id": 38,
				"spell": "shijiazhuang",
				"name": "石家庄"
			}, {
				"id": 39,
				"spell": "suzhou",
				"name": "苏州"
			}, {
				"id": 237,
				"spell": "sanmenxia",
				"name": "三门峡"
			}, {
				"id": 238,
				"spell": "sanming",
				"name": "三明"
			}, {
				"id": 239,
				"spell": "sanya",
				"name": "三亚"
			}, {
				"id": 240,
				"spell": "shangluo",
				"name": "商洛"
			}, {
				"id": 241,
				"spell": "shangqiu",
				"name": "商丘"
			}, {
				"id": 242,
				"spell": "shangrao",
				"name": "上饶"
			}, {
				"id": 243,
				"spell": "shannan",
				"name": "山南"
			}, {
				"id": 244,
				"spell": "shantou",
				"name": "汕头"
			}, {
				"id": 245,
				"spell": "shanwei",
				"name": "汕尾"
			}, {
				"id": 246,
				"spell": "shaoguan",
				"name": "韶关"
			}, {
				"id": 247,
				"spell": "shaoxing",
				"name": "绍兴"
			}, {
				"id": 248,
				"spell": "shaoyang",
				"name": "邵阳"
			}, {
				"id": 249,
				"spell": "shiyan",
				"name": "十堰"
			}, {
				"id": 250,
				"spell": "shizuishan",
				"name": "石嘴山"
			}, {
				"id": 251,
				"spell": "shuangyashan",
				"name": "双鸭山"
			}, {
				"id": 252,
				"spell": "shuozhou",
				"name": "朔州"
			}, {
				"id": 253,
				"spell": "siping",
				"name": "四平"
			}, {
				"id": 254,
				"spell": "songyuan",
				"name": "松原"
			}, {
				"id": 255,
				"spell": "suihua",
				"name": "绥化"
			}, {
				"id": 256,
				"spell": "suining",
				"name": "遂宁"
			}, {
				"id": 257,
				"spell": "suizhou",
				"name": "随州"
			}, {
				"id": 258,
				"spell": "suqian",
				"name": "宿迁"
			}, {
				"id": 259,
				"spell": "suzhou",
				"name": "宿州"
			}, {
				"id": 719,
				"spell": "sanjiang",
				"name": "三江"
			}, {
				"id": 720,
				"spell": "sanmen",
				"name": "三门"
			}, {
				"id": 721,
				"spell": "saoan",
				"name": "诏安"
			}, {
				"id": 722,
				"spell": "shanggao",
				"name": "上高"
			}, {
				"id": 723,
				"spell": "shanghang",
				"name": "上杭"
			}, {
				"id": 724,
				"spell": "shanghe",
				"name": "商河"
			}, {
				"id": 725,
				"spell": "shangli",
				"name": "上栗"
			}, {
				"id": 726,
				"spell": "shanglin",
				"name": "上林"
			}, {
				"id": 727,
				"spell": "shangrao",
				"name": "上饶"
			}, {
				"id": 728,
				"spell": "shangyou",
				"name": "上犹"
			}, {
				"id": 729,
				"spell": "shangyu",
				"name": "上虞"
			}, {
				"id": 730,
				"spell": "shangzhi",
				"name": "尚志"
			}, {
				"id": 731,
				"spell": "shaowu",
				"name": "邵武"
			}, {
				"id": 732,
				"spell": "shaoxing",
				"name": "绍兴"
			}, {
				"id": 733,
				"spell": "shaxian",
				"name": "沙县"
			}, {
				"id": 734,
				"spell": "shengsi",
				"name": "嵊泗"
			}, {
				"id": 735,
				"spell": "shengzhou",
				"name": "嵊州"
			}, {
				"id": 736,
				"spell": "shenxian",
				"name": "莘县"
			}, {
				"id": 737,
				"spell": "shenze",
				"name": "深泽"
			}, {
				"id": 738,
				"spell": "shexian",
				"name": "歙县"
			}, {
				"id": 739,
				"spell": "sheyang",
				"name": "射阳"
			}, {
				"id": 740,
				"spell": "shicheng",
				"name": "石城"
			}, {
				"id": 741,
				"spell": "shilin",
				"name": "石林"
			}, {
				"id": 742,
				"spell": "shishi",
				"name": "石狮"
			}, {
				"id": 743,
				"spell": "shitai",
				"name": "石台"
			}, {
				"id": 744,
				"spell": "shixing",
				"name": "始兴"
			}, {
				"id": 745,
				"spell": "shizhu",
				"name": "石柱"
			}, {
				"id": 746,
				"spell": "shouguang",
				"name": "寿光"
			}, {
				"id": 747,
				"spell": "shouning",
				"name": "寿宁"
			}, {
				"id": 748,
				"spell": "shouxian",
				"name": "寿县"
			}, {
				"id": 749,
				"spell": "shuangcheng",
				"name": "双城"
			}, {
				"id": 750,
				"spell": "shuangliu",
				"name": "双流"
			}, {
				"id": 751,
				"spell": "shucheng",
				"name": "舒城"
			}, {
				"id": 752,
				"spell": "shulan",
				"name": "舒兰"
			}, {
				"id": 753,
				"spell": "shunchang",
				"name": "顺昌"
			}, {
				"id": 754,
				"spell": "shuyang",
				"name": "沭阳"
			}, {
				"id": 755,
				"spell": "sihong",
				"name": "泗洪"
			}, {
				"id": 756,
				"spell": "sihui",
				"name": "四会"
			}, {
				"id": 757,
				"spell": "sishui",
				"name": "泗水"
			}, {
				"id": 758,
				"spell": "sixian",
				"name": "泗县"
			}, {
				"id": 759,
				"spell": "siyang",
				"name": "泗阳"
			}, {
				"id": 760,
				"spell": "songming",
				"name": "嵩明"
			}, {
				"id": 761,
				"spell": "songxi",
				"name": "松溪"
			}, {
				"id": 762,
				"spell": "songxian",
				"name": "嵩县"
			}, {
				"id": 763,
				"spell": "songyang",
				"name": "松阳"
			}, {
				"id": 764,
				"spell": "suichang",
				"name": "遂昌"
			}, {
				"id": 765,
				"spell": "suichuan",
				"name": "遂川"
			}, {
				"id": 766,
				"spell": "suining",
				"name": "睢宁"
			}, {
				"id": 767,
				"spell": "suixi",
				"name": "濉溪"
			}, {
				"id": 768,
				"spell": "suixi",
				"name": "遂溪"
			}, {
				"id": 769,
				"spell": "susong",
				"name": "宿松"
			}, {
				"id": 770,
				"spell": "suyu",
				"name": "宿豫"
			}],
			"T": [{
				"id": 4,
				"spell": "tianjin",
				"name": "天津"
			}, {
				"id": 40,
				"spell": "taizhou",
				"name": "台州"
			}, {
				"id": 41,
				"spell": "tangshan",
				"name": "唐山"
			}, {
				"id": 260,
				"spell": "tachengdi",
				"name": "塔城地"
			}, {
				"id": 261,
				"spell": "taian",
				"name": "泰安"
			}, {
				"id": 262,
				"spell": "taiyuan",
				"name": "太原"
			}, {
				"id": 263,
				"spell": "taizhou",
				"name": "泰州"
			}, {
				"id": 264,
				"spell": "tianshui",
				"name": "天水"
			}, {
				"id": 265,
				"spell": "tieling",
				"name": "铁岭"
			}, {
				"id": 266,
				"spell": "tongchuan",
				"name": "铜川"
			}, {
				"id": 267,
				"spell": "tonghua",
				"name": "通化"
			}, {
				"id": 268,
				"spell": "tongliao",
				"name": "通辽"
			}, {
				"id": 269,
				"spell": "tongling",
				"name": "铜陵"
			}, {
				"id": 270,
				"spell": "tongren",
				"name": "铜仁"
			}, {
				"id": 271,
				"spell": "tulufan",
				"name": "吐鲁番"
			}, {
				"id": 771,
				"spell": "taicang",
				"name": "太仓"
			}, {
				"id": 772,
				"spell": "taihe",
				"name": "太和"
			}, {
				"id": 773,
				"spell": "taihe",
				"name": "泰和"
			}, {
				"id": 774,
				"spell": "taihu",
				"name": "太湖"
			}, {
				"id": 775,
				"spell": "taining",
				"name": "泰宁"
			}, {
				"id": 776,
				"spell": "taishan",
				"name": "台山"
			}, {
				"id": 777,
				"spell": "taishun",
				"name": "泰顺"
			}, {
				"id": 778,
				"spell": "taixing",
				"name": "泰兴"
			}, {
				"id": 779,
				"spell": "tancheng",
				"name": "郯城"
			}, {
				"id": 780,
				"spell": "tanghai",
				"name": "唐海"
			}, {
				"id": 781,
				"spell": "tengzhou",
				"name": "滕州"
			}, {
				"id": 782,
				"spell": "tianchang",
				"name": "天长"
			}, {
				"id": 783,
				"spell": "tiantai",
				"name": "天台"
			}, {
				"id": 784,
				"spell": "tongcheng",
				"name": "桐城"
			}, {
				"id": 785,
				"spell": "tonggu",
				"name": "铜鼓"
			}, {
				"id": 786,
				"spell": "tonghe",
				"name": "通河"
			}, {
				"id": 787,
				"spell": "tongliang",
				"name": "铜梁"
			}, {
				"id": 788,
				"spell": "tongling",
				"name": "铜陵"
			}, {
				"id": 789,
				"spell": "tonglu",
				"name": "桐庐"
			}, {
				"id": 790,
				"spell": "tongnan",
				"name": "潼南"
			}, {
				"id": 791,
				"spell": "tongshan",
				"name": "铜山"
			}, {
				"id": 792,
				"spell": "tongxiang",
				"name": "桐乡"
			}, {
				"id": 793,
				"spell": "tongzhou",
				"name": "通州"
			}],
			"W": [{
				"id": 42,
				"spell": "weifang",
				"name": "潍坊"
			}, {
				"id": 43,
				"spell": "weihai",
				"name": "威海"
			}, {
				"id": 44,
				"spell": "wuhan",
				"name": "武汉"
			}, {
				"id": 45,
				"spell": "wuxi",
				"name": "无锡"
			}, {
				"id": 272,
				"spell": "weinan",
				"name": "渭南"
			}, {
				"id": 273,
				"spell": "wenshan",
				"name": "文山"
			}, {
				"id": 274,
				"spell": "wenzhou",
				"name": "温州"
			}, {
				"id": 275,
				"spell": "wuhai",
				"name": "乌海"
			}, {
				"id": 276,
				"spell": "wuhu",
				"name": "芜湖"
			}, {
				"id": 277,
				"spell": "wulanchabu",
				"name": "乌兰察布"
			}, {
				"id": 278,
				"spell": "wulumuqi",
				"name": "乌鲁木齐"
			}, {
				"id": 279,
				"spell": "wuwei",
				"name": "武威"
			}, {
				"id": 280,
				"spell": "wuzhong",
				"name": "吴忠"
			}, {
				"id": 281,
				"spell": "wuzhou",
				"name": "梧州"
			}, {
				"id": 794,
				"spell": "wafangdian",
				"name": "瓦房店"
			}, {
				"id": 795,
				"spell": "wanan",
				"name": "万安"
			}, {
				"id": 796,
				"spell": "wangcheng",
				"name": "望城"
			}, {
				"id": 797,
				"spell": "wangjiang",
				"name": "望江"
			}, {
				"id": 798,
				"spell": "wannian",
				"name": "万年"
			}, {
				"id": 799,
				"spell": "wanzai",
				"name": "万载"
			}, {
				"id": 800,
				"spell": "weishan",
				"name": "微山"
			}, {
				"id": 801,
				"spell": "wencheng",
				"name": "文成"
			}, {
				"id": 802,
				"spell": "wendeng",
				"name": "文登"
			}, {
				"id": 803,
				"spell": "wengyuan",
				"name": "翁源"
			}, {
				"id": 804,
				"spell": "wenling",
				"name": "温岭"
			}, {
				"id": 805,
				"spell": "wenshang",
				"name": "汶上"
			}, {
				"id": 806,
				"spell": "wenxian",
				"name": "温县"
			}, {
				"id": 807,
				"spell": "woyang",
				"name": "涡阳"
			}, {
				"id": 808,
				"spell": "wuchang",
				"name": "五常"
			}, {
				"id": 809,
				"spell": "wucheng",
				"name": "武城"
			}, {
				"id": 810,
				"spell": "wuchuan",
				"name": "吴川"
			}, {
				"id": 811,
				"spell": "wudi",
				"name": "无棣"
			}, {
				"id": 812,
				"spell": "wuhe",
				"name": "五河"
			}, {
				"id": 813,
				"spell": "wuhu",
				"name": "芜湖"
			}, {
				"id": 814,
				"spell": "wuhua",
				"name": "五华"
			}, {
				"id": 815,
				"spell": "wuji",
				"name": "无极"
			}, {
				"id": 816,
				"spell": "wujiang",
				"name": "吴江"
			}, {
				"id": 817,
				"spell": "wulian",
				"name": "五莲"
			}, {
				"id": 818,
				"spell": "wulong",
				"name": "武隆"
			}, {
				"id": 819,
				"spell": "wuming",
				"name": "武鸣"
			}, {
				"id": 820,
				"spell": "wuning",
				"name": "武宁"
			}, {
				"id": 821,
				"spell": "wuping",
				"name": "武平"
			}, {
				"id": 822,
				"spell": "wushan",
				"name": "巫山"
			}, {
				"id": 823,
				"spell": "wuwei",
				"name": "无为"
			}, {
				"id": 824,
				"spell": "wuxi",
				"name": "巫溪"
			}, {
				"id": 825,
				"spell": "wuyi",
				"name": "武义"
			}, {
				"id": 826,
				"spell": "wuyishan",
				"name": "武夷山"
			}, {
				"id": 827,
				"spell": "wuyuan",
				"name": "婺源"
			}, {
				"id": 828,
				"spell": "wuzhi",
				"name": "武陟"
			}],
			"X": [{
				"id": 46,
				"spell": "xiamen",
				"name": "厦门"
			}, {
				"id": 47,
				"spell": "xian",
				"name": "西安"
			}, {
				"id": 48,
				"spell": "xuchang",
				"name": "许昌"
			}, {
				"id": 49,
				"spell": "xuzhou",
				"name": "徐州"
			}, {
				"id": 282,
				"spell": "xiangfan",
				"name": "襄樊"
			}, {
				"id": 283,
				"spell": "xiangtan",
				"name": "湘潭"
			}, {
				"id": 284,
				"spell": "xiangxi",
				"name": "湘西"
			}, {
				"id": 285,
				"spell": "xianning",
				"name": "咸宁"
			}, {
				"id": 286,
				"spell": "xianyang",
				"name": "咸阳"
			}, {
				"id": 287,
				"spell": "xiaogan",
				"name": "孝感"
			}, {
				"id": 288,
				"spell": "xilinguolemeng",
				"name": "锡林郭勒盟"
			}, {
				"id": 289,
				"spell": "xinganmeng",
				"name": "兴安盟"
			}, {
				"id": 290,
				"spell": "xingtai",
				"name": "邢台"
			}, {
				"id": 291,
				"spell": "xining",
				"name": "西宁"
			}, {
				"id": 292,
				"spell": "xinxiang",
				"name": "新乡"
			}, {
				"id": 293,
				"spell": "xinyang",
				"name": "信阳"
			}, {
				"id": 294,
				"spell": "xinyu",
				"name": "新余"
			}, {
				"id": 295,
				"spell": "xinzhou",
				"name": "忻州"
			}, {
				"id": 296,
				"spell": "xishuangbanna",
				"name": "西双版纳"
			}, {
				"id": 297,
				"spell": "xuancheng",
				"name": "宣城"
			}, {
				"id": 829,
				"spell": "xiajiang",
				"name": "峡江"
			}, {
				"id": 830,
				"spell": "xiajin",
				"name": "夏津"
			}, {
				"id": 831,
				"spell": "xiangshan",
				"name": "象山"
			}, {
				"id": 832,
				"spell": "xiangshui",
				"name": "响水"
			}, {
				"id": 833,
				"spell": "xianju",
				"name": "仙居"
			}, {
				"id": 834,
				"spell": "xianyou",
				"name": "仙游"
			}, {
				"id": 835,
				"spell": "xiaoxian",
				"name": "萧县"
			}, {
				"id": 836,
				"spell": "xiapu",
				"name": "霞浦"
			}, {
				"id": 837,
				"spell": "xifeng",
				"name": "息烽"
			}, {
				"id": 838,
				"spell": "xinan",
				"name": "新安"
			}, {
				"id": 839,
				"spell": "xinchang",
				"name": "新昌"
			}, {
				"id": 840,
				"spell": "xinfeng",
				"name": "信丰"
			}, {
				"id": 841,
				"spell": "xinfeng",
				"name": "新丰"
			}, {
				"id": 842,
				"spell": "xingan",
				"name": "新干"
			}, {
				"id": 843,
				"spell": "xingguo",
				"name": "兴国"
			}, {
				"id": 844,
				"spell": "xinghua",
				"name": "兴化"
			}, {
				"id": 845,
				"spell": "xingning",
				"name": "兴宁"
			}, {
				"id": 846,
				"spell": "xingtang",
				"name": "行唐"
			}, {
				"id": 847,
				"spell": "xingyang",
				"name": "荥阳"
			}, {
				"id": 848,
				"spell": "xingzi",
				"name": "星子"
			}, {
				"id": 849,
				"spell": "xinji",
				"name": "辛集"
			}, {
				"id": 850,
				"spell": "xinjian",
				"name": "新建"
			}, {
				"id": 851,
				"spell": "xinjin",
				"name": "新津"
			}, {
				"id": 852,
				"spell": "xinle",
				"name": "新乐"
			}, {
				"id": 853,
				"spell": "xinmin",
				"name": "新民"
			}, {
				"id": 854,
				"spell": "xinmi",
				"name": "新密"
			}, {
				"id": 855,
				"spell": "xintai",
				"name": "新泰"
			}, {
				"id": 856,
				"spell": "xinxing",
				"name": "新兴"
			}, {
				"id": 857,
				"spell": "xinyi",
				"name": "新沂"
			}, {
				"id": 858,
				"spell": "xinyi",
				"name": "信宜"
			}, {
				"id": 859,
				"spell": "xinzheng",
				"name": "新郑"
			}, {
				"id": 860,
				"spell": "xiuning",
				"name": "休宁"
			}, {
				"id": 861,
				"spell": "xiushan",
				"name": "秀山"
			}, {
				"id": 862,
				"spell": "xiushui",
				"name": "修水"
			}, {
				"id": 863,
				"spell": "xiuwen",
				"name": "修文"
			}, {
				"id": 864,
				"spell": "xiuwu",
				"name": "修武"
			}, {
				"id": 865,
				"spell": "xundian",
				"name": "寻甸"
			}, {
				"id": 866,
				"spell": "xunwu",
				"name": "寻乌"
			}, {
				"id": 867,
				"spell": "xuwen",
				"name": "徐闻"
			}, {
				"id": 868,
				"spell": "xuyi",
				"name": "盱眙"
			}],
			"Y": [{
				"id": 50,
				"spell": "yangzhou",
				"name": "扬州"
			}, {
				"id": 51,
				"spell": "yantai",
				"name": "烟台"
			}, {
				"id": 298,
				"spell": "yaan",
				"name": "雅安"
			}, {
				"id": 299,
				"spell": "yanan",
				"name": "延安"
			}, {
				"id": 300,
				"spell": "yanbian",
				"name": "延边"
			}, {
				"id": 301,
				"spell": "yancheng",
				"name": "盐城"
			}, {
				"id": 302,
				"spell": "yangjiang",
				"name": "阳江"
			}, {
				"id": 303,
				"spell": "yangquan",
				"name": "阳泉"
			}, {
				"id": 304,
				"spell": "yibin",
				"name": "宜宾"
			}, {
				"id": 305,
				"spell": "yichang",
				"name": "宜昌"
			}, {
				"id": 306,
				"spell": "yichun",
				"name": "伊春"
			}, {
				"id": 307,
				"spell": "yichun",
				"name": "宜春"
			}, {
				"id": 308,
				"spell": "yilihasake",
				"name": "伊犁哈萨克"
			}, {
				"id": 309,
				"spell": "yinchuan",
				"name": "银川"
			}, {
				"id": 310,
				"spell": "yingkou",
				"name": "营口"
			}, {
				"id": 311,
				"spell": "yingtan",
				"name": "鹰潭"
			}, {
				"id": 312,
				"spell": "yiyang",
				"name": "益阳"
			}, {
				"id": 313,
				"spell": "yongzhou",
				"name": "永州"
			}, {
				"id": 314,
				"spell": "yueyang",
				"name": "岳阳"
			}, {
				"id": 315,
				"spell": "yulin",
				"name": "玉林"
			}, {
				"id": 316,
				"spell": "yulin",
				"name": "榆林"
			}, {
				"id": 317,
				"spell": "yuncheng",
				"name": "运城"
			}, {
				"id": 318,
				"spell": "yunfu",
				"name": "云浮"
			}, {
				"id": 319,
				"spell": "yushu",
				"name": "玉树"
			}, {
				"id": 320,
				"spell": "yuxi",
				"name": "玉溪"
			}, {
				"id": 869,
				"spell": "yangchun",
				"name": "阳春"
			}, {
				"id": 870,
				"spell": "yangdong",
				"name": "阳东"
			}, {
				"id": 871,
				"spell": "yanggu",
				"name": "阳谷"
			}, {
				"id": 872,
				"spell": "yangshan",
				"name": "阳山"
			}, {
				"id": 873,
				"spell": "yangxin",
				"name": "阳信"
			}, {
				"id": 874,
				"spell": "yangxi",
				"name": "阳西"
			}, {
				"id": 875,
				"spell": "yangzhong",
				"name": "扬中"
			}, {
				"id": 876,
				"spell": "yanshi",
				"name": "偃师"
			}, {
				"id": 877,
				"spell": "yanshou",
				"name": "延寿"
			}, {
				"id": 878,
				"spell": "yanzhou",
				"name": "兖州"
			}, {
				"id": 879,
				"spell": "yichuan",
				"name": "伊川"
			}, {
				"id": 880,
				"spell": "yifeng",
				"name": "宜丰"
			}, {
				"id": 881,
				"spell": "yihuang",
				"name": "宜黄"
			}, {
				"id": 882,
				"spell": "yilan",
				"name": "依兰"
			}, {
				"id": 883,
				"spell": "yiliang",
				"name": "宜良"
			}, {
				"id": 884,
				"spell": "yinan",
				"name": "沂南"
			}, {
				"id": 885,
				"spell": "yingde",
				"name": "英德"
			}, {
				"id": 886,
				"spell": "yingshang",
				"name": "颍上"
			}, {
				"id": 887,
				"spell": "yishui",
				"name": "沂水"
			}, {
				"id": 888,
				"spell": "yiwu",
				"name": "义乌"
			}, {
				"id": 889,
				"spell": "yixian",
				"name": "黟县"
			}, {
				"id": 890,
				"spell": "yixing",
				"name": "宜兴"
			}, {
				"id": 891,
				"spell": "yiyang",
				"name": "弋阳"
			}, {
				"id": 892,
				"spell": "yiyang",
				"name": "宜阳"
			}, {
				"id": 893,
				"spell": "yiyuan",
				"name": "沂源"
			}, {
				"id": 894,
				"spell": "yizheng",
				"name": "仪征"
			}, {
				"id": 895,
				"spell": "yongan",
				"name": "永安"
			}, {
				"id": 896,
				"spell": "yongchuan",
				"name": "永川"
			}, {
				"id": 897,
				"spell": "yongchun",
				"name": "永春"
			}, {
				"id": 898,
				"spell": "yongdeng",
				"name": "永登"
			}, {
				"id": 899,
				"spell": "yongding",
				"name": "永定"
			}, {
				"id": 900,
				"spell": "yongfeng",
				"name": "永丰"
			}, {
				"id": 901,
				"spell": "yongji",
				"name": "永吉"
			}, {
				"id": 902,
				"spell": "yongjia",
				"name": "永嘉"
			}, {
				"id": 903,
				"spell": "yongkang",
				"name": "永康"
			}, {
				"id": 904,
				"spell": "yongning",
				"name": "邕宁"
			}, {
				"id": 905,
				"spell": "yongtai",
				"name": "永泰"
			}, {
				"id": 906,
				"spell": "yongxin",
				"name": "永新"
			}, {
				"id": 907,
				"spell": "yongxiu",
				"name": "永修"
			}, {
				"id": 908,
				"spell": "youxi",
				"name": "尤溪"
			}, {
				"id": 909,
				"spell": "youyang",
				"name": "酉阳"
			}, {
				"id": 910,
				"spell": "yuanshi",
				"name": "元氏"
			}, {
				"id": 911,
				"spell": "yucheng",
				"name": "禹城"
			}, {
				"id": 912,
				"spell": "yudu",
				"name": "于都"
			}, {
				"id": 913,
				"spell": "yuexi",
				"name": "岳西"
			}, {
				"id": 914,
				"spell": "yugan",
				"name": "余干"
			}, {
				"id": 915,
				"spell": "yuhuan",
				"name": "玉环"
			}, {
				"id": 916,
				"spell": "yujiang",
				"name": "余江"
			}, {
				"id": 917,
				"spell": "yunan",
				"name": "郁南"
			}, {
				"id": 918,
				"spell": "yunan",
				"name": "云安"
			}, {
				"id": 919,
				"spell": "yuncheng",
				"name": "郓城"
			}, {
				"id": 920,
				"spell": "yunhe",
				"name": "云和"
			}, {
				"id": 921,
				"spell": "yunxiao",
				"name": "云霄"
			}, {
				"id": 922,
				"spell": "yunyang",
				"name": "云阳"
			}, {
				"id": 923,
				"spell": "yushan",
				"name": "玉山"
			}, {
				"id": 924,
				"spell": "yushu",
				"name": "榆树"
			}, {
				"id": 925,
				"spell": "yutai",
				"name": "鱼台"
			}, {
				"id": 926,
				"spell": "yutian",
				"name": "玉田"
			}, {
				"id": 927,
				"spell": "yuyao",
				"name": "余姚"
			}, {
				"id": 928,
				"spell": "yuzhong",
				"name": "榆中"
			}],
			"Z": [{
				"id": 52,
				"spell": "zhangzhou",
				"name": "漳州"
			}, {
				"id": 53,
				"spell": "zhengzhou",
				"name": "郑州"
			}, {
				"id": 54,
				"spell": "zhongshan",
				"name": "中山"
			}, {
				"id": 55,
				"spell": "zhuhai",
				"name": "珠海"
			}, {
				"id": 321,
				"spell": "zaozhuang",
				"name": "枣庄"
			}, {
				"id": 322,
				"spell": "zhangjiajie",
				"name": "张家界"
			}, {
				"id": 323,
				"spell": "zhangjiakou",
				"name": "张家口"
			}, {
				"id": 324,
				"spell": "zhangye",
				"name": "张掖"
			}, {
				"id": 325,
				"spell": "zhanjiang",
				"name": "湛江"
			}, {
				"id": 326,
				"spell": "zhaoqing",
				"name": "肇庆"
			}, {
				"id": 327,
				"spell": "zhaotong",
				"name": "昭通"
			}, {
				"id": 328,
				"spell": "zhenjiang",
				"name": "镇江"
			}, {
				"id": 329,
				"spell": "zhongwei",
				"name": "中卫"
			}, {
				"id": 330,
				"spell": "zhoukou",
				"name": "周口"
			}, {
				"id": 331,
				"spell": "zhoushan",
				"name": "舟山"
			}, {
				"id": 332,
				"spell": "zhumadian",
				"name": "驻马店"
			}, {
				"id": 333,
				"spell": "zhuzhou",
				"name": "株洲"
			}, {
				"id": 334,
				"spell": "zibo",
				"name": "淄博"
			}, {
				"id": 335,
				"spell": "zigong",
				"name": "自贡"
			}, {
				"id": 336,
				"spell": "ziyang",
				"name": "资阳"
			}, {
				"id": 337,
				"spell": "zunyi",
				"name": "遵义"
			}, {
				"id": 929,
				"spell": "zanhuang",
				"name": "赞皇"
			}, {
				"id": 930,
				"spell": "zengcheng",
				"name": "增城"
			}, {
				"id": 931,
				"spell": "zhangjiagang",
				"name": "张家港"
			}, {
				"id": 932,
				"spell": "zhangping",
				"name": "漳平"
			}, {
				"id": 933,
				"spell": "zhangpu",
				"name": "漳浦"
			}, {
				"id": 934,
				"spell": "zhangqiu",
				"name": "章丘"
			}, {
				"id": 935,
				"spell": "zhangshu",
				"name": "樟树"
			}, {
				"id": 936,
				"spell": "zhanhua",
				"name": "沾化"
			}, {
				"id": 937,
				"spell": "zhaoxian",
				"name": "赵县"
			}, {
				"id": 938,
				"spell": "zhaoyuan",
				"name": "招远"
			}, {
				"id": 939,
				"spell": "zhengding",
				"name": "正定"
			}, {
				"id": 940,
				"spell": "zhenghe",
				"name": "政和"
			}, {
				"id": 941,
				"spell": "zherong",
				"name": "柘荣"
			}, {
				"id": 942,
				"spell": "zhongmou",
				"name": "中牟"
			}, {
				"id": 943,
				"spell": "zhongxian",
				"name": "忠县"
			}, {
				"id": 944,
				"spell": "zhouning",
				"name": "周宁"
			}, {
				"id": 945,
				"spell": "zhouzhi",
				"name": "周至"
			}, {
				"id": 946,
				"spell": "zhuanghe",
				"name": "庄河"
			}, {
				"id": 947,
				"spell": "zhucheng",
				"name": "诸城"
			}, {
				"id": 948,
				"spell": "zhuji",
				"name": "诸暨"
			}, {
				"id": 949,
				"spell": "zijin",
				"name": "紫金"
			}, {
				"id": 950,
				"spell": "zixi",
				"name": "资溪"
			}, {
				"id": 951,
				"spell": "zoucheng",
				"name": "邹城"
			}, {
				"id": 952,
				"spell": "zouping",
				"name": "邹平"
			}, {
				"id": 953,
				"spell": "zunhua",
				"name": "遵化"
			}]
		}
	}
}



三、组件化开发

在这里插入图片描述

该页面可分为’Header’、‘Search’、‘List’、'Alphabet’四个组件组成



1.创建城市列表首页

a.创建’City’文件夹和’City.vue’文件(路径: src/pages/city/city.vue) - - - 创建城市切换的首页
<template>
  <div>
    <city-header></city-header>
    <city-search :cities='cities'></city-search>
    <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 CityHeader from './components/Header'
import CitySearch from './components/Search'
import CityList from './components/List'
import CityAlphabet from './components/Alphabet'
export default {
  name: 'City',
  components: {
    CityHeader,
    CitySearch,
    CityList,
    CityAlphabet
  },
  data () {
    return {
      cities: {},
      hotCities: [],
      letter: ''
    }
  },
  // 定义这个方法
  methods: {
    getCityInfo () {
      axios.get('/api/city.json')
        .then(this.handleGetCityInfoSucc)
    },
    handleGetCityInfoSucc (res) {
      // console.log(res)
      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
    }
  },
  // 创建一个生命周期函数来调用ajax的方法
  mounted () {
    this.getCityInfo()
  }
}
</script>

<style lang="stylus" scoped>

</style>


2.Header

a.编辑’Header.vue’文件(路径: src/pages/home/components/Header.vue) - - - 实现点击’城市’可以跳转到城市选择页
    <!-- 实现页面跳转 -->
    <router-link to='/city'>
      <div class="header-right">
        <!-- 城市 -->
        <!-- {{this.city}} -->
        <!-- 通过前端mand.js传值,而不需要后端传值过来了 -->
        <!-- {{this.$store.state.city}} -->
        {{this.city}}
        <!-- 可以通过getter的计算来获得新的数据 -->
        <!-- {{this.doubleCity}} -->
        <span class="iconfont arrow-icon">&#xe65c;</span>
      </div>
    </router-link>


b.编辑’City.vue’文件(路径: src/pages/city/City.vue) - - - 引用’Header.vue’组件
<template>
    <city-header></city-header>
</template>

<script>
import CityHeader from './components/Header'
export default {
  name: 'City',
  components: {
    CityHeader,
  }
</script>

<style lang="stylus" scoped>
</style>

c.编辑’Header.vue’文件(路径: src/pages/home/components/Header.vue) - - - 完善内容
<template>
  <div class="header">
    <!-- 点击返回,设置路径 -->
    <router-link to='./'>
      <div class="iconfont header-back">&#xe743;</div>
    </router-link>
    城市选择
  </div>
</template>

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

<style lang="stylus" scoped>
  @import '~styles/varibles.styl'
  .header
    position relative
    overflow hidden
    height $headerHight
    line-height $headerHight
    text-align center
    color #fff
    background $bgColor
    font-size .32rem
    .header-back
      position absolute
      top 0
      left 0
      width .64rem
      text-align center
      font-size .4rem
      color #fff
</style>


3.Search

a.创建’Search.vue’文件(路径: src/pages/city/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'
</style>


b.编辑’City.vue’文件(路径: src/pages/city/City.vue) - - - 引用’Search.vue’组件
<template>
  <div>
    <city-header></city-header>
    <city-search></city-search>
  </div>
</template>

<script>
import CityHeader from './components/Header'
import CitySearch from './components/Search'
export default {
  name: 'City',
  components: {
    CityHeader,
    CitySearch
  }
</script>

<style lang="stylus" scoped>
</style>


c.编辑’Search.vue’文件(路径: src/pages/city/Search.vue) - - - 完善搜索条
<template>
  <div>
    <div class="search">
      <input
        v-model="keyword"
        class="search-input"
        type="text"
        placeholder="请输入城市名或者拼音"
      >
    </div>
    <!-- 页面有内容时候才显示 -->
    <div
      class="search-content"
      ref="search"
      v-show="keyword"
    >
      <ul>
        <li
          class="search-item border-bottom"
          v-for="item of list"
          :key="item.id"
          @click="handleCityClick(item.name)"
        >
          {{item.name}}
        </li>
        <!-- list长度为零时显示的内容 -->
        <!-- 模板里面尽量不要涉及逻辑运算 -->
        <!-- <li class="search-item border-bottom" v-show="!list.length"> -->
        <li class="search-item border-bottom" v-show="hasNoData">
          哎呀~没有找到匹配城市
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
import { mapMutations } from 'vuex'
import BScroll from 'better-scroll'
export default {
  name: 'CitySearch',
  props: {
    cities: Object
  },
  data () {
    return {
      keyword: '',
      list: [],
      timer: ''
    }
  },
  methods: {
    handleCityClick (city) {
      this.changeCity(city)
      this.$router.push('/')
    },
    ...mapMutations(['changeCity'])
  },
  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, {
      click: true
    })
  }
}
</script>

<style lang="stylus" scoped>
@import '~styles/varibles.styl'
.search
  height .72rem
  padding 0 .1rem
  background $bgColor
  .search-input
    box-sizing border-box
    width 100%
    height .62rem
    padding 0 .1rem
    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
    color #666
    background #fff
</style>


4.List

a.创建’List.vue’文件(路径: src/pages/city/List.vue) - - - 创建城市列表
<template>
    <div class="list">
      List
  </div>
</template>

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

<style lang="stylus" scoped>
@import '~styles/varibles.styl'
</style>


b.编辑’City.vue’文件(路径: src/pages/city/City.vue) - - - 引用’LIst.vue’组件
<template>
  <div>
    <city-header></city-header>
    <city-search></city-search>
    <city-list></city-list>
  </div>
</template>

<script>
import CityHeader from './components/Header'
import CitySearch from './components/Search'
import CitySearch from './components/List'
export default {
  name: 'City',
  components: {
    CityHeader,
    CitySearch,
    CityList
  }
</script>

<style lang="stylus" scoped>
</style>


c.编辑’List.vue’文件(路径: src/pages/city/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.$store.state.city}} -->
                {{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>
      </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>
      </div>
    </div>
  </div>
</template>

<script>
// 引入better-scroll
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) {
  //     // alert(city)
  //     // this.$store.dispatch('changeCity', city)
  //     // this.$store.commit('changeCity', city)
  //     this.changeCity(city)
  //     // 修改城市之后,跳转到首页
  //     this.$router.push('/')
  //   },
  //   ...mapMutations(['changeCity'])
  // },
  methods: {
    handleCityClick (city) {
      this.changeCity(city)
      this.$router.push('/')
    },
    ...mapMutations(['changeCity'])
  },
  // 侦听器  监听letter数据改变
  watch: {
    letter () {
      if (this.letter) {
        const element = this.$refs[this.letter][0]
        // console.log(element)
        this.scroll.scrollToElement(element)
      }
      // console.log(this.letter)
    },
    cities () {
      this.$nextTick(function () {
        this.scroll = new BScroll(this.$refs.wrapper, {
          click: true,
          mouseWheel: true,
          tap: true,
          disableMouse: false,
          disableTouch: false
        })
      })
    }
  }
  // 创建一个生命周期函数
  // mounted () {
  // //   // 创建一个scroll实例
  // //   // this.scroll = new Bscroll(this.$refs.wrapper)
  // //   // console.log(BScroll)
  //   this.$nextTick(function () {
  //   this.scroll = new BScroll(this.$refs.wrapper, {
  //     click: true,
  //     mouseWheel: true,
  //     tap: true,
  //     disableMouse: false,
  //     disableTouch: false
  //   })
  //   })
  // // this.scroll = new Bscroll(this.$refs.wrapper, {
  // //   click: true
  // // })
  // //   this.scroll = new Bscroll(this.$refs.wrapper, {
  // //     click: true})
  // }
}

</script>

<style lang="stylus" scoped>
@import '~styles/varibles.styl'
  .border-topbottom
    &:before
      border-color #ccc
    &:after
      border-color #ccc
  .border-bottom
    &:before
      border-color #ccc
  .list
    overflow hidden
    position absolute
    top 1.58rem
    left 0
    right 0
    bottom 0
    .title
      line-height .54rem
      color #666
      font-size .26rem
      padding-left .2rem
      background #eee
    .button-list
      overflow hidden
      padding .1rem .6rem .1rem .1rem
      .button-wrapper
        float left
        width 33.33%
        .button
          margin .1rem
          padding .1rem 0
          text-align center
          border .02rem solid #ccc
          border-radius .06rem
    .item-list
      .item
        line-height .76rem
        padding-left .2rem
</style>


5.Alphabet

a.创建’Alphabet.vue’文件(路径: src/pages/city/Alphabet.vue) - - - 创建右侧字母表
<template>
  <ul class="list">
    <!-- 点击字母时,触发跳转事件 -->
      <!-- v-for="(item, key) of cities" -->
      <!-- :key="key" -->
    <li
      class="item"
      v-for="item of letters"
      :key="item"
      :ref="item"
      @touchstart="handleTouchStart"
      @touchmove="handleTouchMove"
      @touchend="handleTouchEnd"
      @click="handleLetterClick"
    >
      <!-- {{key}} -->
      {{item}}
    </li>
  </ul>
</template>

<script>
export default {
  name: 'CityAlphabet',
  props: {
    cities: Object
  },
  // 创建一个数组, 返回右侧字母栏
  computed: {
    letters () {
      const letters = []
      for (let i in this.cities) {
        letters.push(i)
      }
      return (letters)
      // 返回的为['A', 'B', 'C,...]
    }
  },
  data () {
    return {
      touchStatus: false,
      // 设置startY初始值为0
      startY: 0,
      // 设置timer为空
      timer: null
    }
  },
  // 创建一个生命周期钩子
  updated () {
    this.startY = this.$refs['A'][0].offsetTop
  },
  methods: {
    handleLetterClick (e) {
      // console.log(e.target.innerText)
      // 向外触发事件
      this.$emit('change', e.target.innerText)
    },
    handleTouchStart () {
      this.touchStatus = true
    },
    handleTouchMove (e) {
      // 思路: 直接计算手指在哪个字母上面比较麻烦, 可以先计算A距离顶部的距离, 再计算手指距离顶部的距离, 差值除以字母的高度, 就可以定位到字母的位置了
      if (this.touchStatus) {
        // 通过函数节流的方式,大大减少handleTouchMove的操作频率,提高网页性能;
        // 执行滚动操作时, 会延迟的16毫秒再执行;如果还在滚动, 则清除上一步操作, 执行新的操作
        if (this.timer) {
          clearTimeout(this.timer)
        }
        this.timer = setTimeout(() => {
          // 性能问题: 因为startY是固定的,所以需要不断的获取它的值(可以用生命周期函数)
          // 获取A元素距离顶部的高度
          // const startY = this.$refs['A'][0].offsetTop
          // console.log(startY)
          // 获取手指距离顶部的高度
          const touchY = e.touches[0].clientY - 79
          // console.log(touchY)
          // 计算手指距离A顶部的距离, 再向下取整
          // const index = Math.floor((touchY - startY) / 20)
          const index = Math.floor((touchY - this.startY) / 20)
          // console.log(index)
          if (index >= 0 && index < this.letters.length) {
            this.$emit('change', this.letters[index])
          }
        }, 5)
      }
    },
    handleTouchEnd () {
      this.touchStatus = false
    }
  }
}
</script>

<style lang="stylus" scoped>
@import '~styles/varibles.styl'
.list
  display flex
  flex-direction column
  justify-content center
  position absolute
  top 1.58rem
  bottom 0
  right 0
  width .4rem
  // background red
  .item
    line-height .4rem
    text-align center
    color $bgColor
</style>


b.编辑’City.vue’文件(路径: src/pages/city/City.vue) - - - 引用’Alphabet.vue’组件
<template>
  <div>
    <city-header></city-header>
    <city-search></city-search>
    <city-list></city-list>
    <city-alphabet></city-alphabet>
  </div>
</template>

<script>
import CityHeader from './components/Header'
import CitySearch from './components/Search'
import CitySearch from './components/List'
import CitySearch from './components/Alphabet'
export default {
  name: 'City',
  components: {
    CityHeader,
    CitySearch,
    CityList,
    Alphabet
  }
</script>

<style lang="stylus" scoped>
</style>


6.兄弟组件数值传递 - - - 点击字母表,跳转至相应城市

a.编辑’Alphabet.vue’文件(路径: src/pages/city/Alphabet.vue) - - - 点击左侧字母表
<template>
  <ul class="list">
    <!-- 点击字母时,触发跳转事件 -->
      <!-- v-for="(item, key) of cities" -->
      <!-- :key="key" -->
    <li
      class="item"
      v-for="item of letters"
      :key="item"
      :ref="item"
      @touchstart="handleTouchStart"
      @touchmove="handleTouchMove"
      @touchend="handleTouchEnd"
      @click="handleLetterClick"
    >
      <!-- {{key}} -->
      {{item}}
    </li>
  </ul>
</template>

<script>
export default {
  name: 'CityAlphabet',
  props: {
    cities: Object
  },
  // 创建一个数组, 返回右侧字母栏
  computed: {
    letters () {
      const letters = []
      for (let i in this.cities) {
        letters.push(i)
      }
      return (letters)
      // 返回的为['A', 'B', 'C,...]
    }
  },
  data () {
    return {
      touchStatus: false,
      // 设置startY初始值为0
      startY: 0,
      // 设置timer为空
      timer: null
    }
  },
  // 创建一个生命周期钩子
  updated () {
    this.startY = this.$refs['A'][0].offsetTop
  },
  methods: {
    handleLetterClick (e) {
      // console.log(e.target.innerText)
      // 向外触发事件
      this.$emit('change', e.target.innerText)
    },
    handleTouchStart () {
      this.touchStatus = true
    },
    handleTouchMove (e) {
      // 思路: 直接计算手指在哪个字母上面比较麻烦, 可以先计算A距离顶部的距离, 再计算手指距离顶部的距离, 差值除以字母的高度, 就可以定位到字母的位置了
      if (this.touchStatus) {
        // 通过函数节流的方式,大大减少handleTouchMove的操作频率,提高网页性能;
        // 执行滚动操作时, 会延迟的16毫秒再执行;如果还在滚动, 则清除上一步操作, 执行新的操作
        if (this.timer) {
          clearTimeout(this.timer)
        }
        this.timer = setTimeout(() => {
          // 性能问题: 因为startY是固定的,所以需要不断的获取它的值(可以用生命周期函数)
          // 获取A元素距离顶部的高度
          // const startY = this.$refs['A'][0].offsetTop
          // console.log(startY)
          // 获取手指距离顶部的高度
          const touchY = e.touches[0].clientY - 79
          // console.log(touchY)
          // 计算手指距离A顶部的距离, 再向下取整
          // const index = Math.floor((touchY - startY) / 20)
          const index = Math.floor((touchY - this.startY) / 20)
          // console.log(index)
          if (index >= 0 && index < this.letters.length) {
            this.$emit('change', this.letters[index])
          }
        }, 5)
      }
    },
    handleTouchEnd () {
      this.touchStatus = false
    }
  }
}
</script>

<style lang="stylus" scoped>
@import '~styles/varibles.styl'
.list
  display flex
  flex-direction column
  justify-content center
  position absolute
  top 1.58rem
  bottom 0
  right 0
  width .4rem
  // background red
  .item
    line-height .4rem
    text-align center
    color $bgColor
</style>


b.编辑’List.vue’文件(路径: src/pages/city/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.$store.state.city}} -->
                {{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>
      </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>
      </div>
    </div>
  </div>
</template>

<script>
// 引入better-scroll
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) {
  //     // alert(city)
  //     // this.$store.dispatch('changeCity', city)
  //     // this.$store.commit('changeCity', city)
  //     this.changeCity(city)
  //     // 修改城市之后,跳转到首页
  //     this.$router.push('/')
  //   },
  //   ...mapMutations(['changeCity'])
  // },
  methods: {
    handleCityClick (city) {
      this.changeCity(city)
      this.$router.push('/')
    },
    ...mapMutations(['changeCity'])
  },
  // 侦听器  监听letter数据改变
  watch: {
    letter () {
      if (this.letter) {
        const element = this.$refs[this.letter][0]
        // console.log(element)
        this.scroll.scrollToElement(element)
      }
      // console.log(this.letter)
    },
    cities () {
      this.$nextTick(function () {
        this.scroll = new BScroll(this.$refs.wrapper, {
          click: true,
          mouseWheel: true,
          tap: true,
          disableMouse: false,
          disableTouch: false
        })
      })
    }
  }
  // 创建一个生命周期函数
  // mounted () {
  // //   // 创建一个scroll实例
  // //   // this.scroll = new Bscroll(this.$refs.wrapper)
  // //   // console.log(BScroll)
  //   this.$nextTick(function () {
  //   this.scroll = new BScroll(this.$refs.wrapper, {
  //     click: true,
  //     mouseWheel: true,
  //     tap: true,
  //     disableMouse: false,
  //     disableTouch: false
  //   })
  //   })
  // // this.scroll = new Bscroll(this.$refs.wrapper, {
  // //   click: true
  // // })
  // //   this.scroll = new Bscroll(this.$refs.wrapper, {
  // //     click: true})
  // }
}

</script>

<style lang="stylus" scoped>
@import '~styles/varibles.styl'
  .border-topbottom
    &:before
      border-color #ccc
    &:after
      border-color #ccc
  .border-bottom
    &:before
      border-color #ccc
  .list
    overflow hidden
    position absolute
    top 1.58rem
    left 0
    right 0
    bottom 0
    .title
      line-height .54rem
      color #666
      font-size .26rem
      padding-left .2rem
      background #eee
    .button-list
      overflow hidden
      padding .1rem .6rem .1rem .1rem
      .button-wrapper
        float left
        width 33.33%
        .button
          margin .1rem
          padding .1rem 0
          text-align center
          border .02rem solid #ccc
          border-radius .06rem
    .item-list
      .item
        line-height .76rem
        padding-left .2rem
</style>


c.编辑’City.vue’文件(路径: src/pages/city/Cityvue) - - - 监听事件
<template>
  <div>
    <city-header></city-header>
    <city-search :cities='cities'></city-search>
    <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 CityHeader from './components/Header'
import CitySearch from './components/Search'
import CityList from './components/List'
import CityAlphabet from './components/Alphabet'
export default {
  name: 'City',
  components: {
    CityHeader,
    CitySearch,
    CityList,
    CityAlphabet
  },
  data () {
    return {
      cities: {},
      hotCities: [],
      letter: ''
    }
  },
  // 定义这个方法
  methods: {
    getCityInfo () {
      axios.get('/api/city.json')
        .then(this.handleGetCityInfoSucc)
    },
    handleGetCityInfoSucc (res) {
      // console.log(res)
      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
    }
  },
  // 创建一个生命周期函数来调用ajax的方法
  mounted () {
    this.getCityInfo()
  }
}
</script>

<style lang="stylus" scoped>

</style>


7.兄弟组件数值传递 - - - 滚动字母表,城市列表相应滚动

a.编辑’Alphabet.vue’文件(路径: src/pages/city/Alphabet.vue)
<template>
  <ul class="list">
    <!-- 点击字母时,触发跳转事件 -->
      <!-- v-for="(item, key) of cities" -->
      <!-- :key="key" -->
    <li
      class="item"
      v-for="item of letters"
      :key="item"
      :ref="item"
      @touchstart="handleTouchStart"
      @touchmove="handleTouchMove"
      @touchend="handleTouchEnd"
      @click="handleLetterClick"
    >
      <!-- {{key}} -->
      {{item}}
    </li>
  </ul>
</template>

<script>
export default {
  name: 'CityAlphabet',
  props: {
    cities: Object
  },
  // 创建一个数组, 返回右侧字母栏
  computed: {
    letters () {
      const letters = []
      for (let i in this.cities) {
        letters.push(i)
      }
      return (letters)
      // 返回的为['A', 'B', 'C,...]
    }
  },
  data () {
    return {
      touchStatus: false,
      // 设置startY初始值为0
      startY: 0,
      // 设置timer为空
      timer: null
    }
  },
  // 创建一个生命周期钩子
  updated () {
    this.startY = this.$refs['A'][0].offsetTop
  },
  methods: {
    handleLetterClick (e) {
      // console.log(e.target.innerText)
      // 向外触发事件
      this.$emit('change', e.target.innerText)
    },
    handleTouchStart () {
      this.touchStatus = true
    },
    handleTouchMove (e) {
      // 思路: 直接计算手指在哪个字母上面比较麻烦, 可以先计算A距离顶部的距离, 再计算手指距离顶部的距离, 差值除以字母的高度, 就可以定位到字母的位置了
      if (this.touchStatus) {
        // 通过函数节流的方式,大大减少handleTouchMove的操作频率,提高网页性能;
        // 执行滚动操作时, 会延迟的16毫秒再执行;如果还在滚动, 则清除上一步操作, 执行新的操作
        if (this.timer) {
          clearTimeout(this.timer)
        }
        this.timer = setTimeout(() => {
          // 性能问题: 因为startY是固定的,所以需要不断的获取它的值(可以用生命周期函数)
          // 获取A元素距离顶部的高度
          // const startY = this.$refs['A'][0].offsetTop
          // console.log(startY)
          // 获取手指距离顶部的高度
          const touchY = e.touches[0].clientY - 79
          // console.log(touchY)
          // 计算手指距离A顶部的距离, 再向下取整
          // const index = Math.floor((touchY - startY) / 20)
          const index = Math.floor((touchY - this.startY) / 20)
          // console.log(index)
          if (index >= 0 && index < this.letters.length) {
            this.$emit('change', this.letters[index])
          }
        }, 5)
      }
    },
    handleTouchEnd () {
      this.touchStatus = false
    }
  }
}
</script>

<style lang="stylus" scoped>
@import '~styles/varibles.styl'
.list
  display flex
  flex-direction column
  justify-content center
  position absolute
  top 1.58rem
  bottom 0
  right 0
  width .4rem
  // background red
  .item
    line-height .4rem
    text-align center
    color $bgColor
</style>


8.城市列表页面性能优化

<template>
  <ul class="list">
    <!-- 点击字母时,触发跳转事件 -->
      <!-- v-for="(item, key) of cities" -->
      <!-- :key="key" -->
    <li
      class="item"
      v-for="item of letters"
      :key="item"
      :ref="item"
      @touchstart="handleTouchStart"
      @touchmove="handleTouchMove"
      @touchend="handleTouchEnd"
      @click="handleLetterClick"
    >
      <!-- {{key}} -->
      {{item}}
    </li>
  </ul>
</template>

<script>
export default {
  name: 'CityAlphabet',
  props: {
    cities: Object
  },
  // 创建一个数组, 返回右侧字母栏
  computed: {
    letters () {
      const letters = []
      for (let i in this.cities) {
        letters.push(i)
      }
      return (letters)
      // 返回的为['A', 'B', 'C,...]
    }
  },
  data () {
    return {
      touchStatus: false,
      // 设置startY初始值为0
      startY: 0,
      // 设置timer为空
      timer: null
    }
  },
  // 创建一个生命周期钩子
  updated () {
    this.startY = this.$refs['A'][0].offsetTop
  },
  methods: {
    handleLetterClick (e) {
      // console.log(e.target.innerText)
      // 向外触发事件
      this.$emit('change', e.target.innerText)
    },
    handleTouchStart () {
      this.touchStatus = true
    },
    handleTouchMove (e) {
      // 思路: 直接计算手指在哪个字母上面比较麻烦, 可以先计算A距离顶部的距离, 再计算手指距离顶部的距离, 差值除以字母的高度, 就可以定位到字母的位置了
      if (this.touchStatus) {
        // 通过函数节流的方式,大大减少handleTouchMove的操作频率,提高网页性能;
        // 执行滚动操作时, 会延迟的16毫秒再执行;如果还在滚动, 则清除上一步操作, 执行新的操作
        if (this.timer) {
          clearTimeout(this.timer)
        }
        this.timer = setTimeout(() => {
          // 性能问题: 因为startY是固定的,所以需要不断的获取它的值(可以用生命周期函数)
          // 获取A元素距离顶部的高度
          // const startY = this.$refs['A'][0].offsetTop
          // console.log(startY)
          // 获取手指距离顶部的高度
          const touchY = e.touches[0].clientY - 79
          // console.log(touchY)
          // 计算手指距离A顶部的距离, 再向下取整
          // const index = Math.floor((touchY - startY) / 20)
          const index = Math.floor((touchY - this.startY) / 20)
          // console.log(index)
          if (index >= 0 && index < this.letters.length) {
            this.$emit('change', this.letters[index])
          }
        }, 5)
      }
    },
    handleTouchEnd () {
      this.touchStatus = false
    }
  }
}
</script>

<style lang="stylus" scoped>
@import '~styles/varibles.styl'
.list
  display flex
  flex-direction column
  justify-content center
  position absolute
  top 1.58rem
  bottom 0
  right 0
  width .4rem
  // background red
  .item
    line-height .4rem
    text-align center
    color $bgColor
</style>


9.搜索逻辑实现

a.编辑’Search.vue’文件(路径: src/pages/city/Search.vue)
<template>
  <div>
    <div class="search">
      <input
        v-model="keyword"
        class="search-input"
        type="text"
        placeholder="请输入城市名或者拼音"
      >
    </div>
    <!-- 页面有内容时候才显示 -->
    <div
      class="search-content"
      ref="search"
      v-show="keyword"
    >
      <ul>
        <li
          class="search-item border-bottom"
          v-for="item of list"
          :key="item.id"
          @click="handleCityClick(item.name)"
        >
          {{item.name}}
        </li>
        <!-- list长度为零时显示的内容 -->
        <!-- 模板里面尽量不要涉及逻辑运算 -->
        <!-- <li class="search-item border-bottom" v-show="!list.length"> -->
        <li class="search-item border-bottom" v-show="hasNoData">
          哎呀~没有找到匹配城市
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
import { mapMutations } from 'vuex'
import BScroll from 'better-scroll'
export default {
  name: 'CitySearch',
  props: {
    cities: Object
  },
  data () {
    return {
      keyword: '',
      list: [],
      timer: ''
    }
  },
  methods: {
    handleCityClick (city) {
      this.changeCity(city)
      this.$router.push('/')
    },
    ...mapMutations(['changeCity'])
  },
  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, {
      click: true
    })
  }
}
</script>

<style lang="stylus" scoped>
@import '~styles/varibles.styl'
.search
  height .72rem
  padding 0 .1rem
  background $bgColor
  .search-input
    box-sizing border-box
    width 100%
    height .62rem
    padding 0 .1rem
    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
    color #666
    background #fff
</style>


#### b.编辑'City.vue'文件(路径: src/pages/city/City.vue)
<template>
  <div>
    <city-header></city-header>
    <city-search :cities='cities'></city-search>
    <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 CityHeader from './components/Header'
import CitySearch from './components/Search'
import CityList from './components/List'
import CityAlphabet from './components/Alphabet'
export default {
  name: 'City',
  components: {
    CityHeader,
    CitySearch,
    CityList,
    CityAlphabet
  },
  data () {
    return {
      cities: {},
      hotCities: [],
      letter: ''
    }
  },
  // 定义这个方法
  methods: {
    getCityInfo () {
      axios.get('/api/city.json')
        .then(this.handleGetCityInfoSucc)
    },
    handleGetCityInfoSucc (res) {
      // console.log(res)
      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
    }
  },
  // 创建一个生命周期函数来调用ajax的方法
  mounted () {
    this.getCityInfo()
  }
}
</script>

<style lang="stylus" scoped>

</style>


9.Vuex实现数据共享1 - - - 选择城市后,首页的城市改变

a.原理

在这里插入图片描述
我们把公用的数据放到公用的空间去进行存储,某一个组件改动了公用数据,其他组件就能感知到
State: 驱动应用的数据源,我们所有的公用数据
Actions: 响应在 view 上的用户输入导致的状态变化; 组件去调用actions
Mutations: 一个个同步地对State的修改


b.安装vuex
npm install vuex --save

c.创建’store’文件夹和’index.js’文件(路径: src/store/index.js)
// 引用vue
import Vue from 'vue'
// 引用vuex
import Vuex from 'vuex'
// 引用state(简化index.js内的内容)
import state from './state'
// 引用mutations(简化index.js的内容)
import mutations from './mutations'
// 使用Vuex这个插件
Vue.use(Vuex)

// // 导出通过Vuex创建的仓库
// export default new Vuex.Store({
//   state: {
//     // 存放全局公用的数据
//     // 默认展示武汉,选择后就用本地存储的城市
//     city: localStorage.city || '武汉'
//   },
//   // 不涉及异步操作和批量操作,操作简单,所以可以跳过Actions
//   // actions: {
//   //   changeCity (ctx, city) {
//   //     // console.log(city)
//   //     ctx.commit('changeCity', city)
//   //   }
//   // },
//   mutations: {
//     changeCity (state, city) {
//       state.city = city
//       // 实现本地存储
//       localStorage.city = city
//     }
//   }
// })

// 有些浏览器对于local的本地存储会报错,用更加规范的书写方式
// let defaultCity = '武汉'
// try {
//   if (localStorage.city) {
//     defaultCity = localStorage.city
//   }
// } catch (e) {}

export default new Vuex.Store({
  // state: {
  //   city: defaultCity
  // },
  // state: state,
  state,
  // mutations: {
  //   changeCity (state, city) {
  //     state.city = city
  //     try {
  //       localStorage.city = city
  //     } catch (e) {}
  //   }
  // }
  // mutations: mutations
  mutations
  // getters: {
  //   doubleCity (state) {
  //     return state.city + ' ' + state.city
  //   }
  // }
})


d.编辑’main.js’文件(路径: src/main.js)
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
// 移动端30毫秒延迟问题
// import fastClick from 'fastClick'
// 引用轮播图插件
import VueAwesomeSwiper from 'vue-awesome-swiper'
// 引用通过Vuex创建的仓库Store
import store from './store'
// css样式
import 'styles/reset.css'
// 解决1px倍率问题
import 'styles/border.css'
// 引用iconfont的字体图标
import 'styles/iconfont.css'
// 引用轮播图插件的css样式
import 'swiper/dist/css/swiper.css'

Vue.config.productionTip = false
// fastClick.attach(document.body)
// 用轮播图插件
Vue.use(VueAwesomeSwiper)

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  // 创建根目录实例
  store,
  components: { App },
  template: '<App/>'
})

// 根据网址的不同,返回不同的内容给用户


e.编辑’Home.vue’文件(路径: src/pages/home/Home.js)
<template>
  <!-- template只能向外暴露一个标签,所以需要在外面再套个盒子 -->
  <div>
    <!-- 引用HomeHeader组件 -->
    <!-- <home-header :city="city"></home-header> -->
    <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'
// 引用icon(金刚区)组件
import HomeIcons from './components/Icons'
// 引用热销推荐
import HomeRecommend from './components/Recommend'
// 引用周末去哪儿
import HomeWeekend from './components/Weekend'
// 引用'axios'获取'ajix'请求
import axios from 'axios'
// 引用vuex
import {mapState} from 'vuex'

export default {
  name: 'Home',
  // 将注册的组件引用到home中来
  components: {
    HomeHeader,
    HomeSwiper,
    HomeIcons,
    HomeRecommend,
    HomeWeekend
  },
  // 所有数据
  data () {
    return {
      // city: '',
      swiperList: [],
      iconList: [],
      recommendList: [],
      weekendList: [],
      lastCity: []
    }
  },
  computed: {
    ...mapState(['city'])
  },
  methods: {
    getHomeInfo () {
      // axios.get('/static/mock/index.json')
      // 测试环境时候访问的本地'static/mock',上线时候访问的是'api'
      // 切换城市后,需要根据选择的城市重新调数据
      // axios.get('/api/index.json')
      axios.get('/api/index.json?city=' + this.city)
        .then(this.getHomeInfoSucc)
    },
    getHomeInfoSucc (res) {
      res = res.data
      // 如果后端返回了数值,并且和data的数据相同
      if (res.ret && res.data) {
        // 定义一个'data'='res.data'
        const data = res.data
        // ajix里面的'data.city'传给了'city'
        // this.city = data.city
        // swiperList里面的数据进行传输
        this.swiperList = data.swiperList
        // iconList里面的数据进行传输
        this.iconList = data.iconList
        // recommendList里面的数据进行传输
        this.recommendList = data.recommendList
        // weekendList里面的数据进行传输
        this.weekendList = data.weekendList
      }
      // console.log(res)
    }
  },
  mounted () {
    this.lastCity = this.city
    this.getHomeInfo()
    // console.log('mounted')
  },
  activated () {
    if (this.lastCity !== this.city) {
      this.lastCity = this.city
      this.getHomeInfo()
    // console.log('activated')
    }
  }
}
</script>

<style>
</style>


f.编辑’Header.vue’文件(路径: src/pages/home/components/Header.vue)
<template>
  <div class="header">
    <div class="header-left">
      <div class="iconfont back-icon">&#xe743;
      </div>
    </div>
    <div class="header-input">
      <span class="iconfont">&#xe632;</span>
      输入城市/景点/游玩主题
    </div>
    <!-- 实现页面跳转 -->
    <router-link to='/city'>
      <div class="header-right">
        <!-- 城市 -->
        <!-- {{this.city}} -->
        <!-- 通过前端mand.js传值,而不需要后端传值过来了 -->
        <!-- {{this.$store.state.city}} -->
        {{this.city}}
        <!-- 可以通过getter的计算来获得新的数据 -->
        <!-- {{this.doubleCity}} -->
        <span class="iconfont arrow-icon">&#xe65c;</span>
      </div>
    </router-link>
  </div>
</template>

<script>
// import {mapState, mapGetters} from 'vuex'
import { mapState } from 'vuex'
export default {
  name: 'HomeHeader',
  // 子组件接收传值
  // props: {
  //   // 切记string要大写,string是字符串的形式
  //   city: String
  // }
  // 把vuex里面的数据映射到computed计算属性里, 把city公用数组映射到city的计算属性中
  // ...mapputed是展开运算符
  computed: {
    ...mapState(['city'])
    // ...mapGetters(['doubleCity'])
  }
}
</script>

<style lang="stylus" scoped>
  // 用'~'引用变量的样式
  @import '~styles/varibles'
  // @import '../../../assets/styles/varibles'  @代表src目录 css中引用其他css样式需要用到'~'
  .header
    display: flex
    line-height: $headerHight
    color: #fff
    background-color: $bgColor
    // background-color: #00bcd4
    .header-left
      width: .64rem
      float: left
      .back-icon
       text-align center
       font-size .6rem
    .header-input
      flex: 1
      margin-top: .12rem
      margin-left: .2rem
      padding-left .2rem
      height: .64rem
      line-height: .64rem
      color: #ccc
      border-radius: .1rem
      background: #fff
    .header-right
      // width: 1.24rem
      // 字符无论是几个字符都没问题了
      min-width 1.04rem
      padding 0 .1rem
      float: right
      text-align: center
      // 修改字体颜色
      color #fff
      .arrow-icon
       margin-left -.1rem
       font-size .4rem
</style>


g.编辑’List.vue’文件(路径: src/pages/city/components/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.$store.state.city}} -->
                {{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>
      </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>
      </div>
    </div>
  </div>
</template>

<script>
// 引入better-scroll
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) {
  //     // alert(city)
  //     // this.$store.dispatch('changeCity', city)
  //     // this.$store.commit('changeCity', city)
  //     this.changeCity(city)
  //     // 修改城市之后,跳转到首页
  //     this.$router.push('/')
  //   },
  //   ...mapMutations(['changeCity'])
  // },
  methods: {
    handleCityClick (city) {
      this.changeCity(city)
      this.$router.push('/')
    },
    ...mapMutations(['changeCity'])
  },
  // 侦听器  监听letter数据改变
  watch: {
    letter () {
      if (this.letter) {
        const element = this.$refs[this.letter][0]
        // console.log(element)
        this.scroll.scrollToElement(element)
      }
      // console.log(this.letter)
    },
    cities () {
      this.$nextTick(function () {
        this.scroll = new BScroll(this.$refs.wrapper, {
          click: true,
          mouseWheel: true,
          tap: true,
          disableMouse: false,
          disableTouch: false
        })
      })
    }
  }
  // 创建一个生命周期函数
  // mounted () {
  // //   // 创建一个scroll实例
  // //   // this.scroll = new Bscroll(this.$refs.wrapper)
  // //   // console.log(BScroll)
  //   this.$nextTick(function () {
  //   this.scroll = new BScroll(this.$refs.wrapper, {
  //     click: true,
  //     mouseWheel: true,
  //     tap: true,
  //     disableMouse: false,
  //     disableTouch: false
  //   })
  //   })
  // // this.scroll = new Bscroll(this.$refs.wrapper, {
  // //   click: true
  // // })
  // //   this.scroll = new Bscroll(this.$refs.wrapper, {
  // //     click: true})
  // }
}

</script>

<style lang="stylus" scoped>
@import '~styles/varibles.styl'
  .border-topbottom
    &:before
      border-color #ccc
    &:after
      border-color #ccc
  .border-bottom
    &:before
      border-color #ccc
  .list
    overflow hidden
    position absolute
    top 1.58rem
    left 0
    right 0
    bottom 0
    .title
      line-height .54rem
      color #666
      font-size .26rem
      padding-left .2rem
      background #eee
    .button-list
      overflow hidden
      padding .1rem .6rem .1rem .1rem
      .button-wrapper
        float left
        width 33.33%
        .button
          margin .1rem
          padding .1rem 0
          text-align center
          border .02rem solid #ccc
          border-radius .06rem
    .item-list
      .item
        line-height .76rem
        padding-left .2rem
</style>


10.Vuex实现数据共享2 - - - 选择城市后,城市列表的当前城市发生改变

a.编辑’List.vue’文件(路径: src/pages/home/components/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.$store.state.city}} -->
                {{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>
      </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>
      </div>
    </div>
  </div>
</template>

<script>
// 引入better-scroll
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) {
  //     // alert(city)
  //     // this.$store.dispatch('changeCity', city)
  //     // this.$store.commit('changeCity', city)
  //     this.changeCity(city)
  //     // 修改城市之后,跳转到首页
  //     this.$router.push('/')
  //   },
  //   ...mapMutations(['changeCity'])
  // },
  methods: {
    handleCityClick (city) {
      this.changeCity(city)
      this.$router.push('/')
    },
    ...mapMutations(['changeCity'])
  },
  // 侦听器  监听letter数据改变
  watch: {
    letter () {
      if (this.letter) {
        const element = this.$refs[this.letter][0]
        // console.log(element)
        this.scroll.scrollToElement(element)
      }
      // console.log(this.letter)
    },
    cities () {
      this.$nextTick(function () {
        this.scroll = new BScroll(this.$refs.wrapper, {
          click: true,
          mouseWheel: true,
          tap: true,
          disableMouse: false,
          disableTouch: false
        })
      })
    }
  }
  // 创建一个生命周期函数
  // mounted () {
  // //   // 创建一个scroll实例
  // //   // this.scroll = new Bscroll(this.$refs.wrapper)
  // //   // console.log(BScroll)
  //   this.$nextTick(function () {
  //   this.scroll = new BScroll(this.$refs.wrapper, {
  //     click: true,
  //     mouseWheel: true,
  //     tap: true,
  //     disableMouse: false,
  //     disableTouch: false
  //   })
  //   })
  // // this.scroll = new Bscroll(this.$refs.wrapper, {
  // //   click: true
  // // })
  // //   this.scroll = new Bscroll(this.$refs.wrapper, {
  // //     click: true})
  // }
}

</script>

<style lang="stylus" scoped>
@import '~styles/varibles.styl'
  .border-topbottom
    &:before
      border-color #ccc
    &:after
      border-color #ccc
  .border-bottom
    &:before
      border-color #ccc
  .list
    overflow hidden
    position absolute
    top 1.58rem
    left 0
    right 0
    bottom 0
    .title
      line-height .54rem
      color #666
      font-size .26rem
      padding-left .2rem
      background #eee
    .button-list
      overflow hidden
      padding .1rem .6rem .1rem .1rem
      .button-wrapper
        float left
        width 33.33%
        .button
          margin .1rem
          padding .1rem 0
          text-align center
          border .02rem solid #ccc
          border-radius .06rem
    .item-list
      .item
        line-height .76rem
        padding-left .2rem
</style>


b.编辑’index.j’s’文件(路径: src/store/index.js)
// 引用vue
import Vue from 'vue'
// 引用vuex
import Vuex from 'vuex'
// 引用state(简化index.js内的内容)
import state from './state'
// 引用mutations(简化index.js的内容)
import mutations from './mutations'
// 使用Vuex这个插件
Vue.use(Vuex)

// // 导出通过Vuex创建的仓库
// export default new Vuex.Store({
//   state: {
//     // 存放全局公用的数据
//     // 默认展示武汉,选择后就用本地存储的城市
//     city: localStorage.city || '武汉'
//   },
//   // 不涉及异步操作和批量操作,操作简单,所以可以跳过Actions
//   // actions: {
//   //   changeCity (ctx, city) {
//   //     // console.log(city)
//   //     ctx.commit('changeCity', city)
//   //   }
//   // },
//   mutations: {
//     changeCity (state, city) {
//       state.city = city
//       // 实现本地存储
//       localStorage.city = city
//     }
//   }
// })

// 有些浏览器对于local的本地存储会报错,用更加规范的书写方式
// let defaultCity = '武汉'
// try {
//   if (localStorage.city) {
//     defaultCity = localStorage.city
//   }
// } catch (e) {}

export default new Vuex.Store({
  // state: {
  //   city: defaultCity
  // },
  // state: state,
  state,
  // mutations: {
  //   changeCity (state, city) {
  //     state.city = city
  //     try {
  //       localStorage.city = city
  //     } catch (e) {}
  //   }
  // }
  // mutations: mutations
  mutations
  // getters: {
  //   doubleCity (state) {
  //     return state.city + ' ' + state.city
  //   }
  // }
})


c.编辑’Search.vue’文件(路径: src/pages/home/components/Search.vue)
<template>
  <div>
    <div class="search">
      <input
        v-model="keyword"
        class="search-input"
        type="text"
        placeholder="请输入城市名或者拼音"
      >
    </div>
    <!-- 页面有内容时候才显示 -->
    <div
      class="search-content"
      ref="search"
      v-show="keyword"
    >
      <ul>
        <li
          class="search-item border-bottom"
          v-for="item of list"
          :key="item.id"
          @click="handleCityClick(item.name)"
        >
          {{item.name}}
        </li>
        <!-- list长度为零时显示的内容 -->
        <!-- 模板里面尽量不要涉及逻辑运算 -->
        <!-- <li class="search-item border-bottom" v-show="!list.length"> -->
        <li class="search-item border-bottom" v-show="hasNoData">
          哎呀~没有找到匹配城市
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
import { mapMutations } from 'vuex'
import BScroll from 'better-scroll'
export default {
  name: 'CitySearch',
  props: {
    cities: Object
  },
  data () {
    return {
      keyword: '',
      list: [],
      timer: ''
    }
  },
  methods: {
    handleCityClick (city) {
      this.changeCity(city)
      this.$router.push('/')
    },
    ...mapMutations(['changeCity'])
  },
  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, {
      click: true
    })
  }
}
</script>

<style lang="stylus" scoped>
@import '~styles/varibles.styl'
.search
  height .72rem
  padding 0 .1rem
  background $bgColor
  .search-input
    box-sizing border-box
    width 100%
    height .62rem
    padding 0 .1rem
    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
    color #666
    background #fff
</style>


d.Vue router - - - 编程式的导航
①. 编辑’Search.vue’文件(路径: src/pages/home/components/Search.vue)
  methods: {
    handleCityClick (city) {
      this.changeCity(city)
      this.$router.push('/')
    },
    ...mapMutations(['changeCity'])
  },
②. 编辑’List.vue’文件(路径: src/pages/home/components/List.vue)
  methods: {
    handleCityClick (city) {
      this.changeCity(city)
      this.$router.push('/')
    },
    ...mapMutations(['changeCity'])
  },

10.Vuex实现数据共享2(本地存储) - - - 选择城市后,刷新页面,依然展示上次选择的城市

a.编辑’index.js’文件(路径: src/store/index.js)
// 引用vue
import Vue from 'vue'
// 引用vuex
import Vuex from 'vuex'
// 引用state(简化index.js内的内容)
import state from './state'
// 引用mutations(简化index.js的内容)
import mutations from './mutations'
// 使用Vuex这个插件
Vue.use(Vuex)

// // 导出通过Vuex创建的仓库
// export default new Vuex.Store({
//   state: {
//     // 存放全局公用的数据
//     // 默认展示武汉,选择后就用本地存储的城市
//     city: localStorage.city || '武汉'
//   },
//   // 不涉及异步操作和批量操作,操作简单,所以可以跳过Actions
//   // actions: {
//   //   changeCity (ctx, city) {
//   //     // console.log(city)
//   //     ctx.commit('changeCity', city)
//   //   }
//   // },
//   mutations: {
//     changeCity (state, city) {
//       state.city = city
//       // 实现本地存储
//       localStorage.city = city
//     }
//   }
// })

// 有些浏览器对于local的本地存储会报错,用更加规范的书写方式
// let defaultCity = '武汉'
// try {
//   if (localStorage.city) {
//     defaultCity = localStorage.city
//   }
// } catch (e) {}

export default new Vuex.Store({
  // state: {
  //   city: defaultCity
  // },
  // state: state,
  state,
  // mutations: {
  //   changeCity (state, city) {
  //     state.city = city
  //     try {
  //       localStorage.city = city
  //     } catch (e) {}
  //   }
  // }
  // mutations: mutations
  mutations
  // getters: {
  //   doubleCity (state) {
  //     return state.city + ' ' + state.city
  //   }
  // }
})

b.创建’mutations.js’文件(路径: src/store/mutations.js)
export default {
  changeCity (state, city) {
    state.city = city
    try {
      localStorage.city = city
    } catch (e) {}
  }
}

c.创建’state.js’文件(路径: src/store/state.js)
let defaultCity = '武汉'
try {
  if (localStorage.city) {
    defaultCity = localStorage.city
  }
} catch (e) {}

export default {
  city: defaultCity
}


11.代码优化

a.编辑’Header.vue’文件(路径: src/pages/home/components/Header.vue)
<template>
  <div class="header">
    <div class="header-left">
      <div class="iconfont back-icon">&#xe743;
      </div>
    </div>
    <div class="header-input">
      <span class="iconfont">&#xe632;</span>
      输入城市/景点/游玩主题
    </div>
    <!-- 实现页面跳转 -->
    <router-link to='/city'>
      <div class="header-right">
        <!-- 城市 -->
        <!-- {{this.city}} -->
        <!-- 通过前端mand.js传值,而不需要后端传值过来了 -->
        <!-- {{this.$store.state.city}} -->
        {{this.city}}
        <!-- 可以通过getter的计算来获得新的数据 -->
        <!-- {{this.doubleCity}} -->
        <span class="iconfont arrow-icon">&#xe65c;</span>
      </div>
    </router-link>
  </div>
</template>

<script>
// import {mapState, mapGetters} from 'vuex'
import { mapState } from 'vuex'
export default {
  name: 'HomeHeader',
  // 子组件接收传值
  // props: {
  //   // 切记string要大写,string是字符串的形式
  //   city: String
  // }
  // 把vuex里面的数据映射到computed计算属性里, 把city公用数组映射到city的计算属性中
  // ...mapputed是展开运算符
  computed: {
    ...mapState(['city'])
    // ...mapGetters(['doubleCity'])
  }
}
</script>

<style lang="stylus" scoped>
  // 用'~'引用变量的样式
  @import '~styles/varibles'
  // @import '../../../assets/styles/varibles'  @代表src目录 css中引用其他css样式需要用到'~'
  .header
    display: flex
    line-height: $headerHight
    color: #fff
    background-color: $bgColor
    // background-color: #00bcd4
    .header-left
      width: .64rem
      float: left
      .back-icon
       text-align center
       font-size .6rem
    .header-input
      flex: 1
      margin-top: .12rem
      margin-left: .2rem
      padding-left .2rem
      height: .64rem
      line-height: .64rem
      color: #ccc
      border-radius: .1rem
      background: #fff
    .header-right
      // width: 1.24rem
      // 字符无论是几个字符都没问题了
      min-width 1.04rem
      padding 0 .1rem
      float: right
      text-align: center
      // 修改字体颜色
      color #fff
      .arrow-icon
       margin-left -.1rem
       font-size .4rem
</style>


b.编辑’List.vue’文件(路径: src/pages/city/components/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.$store.state.city}} -->
                {{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>
      </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>
      </div>
    </div>
  </div>
</template>

<script>
// 引入better-scroll
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) {
  //     // alert(city)
  //     // this.$store.dispatch('changeCity', city)
  //     // this.$store.commit('changeCity', city)
  //     this.changeCity(city)
  //     // 修改城市之后,跳转到首页
  //     this.$router.push('/')
  //   },
  //   ...mapMutations(['changeCity'])
  // },
  methods: {
    handleCityClick (city) {
      this.changeCity(city)
      this.$router.push('/')
    },
    ...mapMutations(['changeCity'])
  },
  // 侦听器  监听letter数据改变
  watch: {
    letter () {
      if (this.letter) {
        const element = this.$refs[this.letter][0]
        // console.log(element)
        this.scroll.scrollToElement(element)
      }
      // console.log(this.letter)
    },
    cities () {
      this.$nextTick(function () {
        this.scroll = new BScroll(this.$refs.wrapper, {
          click: true,
          mouseWheel: true,
          tap: true,
          disableMouse: false,
          disableTouch: false
        })
      })
    }
  }
  // 创建一个生命周期函数
  // mounted () {
  // //   // 创建一个scroll实例
  // //   // this.scroll = new Bscroll(this.$refs.wrapper)
  // //   // console.log(BScroll)
  //   this.$nextTick(function () {
  //   this.scroll = new BScroll(this.$refs.wrapper, {
  //     click: true,
  //     mouseWheel: true,
  //     tap: true,
  //     disableMouse: false,
  //     disableTouch: false
  //   })
  //   })
  // // this.scroll = new Bscroll(this.$refs.wrapper, {
  // //   click: true
  // // })
  // //   this.scroll = new Bscroll(this.$refs.wrapper, {
  // //     click: true})
  // }
}

</script>

<style lang="stylus" scoped>
@import '~styles/varibles.styl'
  .border-topbottom
    &:before
      border-color #ccc
    &:after
      border-color #ccc
  .border-bottom
    &:before
      border-color #ccc
  .list
    overflow hidden
    position absolute
    top 1.58rem
    left 0
    right 0
    bottom 0
    .title
      line-height .54rem
      color #666
      font-size .26rem
      padding-left .2rem
      background #eee
    .button-list
      overflow hidden
      padding .1rem .6rem .1rem .1rem
      .button-wrapper
        float left
        width 33.33%
        .button
          margin .1rem
          padding .1rem 0
          text-align center
          border .02rem solid #ccc
          border-radius .06rem
    .item-list
      .item
        line-height .76rem
        padding-left .2rem
</style>


c.编辑’Search.vue’文件(路径: src/pages/city/components/Search.vue)
<template>
  <div>
    <div class="search">
      <input
        v-model="keyword"
        class="search-input"
        type="text"
        placeholder="请输入城市名或者拼音"
      >
    </div>
    <!-- 页面有内容时候才显示 -->
    <div
      class="search-content"
      ref="search"
      v-show="keyword"
    >
      <ul>
        <li
          class="search-item border-bottom"
          v-for="item of list"
          :key="item.id"
          @click="handleCityClick(item.name)"
        >
          {{item.name}}
        </li>
        <!-- list长度为零时显示的内容 -->
        <!-- 模板里面尽量不要涉及逻辑运算 -->
        <!-- <li class="search-item border-bottom" v-show="!list.length"> -->
        <li class="search-item border-bottom" v-show="hasNoData">
          哎呀~没有找到匹配城市
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
import { mapMutations } from 'vuex'
import BScroll from 'better-scroll'
export default {
  name: 'CitySearch',
  props: {
    cities: Object
  },
  data () {
    return {
      keyword: '',
      list: [],
      timer: ''
    }
  },
  methods: {
    handleCityClick (city) {
      this.changeCity(city)
      this.$router.push('/')
    },
    ...mapMutations(['changeCity'])
  },
  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, {
      click: true
    })
  }
}
</script>

<style lang="stylus" scoped>
@import '~styles/varibles.styl'
.search
  height .72rem
  padding 0 .1rem
  background $bgColor
  .search-input
    box-sizing border-box
    width 100%
    height .62rem
    padding 0 .1rem
    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
    color #666
    background #fff
</style>


d.编辑’store’文件(路径: src/store/store.js)
// 引用vue
import Vue from 'vue'
// 引用vuex
import Vuex from 'vuex'
// 引用state(简化index.js内的内容)
import state from './state'
// 引用mutations(简化index.js的内容)
import mutations from './mutations'
// 使用Vuex这个插件
Vue.use(Vuex)

// // 导出通过Vuex创建的仓库
// export default new Vuex.Store({
//   state: {
//     // 存放全局公用的数据
//     // 默认展示武汉,选择后就用本地存储的城市
//     city: localStorage.city || '武汉'
//   },
//   // 不涉及异步操作和批量操作,操作简单,所以可以跳过Actions
//   // actions: {
//   //   changeCity (ctx, city) {
//   //     // console.log(city)
//   //     ctx.commit('changeCity', city)
//   //   }
//   // },
//   mutations: {
//     changeCity (state, city) {
//       state.city = city
//       // 实现本地存储
//       localStorage.city = city
//     }
//   }
// })

// 有些浏览器对于local的本地存储会报错,用更加规范的书写方式
// let defaultCity = '武汉'
// try {
//   if (localStorage.city) {
//     defaultCity = localStorage.city
//   }
// } catch (e) {}

export default new Vuex.Store({
  // state: {
  //   city: defaultCity
  // },
  // state: state,
  state,
  // mutations: {
  //   changeCity (state, city) {
  //     state.city = city
  //     try {
  //       localStorage.city = city
  //     } catch (e) {}
  //   }
  // }
  // mutations: mutations
  mutations
  // getters: {
  //   doubleCity (state) {
  //     return state.city + ' ' + state.city
  //   }
  // }
})


e.编辑’Header.vue’文件(路径: src/pages/home/components/Header.vue)
<template>
  <div class="header">
    <div class="header-left">
      <div class="iconfont back-icon">&#xe743;
      </div>
    </div>
    <div class="header-input">
      <span class="iconfont">&#xe632;</span>
      输入城市/景点/游玩主题
    </div>
    <!-- 实现页面跳转 -->
    <router-link to='/city'>
      <div class="header-right">
        <!-- 城市 -->
        <!-- {{this.city}} -->
        <!-- 通过前端mand.js传值,而不需要后端传值过来了 -->
        <!-- {{this.$store.state.city}} -->
        {{this.city}}
        <!-- 可以通过getter的计算来获得新的数据 -->
        <!-- {{this.doubleCity}} -->
        <span class="iconfont arrow-icon">&#xe65c;</span>
      </div>
    </router-link>
  </div>
</template>

<script>
// import {mapState, mapGetters} from 'vuex'
import { mapState } from 'vuex'
export default {
  name: 'HomeHeader',
  // 子组件接收传值
  // props: {
  //   // 切记string要大写,string是字符串的形式
  //   city: String
  // }
  // 把vuex里面的数据映射到computed计算属性里, 把city公用数组映射到city的计算属性中
  // ...mapputed是展开运算符
  computed: {
    ...mapState(['city'])
    // ...mapGetters(['doubleCity'])
  }
}
</script>

<style lang="stylus" scoped>
  // 用'~'引用变量的样式
  @import '~styles/varibles'
  // @import '../../../assets/styles/varibles'  @代表src目录 css中引用其他css样式需要用到'~'
  .header
    display: flex
    line-height: $headerHight
    color: #fff
    background-color: $bgColor
    // background-color: #00bcd4
    .header-left
      width: .64rem
      float: left
      .back-icon
       text-align center
       font-size .6rem
    .header-input
      flex: 1
      margin-top: .12rem
      margin-left: .2rem
      padding-left .2rem
      height: .64rem
      line-height: .64rem
      color: #ccc
      border-radius: .1rem
      background: #fff
    .header-right
      // width: 1.24rem
      // 字符无论是几个字符都没问题了
      min-width 1.04rem
      padding 0 .1rem
      float: right
      text-align: center
      // 修改字体颜色
      color #fff
      .arrow-icon
       margin-left -.1rem
       font-size .4rem
</style>


12.keep-alive 优化网页性能

a.编辑’App.vue’文件(路径: src/App.vue)
<template>
  <div id="app">
    <!-- 路由加载过一次之后,就把加载过的内容放到内存之中,下一次加载不需要重新渲染这个组件,直接从路由中调用 -->
    <keep-alive exclude="Detail">
      <!-- 显示当前路由地址所对应的内容 -->
      <router-view/>
    </keep-alive>
  </div>
</template>

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

<style></style>

b.编辑’index.js’文件(路径: src/store/index.js)
// 引用vue
import Vue from 'vue'
// 引用vuex
import Vuex from 'vuex'
// 引用state(简化index.js内的内容)
import state from './state'
// 引用mutations(简化index.js的内容)
import mutations from './mutations'
// 使用Vuex这个插件
Vue.use(Vuex)

// // 导出通过Vuex创建的仓库
// export default new Vuex.Store({
//   state: {
//     // 存放全局公用的数据
//     // 默认展示武汉,选择后就用本地存储的城市
//     city: localStorage.city || '武汉'
//   },
//   // 不涉及异步操作和批量操作,操作简单,所以可以跳过Actions
//   // actions: {
//   //   changeCity (ctx, city) {
//   //     // console.log(city)
//   //     ctx.commit('changeCity', city)
//   //   }
//   // },
//   mutations: {
//     changeCity (state, city) {
//       state.city = city
//       // 实现本地存储
//       localStorage.city = city
//     }
//   }
// })

// 有些浏览器对于local的本地存储会报错,用更加规范的书写方式
// let defaultCity = '武汉'
// try {
//   if (localStorage.city) {
//     defaultCity = localStorage.city
//   }
// } catch (e) {}

export default new Vuex.Store({
  // state: {
  //   city: defaultCity
  // },
  // state: state,
  state,
  // mutations: {
  //   changeCity (state, city) {
  //     state.city = city
  //     try {
  //       localStorage.city = city
  //     } catch (e) {}
  //   }
  // }
  // mutations: mutations
  mutations
  // getters: {
  //   doubleCity (state) {
  //     return state.city + ' ' + state.city
  //   }
  // }
})


#### c.编辑'Header.vue'文件(路径: src/pages/home/components/Header.vue)
<template>
  <div class="header">
    <div class="header-left">
      <div class="iconfont back-icon">&#xe743;
      </div>
    </div>
    <div class="header-input">
      <span class="iconfont">&#xe632;</span>
      输入城市/景点/游玩主题
    </div>
    <!-- 实现页面跳转 -->
    <router-link to='/city'>
      <div class="header-right">
        <!-- 城市 -->
        <!-- {{this.city}} -->
        <!-- 通过前端mand.js传值,而不需要后端传值过来了 -->
        <!-- {{this.$store.state.city}} -->
        {{this.city}}
        <!-- 可以通过getter的计算来获得新的数据 -->
        <!-- {{this.doubleCity}} -->
        <span class="iconfont arrow-icon">&#xe65c;</span>
      </div>
    </router-link>
  </div>
</template>

<script>
// import {mapState, mapGetters} from 'vuex'
import { mapState } from 'vuex'
export default {
  name: 'HomeHeader',
  // 子组件接收传值
  // props: {
  //   // 切记string要大写,string是字符串的形式
  //   city: String
  // }
  // 把vuex里面的数据映射到computed计算属性里, 把city公用数组映射到city的计算属性中
  // ...mapputed是展开运算符
  computed: {
    ...mapState(['city'])
    // ...mapGetters(['doubleCity'])
  }
}
</script>

<style lang="stylus" scoped>
  // 用'~'引用变量的样式
  @import '~styles/varibles'
  // @import '../../../assets/styles/varibles'  @代表src目录 css中引用其他css样式需要用到'~'
  .header
    display: flex
    line-height: $headerHight
    color: #fff
    background-color: $bgColor
    // background-color: #00bcd4
    .header-left
      width: .64rem
      float: left
      .back-icon
       text-align center
       font-size .6rem
    .header-input
      flex: 1
      margin-top: .12rem
      margin-left: .2rem
      padding-left .2rem
      height: .64rem
      line-height: .64rem
      color: #ccc
      border-radius: .1rem
      background: #fff
    .header-right
      // width: 1.24rem
      // 字符无论是几个字符都没问题了
      min-width 1.04rem
      padding 0 .1rem
      float: right
      text-align: center
      // 修改字体颜色
      color #fff
      .arrow-icon
       margin-left -.1rem
       font-size .4rem
</style>


#### d.编辑'Home.vue'文件(路径: src/pages/home/Home.vue)
<template>
  <!-- template只能向外暴露一个标签,所以需要在外面再套个盒子 -->
  <div>
    <!-- 引用HomeHeader组件 -->
    <!-- <home-header :city="city"></home-header> -->
    <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'
// 引用icon(金刚区)组件
import HomeIcons from './components/Icons'
// 引用热销推荐
import HomeRecommend from './components/Recommend'
// 引用周末去哪儿
import HomeWeekend from './components/Weekend'
// 引用'axios'获取'ajix'请求
import axios from 'axios'
// 引用vuex
import {mapState} from 'vuex'

export default {
  name: 'Home',
  // 将注册的组件引用到home中来
  components: {
    HomeHeader,
    HomeSwiper,
    HomeIcons,
    HomeRecommend,
    HomeWeekend
  },
  // 所有数据
  data () {
    return {
      // city: '',
      swiperList: [],
      iconList: [],
      recommendList: [],
      weekendList: [],
      lastCity: []
    }
  },
  computed: {
    ...mapState(['city'])
  },
  methods: {
    getHomeInfo () {
      // axios.get('/static/mock/index.json')
      // 测试环境时候访问的本地'static/mock',上线时候访问的是'api'
      // 切换城市后,需要根据选择的城市重新调数据
      // axios.get('/api/index.json')
      axios.get('/api/index.json?city=' + this.city)
        .then(this.getHomeInfoSucc)
    },
    getHomeInfoSucc (res) {
      res = res.data
      // 如果后端返回了数值,并且和data的数据相同
      if (res.ret && res.data) {
        // 定义一个'data'='res.data'
        const data = res.data
        // ajix里面的'data.city'传给了'city'
        // this.city = data.city
        // swiperList里面的数据进行传输
        this.swiperList = data.swiperList
        // iconList里面的数据进行传输
        this.iconList = data.iconList
        // recommendList里面的数据进行传输
        this.recommendList = data.recommendList
        // weekendList里面的数据进行传输
        this.weekendList = data.weekendList
      }
      // console.log(res)
    }
  },
  mounted () {
    this.lastCity = this.city
    this.getHomeInfo()
    // console.log('mounted')
  },
  activated () {
    if (this.lastCity !== this.city) {
      this.lastCity = this.city
      this.getHomeInfo()
    // console.log('activated')
    }
  }
}
</script>

<style>
</style>


e.编辑’App.vue’文件(路径: src/App.vue)
<template>
  <div id="app">
    <!-- 路由加载过一次之后,就把加载过的内容放到内存之中,下一次加载不需要重新渲染这个组件,直接从路由中调用 -->
    <keep-alive exclude="Detail">
      <!-- 显示当前路由地址所对应的内容 -->
      <router-view/>
    </keep-alive>
  </div>
</template>

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

<style></style>


#### d.编辑'Home.vue'文件(路径: src/pages/home/Home.vue)
<template>
  <!-- template只能向外暴露一个标签,所以需要在外面再套个盒子 -->
  <div>
    <!-- 引用HomeHeader组件 -->
    <!-- <home-header :city="city"></home-header> -->
    <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'
// 引用icon(金刚区)组件
import HomeIcons from './components/Icons'
// 引用热销推荐
import HomeRecommend from './components/Recommend'
// 引用周末去哪儿
import HomeWeekend from './components/Weekend'
// 引用'axios'获取'ajix'请求
import axios from 'axios'
// 引用vuex
import {mapState} from 'vuex'

export default {
  name: 'Home',
  // 将注册的组件引用到home中来
  components: {
    HomeHeader,
    HomeSwiper,
    HomeIcons,
    HomeRecommend,
    HomeWeekend
  },
  // 所有数据
  data () {
    return {
      // city: '',
      swiperList: [],
      iconList: [],
      recommendList: [],
      weekendList: [],
      lastCity: []
    }
  },
  computed: {
    ...mapState(['city'])
  },
  methods: {
    getHomeInfo () {
      // axios.get('/static/mock/index.json')
      // 测试环境时候访问的本地'static/mock',上线时候访问的是'api'
      // 切换城市后,需要根据选择的城市重新调数据
      // axios.get('/api/index.json')
      axios.get('/api/index.json?city=' + this.city)
        .then(this.getHomeInfoSucc)
    },
    getHomeInfoSucc (res) {
      res = res.data
      // 如果后端返回了数值,并且和data的数据相同
      if (res.ret && res.data) {
        // 定义一个'data'='res.data'
        const data = res.data
        // ajix里面的'data.city'传给了'city'
        // this.city = data.city
        // swiperList里面的数据进行传输
        this.swiperList = data.swiperList
        // iconList里面的数据进行传输
        this.iconList = data.iconList
        // recommendList里面的数据进行传输
        this.recommendList = data.recommendList
        // weekendList里面的数据进行传输
        this.weekendList = data.weekendList
      }
      // console.log(res)
    }
  },
  mounted () {
    this.lastCity = this.city
    this.getHomeInfo()
    // console.log('mounted')
  },
  activated () {
    if (this.lastCity !== this.city) {
      this.lastCity = this.city
      this.getHomeInfo()
    // console.log('activated')
    }
  }
}
</script>

<style>
</style>

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

后海 0_o

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值