前面用vue開發了三四個組件了,都是H5的,如今來看看PC是如何玩轉組件的?其實和H5相同,樣式不一樣而已。javascript
《VUE開發一個組件——日曆選擇控件》 《VUE開發一個組件——移動端彈出層(IOS版)》 《VUE開發一個組件——Vue tree樹形結構》css
都提供源碼,能夠去github上面獲取。html
開始今天的課題,製做一個PC版的城市選擇控件。vue
<template>
<div id="app">
<p>{{title}}</p>
<div class="city">
<input type="text" placeholder="出發城市" @focus="showCityDialog" @blur="hideCityDialog">
<div class="city-components" v-if="showCity">
城市控件
</div>
</div>
</div>
</template>
複製代碼
經過focus
獲取焦點事件,控制組件的顯示,blur
失去焦點事件,控制組件的隱藏java
export default {
name: 'app',
data () {
return {
title: 'web秀 - VUE開發一個組件——Vue PC城市選擇',
showCity: false
}
},
methods: {
hideCityDialog(){
this.showCity = false;
},
showCityDialog(){
this.showCity = true;
}
}
}
複製代碼
css佈局,外層用相對位置,裏層用絕對位置,讓城市組件.city-components
跟着input
的位置,這裏用box-shadow
來凸顯組件。git
.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;
}
}
複製代碼
初步效果 github
[
{
"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": "阿克蘇地區",
"airportName": "阿克蘇",
"status": 0,
"lat": 41.2657516858,
"lng": 80.3049157658
},
{
"airportCode": "NGQ",
"cityInfo": "AL-阿里-NGQ",
"cityName": "阿里地區",
"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
}
...
]
複製代碼
這裏只有部分數據,主要是給你們看看結構,數組裏麪包含對象,對象包含多個字段,下面咱們將用airportCode
字段的首字母來分組,排序等。web
相關推薦《js數據如何分組排序?》json
這裏的this.dataList就是數據源數組
let map = {}; // 處理事後的數據對象
let temps = []; // 臨時變量
this.dataList.map(item=>{
if(item.airportCode){
let ekey = item.airportCode.charAt(0).toUpperCase(); // 根據key值的第一個字母分組,而且轉換成大寫
temps = map[ekey] || []; // 若是map裏面有這個key了,就取,沒有就是空數組
temps.push({
airportCode: item.airportCode,
airportName: item.cityName
});
map[ekey] = temps;
}
})
console.log(map);
複製代碼
打印map值
能夠看到已經分組成功,可是這樣的數據結構在頁面遍歷很差處理,咱們進一步處理數據
這裏的map就是上面得出的結果
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);
複製代碼
處理後的數據是否是看起來更容易理解了?數組包含23的對象,A-Z(中間個別沒有),對象兩個字段,一個是首字母key,另一個對象cityList是數組,包含A(Z)的全部機場城市。
這時候的結果是否是咱們想要的了?請看第一張圖,好像是每4個字母一組,同時咱們把分組的key也用一個數組存起來,這時候還得從新分組。
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);
複製代碼
終於數據是咱們要的了,這時候直接將數據渲染到頁面便可。(固然若是後臺能直接給你這樣的數據結構,你就感受感謝吧)
<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
渲染出來,並添加樣式
.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,繼續把下面的數據渲染,這時候就須要事件處理,手勢滑動到哪裏,就展現那塊的數據(好比鼠標知道EFGH,這時候就只能展現EFGH字母開頭的數據)。前面作了那麼多工做,這裏就很好解決了,這裏的cityListKey
自己就是從分好組的數據裏面提取的,因此知道下標就能夠獲得想要的數據了。
因此upCityListKey
方法傳入index
下標。來取對應數據。
upCityListKey(index){
this.upCityListIndex = index;
this.upCityList = this.cityList[index];
}
複製代碼
這裏用upCityListIndex
存入下標,用來添加鼠標劃入的高亮樣式,用upCityList
存須要展現的城市數據。而後將upCityList
渲染到頁面
<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;
}
}
複製代碼
同時去掉..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