西西软件下载最安全的下载网站、值得信赖的软件下载站!
缁崵绮哄銉ュ徔
U婢堆冪瑎v4.7.37.56 閺堚偓閺傛壆澧�U婢堆冪瑎v4.7.37.56 閺堚偓閺傛壆澧�
HD Tune  Prov5.75 濮瑰瀵茬紒鑳閻楃懓鍩嗛悧锟�HD Tune Prov5.75 濮瑰瀵茬紒鑳閻楃懓鍩嗛悧锟�
DiskGenius 娑撴挷绗熼悧鍦�5.2.1.941 鐎规ɑ鏌熼悧锟�DiskGenius 娑撴挷绗熼悧鍦�5.2.1.941 鐎规ɑ鏌熼悧锟�
360鏉烆垯娆㈢粻鈥愁啀v7.5.0.1460 鐎规ɑ鏌熼張鈧弬鎵360鏉烆垯娆㈢粻鈥愁啀v7.5.0.1460 鐎规ɑ鏌熼張鈧弬鎵
Cpu-Z娑擃厽鏋冮悧鍧�1.98.0 缂佽儻澹婃稉顓熸瀮閻楋拷Cpu-Z娑擃厽鏋冮悧鍧�1.98.0 缂佽儻澹婃稉顓熸瀮閻楋拷
缂冩垹绮跺銉ュ徔
閼垫崘顔嗛悽浣冨壋缁犫€愁啀V15.2 鐎规ɑ鏌熷锝呯础閻楋拷閼垫崘顔嗛悽浣冨壋缁犫€愁啀V15.2 鐎规ɑ鏌熷锝呯础閻楋拷
office2016濠碘偓濞茶浼愰崗绌攎sv19.5.2 鐎规ɑ鏌熼張鈧弬鎵office2016濠碘偓濞茶浼愰崗绌攎sv19.5.2 鐎规ɑ鏌熼張鈧弬鎵
鏉╁懘娴�11閺堚偓閺傛壆澧梫11.3.6.1870 鐎规ɑ鏌熼悧锟�鏉╁懘娴�11閺堚偓閺傛壆澧梫11.3.6.1870 鐎规ɑ鏌熼悧锟�
360閸忓秷鍨倃ifi5.3.0.5000 鐎规ɑ鏌熼張鈧弬鎵360閸忓秷鍨倃ifi5.3.0.5000 鐎规ɑ鏌熼張鈧弬鎵
360鐎瑰鍙忓ù蹇氼潔閸o拷2022v13.1.5188.0 鐎规ɑ鏌熷锝呯础閻楋拷360鐎瑰鍙忓ù蹇氼潔閸o拷2022v13.1.5188.0 鐎规ɑ鏌熷锝呯础閻楋拷
婢舵艾鐛熸担鎾惰
闁伴攱鍨滈棅鍏呯閻╋拷2022v9.1.6.2 鐎规ɑ鏌熷锝呯础閻楋拷闁伴攱鍨滈棅鍏呯閻╋拷2022v9.1.6.2 鐎规ɑ鏌熷锝呯础閻楋拷
閺嗘挳顥撹ぐ閬嶇叾2021V5.81.0202.1111鐎规ɑ鏌熷锝呯础閻楋拷閺嗘挳顥撹ぐ閬嶇叾2021V5.81.0202.1111鐎规ɑ鏌熷锝呯础閻楋拷
韫囶偅鎸�5.0濮橀晲绗夐崡鍥╅獓閻楋拷5.0.80 妤犮劌銇旈悧锟�韫囶偅鎸�5.0濮橀晲绗夐崡鍥╅獓閻楋拷5.0.80 妤犮劌銇旈悧锟�
娴兼﹢鍙�2022鐎广垺鍩涚粩鐤�8.0.9.11050 鐎规ɑ鏌熼張鈧弬鎵娴兼﹢鍙�2022鐎广垺鍩涚粩鐤�8.0.9.11050 鐎规ɑ鏌熼張鈧弬鎵
閻栧崬顨岄懝楦款潒妫版叆13.1.5鐎规ɑ鏌熺€瑰宕滈悧锟�閻栧崬顨岄懝楦款潒妫版叆13.1.5鐎规ɑ鏌熺€瑰宕滈悧锟�
閸ユ儳鑸伴崶鎯у剼
photoshop cs6 娑擃厽鏋冮悧锟�13.1.2.3 閸忓秷鍨傛稉顓熸瀮閻楋拷photoshop cs6 娑擃厽鏋冮悧锟�13.1.2.3 閸忓秷鍨傛稉顓熸瀮閻楋拷
Autodesk 3ds Max 2012鐎规ɑ鏌熺粻鈧担鎾茶厬閺傚洨澧梉32&64]Autodesk 3ds Max 2012鐎规ɑ鏌熺粻鈧担鎾茶厬閺傚洨澧梉32&64]
CAD2007閸忓秷鍨傛稉顓熸瀮閻楋拷CAD2007閸忓秷鍨傛稉顓熸瀮閻楋拷
vc鏉╂劘顢戞惔锟�2019閺堚偓閺傛壆澧梫2019.3.2(32&64娴o拷)vc鏉╂劘顢戞惔锟�2019閺堚偓閺傛壆澧梫2019.3.2(32&64娴o拷)
.NET Framework 4.8鐎规ɑ鏌熼悧锟�4.8.3646.NET Framework 4.8鐎规ɑ鏌熼悧锟�4.8.3646
閼卞﹤銇夐懕鏃傜捕
QQ2022v9.5.6.28129 鐎规ɑ鏌熼張鈧弬鎵QQ2022v9.5.6.28129 鐎规ɑ鏌熼張鈧弬鎵
瀵邦喕淇婇悽浣冨壋閻楋拷2022v3.5.0.44 鐎规ɑ鏌熷锝呯础閻楋拷瀵邦喕淇婇悽浣冨壋閻楋拷2022v3.5.0.44 鐎规ɑ鏌熷锝呯础閻楋拷
閸楀啰澧伴崡鏍ь啀瀹搞儰缍旈獮鍐插酱v9.02.02N 鐎规ɑ鏌熼悧锟�閸楀啰澧伴崡鏍ь啀瀹搞儰缍旈獮鍐插酱v9.02.02N 鐎规ɑ鏌熼悧锟�
QT鐠囶參鐓禫4.6.80.18262鐎规ɑ鏌熼張鈧弬鎵QT鐠囶參鐓禫4.6.80.18262鐎规ɑ鏌熼張鈧弬鎵
妞嬬偘淇�2018V6.2.0700 鐎规ɑ鏌熷锝呯础閻楋拷妞嬬偘淇�2018V6.2.0700 鐎规ɑ鏌熷锝呯础閻楋拷
閻㈢喐妞块張宥呭
閺€顖欑帛鐎规繈鎸堕崠锟�(Alipay)V10.2.53.7000 鐎瑰宕滈悧锟�閺€顖欑帛鐎规繈鎸堕崠锟�(Alipay)V10.2.53.7000 鐎瑰宕滈悧锟�
閻ф儳瀹抽崷鏉挎禈鐎佃壈鍩�2022V15.12.10 鐎瑰宕滈幍瀣簚閻楋拷閻ф儳瀹抽崷鏉挎禈鐎佃壈鍩�2022V15.12.10 鐎瑰宕滈幍瀣簚閻楋拷
閹靛婧€濞fê鐤傜€广垺鍩涚粩鐥�10.8.40鐎规ɑ鏌熼張鈧弬鎵閹靛婧€濞fê鐤傜€广垺鍩涚粩鐥�10.8.40鐎规ɑ鏌熼張鈧弬鎵
閻e懘鈧梻缍夐幍瀣簚鐎广垺鍩涚粩鐥�5.6.9 鐎规ɑ鏌熼張鈧弬鎵閻e懘鈧梻缍夐幍瀣簚鐎广垺鍩涚粩鐥�5.6.9 鐎规ɑ鏌熼張鈧弬鎵
閸楀啳浜伴惌銉ㄧ槕閺堝秴濮焌ppv4.5.1鐎规ɑ鏌熼悧锟�閸楀啳浜伴惌銉ㄧ槕閺堝秴濮焌ppv4.5.1鐎规ɑ鏌熼悧锟�
瑜伴亶鐓堕幘顓熸杹
p2psearcher鐎瑰宕滈悧锟�7.3  閹靛婧€閻楋拷p2psearcher鐎瑰宕滈悧锟�7.3 閹靛婧€閻楋拷
闁伴瀚嶉棅鍏呯2022鐎规ɑ鏌熼悧鍦�11.0.8 鐎规ɑ鏌熺€瑰宕滈悧锟�闁伴瀚嶉棅鍏呯2022鐎规ɑ鏌熼悧鍦�11.0.8 鐎规ɑ鏌熺€瑰宕滈悧锟�
閻栧崬顨岄懝鐑樺閺堣櫣澧梫13.1.0閻栧崬顨岄懝鐑樺閺堣櫣澧梫13.1.0
閻ф儳瀹宠ぐ閬嶇叾7.13.0 鐎规ɑ鏌熼張鈧弬鎵閻ф儳瀹宠ぐ閬嶇叾7.13.0 鐎规ɑ鏌熼張鈧弬鎵
瑜伴亶鐓堕崗鍫ユ敱v6.9.0 鐎瑰宕滈幍瀣簚閻楋拷瑜伴亶鐓堕崗鍫ユ敱v6.9.0 鐎瑰宕滈幍瀣簚閻楋拷
闂冨懓顕板銉ュ徔
閼垫崘顔嗛崝銊︽瀬V9.11.5 鐎瑰宕滈悧锟�閼垫崘顔嗛崝銊︽瀬V9.11.5 鐎瑰宕滈悧锟�
娑旓附妫楃亸蹇氼嚛閸忓秷鍨傞悧鍫熸拱v11.5.5.153 鐎规ɑ鏌熼張鈧弬鎵娑旓附妫楃亸蹇氼嚛閸忓秷鍨傞悧鍫熸拱v11.5.5.153 鐎规ɑ鏌熼張鈧弬鎵
QQ闂冨懓顕伴崳鈺漰pV7.7.1.910 鐎规ɑ鏌熼張鈧弬鎵QQ闂冨懓顕伴崳鈺漰pV7.7.1.910 鐎规ɑ鏌熼張鈧弬鎵
閹虫帊姹夐悾鍛儔閸氼兛鍔焌ppv7.1.5 鐎规ɑ鏌熺€瑰宕滈悧锟�閹虫帊姹夐悾鍛儔閸氼兛鍔焌ppv7.1.5 鐎规ɑ鏌熺€瑰宕滈悧锟�
鐠ч鍋g拠璁冲姛app閺傛壆澧楅張锟�20227.9.186 鐎瑰宕滈悧锟�鐠ч鍋g拠璁冲姛app閺傛壆澧楅張锟�20227.9.186 鐎瑰宕滈悧锟�
闁叉垼鐎洪悶鍡氬偍
楠炲啿鐣ㄧ拠浣稿煖鐎瑰…閻炲棜鍌╒9.1.0.1 鐎规ɑ鏌熺€瑰宕滈悧锟�楠炲啿鐣ㄧ拠浣稿煖鐎瑰…閻炲棜鍌╒9.1.0.1 鐎规ɑ鏌熺€瑰宕滈悧锟�
濞寸兘鈧俺鐦夐崚鍛婂閺堣櫣澧�(e濞寸兘鈧俺鍌�)8.71 鐎规ɑ鏌熺€瑰宕滈悧锟�濞寸兘鈧俺鐦夐崚鍛婂閺堣櫣澧�(e濞寸兘鈧俺鍌�)8.71 鐎规ɑ鏌熺€瑰宕滈悧锟�
娑撴粍鎹g拠浣稿煖娑撴粍鎹i悶鍡氬偍4.0.5 鐎瑰宕滈悧锟�娑撴粍鎹g拠浣稿煖娑撴粍鎹i悶鍡氬偍4.0.5 鐎瑰宕滈悧锟�
娑擃參鎽辩拠浣稿煖缁夎濮╅悶鍡氬偍鏉烆垯娆�6.02.010 鐎规ɑ鏌熺€瑰宕滈悧锟�娑擃參鎽辩拠浣稿煖缁夎濮╅悶鍡氬偍鏉烆垯娆�6.02.010 鐎规ɑ鏌熺€瑰宕滈悧锟�
閸楀酣绶崇拠浣稿煖鐏忓繘鍣鹃幍瀣簚閻炲棜鍌ㄦ潪顖欐3.2.4 鐎瑰宕滈悧锟�閸楀酣绶崇拠浣稿煖鐏忓繘鍣鹃幍瀣簚閻炲棜鍌ㄦ潪顖欐3.2.4 鐎瑰宕滈悧锟�
閹靛婧€闁炬儼顢�
缁傚繐缂撻崘婊勬綑娣囷紕鏁ょ粈鐐閺堟椽鎽辩悰灞筋吂閹撮顏�2.3.4 鐎瑰宕滈悧锟�缁傚繐缂撻崘婊勬綑娣囷紕鏁ょ粈鐐閺堟椽鎽辩悰灞筋吂閹撮顏�2.3.4 鐎瑰宕滈悧锟�
閺勬挸鍩楁担婊嗩潒妫版垵澹€鏉堟叧pp4.1.16鐎瑰宕滈悧锟�閺勬挸鍩楁担婊嗩潒妫版垵澹€鏉堟叧pp4.1.16鐎瑰宕滈悧锟�
閺€顖欑帛鐎规繈鎸堕崠锟�(Alipay)V10.2.53.7000 鐎瑰宕滈悧锟�閺€顖欑帛鐎规繈鎸堕崠锟�(Alipay)V10.2.53.7000 鐎瑰宕滈悧锟�
娑擃厼娴楀銉ユ櫌闁炬儼顢戦幍瀣簚闁炬儼顢慳ppV7.0.1.2.5 鐎瑰宕滈悧锟�娑擃厼娴楀銉ユ櫌闁炬儼顢戦幍瀣簚闁炬儼顢慳ppV7.0.1.2.5 鐎瑰宕滈悧锟�
娑擃厼娴楅柧鎯邦攽閹靛婧€闁炬儼顢戠€广垺鍩涚粩锟�7.2.5 鐎规ɑ鏌熺€瑰宕滈悧锟�娑擃厼娴楅柧鎯邦攽閹靛婧€闁炬儼顢戠€广垺鍩涚粩锟�7.2.5 鐎规ɑ鏌熺€瑰宕滈悧锟�
娴兼垿妫介惄濠冩
閼垫崘顔嗛悮搴ㄥ鏉堝彞姹夐幍瀣簚閻楀湸2.3.0.0 鐎规ɑ鏌熺€瑰宕滈悧锟�閼垫崘顔嗛悮搴ㄥ鏉堝彞姹夐幍瀣簚閻楀湸2.3.0.0 鐎规ɑ鏌熺€瑰宕滈悧锟�
閸旇尪鍨堕崶銏犵暭閺傝顒滈悧鍫熷濞撶1.2.1鐎规ɑ鏌熼悧锟�閸旇尪鍨堕崶銏犵暭閺傝顒滈悧鍫熷濞撶1.2.1鐎规ɑ鏌熼悧锟�
妤椼儵銈挎ご銊╁鏉╂稑瀵查弮鐘绘闁借崵鐓堕悧鍧�7.8.0.0鐎瑰宕滈悧锟�妤椼儵銈挎ご銊╁鏉╂稑瀵查弮鐘绘闁借崵鐓堕悧鍧�7.8.0.0鐎瑰宕滈悧锟�
濡炲秶澧挎径褎鍨崓闈涙閸忋劍妲戦弰锟�1.0.91 鐎瑰宕滈悧锟�濡炲秶澧挎径褎鍨崓闈涙閸忋劍妲戦弰锟�1.0.91 鐎瑰宕滈悧锟�
閸斻劋缍旂亸鍕毊
閸﹂绗呴崺搴g崐閸戞槒鈧崑t閻楋拷1.6.3 鐎规ɑ鏌熼悧锟�閸﹂绗呴崺搴g崐閸戞槒鈧崑t閻楋拷1.6.3 鐎规ɑ鏌熼悧锟�
鐟佸懐鏁抽懕鏃傛礃1.325.157 鐎瑰宕滈悧锟�鐟佸懐鏁抽懕鏃傛礃1.325.157 鐎瑰宕滈悧锟�
閸︼絾鏋熸竟顐fЕ閻垽娉︾紒鎼�4.2.1 鐎瑰宕滈悧锟�閸︼絾鏋熸竟顐fЕ閻垽娉︾紒鎼�4.2.1 鐎瑰宕滈悧锟�
闁喖銇�3D閹靛鐖�1.0.9鐎瑰宕滈悧锟�闁喖銇�3D閹靛鐖�1.0.9鐎瑰宕滈悧锟�
婵夋棃妲诲〒鍛婂灆
鐎瑰宕滃宥囧⒖婢堆勫灛閸嶉潧妗�2姒涙垶娈弮鏈靛敩娣囶喗鏁奸悧鍦�1.9.5 閺堚偓閺傛壆澧�鐎瑰宕滃宥囧⒖婢堆勫灛閸嶉潧妗�2姒涙垶娈弮鏈靛敩娣囶喗鏁奸悧鍦�1.9.5 閺堚偓閺傛壆澧�
娑旇鲸鏋熺憲鎸庣埗2v1.0.150鐎瑰宕滈悧锟�娑旇鲸鏋熺憲鎸庣埗2v1.0.150鐎瑰宕滈悧锟�
娣囨繂宕奸拃婵嗗椽3閺冪娀妾洪柦鑽ょ叾閺堚偓閺傛壆澧梫2.0.0.1 鐎瑰宕滈悧锟�娣囨繂宕奸拃婵嗗椽3閺冪娀妾洪柦鑽ょ叾閺堚偓閺傛壆澧梫2.0.0.1 鐎瑰宕滈悧锟�
閸欙綀顣伴懟閬嶆碂閸楁洘婧€閻楋拷1.2.0 鐎瑰宕滈悧锟�閸欙綀顣伴懟閬嶆碂閸楁洘婧€閻楋拷1.2.0 鐎瑰宕滈悧锟�
鐏忓繐鐨崘娑樻礋鐎瑰宕滈悧锟�2.7.4 閺冪娀妾洪柌鎴濈娣囶喗鏁奸悧锟�鐏忓繐鐨崘娑樻礋鐎瑰宕滈悧锟�2.7.4 閺冪娀妾洪柌鎴濈娣囶喗鏁奸悧锟�
鐠ф稖婧呯粩鐐村Η
閻ц鍖楃挧娑滄簠2閹靛鐖�1.47.1  鐎瑰宕滈悧锟�閻ц鍖楃挧娑滄簠2閹靛鐖�1.47.1 鐎瑰宕滈悧锟�
娑撯偓鐠ч攱娼垫鐐舵簠鐎瑰宕滈悧鍧�2.9.14 閺堚偓閺傛壆澧�娑撯偓鐠ч攱娼垫鐐舵簠鐎瑰宕滈悧鍧�2.9.14 閺堚偓閺傛壆澧�
鐠烘垼绐囬崡鈥茬鏉烇附澧滈張铏瑰鐎规ɑ鏌熼張鈧弬鎵v1.16.2 鐎瑰宕滈悧锟�鐠烘垼绐囬崡鈥茬鏉烇附澧滈張铏瑰鐎规ɑ鏌熼張鈧弬鎵v1.16.2 鐎瑰宕滈悧锟�
閻欏倿鍣规娆掓簠8閺嬩線鈧喎鍣锋禍鎴滄叏閺€鍦(閸忓秵鏆熼幑顔煎瘶)v4.6.0j 闁叉垵绔甸弮鐘绘閻楋拷閻欏倿鍣规娆掓簠8閺嬩線鈧喎鍣锋禍鎴滄叏閺€鍦(閸忓秵鏆熼幑顔煎瘶)v4.6.0j 闁叉垵绔甸弮鐘绘閻楋拷
閻у彞绠伴崡鍐仏閹规洟濂�2021閺堚偓閺傛壆澧�5.78 鐎瑰宕滈悧锟�閻у彞绠伴崡鍐仏閹规洟濂�2021閺堚偓閺傛壆澧�5.78 鐎瑰宕滈悧锟�
鐟欐帟澹婇幍顔界川
濮婏箑澶熼崜鎴e灦閼板懎褰夐幀浣哄1.0.1.2鐎瑰宕滈悧锟�濮婏箑澶熼崜鎴e灦閼板懎褰夐幀浣哄1.0.1.2鐎瑰宕滈悧锟�
娴犳瑥顣ㄦ导鐘侯嚛ro婢跺秴鍙寸€瑰宕滈悧锟�1.20.3閺堚偓閺傛壆澧�娴犳瑥顣ㄦ导鐘侯嚛ro婢跺秴鍙寸€瑰宕滈悧锟�1.20.3閺堚偓閺傛壆澧�
濮婏箑澶熺拠娑楃舶閹靛鐖堕悧锟�1.3.6 鐎规ɑ鏌熺€瑰宕滈悧锟�濮婏箑澶熺拠娑楃舶閹靛鐖堕悧锟�1.3.6 鐎规ɑ鏌熺€瑰宕滈悧锟�
閻滃鈧懓宕抽懓鈧琕3.72.1.1 鐎瑰宕滈張鈧弬鏉跨暭閺傚湱澧�閻滃鈧懓宕抽懓鈧琕3.72.1.1 鐎瑰宕滈張鈧弬鏉跨暭閺傚湱澧�
鐠嬩礁顔嶇亸蹇氭簠瀵儤澧滈張铏瑰v1.0.49 鐎瑰宕滈悧锟�鐠嬩礁顔嶇亸蹇氭簠瀵儤澧滈張铏瑰v1.0.49 鐎瑰宕滈悧锟�
缁崵绮烘潪顖欐
mac绾句胶娲忛崚鍡楀隘瀹搞儱鍙�(Paragon Camptune X)V10.8.12鐎规ɑ鏌熼張鈧弬鎵mac绾句胶娲忛崚鍡楀隘瀹搞儱鍙�(Paragon Camptune X)V10.8.12鐎规ɑ鏌熼張鈧弬鎵
閼昏鐏夐幙宥勭稊缁崵绮篗ACOSX 10.9.4 Mavericks鐎瑰苯鍙忛崗宥堝瀭閻楋拷閼昏鐏夐幙宥勭稊缁崵绮篗ACOSX 10.9.4 Mavericks鐎瑰苯鍙忛崗宥堝瀭閻楋拷
Rar鐟欙絽甯囬崚鈺佹珤mac閻楀澊1.4 鐎规ɑ鏌熼崗宥堝瀭閻楋拷Rar鐟欙絽甯囬崚鈺佹珤mac閻楀澊1.4 鐎规ɑ鏌熼崗宥堝瀭閻楋拷
Mac鐎瑰宕滃Ο鈩冨珯閸o拷(ARC Welder)v1.0 鐎规ɑ鏌熼張鈧弬鎵Mac鐎瑰宕滃Ο鈩冨珯閸o拷(ARC Welder)v1.0 鐎规ɑ鏌熼張鈧弬鎵
Charles for MacV3.9.3鐎规ɑ鏌熼悧锟�Charles for MacV3.9.3鐎规ɑ鏌熼悧锟�
缂冩垹绮跺銉ュ徔
閹兼粎瀚嶅ù蹇氼潔閸b暕ac閻楀澊5.2 鐎规ɑ鏌熷锝呯础閻楋拷閹兼粎瀚嶅ù蹇氼潔閸b暕ac閻楀澊5.2 鐎规ɑ鏌熷锝呯础閻楋拷
闁挎劖宓庣€广垺鍩涚粩鐥琣c閻楀湸1.33鐎规ɑ鏌熼張鈧弬鎵闁挎劖宓庣€广垺鍩涚粩鐥琣c閻楀湸1.33鐎规ɑ鏌熼張鈧弬鎵
韫囶偆澧甿ac閻楀澊1.3.2 鐎规ɑ鏌熷锝呯础閻楋拷韫囶偆澧甿ac閻楀澊1.3.2 鐎规ɑ鏌熷锝呯础閻楋拷
閺嬩胶鍋f禍鏃傜應Mac閻楋拷7.13濮濓絽绱¢悧锟�閺嬩胶鍋f禍鏃傜應Mac閻楋拷7.13濮濓絽绱¢悧锟�
婵帊缍嬪銉ュ徔
Apple Logic Pro xV10.3.2Apple Logic Pro xV10.3.2
Adobe Premiere Pro CC 2017 mac閻楀澊11.0.0 娑擃厽鏋冮悧锟�Adobe Premiere Pro CC 2017 mac閻楀澊11.0.0 娑擃厽鏋冮悧锟�
閸楀啫宕堥棃娆忔儔Mac閻楀湸9.1.1 鐎规ɑ鏌熼張鈧弬鎵閸楀啫宕堥棃娆忔儔Mac閻楀湸9.1.1 鐎规ɑ鏌熼張鈧弬鎵
Mac缂冩垹绮堕惄瀛樻尡鏉烆垯娆�(MacTV)v0.121 鐎规ɑ鏌熼張鈧弬鎵Mac缂冩垹绮堕惄瀛樻尡鏉烆垯娆�(MacTV)v0.121 鐎规ɑ鏌熼張鈧弬鎵
Adobe Fireworks CS6 Mac閻楀湑S6鐎规ɑ鏌熺粻鈧担鎾茶厬閺傚洨澧�Adobe Fireworks CS6 Mac閻楀湑S6鐎规ɑ鏌熺粻鈧担鎾茶厬閺傚洨澧�
閸ユ儳鑸伴崶鎯у剼
AutoCAD2015 mac娑擃厽鏋冮悧鍫熸拱v1.0 鐎规ɑ鏌熷锝呯础閻楋拷AutoCAD2015 mac娑擃厽鏋冮悧鍫熸拱v1.0 鐎规ɑ鏌熷锝呯础閻楋拷
Adobe Photoshop cs6 mac閻楀澊13.0.3 鐎规ɑ鏌熸稉顓熸瀮閻楋拷Adobe Photoshop cs6 mac閻楀澊13.0.3 鐎规ɑ鏌熸稉顓熸瀮閻楋拷
Mac閻垽鍣虹紒妯烘禈鏉烆垯娆�(Sketch mac)v3.3.2 娑擃厽鏋冮悧锟�Mac閻垽鍣虹紒妯烘禈鏉烆垯娆�(Sketch mac)v3.3.2 娑擃厽鏋冮悧锟�
Adobe After Effects cs6 mac閻楀澊1.0娑擃厽鏋冮悧锟�Adobe After Effects cs6 mac閻楀澊1.0娑擃厽鏋冮悧锟�
Adobe InDesign cs6 mac1.0 鐎规ɑ鏌熸稉顓熸瀮閻楋拷Adobe InDesign cs6 mac1.0 鐎规ɑ鏌熸稉顓熸瀮閻楋拷
鎼存梻鏁ゆ潪顖欐
Mac閻楀牆鎻╅幘锟�1.1.26 鐎规ɑ鏌熷锝呯础閻楀溂dmg]Mac閻楀牆鎻╅幘锟�1.1.26 鐎规ɑ鏌熷锝呯础閻楀溂dmg]
Mac鐠囪鍟揘TFS(Paragon NTFS for Mac)12.1.62 鐎规ɑ鏌熷锝呯础閻楋拷Mac鐠囪鍟揘TFS(Paragon NTFS for Mac)12.1.62 鐎规ɑ鏌熷锝呯础閻楋拷
鏉╁懘娴�10 for macv3.4.1.4368 鐎规ɑ鏌熼張鈧弬鎵鏉╁懘娴�10 for macv3.4.1.4368 鐎规ɑ鏌熼張鈧弬鎵
Mac娑撳娓跺鍝勩亣閻ㄥ嫮閮寸紒鐔哥閻炲棗浼愰崗锟�(CleanMyMac for mac)v3.1.1 濮濓絽绱¢悧锟�Mac娑撳娓跺鍝勩亣閻ㄥ嫮閮寸紒鐔哥閻炲棗浼愰崗锟�(CleanMyMac for mac)v3.1.1 濮濓絽绱¢悧锟�
閼昏鐏塀ootCamp5.1.5640 鐎规ɑ鏌熼張鈧弬鎵閼昏鐏塀ootCamp5.1.5640 鐎规ɑ鏌熼張鈧弬鎵
ios缁€鍙ユ唉閼卞﹤銇�
瀵邦喕淇奿pad閻楋拷2020v7.0.12 鐎规ɑ鏌熼悧锟�瀵邦喕淇奿pad閻楋拷2020v7.0.12 鐎规ɑ鏌熼悧锟�
iphone閹靛婧€qq2021v8.5.0 鐎规ɑ鏌熼悧锟�iphone閹靛婧€qq2021v8.5.0 鐎规ɑ鏌熼悧锟�
閺勬挷淇奿OS閻楀澊7.3.13 iPhone閻楋拷閺勬挷淇奿OS閻楀澊7.3.13 iPhone閻楋拷
闂勫矂妾� iphoneV8.32.4 鐎规ɑ鏌熷锝呯础閻楋拷闂勫矂妾� iphoneV8.32.4 鐎规ɑ鏌熷锝呯础閻楋拷
閸楀啰澧� iphone閻楋拷9.2.5 鐎规ɑ鏌熼悧锟�閸楀啰澧� iphone閻楋拷9.2.5 鐎规ɑ鏌熼悧锟�
ios閻㈢喐妞块張宥呭
99娑撱儵鈧娓堕弬鎵V1.3.699娑撱儵鈧娓堕弬鎵V1.3.6
韫囶偆澧甶Phone閻楋拷5.7.3 鐎规ɑ鏌熼悧锟�韫囶偆澧甶Phone閻楋拷5.7.3 鐎规ɑ鏌熼悧锟�
濞fê鐤� for iPhonev9.5.15 鐎规ɑ鏌熼張鈧弬鎵濞fê鐤� for iPhonev9.5.15 鐎规ɑ鏌熼張鈧弬鎵
婢с劏鎶楁径鈺傜毜 for iphoneV7.5.3鐎规ɑ鏌熼張鈧弬鎵IPA婢с劏鎶楁径鈺傜毜 for iphoneV7.5.3鐎规ɑ鏌熼張鈧弬鎵IPA
鐠嬮攱鐡曢崷鏉挎禈iphone(Google Maps)4.54  娑擃厽鏋冮悧锟�鐠嬮攱鐡曢崷鏉挎禈iphone(Google Maps)4.54 娑擃厽鏋冮悧锟�
ios瑜伴亶鐓舵繛鍙樼
韫囶偅鎸遍懟瑙勭亯閻楀湸3.3.35 鐎规ɑ鏌熼悧鍦糹pa]韫囶偅鎸遍懟瑙勭亯閻楀湸3.3.35 鐎规ɑ鏌熼悧鍦糹pa]
閸氬鎮忚ぐ閬嶇叾閹绢厽鏂侀崳鈺s閻楋拷1.0.1017 閼昏鐏塱pad閻楋拷閸氬鎮忚ぐ閬嶇叾閹绢厽鏂侀崳鈺s閻楋拷1.0.1017 閼昏鐏塱pad閻楋拷
瑜伴亶鐓堕崗鍫ユ敱閹绢厽鏂侀崳鈺s閻楋拷2.8.0 鐎规ɑ鏌熼悧锟�瑜伴亶鐓堕崗鍫ユ敱閹绢厽鏂侀崳鈺s閻楋拷2.8.0 鐎规ɑ鏌熼悧锟�
閺傛濂旈惄瀛樻尡鐎广垺鍩涚粩鐥爋s閻楋拷7.0.1 鐎规ɑ鏌熼張鈧弬鎵閺傛濂旈惄瀛樻尡鐎广垺鍩涚粩鐥爋s閻楋拷7.0.1 鐎规ɑ鏌熼張鈧弬鎵
闁伴瀚嶉棅鍏呯 for iPhonev10.9.0 鐎规ɑ鏌熼張鈧弬鎵闁伴瀚嶉棅鍏呯 for iPhonev10.9.0 鐎规ɑ鏌熼張鈧弬鎵
ios閸ユ儳鑸伴崶鎯у剼
How old do I look ios閻楋拷1.02 鐎规ɑ鏌熼悧锟�How old do I look ios閻楋拷1.02 鐎规ɑ鏌熼悧锟�
缂囧骸娴樼粔鈧粔鈧琲Phone閻楀湸8.6.62 閺堚偓閺傜増顒滃蹇曞缂囧骸娴樼粔鈧粔鈧琲Phone閻楀湸8.6.62 閺堚偓閺傜増顒滃蹇曞
濮樻潙宓冮梼鐔兼毐閼昏鐏夐悧鍧�1.0.0濮樻潙宓冮梼鐔兼毐閼昏鐏夐悧鍧�1.0.0
婢垛晛銇塸閸ョ穭pad閻楋拷5.7.4 鐎规ɑ鏌熼悧锟�婢垛晛銇塸閸ョ穭pad閻楋拷5.7.4 鐎规ɑ鏌熼悧锟�
韫囶偅澧渋os閻楀湸9.6.30 鐎规ɑ鏌熼悧锟�韫囶偅澧渋os閻楀湸9.6.30 鐎规ɑ鏌熼悧锟�
ios濞村繗顫嶅銉ュ徔
閼冲苯瀵橀崷鏉挎禈ios閻楋拷1.0 鐎规ɑ鏌熼張鈧弬鎵閼冲苯瀵橀崷鏉挎禈ios閻楋拷1.0 鐎规ɑ鏌熼張鈧弬鎵
閹靛婧€鐎瑰鍙忛崝鈺傚閼昏鐏夐悧鍧�1.0 鐎规ɑ鏌熼張鈧弬鎵閹靛婧€鐎瑰鍙忛崝鈺傚閼昏鐏夐悧鍧�1.0 鐎规ɑ鏌熼張鈧弬鎵
UC濞村繗顫嶉崳鈺�113.5.5.1555娑擃厽鏋冮悧锟�UC濞村繗顫嶉崳鈺�113.5.5.1555娑擃厽鏋冮悧锟�
360濞村繗顫嶉崳鈩塂 for iPadV4.1.3  濮濓絽绱¢悧锟�360濞村繗顫嶉崳鈩塂 for iPadV4.1.3 濮濓絽绱¢悧锟�
iPhone閹靛婧€QQ濞村繗顫嶉崳鈺�8.9.1 鐎规ɑ鏌熼悧锟�iPhone閹靛婧€QQ濞村繗顫嶉崳鈺�8.9.1 鐎规ɑ鏌熼悧锟�

