前言
前面用vue開發(fā)了三四個(gè)組件了,都是H5的,現(xiàn)在來(lái)看看PC是如何玩轉(zhuǎn)組件的?其實(shí)和H5相同,樣式不同而已。

相關(guān)推薦
《VUE開發(fā)一個(gè)組件——日歷選擇控件》
《VUE開發(fā)一個(gè)組件——移動(dòng)端彈出層(IOS版)》
《VUE開發(fā)一個(gè)組件——Vue tree樹形結(jié)構(gòu)》
都提供源碼,可以去github上面獲取。
城市控件
開始今天的課題,制作一個(gè)PC版的城市選擇控件。
樣式制作
<template>
<div id="app">
<p>{{title}}</p>
<div class="city">
<input type="text" placeholder="出發(fā)城市" @focus="showCityDialog" @blur="hideCityDialog">
<div class="city-components" v-if="showCity">
城市控件
</div>
</div>
</div>
</template>
通過(guò)focus獲取焦點(diǎn)事件,控制組件的顯示,blur失去焦點(diǎn)事件,控制組件的隱藏
export default {
name: 'app',
data () {
return {
title: 'web秀 - VUE開發(fā)一個(gè)組件——Vue PC城市選擇',
showCity: false
}
},
methods: {
hideCityDialog(){
this.showCity = false;
},
showCityDialog(){
this.showCity = true;
}
}
}
css布局,外層用相對(duì)位置,里層用絕對(duì)位置,讓城市組件.city-components跟著input的位置,這里用box-shadow來(lái)凸顯組件。
.city{
position:relative;
.city-components{
position: absolute;
width: 400px;
height: 200px;
box-shadow: 0 0 4px 0 rgba(117,117,117,0.5);
border-radius: 2px;
padding: 20px 21px;
}
}
初步效果

數(shù)據(jù)部分
[
{
"airportCode": "PEK",
"cityInfo": "BJ-北京-PEK",
"cityName": "北京",
"airportName": "首都",
"status": 1,
"lat": 40.0881944004,
"lng": 116.6033998315
},
{
"airportCode": "YIE",
"cityInfo": "AES-阿爾山-YIE",
"cityName": "阿爾山市",
"airportName": "伊爾施",
"status": 0,
"lat": 47.3155940318,
"lng": 119.9293992017
},
{
"airportCode": "AKU",
"cityInfo": "AKS-阿克蘇-AKU",
"cityName": "阿克蘇地區(qū)",
"airportName": "阿克蘇",
"status": 0,
"lat": 41.2657516858,
"lng": 80.3049157658
},
{
"airportCode": "NGQ",
"cityInfo": "AL-阿里-NGQ",
"cityName": "阿里地區(qū)",
"airportName": "昆莎",
"status": 0,
"lat": 32.1081287447,
"lng": 80.0637591367
},
{
"airportCode": "ALA",
"cityInfo": "ALMT-阿爾瑪塔-ALA",
"cityName": "阿拉木圖",
"airportName": "阿爾瑪塔",
"status": 0
},
{
"airportCode": "RHT",
"cityInfo": "ALSYQ-阿拉善右旗-RHT",
"cityName": "阿拉善右旗",
"airportName": "阿拉善右旗",
"status": 0,
"lat": 39.2338594871,
"lng": 101.449757309
},
{
"airportCode": "YIW",
"cityInfo": "YW-義烏-YIW",
"cityName": "義烏市",
"airportName": "義烏",
"status": 0,
"lat": 29.3464578386,
"lng": 120.0389750211
},
{
"airportCode": "ZQZ",
"cityInfo": "ZJK-張家口-ZQZ",
"cityName": "張家口",
"airportName": "張家口",
"status": 0,
"lat": 40.7461174707,
"lng": 114.9436254875
},
{
"airportCode": "HSN",
"cityInfo": "ZS-舟山-HSN",
"cityName": "舟山",
"airportName": "普陀山",
"status": 0,
"lat": 29.9396135515,
"lng": 122.3683649114
},
{
"airportCode": "CGO",
"cityInfo": "ZZ-鄭州-CGO",
"cityName": "鄭州",
"airportName": "新鄭",
"status": 1,
"lat": 34.5308189222,
"lng": 113.8526878594
}
...
]
這里只有部分?jǐn)?shù)據(jù),主要是給大家看看結(jié)構(gòu),數(shù)組里面包含對(duì)象,對(duì)象包含多個(gè)字段,下面我們將用airportCode字段的首字母來(lái)分組,排序等。
相關(guān)推薦《js數(shù)據(jù)如何分組排序?》
分組
這里的this.dataList就是數(shù)據(jù)源
let map = {}; // 處理過(guò)后的數(shù)據(jù)對(duì)象
let temps = []; // 臨時(shí)變量
this.dataList.map(item=>{
if(item.airportCode){
let ekey = item.airportCode.charAt(0).toUpperCase(); // 根據(jù)key值的第一個(gè)字母分組,并且轉(zhuǎn)換成大寫
temps = map[ekey] || []; // 如果map里面有這個(gè)key了,就取,沒(méi)有就是空數(shù)組
temps.push({
airportCode: item.airportCode,
airportName: item.cityName
});
map[ekey] = temps;
}
})
console.log(map);
打印map值

