本來(lái)對(duì)實(shí)習(xí)僧網(wǎng)站是沒(méi)什么好感的,因?yàn)橹白约涸趯?shí)習(xí)僧上投的實(shí)習(xí)簡(jiǎn)歷幾乎全部都石沉大海了(一個(gè)文科生偏要去投數(shù)據(jù)分析崗不碰壁才怪~_~)!
然鵝看到最近知乎爬蟲(chóng)圈兒里的兩大趨勢(shì):爬美圖;爬招聘網(wǎng)站。
后來(lái)大致了解下了,幾乎各類(lèi)大型的招聘文章都被別人爬過(guò)了,自己再去寫(xiě)免不了模仿之嫌,而且大神們都是用Python去爬的(Python我剛學(xué)會(huì)裝包和導(dǎo)數(shù)據(jù)),自己也學(xué)不來(lái)。
現(xiàn)在只能選一個(gè)還沒(méi)怎么被盯上的招聘網(wǎng)站,沒(méi)錯(cuò)就它了——實(shí)習(xí)僧。
說(shuō)老實(shí)話,實(shí)習(xí)僧的網(wǎng)站做的還是不錯(cuò)的,看著結(jié)構(gòu)挺簡(jiǎn)單,可是我用比較主流的Rvest和RCurl都失敗了(主要自己技術(shù)太渣了,抓包又抓不好)。最后只能勉強(qiáng)用RSelenium爬完了全部所需內(nèi)容。(用代碼驅(qū)動(dòng)瀏覽器的好處就是不用怎么考慮時(shí)延和偽裝包頭了,但是要遍歷成百上千頁(yè)網(wǎng)址真的很耗時(shí),爬完這個(gè)數(shù)據(jù)用了大約40多分鐘)。
以下是爬蟲(chóng)部分:
library(rvest)
library(stringr)
library(plyr)
library(dplyr)
library(Rwebdriver)
library(dplyr)
library(Rwordseg)
library(wordcloud2)
library(treemap)
library(showtext)
library(Cairo)
library(ggplot2)
library(scales)
library(grid)
library(RColorBrewer)
library(ggimage)
library(geojsonio)
本文主要用的Rwebdriver包來(lái)驅(qū)動(dòng)Chrome瀏覽器,使用該包需要提前配置好桌面環(huán)境:
下載selenium啟動(dòng)服務(wù)器;
下載Chrome的chromedriver插件并放入Chrome主目錄(添加系統(tǒng)環(huán)境變量)
下載Rwebdriver包
在cmd或者powershell中啟動(dòng)Selenium服務(wù)器:
options(stringsAsFactors=FALSE,warn=FALSE)
cd "D:/Rwebdriver-master"
java -jar selenium-server-standalone-3.3.1.jar
在Rsudio中新建進(jìn)程:
start_session(root="http://localhost:4444/wd/hub/",browser="chrome")
遍歷實(shí)習(xí)僧的招聘信息網(wǎng)頁(yè)
baseurl<-"http://www.shixiseng.com/interns?k=&t=zh&c=%E5%85%A8%E5%9B%BD&p="
pageurl<-paste0(baseurl,1:500)
本文所用到的爬蟲(chóng)代碼部分:
homepage=internship=companyweb=company=Position=address=salary=period=duration=NULL
fun<-function(url){
post.url(url=url)
baseinfo<-read_html(url,encoding="utf-8")
homepage <-baseinfo%>%html_nodes("div.po-name>div.names>a")%>% html_attr("href")
internship<-baseinfo%>%html_nodes("div.po-name>div.names>a")%>%html_text()
companyweb<-baseinfo%>%html_nodes("div.po-name>div.part>a")%>%html_attr("href")
company <-baseinfo%>%html_nodes("div.po-name>div.part>a")%>%
html_text()
Position <-baseinfo%>%html_nodes("div.po-name>div.part")%>%
html_text()
address <-baseinfo%>%html_nodes("div.po-detail>div.addr>span")%>%
html_text()
salary <-baseinfo%>%html_nodes("div.po-detail>div.xz>span:nth-child(2)")%>%
html_text()
period <-baseinfo%>%html_nodes("div.po-detail>div.xz>span:nth-child(5)")%>%
html_text()
duration <-baseinfo%>%html_nodes("div.po-detail>div.xz>span:nth-child(8)")%>%
html_text()
interninfo<-data.frame(homepage,internship,companyweb,company,Position,address,salary,period,duration)
}
用一個(gè)循環(huán)執(zhí)行上述程序:
final<-data.frame()
for (i in pageurl){
final<-rbind(final,fun(i))
}
quit_session()
DT::datatable(final)
保存本地:
write.table (final,"D:/R/File/shixiseng.csv",sep=",",row.names=FALSE)
##############################################
接下來(lái)做數(shù)據(jù)清洗:
mydata<-read.csv("D:/R/File/shixiseng.csv",stringsAsFactors=FALSE,check.names=FALSE)
mydata<-mydata[-5001,]
#補(bǔ)全實(shí)習(xí)發(fā)布單位的招聘信息主頁(yè):
mydata$homepage<-str_c("http://www.shixiseng.com",mydata$homepage,sep="")
#補(bǔ)全實(shí)習(xí)發(fā)布單位的公司信息主頁(yè):
mydata$companyweb<-str_c("http://www.shixiseng.com",mydata$companyweb,sep="")
mydata$work<-str_split(mydata$Position[1:10], " - ", simplify=TRUE)[,2]
#清除salary中的空格和斜杠
mydata$salary<-str_trim(mydata$salary,side="both")
mydata$salary<-str_extract(mydata$salary,"\d+\-\d+")
#拆分實(shí)習(xí)工資的高低區(qū)間
mydata$salary_low<-str_split(mydata$salary, "-", simplify=TRUE)[,1]
mydata$salary_high<-str_split(mydata$salary, "-", simplify=TRUE)[,2]
#清除period中的漢字和特殊字符
mydata$period<-str_extract(mydata$period,"\d+")
#清除duration中的漢字和特殊字符
mydata$duration<-str_extract(mydata$duration,"\d+")
mydata <- tbl_df(mydata)
mydata<-select(mydata,-Position)
#因?yàn)閍ddress中所含的地址可能有存在多個(gè),影響我們后續(xù)的可視化分析,這里為了方便起見(jiàn),一律使用第一個(gè)地址。
mydata$address_unique<-str_split(mydata$address, ",", simplify=TRUE)[,1]
至此,數(shù)據(jù)清洗工作告一段落,接下來(lái)我們要進(jìn)入分析與可視化階段
names(mydata)
"homepage"-------公司實(shí)習(xí)職位簡(jiǎn)介
"internship"-----公司招聘性質(zhì)
"companyweb"-----公司主頁(yè)
"company"--------公司名稱
"address"--------所在地
"address_unique"-所在地(唯一值,只取默認(rèn)第一個(gè)地址)
"salary"---------實(shí)習(xí)工資區(qū)間
"salary_low"-----實(shí)習(xí)工資(最低值)
"salary_high"----實(shí)習(xí)工資(最高值)
"period"---------到崗天數(shù)(每周)
"duration"-------實(shí)習(xí)周期(按月算)
"work"-----------具體職位
我們最終獲取的清洗后數(shù)據(jù)如上所示。
假如本次項(xiàng)目需求(虛擬)要求我們獲取以下幾個(gè)問(wèn)題:
1、實(shí)習(xí)僧的實(shí)習(xí)招聘主頁(yè)崗位主要是什么性質(zhì)的?
2、哪些公司最缺實(shí)習(xí)僧?
3、實(shí)習(xí)崗位具體分布的地域和城市?
4、哪些城市對(duì)實(shí)習(xí)僧的需要最為強(qiáng)烈?
5、實(shí)習(xí)工資大致什么水平,與城市和地域是否有關(guān)系?
6、實(shí)習(xí)崗位一般都要求每周到崗多少天?
7、實(shí)習(xí)周期一般需要多長(zhǎng)時(shí)間?
8、哪些職位需求最為頻繁,職位需要量與城市之間的大致是如何分布的?
帶著這些個(gè)問(wèn)題,讓我們盡情的暢游在可視化的世界里吧……
1、實(shí)習(xí)僧的實(shí)習(xí)招聘主頁(yè)主要是什么性質(zhì)的?
length(unique(mydata$internship))
3357
絕望了,一共爬了5000條實(shí)習(xí)職位信息,做了去重處理,顯示仍有3357條,建議實(shí)習(xí)僧的產(chǎn)品運(yùn)營(yíng)團(tuán)隊(duì)考慮下要不要標(biāo)準(zhǔn)化一下這個(gè)職位性質(zhì),內(nèi)門(mén)怎么可以創(chuàng)造這么多獨(dú)特的職位~_~
對(duì)于這個(gè)問(wèn)題,真的難倒我了,因?yàn)樗罃?shù)據(jù)中的職位性質(zhì)沒(méi)有統(tǒng)一的預(yù)設(shè)標(biāo)準(zhǔn),所以我只能用文本分詞的形式來(lái)進(jìn)行提取了,先分詞,然后統(tǒng)計(jì)高頻詞,最后按照詞頻來(lái)進(jìn)行模糊分析啦(可我我對(duì)文本挖掘一竅不通啊~_~)
top100<-table(mydata$internship)%>%as.data.frame(stringsAsFactors=FALSE)%>% arrange(desc(Freq))%>%.[1:100,]
treemap(top100, index=c("Var1"), vSize="Freq",title='實(shí)習(xí)僧職位性質(zhì)分布圖',palette='RdBu',
fontsize.title=18,fontsize.labels=12,fontface.labels="plain",fontfamily.title="mono",fontfamily.labels="mono")
從實(shí)習(xí)職位分布圖上來(lái)看,人力資源實(shí)習(xí)生職位需求最為強(qiáng)烈,其次是運(yùn)營(yíng)、財(cái)務(wù)、新媒體,這些類(lèi)型的職位多為現(xiàn)代新興服務(wù)業(yè),更為符合大學(xué)生這一群體的口味和興趣。
myrevieww<-mydata$internship
thewords <- segmentCN(myrevieww,nature=T)%>%unlist()
thewords <- gsub("[a-z]|\.", "", thewords)
thewords<-thewords[nchar(thewords)>1]
reviewdata<-table(thewords)%>%as.data.frame(stringsAsFactors=FALSE)%>% arrange(desc(Freq))%>%filter(thewords!="實(shí)習(xí)生")
wordcloud<-wordcloud2(reviewdata[1:1000,],color="random-light",minSize=.6,size=1,backgroundColor="dark",minRotation=-pi/6,maxRotation=-pi/6,fontFamily="微軟雅黑");wordcloud
但是將職位性質(zhì)分詞整理成關(guān)鍵詞后,似乎結(jié)果有所不同。
2、哪些公司最缺實(shí)習(xí)僧?
這里我們來(lái)統(tǒng)計(jì)所爬職位信息中公司發(fā)布職位的頻率,發(fā)布最多的則作為評(píng)價(jià)公司對(duì)實(shí)習(xí)生需求的標(biāo)準(zhǔn)。
myjob<-table(mydata$company)%>%as.data.frame(stringsAsFactors=FALSE)%>%arrange(desc(Freq))
#看看前十名都是那些公司:
myjob15<-arrange(myjob[1:15,],desc(Freq))
CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/circle-rose.png",width=1580,height=950)
showtext.begin()
ggplot(data=myjob15,aes(x=reorder(Var1,-Freq),y=Freq,fill=Freq))+
geom_linerange(aes(ymin=0,ymax=42),linetype=5,size=.2,colour="#858585")+
geom_image(aes(x=0,y=-40),image="D:/R/Image/image1.jpg", size=.2)+
geom_text(aes(y=45,label=paste0(Var1,"\n",Freq)),vjust=1,size=5)+
geom_bar(stat="identity",width=1,col="white")+
geom_hline(yintercept=54,color="black",size=.5)+
geom_point(aes(y=48,size=Freq),shape=21,fill="#ED7D31",,alpha=0.6,col="orange")+
labs(title="Top 15 of Company",caption="Data Source:shixiseng")+
coord_polar(theta="x")+
ylim(-40,60)+
scale_size_area(max_size=20)+
guides(fill=FALSE,size=guide_legend(reverse=TRUE,title=NULL))+
theme_minimal()+
theme(
axis.title=element_blank(),
axis.text=element_blank(),
panel.grid=element_blank(),
legend.text=element_text(family="myfont",size=12),
legend.title=element_text(family="myfont",size=15,hjust=1),
plot.title=element_text(family="myfont",size=35),
plot.caption=element_text(family="myfont",size=18,hjust=0,lineheight=1.2)
)
showtext.end()
dev.off()
write.table (myjob[1:100,],"D:/R/File/shixiseng_job.csv",sep=",",row.names=FALSE)
前一百個(gè)實(shí)習(xí)生需求最旺盛企業(yè):
3、實(shí)習(xí)崗位具體分布的地域和城市?
先做一個(gè)地域分布圖:
add<-table(mydata$address_unique)%>%as.data.frame(stringsAsFactors=FALSE)%>%arrange(desc(Freq))%>%filter(nchar(Var1)==2)
#城市經(jīng)緯度查詢:
library(rjson)
library(RCurl)
library(REmap)
library(baidumap)
address<-add$Var1
baidu_lng <- c()
baidu_lat <- c()
ak<-"X8zlxPUdSe2weshrZ1WqnWxb43cfBI2N"
for(location in address){
url<-paste("http://api.map.baidu.com/geocoder/v2/?ak=",ak,"&callback=renderOption&output=json&address=",location,sep="")
url_string <- URLencode(url)
msg.load <- tryCatch({
json <-readLines(url_string,warn=F,encoding="UTF-8")
msg.load <- "TRUE"
},error=function(e) {
"error"
}
)
if(msg.load=='error'){
Sys.sleep(runif(1,3,10))
msg.load <- tryCatch({
connect <- readLines(url_string,warn=F,encoding="UTF-8")
msg.load <- "TRUE"
}, error=function(e){
"error"
}
)
}
geo <- fromJSON(substr(json,regexpr("\(",json)+1,nchar(json)-1))
if(msg.load=='error'){
lng<-'error1'
lat<-'error1'
}else{
lng<-geo$result$location$lng
lat<-geo$result$location$lat
if(length(lng)==0){
lng <- "error2"
lat <- "error2"
}
}
lng<-geo$result$location$lng
lat<-geo$result$location$lat
baidu_lng<-c(baidu_lng,lng)
baidu_lat<-c(baidu_lat,lat)
}
result<-data.frame(address=address,long=baidu_lng,lat=baidu_lat,stringsAsFactors=FALSE)
pointdata<-left_join(add,result,by=c("Var1"="address"))
#成功獲取目標(biāo)城市經(jīng)緯度信息:
解析來(lái)制作分布圖:
geojson <-readOGR("D:/R/mapdata/State/china.geojson","OGRGeoJSON",stringsAsFactors=FALSE)
Encoding(geojson$name)<-"UTF-8"
china_Mapdata<-geojson@data
china_MapdataPloygon<-fortify(geojson)
CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/shixiseng_jobcity.png",width=1200,height=640)
showtext.begin()
ggplot()+
geom_polygon(data=china_MapdataPloygon,aes(x=long,y=lat,group=group),col="grey60",fill="white",size=.2,alpha=.4)+
geom_point(data=pointdata,aes(x=long,y=lat,size=Freq),shape=21,fill="#C72E29",col="#014D64",alpha=0.6)+
scale_size_area(max_size=15,guide=guide_legend(reverse=TRUE,title=NULL))+
coord_map("polyconic") +
labs(title="實(shí)習(xí)僧職位需求城市分布圖",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+
theme(
title=element_text(family="myfont",size=18),
plot.title=element_text(size=24),
plot.caption=element_text(family="myfont",size=18,hjust=0),
panel.grid=element_blank(),
panel.background=element_blank(),
axis.text=element_blank(),
axis.ticks=element_blank(),
axis.title=element_blank(),
legend.position=c(0.02,0.6),
)
showtext.end()
dev.off()
4、哪些城市對(duì)實(shí)習(xí)僧的需要最為強(qiáng)烈?
從第三個(gè)問(wèn)題及其分析結(jié)果上我們已經(jīng)看出了整體形勢(shì),北上廣深依然是需求最為旺盛的地區(qū),這也符合城市的實(shí)際經(jīng)濟(jì)發(fā)展情況及我們的預(yù)期。
CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/jingjixue2.png",width=800,height=600)
showtext.begin()
ggplot(pointdata[1:20,],aes(reorder(Var1,Freq),Freq))+
geom_bar(fill="#0C8DC4",stat="identity")+
coord_flip()+
labs(title="實(shí)習(xí)僧職位需求城市分布",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+
geom_text(aes(y=Freq+25,label=Freq),hjust=2,colour="#C72E29",size=5)+
theme_bw()+
theme(
panel.border=element_blank(),
panel.grid.major=element_line(linetype="dashed"),
panel.grid.minor=element_blank(),
plot.title=element_text(size=15,colour="#003087",family="myfont"),
plot.caption=element_text(hjust=0,size=10),
axis.title=element_blank(),
axis.text=element_text(size=15)
)
showtext.end()
dev.off()
5、實(shí)習(xí)工資大致什么水平,與城市和地域是否有關(guān)系?
myjob_salary<-mydata[,c("address_unique","salary_low","salary_high")]
myjob_salary$salary_low<-as.numeric(myjob_salary$salary_low)
myjob_salary$salary_high<-as.numeric(myjob_salary$salary_high)
myjob_salary<-na.omit(myjob_salary)%>%arrange(salary_high)%>%filter(salary_high>=20&salary_high<=500)
myjob_salary$id<-seq_len(nrow(myjob_salary))
myjob_salary$meansalary<-(myjob_salary$salary_low+myjob_salary$salary_high)/2
CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/shixiseng_jobsaleryarea.png",width=1200,height=800)
showtext.begin()
ggplot(myjob_salary,aes(id))+
geom_ribbon(aes(ymin=salary_low,ymax=salary_high),fill="grey70")+
labs(title="實(shí)習(xí)僧職位工資區(qū)間分布",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+
geom_line(aes(y=meansalary))+
theme_minimal()+
theme(
panel.border=element_blank(),
panel.grid.major=element_line(linetype="dashed"),
panel.grid.minor=element_blank(),
plot.title=element_text(size=30,colour="#003087",family="myfont"),
plot.caption=element_text(hjust=0,size=20),
axis.title=element_blank(),
axis.text.y=element_text(size=15),
axis.text.x=element_blank()
)
showtext.end()
dev.off()
myjob_salary$address_unique<-substr(myjob_salary$address_unique,1,2)
myjobcitysalary<-aggregate(meansalary~address_unique,data=myjob_salary,FUN=mean)
treemap(na.omit(myjobcitysalary), index=c("address_unique"),
vSize="meansalary",title='實(shí)習(xí)僧職位薪酬地域分布圖',palette='RdBu',
fontsize.title=18,fontsize.labels=12,fontface.labels="plain",
fontfamily.title="mono",fontfamily.labels="mono")
按照全部參與計(jì)算聚合的平均工資來(lái)看,北上廣深反而沒(méi)有什么吸引力了排名普遍不高,我猜想是因?yàn)橐痪€城市的低工資職位數(shù)量過(guò)多,壓低了平均值。
接下來(lái)我們按照100,150的臨界點(diǎn)進(jìn)行工資高低的劃分。
salary100<-myjob_salary%>%filter(meansalary<=100)%>%select(address_unique)%>%table()%>%as.data.frame(stringsAsFactors=FALSE)
salary100<-na.omit(salary100)%>%arrange(desc(Freq));names(salary100)<-c("city","num")
CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/salary100.png",width=1200,height=900)
showtext.begin()
ggplot(salary100[salary100$num>=5,],aes(reorder(city,-num),num))+
geom_bar(fill="#0C8DC4",stat="identity")+
labs(title="實(shí)習(xí)僧職位薪資城市分布(日薪低于100)",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+
geom_text(aes(y=num+10,label=num),hjust=.5,colour="#C72E29",size=5)+
theme_bw()+
theme(
panel.border=element_blank(),
panel.grid.major=element_line(linetype="dashed"),
panel.grid.minor=element_blank(),
plot.title=element_text(size=25,colour="#003087",family="myfont"),
plot.caption=element_text(hjust=0,size=18),
axis.title=element_blank(),
axis.text=element_text(size=15)
)
showtext.end()
dev.off()
salary200<-myjob_salary%>%filter(meansalary>=200)%>%select(address_unique)%>%table()%>%as.data.frame(stringsAsFactors=FALSE)
salary200<-na.omit(salary200)%>%arrange(desc(Freq));names(salary200)<-c("city","num")
CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/salary200.png",width=1200,height=900)
showtext.begin()
ggplot(salary200,aes(reorder(city,-num),num))+
geom_bar(fill="#0C8DC4",stat="identity")+
labs(title="實(shí)習(xí)僧職位薪資城市分布(日薪高于200)",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+
geom_text(aes(y=num+10,label=num),hjust=.5,colour="#C72E29",size=5)+
theme_bw()+
theme(
panel.border=element_blank(),
panel.grid.major=element_line(linetype="dashed"),
panel.grid.minor=element_blank(),
plot.title=element_text(size=25,colour="#003087",family="myfont"),
plot.caption=element_text(hjust=0,size=18),
axis.title=element_blank(),
axis.text=element_text(size=15)
)
showtext.end()
dev.off()
salary100_200<-myjob_salary%>%filter(meansalary>100 & meansalary<200)%>%select(address_unique)%>%table()%>%as.data.frame(stringsAsFactors=FALSE)
salary100_200<-na.omit(salary100_200)%>%arrange(desc(Freq));names(salary100_200)<-c("city","num")
CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/salary100-200.png",width=1600,height=900)
showtext.begin()
ggplot(salary100_200,aes(reorder(city,-num),num))+
geom_bar(fill="#0C8DC4",stat="identity")+
labs(title="實(shí)習(xí)僧職位薪資城市分布(日薪處于100-200之間)",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+
geom_text(aes(y=num+10,label=num),hjust=.5,colour="#C72E29",size=5)+
theme_bw()+
theme(
panel.border=element_blank(),
panel.grid.major=element_line(linetype="dashed"),
panel.grid.minor=element_blank(),
plot.title=element_text(size=25,colour="#003087",family="myfont"),
plot.caption=element_text(hjust=0,size=18),
axis.title=element_blank(),
axis.text=element_text(size=15)
)
showtext.end()
dev.off()
分析到這里,趨勢(shì)已經(jīng)很明顯了,因?yàn)楸鄙蠌V深等一線城市的職位實(shí)在是太多了,無(wú)論是高新職位還是低薪實(shí)習(xí)崗位都能排在全國(guó)各城市的前列,所以出現(xiàn)日均工資很普通的現(xiàn)象。相對(duì)而言,日薪在200以上的高薪職位更能代表各大城市對(duì)日常實(shí)習(xí)生需求的強(qiáng)烈程度,因?yàn)樵谶@一階段,北上廣深的優(yōu)勢(shì)非常明顯,遙遙領(lǐng)先與其他二線城市,而針對(duì)日薪高于200的實(shí)習(xí)職位統(tǒng)計(jì)結(jié)果可以看出來(lái),北上技?jí)喝盒郏ú焕⑹堑鄱己湍Ф迹?,深圳和廣州處于第二線,200以上的高新實(shí)習(xí)職位遇北上相比,相差比較大,僅占前兩者約1/3~1/5。而杭州、南京、武漢、合肥則穩(wěn)穩(wěn)處于第三梯隊(duì)。
6、實(shí)習(xí)崗位一般都要求每周到崗多少天?
myperiod<-mydata$period
CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/internperiod.png",width=1000,height=750)
showtext.begin()
ggplot(data=NULL,aes(myperiod)) +
geom_histogram(stat="count",show.legend=FALSE,binwidth=1,fill="#F86977",col=NA) +
labs(title="實(shí)習(xí)職位要求每周工作天數(shù)",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+
theme(panel.background=element_rect(fill=NA),
plot.background=element_rect(fill=NA),
plot.title=element_text(size=20,family="myfont"),
plot.caption=element_text(hjust=0,family="myfont"),
axis.line=element_line(colour="grey80"),
axis.text=element_text(size=12,family="myfont"),
axis.title=element_blank())
showtext.end()
dev.off()
從分布上看,一周五天居多,這樣是正常的工作日現(xiàn)象。3天、4天也是用人單位補(bǔ)繳能接受的周工作天數(shù)。
7、實(shí)習(xí)周期一般需要多長(zhǎng)時(shí)間?
myduration<-mydata$duration
mydurationhz<-table(myduration)%>%as.data.frame(stringsAsFactors=FALSE)%>%arrange(desc(Freq))
CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/internduration.png",width=1000,height=750)
showtext.begin()
ggplot(data=mydurationhz,aes(reorder(myduration,-Freq),Freq)) +
geom_bar(stat="identity",show.legend=FALSE,width=1,fill="#065573",col=NA) +
geom_text(aes(y=Freq+20,label=Freq),hjust=.5,colour="#C72E29",size=5)+
labs(title="實(shí)習(xí)職位要求工作時(shí)間周期",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+
theme(panel.background=element_rect(fill=NA),
plot.background=element_rect(fill=NA),
plot.title=element_text(size=20,family="myfont"),
plot.caption=element_text(hjust=0,family="myfont"),
axis.line=element_line(colour="grey80"),
axis.text=element_text(size=12,family="myfont"),
axis.title=element_blank())
showtext.end()
dev.off()
8、哪些職位需求最為旺盛?
下面開(kāi)始分析最后一個(gè)問(wèn)題,也是我認(rèn)為最有價(jià)值,最值得探究的問(wèn)題,最后一個(gè)待分析指標(biāo)是實(shí)習(xí)職位,這個(gè)指標(biāo)跟我們最初分析的那個(gè)崗位性質(zhì)略有不同,該變量相對(duì)比較規(guī)范(職位類(lèi)別有確定的預(yù)設(shè)范圍)。
我們新建一個(gè)分析數(shù)據(jù),用職位、工資區(qū)間的中間值,地區(qū)三個(gè)變量進(jìn)行后續(xù)分析:
mydata$salary_high<-as.numeric(mydata$salary_high)
mydata$salary_low<-as.numeric(mydata$salary_low)
mydata$salary_mean<-(mydata$salary_low+mydata$salary_high)/2
myworkdata<-mydata[,c("address_unique","work","salary_mean")]
首先分析下崗位的集中分布情況:
myworkcount<-table(myworkdata[,2])%>%as.data.frame(stringsAsFactors=FALSE)%>%arrange(desc(Freq))
CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/interndworkcount.png",width=1000,height=750)
showtext.begin()
ggplot(data=myworkcount,aes(reorder(Var1,-Freq),Freq)) +
geom_bar(stat="identity",show.legend=FALSE,width=.75,fill="#5D8DA6",col=NA) +
geom_text(aes(y=Freq+50,label=Freq),hjust=.5,colour="#C72E29",size=5)+
labs(title="實(shí)習(xí)職位類(lèi)別分布",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+
theme(panel.background=element_rect(fill=NA),
plot.background=element_rect(fill=NA),
plot.title=element_text(size=20,family="myfont"),
plot.caption=element_text(hjust=0,family="myfont"),
axis.line=element_line(colour="grey80"),
axis.text=element_text(size=12,family="myfont"),
axis.title=element_blank())
showtext.end()
dev.off()
各個(gè)崗位工資分布:
myworkmean<-aggregate(salary_mean~work,data=myworkdata,FUN=mean)
CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/interndworkmean.png",width=1000,height=750)
showtext.begin()
ggplot(data=myworkmean,aes(reorder(work,-salary_mean),salary_mean)) +
geom_bar(stat="identity",show.legend=FALSE,width=.75,fill="#5D8DA6",col=NA) +
geom_text(aes(y=salary_mean+5,label=round(salary_mean,1)),hjust=.5,colour="#C72E29",size=10)+
labs(title="實(shí)習(xí)職位類(lèi)別平均工資",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+
theme(panel.background=element_rect(fill=NA),
plot.background=element_rect(fill=NA),
plot.title=element_text(size=25,family="myfont"),
plot.caption=element_text(hjust=0,family="myfont",size=20),
axis.line=element_line(colour="grey80"),
axis.text=element_text(size=18,family="myfont"),
axis.title=element_blank())
showtext.end()
dev.off()
從工資均數(shù)上來(lái)看,七大類(lèi)職位差距不大,說(shuō)明僅就實(shí)習(xí)崗位工資而言,結(jié)合爬取的總體樣本,不考慮地域差異,實(shí)習(xí)工資差異不很明顯。也許是因?yàn)閷?shí)習(xí)崗位中真正有含金量的并不多,換句話說(shuō),企業(yè)的高價(jià)值崗位,對(duì)于工作經(jīng)驗(yàn)、技能的要求相對(duì)較高,而實(shí)習(xí)生則在這方面都不具備優(yōu)勢(shì)。(如果是社招或者小校招崗位信息的話,可能工資均值的差異會(huì)大一些)。
最后,讓我們用一個(gè)桑基圖來(lái)完結(jié)本次針對(duì)實(shí)習(xí)僧網(wǎng)站的爬蟲(chóng)分析:
write.table (myworkdata,"D:/R/File/shixiseng_workdata.csv",sep=",",row.names=FALSE)
?;飨驁D的趨勢(shì)灰常明顯,北上兩市在所有類(lèi)別職位(7大類(lèi))上均居前列,各職位類(lèi)別中,市場(chǎng)和運(yùn)營(yíng)職位需求最為強(qiáng)烈,北京和上海在對(duì)市場(chǎng)和運(yùn)營(yíng)職位的需求容量機(jī)會(huì)平分秋色。廣州和深圳仍然略于北上,但是與其他二線城市相比較,優(yōu)勢(shì)仍然很明顯。(也許是因?yàn)閷?shí)習(xí)僧做為主打校園實(shí)習(xí)崗位信息咨詢平臺(tái),針對(duì)的主流群體基本以在校大學(xué)生為主,而北上廣深的高等教育資源分布差異明顯,在高校數(shù)量方面,北上的要沾光很多,廣州與深圳的高校資源相對(duì)比較匱乏,在以上分析的各項(xiàng)指標(biāo)中都占盡劣勢(shì))。
爬蟲(chóng)和代碼分析,算起來(lái)整整花了將近12個(gè)小時(shí),雖然分析的不是很精準(zhǔn)、客觀,但是過(guò)程還是很有收獲的,期待下一次做的更好!
End.
來(lái)源:R語(yǔ)言中文社區(qū)
I 鑒賞
早幾年學(xué)習(xí)前端,大家都非常熱衷于研究jQuery源碼。
我至今還記得當(dāng)初從jQuery源碼中學(xué)到一星半點(diǎn)應(yīng)用技巧的時(shí)候常會(huì)有一種發(fā)自內(nèi)心的驚嘆,“原來(lái)JavaScript居然可以這樣用!”
但是隨著前端的迅猛發(fā)展,另外幾種前端框架的崛起,jQuery慢慢變得不再是必須。所有人對(duì)jQuery的熱情都降低了許多。
jQuery在前端史上有它非常超然的歷史地位,許多從中學(xué)到的技巧在實(shí)踐開(kāi)發(fā)中仍然非常好用。簡(jiǎn)單的了解它有助于我們更加深入的理解JavaScript。如果你能夠從中看明白jquery是如何一步步被取代的,那么,我想你的收益遠(yuǎn)不止學(xué)會(huì)使用了一個(gè)庫(kù)那么簡(jiǎn)單。
因此,我的態(tài)度是,項(xiàng)目中你可以不用,但是我仍然建議你學(xué)。
這篇文章的主要目的,是從面向?qū)ο蟮慕嵌?,跟大家分享jquery對(duì)象是如何封裝的。算是對(duì)大家進(jìn)一步學(xué)習(xí)jQuery源碼的一個(gè)拋磚引玉。
使用jQuery對(duì)象時(shí),我們這樣寫(xiě):
// 聲明一個(gè)jQuery對(duì)象
$('.target')
// 獲取元素的css屬性
$('.target').css('width')
// 獲取元素的位置信息
$('.target').offset()
在使用之初可能會(huì)有許多疑問(wèn),比如$是怎么回事?為什么不用new就可以直接聲明一個(gè)對(duì)象?等等。了解之后,才知道原來(lái)這正是jQuery對(duì)象創(chuàng)建的巧妙之處。
先直接用代碼展示出來(lái),再用圖跟大家解釋是怎么回事。
;
(function (ROOT) {
// 構(gòu)造函數(shù)
var jQuery=function (selector) {
// 在jQuery中直接返回new過(guò)的實(shí)例,這里的init是jQuery的真正構(gòu)造函數(shù)
return new jQuery.fn.init(selector)
}
jQuery.fn=jQuery.prototype={
constructor: jQuery,
version: '1.0.0',
init: function (selector) {
// 在jquery中這里有一個(gè)復(fù)雜的判斷,但是這里我做了簡(jiǎn)化
var elem, selector;
elem=document.querySelector(selector);
this[0]=elem;
// 在jquery中返回一個(gè)由所有原型屬性方法組成的數(shù)組,我們這里簡(jiǎn)化,直接返回this即可
// return jQuery.makeArray(selector, this);
return this;
},
// 在原型上添加一堆方法
toArray: function () { },
get: function () { },
each: function () { },
ready: function () { },
first: function () { },
slice: function () { }
// ... ...
}
jQuery.fn.init.prototype=jQuery.fn;
// 實(shí)現(xiàn)jQuery的兩種擴(kuò)展方式
jQuery.extend=jQuery.fn.extend=function (options) {
// 在jquery源碼中會(huì)根據(jù)參數(shù)不同進(jìn)行很多判斷,我們這里就直接走一種方式,所以就不用判斷了
var target=this;
var copy;
for (name in options) {
copy=options[name];
target[name]=copy;
}
return target;
}
// jQuery中利用上面實(shí)現(xiàn)的擴(kuò)展機(jī)制,添加了許多方法,其中
// 直接添加在構(gòu)造函數(shù)上,被稱為工具方法
jQuery.extend({
isFunction: function () { },
type: function () { },
parseHTML: function () { },
parseJSON: function () { },
ajax: function () { }
// ...
})
// 添加到原型上
jQuery.fn.extend({
queue: function () { },
promise: function () { },
attr: function () { },
prop: function () { },
addClass: function () { },
removeClass: function () { },
val: function () { },
css: function () { }
// ...
})
// $符號(hào)的由來(lái),實(shí)際上它就是jQuery,一個(gè)簡(jiǎn)化的寫(xiě)法,在這里我們還可以替換成其他可用字符
ROOT.jQuery=ROOT.$=jQuery;
})(window);
在上面的代碼中,我封裝了一個(gè)簡(jiǎn)化版的jQuery對(duì)象。
它向大家簡(jiǎn)單展示了jQuery的整體骨架。
在代碼中可以看到,jQuery自身對(duì)于原型的處理使用了一些巧妙的方式,比如jQuery.fn=jQuery.prototype,jQuery.fn.init.prototype=jQuery.fn;等,這幾句正是jQuery對(duì)象的關(guān)鍵所在??磮D分析。
jQuery對(duì)象核心圖
對(duì)象封裝分析
在上面的實(shí)現(xiàn)中,首先在jQuery構(gòu)造函數(shù)里聲明了一個(gè)fn屬性,并將其指向了原型jQuery.prototype。然后在原型中添加了init方法。
jQuery.fn=jQuery.prototype={
init: {}
}
之后又將init的原型,指向了jQuery.prototype。
jQuery.fn.init.prototype=jQuery.fn;
而在構(gòu)造函數(shù)jQuery中,返回了init的實(shí)例對(duì)象。
var jQuery=function (selector) {
// 在jQuery中直接返回new過(guò)的實(shí)例,這里的init是jQuery的真正構(gòu)造函數(shù)
return new jQuery.fn.init(selector)
}
最后對(duì)外暴露入口時(shí),將字符$與jQuery對(duì)等起來(lái)。
ROOT.jQuery=ROOT.$=jQuery;
因此當(dāng)我們直接使用$('#test')創(chuàng)建一個(gè)對(duì)象時(shí),實(shí)際上是創(chuàng)建了一個(gè)init的實(shí)例,這里的真正構(gòu)造函數(shù)是原型中的init方法。
注意:許多對(duì)jQuery內(nèi)部實(shí)現(xiàn)不太了解的盆友,常常會(huì)毫無(wú)節(jié)制使用$(),比如對(duì)于同一個(gè)元素的不同操作:
var width=parseInt($('#test').css('width'));
if(width > 20) {
$('#test').css('backgroundColor', 'red');
}
通過(guò)我們上面的一系列分析,我們知道每當(dāng)我們執(zhí)行$()時(shí),就會(huì)重新生成一個(gè)init的實(shí)例對(duì)象,因此當(dāng)我們這樣沒(méi)有節(jié)制的使用jQuery是非常不正確的,雖然看上去方便了一些,但是對(duì)于內(nèi)存的消耗非常大。正確的做法是既然是同一個(gè)對(duì)象,那么就用一個(gè)變量保存起來(lái)后續(xù)使用即可。
var $test=$('#test');
var width=parseInt($test.css('width'));
if(width > 20) {
$test.css('backgroundColor', 'red');
}
擴(kuò)展方法分析
在上面的代碼實(shí)現(xiàn)中,我還簡(jiǎn)單實(shí)現(xiàn)了兩個(gè)擴(kuò)展方法。
jQuery.extend=jQuery.fn.extend=function (options) {
// 在jquery源碼中會(huì)根據(jù)參數(shù)不同進(jìn)行很多判斷,我們這里就直接走一種方式,所以就不用判斷了
var target=this;
var copy;
for (name in options) {
copy=options[name];
target[name]=copy;
}
return target;
}
要理解它的實(shí)現(xiàn),首先要明確知道this的指向。如果你搞不清楚,可以回頭去看看我們之前關(guān)于this指向的講解。
傳入的參數(shù)options為一個(gè)key: value模式的對(duì)象,我通過(guò)for in遍歷options,將key作為jQuery的新屬性,value作為該新屬性所對(duì)應(yīng)的新方法,分別添加到j(luò)Query方法和jQuery.fn中。
也就是說(shuō),當(dāng)我們通過(guò)jQuery.extend擴(kuò)展jQuery時(shí),方法被添加到了jQuery構(gòu)造函數(shù)中,而當(dāng)我們通過(guò)jQuery.fn.extend擴(kuò)展jQuery時(shí),方法被添加到了jQuery原型中。
上面的例子中,我也簡(jiǎn)單展示了在jQuery內(nèi)部,許多方法的實(shí)現(xiàn)都是通過(guò)這兩個(gè)擴(kuò)展方法來(lái)完成的。
當(dāng)我們通過(guò)上面的知識(shí)了解了jQuery的大體框架之后,我們對(duì)于jQuery的學(xué)習(xí)就可以具體到諸如css/val/attr等方法是如何實(shí)現(xiàn)這樣的程度,那么源碼學(xué)習(xí)起來(lái)就會(huì)輕松很多,節(jié)省更多的時(shí)間。也給一些對(duì)于源碼敬而遠(yuǎn)之的朋友提供一個(gè)學(xué)習(xí)的可能。
有一個(gè)朋友留言給我,說(shuō)她被靜態(tài)方法,工具方法和實(shí)例方法這幾個(gè)概念困擾了很久,到底他們有什么區(qū)別?
其實(shí)在上一篇文章中,關(guān)于封裝一個(gè)對(duì)象,我跟大家分享了一個(gè)非常非常干,但是卻只有少數(shù)幾個(gè)讀者大佬g(shù)et到的知識(shí),那就是在封裝對(duì)象時(shí),屬性和方法可以具體放置的三個(gè)位置,并且對(duì)于這三個(gè)位置的不同做了一個(gè)詳細(xì)的解讀。
image.png
在實(shí)現(xiàn)jQuery擴(kuò)展方法時(shí),一部分方法需要擴(kuò)展到構(gòu)造函數(shù)中,一部分方法需要擴(kuò)展到原型中,當(dāng)我們通讀jQuery源碼時(shí),還發(fā)現(xiàn)有一些方法放在了模塊作用域中,至于為什么會(huì)有這樣的區(qū)別,建議大家回過(guò)頭去讀讀前一篇文章。
這里用一個(gè)例子簡(jiǎn)單區(qū)分一下。
// 模塊內(nèi)部
const a=20;
function Person(name, age) {
this.name=name;
this.age=age;
// 構(gòu)造函數(shù)方法,每聲明一個(gè)實(shí)例,都會(huì)重新創(chuàng)建一次,屬于實(shí)例獨(dú)有
this.getName=function() {
return this.name;
}
}
// 原型方法,僅在原型創(chuàng)建時(shí)聲明一次,屬于所有實(shí)例共享
Person.prototype.getAge=function() {
return this.age;
}
// 工具方法,直接掛載在構(gòu)造函數(shù)名上,僅聲明一次,無(wú)法直接訪問(wèn)實(shí)例內(nèi)部屬性與方法
Person.each=function() {}
如上例中,each就是一個(gè)工具方法,或者說(shuō)靜態(tài)方法。
工具方法的特性也和工具一詞非常貼近,他們與實(shí)例的自身屬性毫無(wú)關(guān)聯(lián),僅僅只是實(shí)現(xiàn)一些通用的功能,我們可以通過(guò)$.each與$('div').each這2個(gè)方法來(lái)體會(huì)工具方法與實(shí)例方法的不同之處。
在實(shí)際開(kāi)發(fā)中,我們運(yùn)用得非常多的一個(gè)工具庫(kù)就是lodash.js,大家如果時(shí)間充裕一定要去學(xué)習(xí)一下他的使用。
$.ajax()
$.isFunction()
$.each()
... ...
放在原型中的方法,在使用時(shí)必須創(chuàng)建了一個(gè)新的實(shí)例對(duì)象才能訪問(wèn),因此這樣的方法叫做實(shí)例方法。也正是因?yàn)檫@一點(diǎn),他的使用成本會(huì)比工具方法高一些。但是相比構(gòu)造函數(shù)方法,原型方法更節(jié)省內(nèi)存。
$('#test').css()
$('#test').attr()
$('div').each()
這樣,那位同學(xué)的疑問(wèn)就被搞定啦。我們?cè)趯W(xué)習(xí)的時(shí)候,一定不要過(guò)分去糾結(jié)一些概念,而要明白這些概念背后的具體場(chǎng)景是怎么回事兒,那么學(xué)習(xí)這件事情就不會(huì)在一些奇奇怪怪的地方卡住了。
所以通過(guò)$.extend擴(kuò)展的方法,其實(shí)就是對(duì)工具方法的擴(kuò)展,而通過(guò)$.fn.extend擴(kuò)展的方法,就是對(duì)于實(shí)例方法的擴(kuò)展。
jQuery插件的實(shí)現(xiàn)
我在初級(jí)階段時(shí),覺(jué)得要自己編寫(xiě)一個(gè)jQuery插件是超級(jí)高大上的事情,可望不可即。但是通過(guò)對(duì)于上面的理解,我就知道擴(kuò)展jQuery插件其實(shí)是一件我們自己也可以完成的事情。
在前面我跟大家分享了jQuery如何實(shí)現(xiàn),以及他們的方法如何擴(kuò)展,并且前一篇文章分享了拖拽對(duì)象的具體實(shí)現(xiàn)。所以建議大家暫時(shí)不要閱讀下去,自己動(dòng)手嘗試將拖拽擴(kuò)展成為jQuery的一個(gè)實(shí)例方法,這就是一個(gè)jQuery插件了。
具體也沒(méi)有什么可多說(shuō)的了,大家看了代碼就可以明白一切。
// Drag對(duì)象簡(jiǎn)化代碼,完整源碼可在上一篇文章中查看
;
(function () {
// 構(gòu)造
function Drag(selector) { }
// 原型
Drag.prototype={
constructor: Drag,
init: function () {
// 初始時(shí)需要做些什么事情
this.setDrag();
},
// 稍作改造,僅用于獲取當(dāng)前元素的屬性,類(lèi)似于getName
getStyle: function (property) { },
// 用來(lái)獲取當(dāng)前元素的位置信息,注意與之前的不同之處
getPosition: function () { },
// 用來(lái)設(shè)置當(dāng)前元素的位置
setPostion: function (pos) { },
// 該方法用來(lái)綁定事件
setDrag: function () { }
}
// 一種對(duì)外暴露的方式
window.Drag=Drag;
})();
// 通過(guò)擴(kuò)展方法將拖拽擴(kuò)展為jQuery的一個(gè)實(shí)例方法
(function ($) {
$.fn.extend({
becomeDrag: function () {
new Drag(this[0]);
return this; // 注意:為了保證jQuery所有的方法都能夠鏈?zhǔn)皆L問(wèn),每一個(gè)方法的最后都需要返回this,即返回jQuery實(shí)例
}
})
})(jQuery);
下一篇:前端基礎(chǔ)進(jìn)階(十四):深入核心,詳解事件循環(huán)機(jī)制
建議收藏,不然刷著刷著就可能找不到了。
我自己是一名從事了多年開(kāi)發(fā)的web前端老程序員,目前辭職在做自己的web前端私人定制課程,今年我花了一個(gè)月整理了一份最適合2020年學(xué)習(xí)的web前端學(xué)習(xí)干貨,各種框架都有整理,送給每一位前端小伙伴,想要獲取的可以關(guān)注我的頭條號(hào)并在后臺(tái)私信我:前端,即可免費(fèi)獲取
i,大家好,我是拾光。
今天給大家?guī)?lái)的是js實(shí)現(xiàn)文本框自動(dòng)填充。
下面貼圖:
HTML:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="jquery-1.8.3.min.js"></script>
<style>
*{
margin:0;
padding:0;
}
ul,li{
list-style:none;
}
.inputElem {
width:198px;
height:22px;
line-height:22px;
border:1px solid #ff4455;
}
.parentCls
{
width:200px;
}
.auto-tip li
{
width:100%;
height:22px;
line-height:22px;
font-size:14px;
}
.auto-tip li.hoverBg{
background:#ddd;
cursor:pointer;
}
.red
{
color:red;
}
.hidden {
display:none;
}
</style>
<script src="emailAutoComplete.js"></script>
</head>
<body>
<div>
<input type="text">
</div>
</body>
</html>
JS:
function EmailAutoComplete(options) {
this.config={
targetCls : '.inputElem',
parentCls : '.parentCls',
hiddenCls : '.hiddenCls',
searchForm : '.jqtransformdone',
hoverBg : 'hoverBg',
inputValColor : 'red',
mailArr : ["@qq.com","@qq2.com","@gmail.com","@126.com","@163.com","@hotmail.com","@yahoo.com","@yahoo.com.cn","@live.com","@sohu.com","@sina.com"],
isSelectHide : true,
callback : null
};
this.cache={
onlyFlag : true,
currentIndex : -1,
oldIndex : -1
};
this.init(options);
}
EmailAutoComplete.prototype={
constructor: EmailAutoComplete,
init: function(options){
this.config=$.extend(this.config,options || {});
var self=this,
_config=self.config,
_cache=self.cache;
$(_config.targetCls).each(function(index,item){
$(item).keyup(function(e){
var target=e.target,
targetVal=$.trim($(this).val()),
keycode=e.keyCode,
elemHeight=$(this).outerHeight(),
elemWidth=$(this).outerWidth(),
parentNode=$(this).closest(_config.parentCls);
$(parentNode).css({'position':'relative'});
if(targetVal=='') {
$(item).attr({'data-html':''});
$(_config.hiddenCls,parentNode).val('');
_cache.currentIndex=-1;
_cache.oldIndex=-1;
$(".auto-tip",parentNode) && !$(".auto-tip",parentNode).hasClass('hidden') && $(".auto-tip",parentNode).addClass('hidden');
self._removeBg(parentNode);
}else {
$(item).attr({'data-html':targetVal});
$(_config.hiddenCls,parentNode).val(targetVal);
$(".auto-tip",parentNode) && $(".auto-tip",parentNode).hasClass('hidden') && $(".auto-tip",parentNode).removeClass('hidden');
self._renderHTML({keycode:keycode,e:e,target:target,targetVal:targetVal,height:elemHeight,width:elemWidth,parentNode:parentNode});
}
});
});
$(_config.searchForm).each(function(index,item) {
$(item).keydown(function(e){
var keyCode=e.keyCode;
if(keyCode==13) {
return false;
}
});
});
$(document).click(function(e){
e.stopPropagation();
var target=e.target,
tagCls=_config.targetCls.replace(/^\./,'');
if(!$(target).hasClass(tagCls)) {
$('.auto-tip') && $('.auto-tip').each(function(index,item){
!$(item).hasClass('hidden') && $(item).addClass('hidden');
});
}
});
},
_renderHTML: function(cfg) {
var self=this,
_config=self.config,
_cache=self.cache,
curVal;
var curIndex=self._keyCode(cfg.keycode);
$('.auto-tip',cfg.parentNode).hasClass('hidden') && $('.auto-tip',cfg.parentNode).removeClass('hidden');
if(curIndex > -1){
self._keyUpAndDown(cfg.targetVal,cfg.e,cfg.parentNode);
}else {
if(/@/.test(cfg.targetVal)) {
curVal=cfg.targetVal.replace(/@.*/,'');
}else {
curVal=cfg.targetVal;
}
if(_cache.onlyFlag) {
$(cfg.parentNode).append('<input type="hidden" class="hiddenCls"/>');
var wrap='<ul class="auto-tip">';
for(var i=0; i < _config.mailArr.length; i++) {
wrap +='<li class="p-index'+i+'">'+'<span class="output-num"></span><em class="em" data-html="'+_config.mailArr[i]+'">'+_config.mailArr[i]+'</em></li>';
}
wrap +='</ul>';
_cache.onlyFlag=false;
$(cfg.parentNode).append(wrap);
$('.auto-tip',cfg.parentNode).css({'position':'absolute','top':cfg.height,'width':cfg.width - 2 + 'px','left':0,
'border':'1px solid #ccc','z-index':10000});
}
$('.auto-tip li',cfg.parentNode).each(function(index,item){
$('.output-num',item).html(curVal);
!$('.output-num',item).hasClass(_config.inputValColor) &&
$('.output-num',item).addClass(_config.inputValColor);
var emVal=$.trim($('.em',item).attr('data-html'));
$(item).attr({'data-html':curVal + '' +emVal});
});
self._accurateMate({target:cfg.target,parentNode:cfg.parentNode});
self._itemHover(cfg.parentNode);
self._executeClick(cfg.parentNode);
}
},
_accurateMate: function(cfg) {
var self=this,
_config=self.config,
_cache=self.cache;
var curVal=$.trim($(cfg.target,cfg.parentNode).attr('data-html')),
newArrs=[];
if(/@/.test(curVal)) {
var prefix=curVal.replace(/@.*/, ""),
suffix=curVal.replace(/.*@/, "");
$.map(_config.mailArr,function(n){
var reg=new RegExp(suffix);
if(reg.test(n)) {
newArrs.push(n);
}
});
if(newArrs.length > 0) {
$('.auto-tip',cfg.parentNode).html('');
$(".auto-tip",cfg.parentNode) && $(".auto-tip",cfg.parentNode).hasClass('hidden') &&
$(".auto-tip",cfg.parentNode).removeClass('hidden');
var html='';
for(var j=0, jlen=newArrs.length; j < jlen; j++) {
html +='<li class="p-index'+j+'">'+'<span class="output-num"></span><em class="em" data-html="'+newArrs[j]+'">'+newArrs[j]+'</em></li>';
}
$('.auto-tip',cfg.parentNode).html(html);
$('.auto-tip li',cfg.parentNode).each(function(index,item){
$('.output-num',item).html(prefix);
!$('.output-num',item).hasClass(_config.inputValColor) &&
$('.output-num',item).addClass(_config.inputValColor);
var emVal=$.trim($('.em',item).attr('data-html'));
$(item).attr('data-html','');
$(item).attr({'data-html':prefix + '' +emVal});
});
_cache.currentIndex=-1;
_cache.oldIndex=-1;
$('.auto-tip .output-num',cfg.parentNode).html(prefix);
self._itemHover(cfg.parentNode);
self._executeClick(cfg.parentNode);
}else {
$(".auto-tip",cfg.parentNode) && !$(".auto-tip",cfg.parentNode).hasClass('hidden') &&
$(".auto-tip",cfg.parentNode).addClass('hidden');
$('.auto-tip',cfg.parentNode).html('');
}
}
},
_itemHover: function(parentNode) {
var self=this,
_config=self.config,
_cache=self.cache;
$('.auto-tip li',parentNode).hover(function(index,item) {
!$(this).hasClass(_config.hoverBg) && $(this).addClass(_config.hoverBg);
},function() {
$(this).hasClass(_config.hoverBg) && $(this).removeClass(_config.hoverBg);
});
},
_removeBg: function(parentNode){
var self=this,
_config=self.config;
$(".auto-tip li",parentNode).each(function(index,item){
$(item).hasClass(_config.hoverBg) && $(item).removeClass(_config.hoverBg);
});
},
_keyUpAndDown: function(targetVal,e,parentNode) {
var self=this,
_cache=self.cache,
_config=self.config;
if($('.auto-tip' + ' li',parentNode) && $('.auto-tip' + ' li').length > 0) {
var plen=$('.auto-tip' + ' li',parentNode).length,
keyCode=e.keyCode;
_cache.oldIndex=_cache.currentIndex;
if(keyCode==38) {
if(_cache.currentIndex==-1) {
_cache.currentIndex=plen - 1;
}else {
_cache.currentIndex=_cache.currentIndex - 1;
if(_cache.currentIndex < 0) {
_cache.currentIndex=plen - 1;
}
}
if(_cache.currentIndex !==-1) {
!$('.auto-tip .p-index'+_cache.currentIndex,parentNode).hasClass(_config.hoverBg) &&
$('.auto-tip .p-index'+_cache.currentIndex,parentNode).addClass(_config.hoverBg).siblings().removeClass(_config.hoverBg);
var curAttr=$('.auto-tip' + ' .p-index'+_cache.currentIndex,parentNode).attr('data-html');
$(_config.targetCls,parentNode).val(curAttr);
$(_config.hiddenCls,parentNode).val(curAttr);
}
}else if(keyCode==40) {
if(_cache.currentIndex==plen - 1) {
_cache.currentIndex=0;
}else {
_cache.currentIndex++;
if(_cache.currentIndex > plen - 1) {
_cache.currentIndex=0;
}
}
if(_cache.currentIndex !==-1) {
!$('.auto-tip .p-index'+_cache.currentIndex,parentNode).hasClass(_config.hoverBg) &&
$('.auto-tip .p-index'+_cache.currentIndex,parentNode).addClass(_config.hoverBg).siblings().removeClass(_config.hoverBg);
var curAttr=$('.auto-tip' + ' .p-index'+_cache.currentIndex,parentNode).attr('data-html');
$(_config.targetCls,parentNode).val(curAttr);
$(_config.hiddenCls,parentNode).val(curAttr);
}
}else if(keyCode==13) {
var curVal=$('.auto-tip' + ' .p-index'+_cache.oldIndex,parentNode).attr('data-html');
$(_config.targetCls,parentNode).val(curVal);
$(_config.hiddenCls,parentNode).val(curVal);
if(_config.isSelectHide) {
!$(".auto-tip",parentNode).hasClass('hidden') && $(".auto-tip",parentNode).addClass('hidden');
}
_config.callback && $.isFunction(_config.callback) && _config.callback();
_cache.currentIndex=-1;
_cache.oldIndex=-1;
}
}
},
_keyCode: function(code) {
var arrs=['17','18','38','40','37','39','33','34','35','46','36','13','45','44','145','19','20','9'];
for(var i=0, ilen=arrs.length; i < ilen; i++) {
if(code==arrs[i]) {
return i;
}
}
return -1;
},
_executeClick: function(parentNode) {
var _self=this,
_config=_self.config;
$('.auto-tip' + ' li',parentNode).unbind('click');
$('.auto-tip' + ' li',parentNode).bind('click',function(e){
var dataAttr=$(this).attr('data-html');
$(_config.targetCls,parentNode).val(dataAttr);
if(_config.isSelectHide) {
!$(".auto-tip",parentNode).hasClass('hidden') && $(".auto-tip",parentNode).addClass('hidden');
}
$(_config.hiddenCls,parentNode).val(dataAttr);
_config.callback && $.isFunction(_config.callback) && _config.callback();
});
}
};
$(function() {
new EmailAutoComplete({});
});
今天就到這里咯~
大家研究一下吧~
希望大家過(guò)的愉快。
Best wishes to you.
LiuDongYu.
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。