首页编程开发其它知识 → CSS选择符表达式引擎的入门知识分享

CSS选择符表达式引擎的入门知识分享

相关文章发表评论 来源:西西整理时间:2013/2/14 10:37:18字体大小:A-A+

作者:西西点击:0次评论:0次标签: CSS选择符

  • 类型:编程辅助大小:134KB语言:中文 评分:3.3
  • 标签:
立即下载

本文的目标读者是入门级Web前端开发人员。  

本文介绍了CSS选择符表达式引擎的基本原理。CSS选择符引擎几乎是前端开发人员每天在使用的工具。本文将逐一介绍实现该引擎的各种策略。首先,我们介绍基于W3C标准API的方法。

W3C标准的Slectors API

能够支持的平台: Safari 3+, Firefox 3.1+, Internet Explorer 8+, Chrome and Opera 10+

两个最常用的方法:

querySelector,该函数接受一个CSS选择符字符串,返回找到的第一个元素,如果没有找到则返回null。

querySelectorAll,该函数接受一个CSS选择符字符串,返回找到的所有元素的集合(NodeList)。

这两个方法存在于所有的DOM元素,DOM文档对象,以及DOM文档片段(fragment)对象上。

<div id="test">
<b>Hello</b>, I'm a ninja!
</div>
<div id="test2"></div>
<script>
window.onload = function () {
var divs = document.querySelectorAll("body > div");
assert(divs.length === 2, "Two divs found using a CSS selector.");
var b = document.getElementById("test")
.querySelector("b:only-child");
assert(b,
"The bold element was found relative to another element.");
};
</script>