可以看到已經(jīng)分組成功,但是這樣的數(shù)據(jù)結(jié)構(gòu)在頁(yè)面遍歷不好處理,我們進(jìn)一步處理數(shù)據(jù)
格式化
這里的map就是上面得出的結(jié)果
let list = [];
for(let gkey in map) {
list.push({
ckey: gkey,
cityList: map[gkey]
})
}
list = list.sort((li1, li2)=> li1.ckey.charCodeAt(0) - li2.ckey.charCodeAt(0));
console.log(list);

處理后的數(shù)據(jù)是不是看起來(lái)更容易理解了?數(shù)組包含23的對(duì)象,A-Z(中間個(gè)別沒(méi)有),對(duì)象兩個(gè)字段,一個(gè)是首字母key,另外一個(gè)對(duì)象cityList是數(shù)組,包含A(Z)的所有機(jī)場(chǎng)城市。
這時(shí)候的結(jié)果是不是我們想要的了?請(qǐng)看第一張圖,好像是每4個(gè)字母一組,同時(shí)我們把分組的key也用一個(gè)數(shù)組存起來(lái),這時(shí)候還得重新分組。
let chunk = 4;
let result =[];
for (var i = 0, j = list.length; i < j; i += chunk) {
result.push(list.slice(i, i + chunk));
}
console.log(result);
let cityListKey = [];
result.map(item=>{
let ckeys = '';
item.map(ritem=>{
ckeys += ritem.ckey;
})
cityListKey.push(ckeys);
})
console.log(cityListKey);

終于數(shù)據(jù)是我們要的了,這時(shí)候直接將數(shù)據(jù)渲染到頁(yè)面即可。(當(dāng)然如果后臺(tái)能直接給你這樣的數(shù)據(jù)結(jié)構(gòu),你就感覺(jué)感謝吧)
數(shù)據(jù)渲染
<div class="city-components" v-if="showCity">
<ul class="filter-tabar clearfix">
<li v-for="(item,index) in cityListKey" :class="{active:upCityListIndex==index}" @mouseover="upCityListKey(index)">{{item}}</li>
</ul>
</div>
先把cityListKey渲染出來(lái),并添加樣式
.clearfix{
&:after{
content: '';
display: block;
clear: both;
}
}
li{
list-style: none;
}
ul{
padding: 0;
margin: 0;
}
.filter-tabar{
border-bottom: 1px solid #d7d7d7;
cursor: pointer;
li{
text-align: center;
padding: 0 14px;
float: left;
padding-bottom: 14px;
font-size: 14px;
margin: 0 8px;
margin-bottom: -1px;
position: relative;
&.active{
border-bottom: 1px solid #ff7362;
}
}
}

Ok,繼續(xù)把下面的數(shù)據(jù)渲染,這時(shí)候就需要事件處理,手勢(shì)滑動(dòng)到哪里,就展示那塊的數(shù)據(jù)(比如鼠標(biāo)知道EFGH,這時(shí)候就只能展示EFGH字母開頭的數(shù)據(jù))。前面做了那么多工作,這里就很好解決了,這里的cityListKey本身就是從分好組的數(shù)據(jù)里面提取的,所以知道下標(biāo)就可以得到想要的數(shù)據(jù)了。

所以upCityListKey方法傳入index下標(biāo)。來(lái)取對(duì)應(yīng)數(shù)據(jù)。
upCityListKey(index){
this.upCityListIndex = index;
this.upCityList = this.cityList[index];
}
這里用upCityListIndex存入下標(biāo),用來(lái)添加鼠標(biāo)劃入的高亮樣式,用upCityList存需要展示的城市數(shù)據(jù)。然后將upCityList渲染到頁(yè)面
<div class="city-components" v-if="showCity">
<ul class="filter-tabar clearfix">
<li v-for="(item,index) in cityListKey" :class="{active:upCityListIndex==index}" @mouseover="upCityListKey(index)">{{item}}</li>
</ul>
<div class="city-content">
<ul v-for="item in upCityList" class="clearfix">
<label for="">{{item.ckey}}</label>
<li v-for="ritem in item.cityList" @click="selectDepCity(ritem)">{{ritem.airportName}}</li>
</ul>
</div>
</div>
.city-content{
max-height: 500px;
overflow-y: auto;
overflow-x: hidden;
padding: 10px 13px 0 13px;
label{
display: block;
margin-bottom: 5px !important;
font-size: 20px !important;
margin-left: 0 !important;
color: #5f5f5f !important;
margin-top: 5px;
}
li{
padding: 6px 0 6px;
float: left;
text-align: left;
font-size: 14px;
min-width: 56px;
margin-right: 24px;
cursor: pointer;
}
}
同時(shí)去掉..city-components的height樣式。
.city-components{
position: absolute;
width: 400px;
// height: 200px;
box-shadow: 0 0 4px 0 rgba(117,117,117,0.5);
border-radius: 2px;
padding: 20px 21px;
}
完成效果

源碼地址: vue-c-city