上述例子的一个缺点是它依赖于浏览器对CSS选择符的支持(老版本IE就歇菜了),因此可以考虑使用以某元素作为根节点对子节点的查询。代码如下。

<script>
window.onload = function () {
var b = document.getElementById("test").querySelector("div b");
assert(b, "Only the last part of the selector matters.");
};
</script>

上述代码有个问题,当以某元素作为根节点对子节点的查询时,query函数只检查最右边的部分是不是包含在父节点里。注意到#test下面压根就没有div标签,可是query函数忽略了查询字符串的前面部分。 

这个现象确实有悖于我们期望的CSS选择符引擎的运行效果,所以我们需要做一些修补工作。最常见的技巧是:临时增加一个新id给那个根节点元素从而强行地包含它里面的内容。代码如下。

<script>
    (function () {
        var count = 1;
        this.rootedQuerySelectorAll = function (elem, query) {
            var oldID = elem.id;
            elem.id = "rooted" + (count++);
            try {
                return elem.querySelectorAll("#" + elem.id + " " + query);
            } catch (e) {
                throw e;
            } finally {
                elem.id = oldID;
            }
        };
    })();
    window.onload = function () {
        var b = rootedQuerySelectorAll( document.getElementById("test"), "div b");
        assert(b.length === 0, "The selector is now rooted properly.");
    };
</script>

在上述代码中我们需要注意到以下几点:

首先,要给父元素一个全局唯一的id,因此需要保存父元素原始的id。然后把这个全局唯一的id添加到查询字符串中。 

接着的收尾部分就是去除新增加的那个id和返回查询结果,这个过程中可能会有一个API异常抛出(多数情况是因为选择符语法错误或者是浏览器不支持的选择符)。因此,我们要在外层用try/catch语句块包住API调用语句,还要在finnally的子句中还原父元素的原始id。你可能会发现,这里隐藏着JavaScript语言神奇的一个地方,就是虽然我们在try语句里已经return了,可是finnally子句还是要被执行的(在结果值被真正return给调用函数前)。

选择器API绝对可以算作W3C标准里最具前途的新API了。一旦主流浏览器支持CSS3(或至少绝大部分CSS3选择符)以后,它可以节省编程人员使用大量的JavaScript代码。

使用 XPath 寻找元素

XPath是一种可以在DOM文档中查询节点的语言。它甚至比CSS选择符更加强大。许多流行的浏览器 (Firefox,Safari 3+, Opera 9+, Chrome)都提供了对XPath的部分函数实现,可以在HTML文档中查找元素。 Internet Explorer 6及之前的版本只能使用XPath查找XML文档(而不是HTML文档)。

Xpath表达式比复杂的CSS选择符执行快。但是,当我们实现一个纯DOM操作方式的CSS选择符引擎时,我们要考虑浏览器支持性的风险。在对于简单的CSS选择符,Xpath就失去优越性了。

因此我们考虑使用一个阈值,当使用Xpath更有利的情况下我们就是用Xpath。决定阈值依赖于开发人员的经验,比如:当查找id或者标签时,使用纯DOM操作代码永远是更快的方式。

如果用户浏览器支持Xpath表达式,我们可以使用下述代码(依赖于prototype库)。

if (typeof document.evaluate === "function") {
    function getElementsByXPath(expression, parentElement) {
        var results = [];
        var query = document.evaluate(expression,
        parentElement || document,
        null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
        for (var i = 0, length = query.snapshotLength; i < length; i++)
        results.push(query.snapshotItem(i));
        return results;
    }
}

虽然使用Xpath可以解决任何选择符问题,但它不是一个可行的方案。对于一个的CSS选择符表达式,对应的Xpath的表达式却是令人生畏的复杂。 下面这个表格展示了如何把CSS选择符转换到Xpath表达式。

当建造一个基于正则表达式的CSS选择符引擎时,我们可以包含Xpath的方式作为一个子模块,它把用户查询的CSS选择符表达式部分转换成Xpath的表达式,然后使用Xpath的办法查找DOM。

实现XPath的部分的代码可能与正则表达式方式的代码一样多。很多开发人员选择抛弃XPath的部分来减少CSS选择符引擎的复杂程度。所以,你需要衡量Xpath带来的的性能提升以及它的代码实现复杂程度。

纯DOM实现方式

CSS选择符引擎的核心是以纯DOM操作方式实现的。它解析用户给出的CSS选择符,然后使用已有的DOM方法(例如getElementById, getElementsByTagName)来查找对应的DOM元素。使用纯DOM方式实现有以下理由:

      第一,Internet Explorer 6 and 7。尽管IE8以上的版本支持querySelectorAll()方法,但是在IE6、7中对Xpath和选择符API的支持使得使用纯DOM实现很有必要。

      第二,向下兼容,如果你希望你的代码能够“降级”支持老版本的浏览器(比如Safari 2),那么你应该使用纯DOM实现。

      第三,为了速度。对于某些CSS选择符表达式,使用纯DOM核心能够处理得更快(比如根据id找元素)。

知道了使用纯DOM核心的重要性,接下来我们要看以两种方式实现选择符引擎:从上往下解析,和从下往上解析。

一个从上往下的引擎是这样解析CSS选择符表达式的:从左往右的匹配元素,在前部分的基础上再接着找下部分匹配的元素。 这种方式是目前主流JavaScript库的实现方式,更通用地,也是寻找页面元素的最佳方式。 让我们来看一段标记

<body>
    <div></div>
    <div class="ninja">
<span>Please </span>
        <a href="/ninja"><span>Click me!</span>
        </a>
    </div>
</body>

如果我们想选"Click me!"那个元素,我们可以这样写 选择符表达式 : div.ninja a span 。

使用从上往下的方法是这样解析这个选择符表达式的:

表达式中的第一项,div.ninja 指明了文档中的一颗子树。在那颗子树中,接着找表达式中下一项对应的子树。最后,span的目标节点被找到。

注意,这只是最简单的情况。在任何层的推进过程中,完全有可能有多颗子树同时匹配表达式。在实现选择符引擎的时候,有两个原则需要考虑:

     返回的结果中元素的顺序应该按照在文档中原本的顺序出现

     返回的结果中的元素不应该有重复的(比如不能一个元素在结果中出现两次)

为了避免这些陷阱,具体的代码实现可能会有一点小技巧。下面是一个简化的top-down方式引擎,它只能够支持按照tag标签名字查找元素。

<div>
    <div>    <span>Span</span>
    </div>
</div>
<script>
    window.onload = function () {
        function find(selector, root) {
            root = root || document;
            var parts = selector.split(" "),
                query = parts[0],
                rest = parts.slice(1).join(" "),
                elems = root.getElementsByTagName(query),
                results = [];
            for (var i = 0; i < elems.length; i++) {
                if (rest) {
                    results = results.concat(find(rest, elems[i]));
                } else {
                    results.push(elems[i]);
                }
            }
            return results;
        }
        var divs = find("div");
        assert(divs.length === 2, "Correct number of divs found.");
        var divs = find("div", document.body);
        assert(divs.length === 2,
            "Correct number of divs found in body.");
        var divs = find("body div");
        assert(divs.length === 2,
            "Correct number of divs found in body.");
        var spans = find("div span");
        assert(spans.length === 2, "A duplicate span was found.");
    };
</script>

在上面的例子中,我们实现了一个简单的支持按照tag标签名字查找元素的从上往下解析方式的选择符引擎。 这个引擎可以分解为几个子部分:解析选择符表达式,在文档中查找元素,过滤元素,递归/合并每一层里的结果。

解析选择符表达式

在上面的例子中,解析过程就是把CSS选择符(例如"div span")分解成字符串数组(["div", "span"])。实际上,在CSS2和CSS3的标准中,使用属性值查找元素是被支持的。因此在选择符中完全有可能有额外的空格,使得上面简单的方法不可行了。但是,这种简单的方法对于处理大部分的情况已经足够了。

要完全实现解析,我们需要一系列的解析规则来处理用户给出的任何表达式。 下面的代码就是使用正则表达式把表达式分解成各个小块(如果需要,则分开逗号)

<script type="text/javascript">
    var selector = "div.class > span:not(:first-child) a[href]"
    var chunker = /((?:\([^\)]+\)|\[[^\]]+\]|[^ ,\(\[]+)+)(\s*,\s*)?/g;
    var parts = [];
    // Reset the position of the chunker regexp (start from beginning)
    chunker.lastIndex = 0;
    // Collect the pieces
    while ((m = chunker.exec(selector)) !== null) {
        parts.push(m[1]);
        // Stop if we've countered a comma
        if (m[2]) {
            extra = RegExp.rightContext;
            break;
        }
    }
    assert(parts.length == 4,
        "Our selector is broken into 4 unique parts.");
    assert(parts[0] === "div.class", "div selector");
    assert(parts[1] === ">", "child selector");
    assert(parts[2] === "span:not(:first-child)", "span selector");
    assert(parts[3] === "a[href]", "a selector");
</script>

显然,这段代码支持的选择符只是一张大拼图中的一小部分。我们需要定义更多的解析规则来支持用户输入的各种表达式组合。绝大多数CSS选择符引擎使用了map结构,来将正则表达式对应到目标处理函数。这样当一个正则表达式匹配用户表达式的一部分时,对应的函数就去处理那一部分表达式的选择符。

寻找元素

在页面中寻找正确的DOM元素有许多种解决方案。使用哪种方案取决于浏览器支持什么样的选择符。

首先是 getElementById() 方法。它只在HTML文档的根节点上存在。它的作用是找到第一个匹配指定id值的元素,因此他可以用来解决 "#id" 这样的表达式。注意,在Internet Explorer 和 Opera,它同样也会查找第一个具有同名 name值的元素。 因此,如果需要值按照 id 值查找,我们需要额外的一步验证工作来排除掉 name值同名的元素。

如果需要支持寻找所有具有给定 id值的元素(这在CSS选择符表达式中是习惯性用法,尽管HTML文法规定一个id只能对应一个元素),有两种方法可以采用:第一种方法,遍历所有的元素,找出所有匹配给定 id值的元素;第二种方法,使用 document.all["id"] ,它将返回一个包含匹配id值元素的数组。

接下来是 getElementsByTagName() 方法,它的作用就如同它的名字所述:找出所有匹配给定标签名的元素。 注意,它还有另一种用法:如果使用 星号* 作为参数标签名,那么它会返回文档中或者一个节点下所有的元素。 这一招对于 处理基于属性值的选择符 很有用,比如 ".class" 或者 "[attr]"。 因为 ".class" 并没有指定标签名,所以我们需要列出某节点下的所有子元素,然后依次判断class名称。

另外,在Internet Explorer中使用 星号* 查找有一个缺点,它同样会返回 注释语句 节点(因为在IE中,注释语句节点有一个 "!" 的标签名,所以它也会被返回)。 这样,我们需要额外的一步过滤工作来排除注释语句节点。

接下来是 getElementsByName() 方法,它的作用只有一个: 找出所有匹配给定 name值的节点(例如,<input> 元素都具有name值 )。因此这个方法可以用来解决 "[name=name]" 这样的表达式。

最后是 getElementsByClassName() 方法。这个方法相对比较新,正在被各主流浏览器实现(Firefox 3+, Safari 3+ 和 Chrome)。它的作用是基于 元素的class名称 进行查找。 这种浏览器原生的方法极大地加快了 按class名称查找 的代码实现。

尽管还有一些其他技巧用来解决元素查找,以上那些方法依然是我们主要使用的工具。一旦找出了所有匹配的备选元素后,接下来就进行元素过滤了。

过滤元素

一个CSS表达式通常是由几个独立的小部分组成的。例如,这样一个表达式 "div.class[id]" 就由三个部分组成: 1. div元素 2. 具有给定的class名称 3. 具有一个名叫id的属性值。

首先我们需要找出选择符的第一部分。例如,在上述表达式中,我们看到第一部分是找div元素,所以我们立刻想到用 getElementsByTagName() 方法找出页面上所有的 <div> 元素。 接下来,我们必须过滤元素,使得剩下的元素具有给定的class名称和id属性值。

过滤元素是选择符引擎的实现中普遍存在的一部分。过滤原则主要依靠元素属性值或者元素在DOM树中与其他节点的关系。

按照属性过滤:访问元素的DOM属性(通常使用 getAttribute() 方法),并且验证它的值是否等于给定值。按照class类名过滤是本类别中的一个子集(访问 className 属性并且验证它的值)。

按照位置关系过滤: 这种情况出现在对于在某父元素上使用 ":nth-child(even)" 或者 ":last-child" 组合的表达式。 如果浏览器支持这样的CSS选择符,那么会返回一个子元素的集合。另外,所有的浏览器都支持 childNodes,它返回一个子元素的集合,其中也包含所有的纯文本节点和注释语句节点。 使用以上两种方法,可以按照元素在DOM树中的位置关系进行过滤。

实现元素过滤功能具有两个目的:第一,可以把这个功能提供给用户让他们测试任意元素是否符合某值;第二,在内部计算时,可以检查元素是否符合用户给出的选择符表达式。

合并元素

在本文的第一段代码中,我们可以看见选择符引擎需要能够递归的找元素(找出后代元素)以及合并所有符合要求的元素,最终返回结果集。

但是,在本小节中,我们初步的代码实现太简单了。注意到,我们最终在文档中找到了两个 <span> 元素。因此,我们需要做额外的一步检查,来确保最终结果的数组中不能包含重复的元素。 大多数top-down方式的选择符引擎中都使用了若干确保元素唯一性的方法。

<div id="test">
<b>Hello</b>, I'm a ninja!</div>
<div id="test2"></div>
<script>
    (function () {
        var run = 0;
        this.unique = function (array) {
            var ret = [];
            run++;
            for (var i = 0, length = array.length; i < length; i++) {
                var elem = array[i];
                if (elem.uniqueID !== run) {
                    elem.uniqueID = run;
                    ret.push(array[i]);
                }
            }
            return ret;
        };
    })();
    window.onload = function () {
        var divs = unique(document.getElementsByTagName("div"));
        assert(divs.length === 2, "No duplicates removed.");
        var body = unique([document.body, document.body]);
        assert(body.length === 1, "body duplicate removed.");
    };
</script>

其中的 unique() 方法给数组中的所有元素增加了一个额外的属性,标记它们是否被访问过。因此,当所有元素都处理后,最终只剩下了不重复的元素。类似本方法的其他算法可以在大多数CSS选择符引擎中见到。

到目前为止,我们大致就构造了一个 从上到下方式(top-down)的 CSS选择符引擎。 现在,我们来看另外的一种方案。

从下到上的方式实现

如果你不用考虑唯一地确定元素,那么你可以以从下到上的方式(bottom-up)实现选择符解析过程。它的流程跟从上到下的方式相反(复习那张解析过程的图示)。例如,对于这样的表达式 "div span",你需要首先找出所有 <span> 元素,然后对于每个候选元素,看看它们是否有一个 <div> 的祖先元素。 

这样的方式并没有 从上到下的方式 流行。尽管它能够良好地处理简单的CSS选择符表达式,但是在每个候选元素上对于祖先的遍历就显得太耗费时间和资源了。

构造从下到上方式的引擎很简单。首先找到CSS选择符表达式中的最后一个部分,然后找出匹配的元素,接着按照一系列的过滤规则过滤掉不符合的元素。下面的代码阐述了这一过程。

<div>
    <div>
<span>Span</span>

    </div>
</div>
<script>
    window.onload = function () {
        function find(selector, root) {
            root = root || document;
            var parts = selector.split(" "),
                query = parts[parts.length - 1],
                rest = parts.slice(0, -1).join("").toUpperCase(),
                elems = root.getElementsByTagName(query),
                results = [];
            for (var i = 0; i < elems.length; i++) {
                if (rest) {
                    var parent = elems[i].parentNode;
                    while (parent && parent.nodeName != rest) {
                        parent = parent.parentNode;
                    }
                    if (parent) {
                        results.push(elems[i]);
                    }
                } else {
                    results.push(elems[i]);
                }
            }
            return results;
        }
        var divs = find("div");
        assert(divs.length === 2, "Correct number of divs found.");
        var divs = find("div", document.body);
        assert(divs.length === 2,
            "Correct number of divs found in body.");
        var divs = find("body div");
        assert(divs.length === 2,
            "Correct number of divs found in body.");
        var spans = find("div span");
        assert(spans.length === 1, "No duplicate span was found.");
    };
</script>

注意,上述代码只能处理一层祖先关系。如果需要处理多层祖先关系,那么当前层的状态则需要被记录。考虑使用两个数组:第一个数组记录将要被返回的元素(其中的某些元素被设置成undefined,如果它们不能匹配表达式);第二个数组记录当前需要被测试的祖先节点。

就如之前所述,这一步额外的祖先关系验证会带来更多的性能开销。但是按照从下到上的方式实现就不需要在结果集中取出重复元素的一步,因此它也算有一些优势。(因为按照从下到上的方式在最开始的时候每个元素就已经是各自独立不重复的了;而如果按照从上到下的方式,由于在递归时子树可能相互重叠,所以那会包含重复的元素)

小结

JavaScript实现的CSS选择符引擎是一个强大的工具。它能让我们轻松地使用若干选择符语法在页面上寻找DOM元素。尽管在完全实现一个选择符引擎时有非常多的细节需要考虑,这种情况正在大大的改善(得益于浏览器原生的方法)。

回顾一下本文讨论的几点:

现代浏览器已经开始实现对于 W3C标准选择符API的支持,但是依然有很长一段路要走.

考虑到性能问题,我们仍然有必要实现自己的选择符引擎。

要创建一个选择符引擎,我们可以:

      利用 W3C标准的选择符API

      利用 XPath

      为了最好的性能,使用纯DOM操作方式

从上到下的方式非常流行,但是它需要一些清理工作:比如确保返回元素不重复。

从下到上的方式避免了那个清理工作,但是它会带来更多的性能开销。

随着浏览器逐渐支持W3C标准选择符,顾虑引擎实现的细节或许会成为过去式了。但是对于许多开发人员来说,那一天或许不能很快的到来。

相关评论

阅读本文后您有什么感想? 已有人给出评价!

  • 8 喜欢喜欢
  • 3 顶
  • 1 难过难过
  • 5 囧
  • 3 围观围观
  • 2 无聊无聊

热门评论

最新评论

发表评论 查看所有评论(0)

昵称:
表情: 高兴 可 汗 我不要 害羞 好 下下下 送花 屎 亲亲
字数: 0/500 (您的评论需要经过审核才能显示)
推荐文章

没有数据