cainiaoblog 23.2.171

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (401) hide show
  1. package/CNAME +1 -0
  2. package/MP_verify_o6dHCK5mIkxNpzvZ.txt +1 -0
  3. package/README.md +8 -0
  4. package/about/index.html +54 -0
  5. package/ads.txt +1 -0
  6. package/app/manual.html +104 -0
  7. package/appConfigs/config +1 -0
  8. package/archives/2018/index.html +48 -0
  9. package/archives/2019/index.html +48 -0
  10. package/archives/2019/page/2/index.html +48 -0
  11. package/archives/2020/index.html +48 -0
  12. package/archives/2021/index.html +48 -0
  13. package/archives/2022/index.html +48 -0
  14. package/archives/2023/index.html +48 -0
  15. package/archives/index.html +48 -0
  16. package/archives/page/2/index.html +48 -0
  17. package/archives/page/3/index.html +48 -0
  18. package/article/10047.html +148 -0
  19. package/article/10164.html +64 -0
  20. package/article/10624.html +436 -0
  21. package/article/10745.html +586 -0
  22. package/article/11674.html +71 -0
  23. package/article/11939.html +72 -0
  24. package/article/12238.html +86 -0
  25. package/article/1230.html +533 -0
  26. package/article/13265.html +69 -0
  27. package/article/13823.html +78 -0
  28. package/article/14125.html +72 -0
  29. package/article/14192.html +561 -0
  30. package/article/14375.html +85 -0
  31. package/article/14744.html +83 -0
  32. package/article/14936.html +451 -0
  33. package/article/1518.html +250 -0
  34. package/article/15428.html +71 -0
  35. package/article/15518.html +288 -0
  36. package/article/15569.html +418 -0
  37. package/article/1566.html +122 -0
  38. package/article/16017.html +156 -0
  39. package/article/16947.html +440 -0
  40. package/article/17096.html +82 -0
  41. package/article/17246.html +89 -0
  42. package/article/17575.html +350 -0
  43. package/article/179.html +757 -0
  44. package/article/18039.html +233 -0
  45. package/article/18071.html +375 -0
  46. package/article/18142.html +71 -0
  47. package/article/19909.html +160 -0
  48. package/article/20014.html +89 -0
  49. package/article/20021.html +389 -0
  50. package/article/20037.html +280 -0
  51. package/article/20056.html +95 -0
  52. package/article/20093.html +404 -0
  53. package/article/2021.html +607 -0
  54. package/article/20459.html +115 -0
  55. package/article/20613.html +263 -0
  56. package/article/20635.html +71 -0
  57. package/article/21317.html +71 -0
  58. package/article/21320.html +90 -0
  59. package/article/21782.html +548 -0
  60. package/article/22230.html +435 -0
  61. package/article/22237.html +347 -0
  62. package/article/22398.html +109 -0
  63. package/article/22422.html +270 -0
  64. package/article/22565.html +300 -0
  65. package/article/23046.html +250 -0
  66. package/article/23083.html +215 -0
  67. package/article/23195.html +297 -0
  68. package/article/23301.html +835 -0
  69. package/article/23589.html +285 -0
  70. package/article/23655.html +338 -0
  71. package/article/23864.html +76 -0
  72. package/article/23914.html +96 -0
  73. package/article/24169.html +135 -0
  74. package/article/24581.html +349 -0
  75. package/article/2475.html +500 -0
  76. package/article/24826.html +77 -0
  77. package/article/24924.html +247 -0
  78. package/article/25164.html +1495 -0
  79. package/article/25318.html +394 -0
  80. package/article/25710.html +1129 -0
  81. package/article/25734.html +83 -0
  82. package/article/26083.html +174 -0
  83. package/article/26147.html +283 -0
  84. package/article/26291.html +110 -0
  85. package/article/26354.html +71 -0
  86. package/article/26624.html +145 -0
  87. package/article/26639.html +298 -0
  88. package/article/26850.html +138 -0
  89. package/article/26940.html +258 -0
  90. package/article/27796.html +190 -0
  91. package/article/27800.html +161 -0
  92. package/article/28963.html +159 -0
  93. package/article/28976.html +247 -0
  94. package/article/29042.html +72 -0
  95. package/article/29596.html +81 -0
  96. package/article/29619.html +183 -0
  97. package/article/29623.html +329 -0
  98. package/article/29829.html +205 -0
  99. package/article/29abbd1c.html +112 -0
  100. package/article/30215.html +178 -0
  101. package/article/30552.html +78 -0
  102. package/article/30818.html +201 -0
  103. package/article/31330.html +364 -0
  104. package/article/3154.html +577 -0
  105. package/article/31695.html +348 -0
  106. package/article/31826.html +71 -0
  107. package/article/31843.html +132 -0
  108. package/article/32280.html +212 -0
  109. package/article/32431.html +74 -0
  110. package/article/32443.html +72 -0
  111. package/article/32732.html +122 -0
  112. package/article/3286.html +251 -0
  113. package/article/32960.html +198 -0
  114. package/article/33713.html +72 -0
  115. package/article/33899.html +615 -0
  116. package/article/34351.html +74 -0
  117. package/article/34372.html +89 -0
  118. package/article/34410.html +74 -0
  119. package/article/34431.html +118 -0
  120. package/article/3447.html +75 -0
  121. package/article/34474.html +142 -0
  122. package/article/34871.html +147 -0
  123. package/article/35397.html +175 -0
  124. package/article/3544.html +199 -0
  125. package/article/35503.html +115 -0
  126. package/article/35624.html +84 -0
  127. package/article/35697.html +384 -0
  128. package/article/35863.html +73 -0
  129. package/article/36037.html +253 -0
  130. package/article/36118.html +71 -0
  131. package/article/3621.html +119 -0
  132. package/article/36251.html +296 -0
  133. package/article/36642.html +352 -0
  134. package/article/37102.html +763 -0
  135. package/article/37336.html +351 -0
  136. package/article/37351.html +89 -0
  137. package/article/3760.html +294 -0
  138. package/article/37749.html +75 -0
  139. package/article/37789.html +83 -0
  140. package/article/38005.html +765 -0
  141. package/article/38009.html +284 -0
  142. package/article/38269.html +194 -0
  143. package/article/38344.html +88 -0
  144. package/article/38359.html +334 -0
  145. package/article/38423.html +379 -0
  146. package/article/38530.html +213 -0
  147. package/article/38743.html +268 -0
  148. package/article/38753.html +204 -0
  149. package/article/38881.html +71 -0
  150. package/article/39087.html +414 -0
  151. package/article/39309.html +84 -0
  152. package/article/39486.html +74 -0
  153. package/article/39637.html +306 -0
  154. package/article/39839.html +72 -0
  155. package/article/39937.html +152 -0
  156. package/article/39970.html +71 -0
  157. package/article/402.html +559 -0
  158. package/article/40698.html +71 -0
  159. package/article/40811.html +71 -0
  160. package/article/40964.html +462 -0
  161. package/article/41011.html +322 -0
  162. package/article/41152.html +78 -0
  163. package/article/41696.html +71 -0
  164. package/article/41717.html +281 -0
  165. package/article/41777.html +149 -0
  166. package/article/419.html +985 -0
  167. package/article/4233.html +136 -0
  168. package/article/4292.html +86 -0
  169. package/article/43302.html +96 -0
  170. package/article/43397.html +106 -0
  171. package/article/43724.html +281 -0
  172. package/article/43999.html +224 -0
  173. package/article/44426.html +77 -0
  174. package/article/44964.html +137 -0
  175. package/article/45004.html +123 -0
  176. package/article/4510.html +83 -0
  177. package/article/45156.html +320 -0
  178. package/article/45157.html +52 -0
  179. package/article/45267.html +87 -0
  180. package/article/45641.html +207 -0
  181. package/article/45960.html +75 -0
  182. package/article/46100.html +1262 -0
  183. package/article/46366.html +74 -0
  184. package/article/46771.html +96 -0
  185. package/article/46911.html +517 -0
  186. package/article/46948.html +137 -0
  187. package/article/46ee4850.html +349 -0
  188. package/article/47019.html +84 -0
  189. package/article/47532.html +94 -0
  190. package/article/4783.html +429 -0
  191. package/article/47972.html +72 -0
  192. package/article/48216.html +127 -0
  193. package/article/48252.html +185 -0
  194. package/article/48520.html +74 -0
  195. package/article/48722.html +75 -0
  196. package/article/48807.html +99 -0
  197. package/article/49126.html +323 -0
  198. package/article/50001.html +88 -0
  199. package/article/50058.html +151 -0
  200. package/article/50343.html +410 -0
  201. package/article/50510.html +82 -0
  202. package/article/51082.html +98 -0
  203. package/article/51677.html +111 -0
  204. package/article/5204.html +1085 -0
  205. package/article/52500.html +538 -0
  206. package/article/52689.html +259 -0
  207. package/article/52877.html +569 -0
  208. package/article/53125.html +191 -0
  209. package/article/53428.html +251 -0
  210. package/article/53524.html +74 -0
  211. package/article/53698.html +322 -0
  212. package/article/53803e6.html +93 -0
  213. package/article/53924.html +291 -0
  214. package/article/53962.html +253 -0
  215. package/article/54006.html +71 -0
  216. package/article/54018.html +88 -0
  217. package/article/54161.html +83 -0
  218. package/article/54178.html +69 -0
  219. package/article/54258.html +327 -0
  220. package/article/54295.html +214 -0
  221. package/article/54313.html +1976 -0
  222. package/article/54351.html +90 -0
  223. package/article/54604.html +80 -0
  224. package/article/54632.html +71 -0
  225. package/article/54912.html +756 -0
  226. package/article/54918.html +129 -0
  227. package/article/55119.html +136 -0
  228. package/article/55756.html +118 -0
  229. package/article/55769.html +136 -0
  230. package/article/55870.html +161 -0
  231. package/article/56139.html +92 -0
  232. package/article/56557.html +69 -0
  233. package/article/56604.html +69 -0
  234. package/article/56816.html +266 -0
  235. package/article/56926.html +153 -0
  236. package/article/57747.html +409 -0
  237. package/article/57965.html +475 -0
  238. package/article/58816.html +78 -0
  239. package/article/59059.html +435 -0
  240. package/article/59095.html +350 -0
  241. package/article/59349.html +244 -0
  242. package/article/59402.html +216 -0
  243. package/article/59448.html +55 -0
  244. package/article/59870.html +94 -0
  245. package/article/59877.html +208 -0
  246. package/article/5dbb6f41.html +86 -0
  247. package/article/6008.html +75 -0
  248. package/article/60327.html +126 -0
  249. package/article/6035.html +76 -0
  250. package/article/60428.html +71 -0
  251. package/article/60544.html +128 -0
  252. package/article/61319.html +95 -0
  253. package/article/61367.html +93 -0
  254. package/article/624d1918.html +292 -0
  255. package/article/62543.html +71 -0
  256. package/article/62887.html +169 -0
  257. package/article/63074.html +120 -0
  258. package/article/63266.html +311 -0
  259. package/article/63351.html +74 -0
  260. package/article/63542.html +104 -0
  261. package/article/63824.html +275 -0
  262. package/article/64051.html +653 -0
  263. package/article/64189b69.html +72 -0
  264. package/article/64354.html +75 -0
  265. package/article/64869.html +79 -0
  266. package/article/64923.html +596 -0
  267. package/article/65128.html +95 -0
  268. package/article/65295.html +79 -0
  269. package/article/6888.html +75 -0
  270. package/article/7065.html +84 -0
  271. package/article/7455.html +85 -0
  272. package/article/7a3ef8f.html +315 -0
  273. package/article/8140.html +188 -0
  274. package/article/8190.html +85 -0
  275. package/article/8225.html +78 -0
  276. package/article/84c9ccd6.html +159 -0
  277. package/article/8f9a9ae3.html +82 -0
  278. package/article/9174.html +73 -0
  279. package/article/9738.html +294 -0
  280. package/article/a4145266.html +71 -0
  281. package/article/bedea419.html +72 -0
  282. package/article/bf7e7421.html +78 -0
  283. package/article/c1867fbf.html +103 -0
  284. package/article/c5576490.html +70 -0
  285. package/article/dcb0db28.html +76 -0
  286. package/article/fc3b727a.html +79 -0
  287. package/atom.xml +445 -0
  288. package/baidusitemap.xml +1079 -0
  289. package/blocks/dns.txt +264 -0
  290. package/blocks/filter.txt +1070 -0
  291. package/blocks/script.js +42 -0
  292. package/categories/CDN/index.html +48 -0
  293. package/categories/IDE/index.html +48 -0
  294. package/categories/git/index.html +48 -0
  295. package/categories/hexo/index.html +48 -0
  296. package/categories//345/205/254/345/205/261/350/212/202/346/227/245/index.html +48 -0
  297. package/categories//345/210/206/344/272/253/index.html +48 -0
  298. package/categories//345/211/215/347/253/257/index.html +48 -0
  299. package/categories//345/211/215/347/253/257/page/2/index.html +48 -0
  300. package/categories//345/211/215/347/253/257//346/265/217/350/247/210/345/231/250/index.html +48 -0
  301. package/categories//345/211/215/347/253/257//346/265/217/350/247/210/345/231/250//347/275/221/347/273/234/345/215/217/350/256/256/index.html +48 -0
  302. package/categories//345/215/232/345/256/242/index.html +48 -0
  303. package/categories//345/267/245/345/205/267/index.html +48 -0
  304. package/categories//345/271/277/345/221/212/350/277/207/346/273/244/index.html +48 -0
  305. package/categories//345/271/277/345/221/212/350/277/207/346/273/244//350/247/206/351/242/221/347/224/265/350/247/206/345/260/217/350/257/264/346/274/253/347/224/273/350/265/204/350/256/257/351/237/263/344/271/220/index.html +48 -0
  306. package/categories//346/255/243/345/210/231/index.html +48 -0
  307. package/categories//346/265/217/350/247/210/345/231/250/index.html +48 -0
  308. package/categories//347/256/227/346/263/225/index.html +48 -0
  309. package/categories//350/265/204/350/256/257/index.html +48 -0
  310. package/categories//350/275/273/346/235/276/344/270/200/345/210/273/index.html +48 -0
  311. package/cdn/css/font-awesome.min.css +4 -0
  312. package/cdn/css/grids-responsive-min.css +7 -0
  313. package/cdn/css/normalize.css +349 -0
  314. package/cdn/css/pure-min.css +11 -0
  315. package/cdn/fonts/fontawesome-webfont.eot +0 -0
  316. package/cdn/fonts/fontawesome-webfont.svg +2671 -0
  317. package/cdn/fonts/fontawesome-webfont.ttf +0 -0
  318. package/cdn/fonts/fontawesome-webfont.woff +0 -0
  319. package/cdn/fonts/fontawesome-webfont.woff2 +0 -0
  320. package/cdn/js/Valine.min.js +17 -0
  321. package/cdn/js/canvas-nest.js +1 -0
  322. package/cdn/js/clipboard.min.js +7 -0
  323. package/cdn/js/crypto-js.js +25 -0
  324. package/cdn/js/jquery.min.js +2 -0
  325. package/css/default.css +1144 -0
  326. package/css/donate.css +338 -0
  327. package/css/hbe.style.css +749 -0
  328. package/css/style.css +2095 -0
  329. package/donate/index.html +39 -0
  330. package/google917dcf72f6e5c7f5.html +1 -0
  331. package/guestbook/index.html +68 -0
  332. package/hosts/ads.txt +149 -0
  333. package/hosts/flash.txt +9 -0
  334. package/hosts/github.txt +6 -0
  335. package/hosts/google.txt +16936 -0
  336. package/hosts/winrar.txt +2 -0
  337. package/img/alipay.svg +46 -0
  338. package/img/bitcoin.svg +135 -0
  339. package/img/blog.ico +0 -0
  340. package/img/blog.png +0 -0
  341. package/img/gaba.png +0 -0
  342. package/img/github.svg +1 -0
  343. package/img/like.svg +1 -0
  344. package/img/mp-mini.jpg +0 -0
  345. package/img/mp.png +0 -0
  346. package/img/paypal.svg +63 -0
  347. package/img/upy_logo.svg +59 -0
  348. package/img/wechat.svg +49 -0
  349. package/index.html +48 -0
  350. package/jd_root.txt +1 -0
  351. package/js/codeblock-resizer.js +51 -0
  352. package/js/dark.js +12 -0
  353. package/js/donate.js +87 -0
  354. package/js/fixedPage.js +106 -0
  355. package/js/gitment.browser.js +3751 -0
  356. package/js/search.js +86 -0
  357. package/js/share.js +60 -0
  358. package/js/smartresize.js +32 -0
  359. package/js/totop.js +12 -0
  360. package/kankan/index.html +77 -0
  361. package/lib/hbe.js +293 -0
  362. package/package.json +25 -0
  363. package/page/10/index.html +49 -0
  364. package/page/11/index.html +59 -0
  365. package/page/12/index.html +67 -0
  366. package/page/13/index.html +63 -0
  367. package/page/14/index.html +66 -0
  368. package/page/15/index.html +60 -0
  369. package/page/16/index.html +60 -0
  370. package/page/17/index.html +62 -0
  371. package/page/18/index.html +61 -0
  372. package/page/19/index.html +58 -0
  373. package/page/2/index.html +48 -0
  374. package/page/20/index.html +57 -0
  375. package/page/21/index.html +61 -0
  376. package/page/22/index.html +55 -0
  377. package/page/23/index.html +64 -0
  378. package/page/24/index.html +60 -0
  379. package/page/25/index.html +58 -0
  380. package/page/26/index.html +48 -0
  381. package/page/27/index.html +58 -0
  382. package/page/3/index.html +48 -0
  383. package/page/4/index.html +48 -0
  384. package/page/5/index.html +51 -0
  385. package/page/6/index.html +51 -0
  386. package/page/7/index.html +51 -0
  387. package/page/8/index.html +53 -0
  388. package/page/9/index.html +48 -0
  389. package/randomcall/README.html +1 -0
  390. package/randomcall/lucker.html +290 -0
  391. package/randomcall/lucky.png +0 -0
  392. package/robots.txt +22 -0
  393. package/search.xml +6740 -0
  394. package/sitemap.xml +2669 -0
  395. package/tags//345/216/237/345/210/233/index.html +48 -0
  396. package/tags//345/250/261/344/271/220/index.html +48 -0
  397. package/tags//346/211/213/345/206/231/index.html +48 -0
  398. package/tags//347/226/253/346/203/205/index.html +48 -0
  399. package/tags//350/275/254/350/275/275/index.html +48 -0
  400. package/tags//350/275/254/350/275/275/page/2/index.html +48 -0
  401. package/v.html +90 -0
@@ -0,0 +1,559 @@
1
+ <!DOCTYPE html><html lang="zh-CN" data-dark><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport"><meta content="yes" name="apple-mobile-web-app-capable"><meta content="black-translucent" name="apple-mobile-web-app-status-bar-style"><meta content="telephone=no" name="format-detection"><meta name="description" content="前端壹菜鸟,记录工作难题,关注前端知识,收集精彩博文,做技术的搬运工"><meta name="msvalidate.01" content="0FE4D8B3381D3D87088996B886E1E2BD"><title>如何用120行代码,实现一个交互完整的拖拽上传组件? | 前端壹菜鸟</title><link rel="stylesheet" type="text/css" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/css/style.min.css"><link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/normalize.css@latest/normalize.min.css"><link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/purecss@latest/build/pure-min.min.css"><link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/purecss@latest/build/grids-responsive-min.css"><link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css"><link rel="icon" mask="" sizes="any" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/blog.ico"><link rel="Shortcut Icon" type="image/x-icon" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/blog.ico"><link rel="apple-touch-icon" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/blog.png"><link rel="apple-touch-icon-precomposed" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/blog.png"><link rel="alternate" type="application/atom+xml" href="/atom.xml"><script type="text/javascript" src="//cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js"></script><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-8385136408348258"></script><script src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" async></script><script>(function(){
2
+ var bp = document.createElement('script');
3
+ var curProtocol = window.location.protocol.split(':')[0];
4
+ if (curProtocol === 'https'){
5
+ bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
6
+ }
7
+ else{
8
+ bp.src = 'http://push.zhanzhang.baidu.com/push.js';
9
+ }
10
+ var s = document.getElementsByTagName("script")[0];
11
+ s.parentNode.insertBefore(bp, s);
12
+ })();
13
+ </script><script>(function(){
14
+ var src = 'https://jspassport.ssl.qhimg.com/11.0.1.js?d182b3f28525f2db83acfaaf6e696dba';
15
+ document.write('<script src="' + src + '" id="sozz"><\/script>');
16
+ })();
17
+ </script><script>var _hmt=_hmt||[];(function(){var hm=document.createElement("script");hm.src='https://hm.baidu.com/hm.js?011f0b44e8452bfa57fbfa23c5fe7683';var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(hm, s);})();
18
+ </script><script async src="https://www.googletagmanager.com/gtag/js?id=UA-150860401-1"></script><script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);};gtag('js',new Date());gtag('config','UA-150860401-1');
19
+ </script><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/fixedPage.min.js"></script><meta name="generator" content="Hexo 6.3.0"></head><body><div class="body_container"><div id="header"><div class="site-name"><a id="logo" href="/.">前端壹菜鸟</a><p class="description">关注前端知识,收集精彩博文,做技术的搬运工</p></div><div id="nav-menu"><a class="current" href="/." target="_self"><i class="fa fa-home"> 首页</i></a><a href="/archives/" target="_self"><i class="fa fa-archive"> 归档</i></a><a href="/guestbook/" target="_self"><i class="fa fa-comments"> 留言</i></a><a href="/about/" target="_self"><i class="fa fa-user"> 关于</i></a><a href="https://laonongmin.online/" target="_target"><i class="fa fa-group"> 看看</i></a><a href="https://love.xuehuayu.cn/" target="_target"><i class="fa fa-heart"> LOVE</i></a></div></div><div class="pure-g" id="layout"><div class="pure-u-1 pure-u-md-3-4"><div class="content_container"><div class="post"><h1 class="post-title c-post">如何用120行代码,实现一个交互完整的拖拽上传组件?</h1><div class="post-meta"><span class="date">2019-12-09</span><span> | </span><span class="tag"><a href="/tags/%E8%BD%AC%E8%BD%BD/">转载 </a></span><span> | </span><span class="category"><a href="/categories/%E5%88%86%E4%BA%AB/">分享 </a></span><span id="busuanzi_container_page_pv"> | <span id="busuanzi_value_page_pv"><i class="fa fa-spinner"></i></span><span> 阅读</span></span><span class="post-time"><span class="post-meta-item-text"> | </span><span class="post-meta-item-icon"><i class="fa fa-keyboard-o"></i><span class="post-count"> 2.3k</span><span class="post-meta-item-text"> 字</span></span></span><span class="post-time"> | <span class="post-meta-item-icon"><i class="fa fa-hourglass-half"></i><span class="post-count"> 11</span><span class="post-meta-item-text"> 分钟</span></span></span></div><a class="disqus-comment-count" href="/article/402.html#vcomment"><span class="waline-comment-count" data-path="/article/402.html"></span><span> 条评论</span></a><div class="post-content"><p><code>原文地址:https://mp.weixin.qq.com/s/cPW8Sr2pShJumnCtXsk-ww</code></p>
20
+ <span id="more"></span>
21
+
22
+ <p>前言</p>
23
+ <p>你将在该篇学到:</p>
24
+ <ul>
25
+ <li><p>如何将现有组件改写为 <code>React Hooks</code>函数组件</p>
26
+ </li>
27
+ <li><p><code>useState</code>、<code>useEffect</code>、<code>useRef</code>是如何替代原生命周期和<code>Ref</code>的。</p>
28
+ </li>
29
+ <li><p>一个完整拖拽上传行为覆盖的四个事件:<code>dragover</code>、<code>dragenter</code>、<code>drop</code>、<code>dragleave</code></p>
30
+ </li>
31
+ <li><p>如何使用<code>React Hooks</code>编写自己的UI组件库。</p>
32
+ </li>
33
+ </ul>
34
+ <p>逛国外社区时看到这篇:</p>
35
+ <p><img src="https://mmbiz.qpic.cn/mmbiz_png/icnrNBicEhkVWy7FdrmvylE8IOtycZZGJQTTRvUiaqjn7XPAic0Dibplv7wE3Cf9A5icgc0IXUseJTITlICwmpfQe7mA/640?wx_fmt=png&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="xuehuayu.cn"></p>
36
+ <blockquote>
37
+ <p>How To Implement Drag and Drop for Files in React</p>
38
+ </blockquote>
39
+ <p>文章讲了<code>React</code>拖拽上传的精简实现,但直接翻译照搬显然不是我的风格。</p>
40
+ <p>于是我又用<code>React Hooks</code> 重写了一版,除<code>CSS</code>的代码总数 <code>120</code>行。<br>效果如下:<br><img src="https://mmbiz.qpic.cn/mmbiz_gif/icnrNBicEhkVWy7FdrmvylE8IOtycZZGJQ22hCiaDib2YSa5Z5tV8S1iagG7I6yxoG2B6vSTs1gQ17opoGf3TpTOBdA/640?wx_fmt=gif&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1" alt="xuehuayu.cn"></p>
41
+ <h2 id="1-添加基本目录骨架"><a href="#1-添加基本目录骨架" class="headerlink" title="1. 添加基本目录骨架"></a>1. 添加基本目录骨架</h2><p><strong>app.js</strong></p>
42
+ <pre><code>import React from &#39;react&#39;;
43
+ import PropTypes from &#39;prop-types&#39;;
44
+
45
+ import &#123; FilesDragAndDrop &#125; from &#39;../components/Common/FilesDragAndDropHook&#39;;
46
+
47
+ export default class App extends React.Component &#123;
48
+ static propTypes = &#123;&#125;;
49
+
50
+ onUpload = (files) =&gt; &#123;
51
+ console.log(files);
52
+ &#125;;
53
+
54
+ render() &#123;
55
+ return (
56
+ &lt;div&gt;
57
+ &lt;FilesDragAndDrop
58
+ onUpload=&#123;this.onUpload&#125;
59
+ /&gt;
60
+ &lt;/div&gt;
61
+ );
62
+ &#125;
63
+ &#125;
64
+ </code></pre>
65
+ <p><strong>FilesDragAndDrop.js(非Hooks):</strong></p>
66
+ <pre><code>import React from &#39;react&#39;;
67
+ import PropTypes from &#39;prop-types&#39;;
68
+
69
+ import &#39;../../scss/components/Common/FilesDragAndDrop.scss&#39;;
70
+
71
+ export default class FilesDragAndDrop extends React.Component &#123;
72
+ static propTypes = &#123;
73
+ onUpload: PropTypes.func.isRequired,
74
+ &#125;;
75
+
76
+ render() &#123;
77
+ return (
78
+ &lt;div className=&#39;FilesDragAndDrop__area&#39;&gt;
79
+ 传下文件试试?
80
+ &lt;span
81
+ role=&#39;img&#39;
82
+ aria-label=&#39;emoji&#39;
83
+ className=&#39;area__icon&#39;
84
+ &gt;
85
+ &amp;#128526;
86
+ &lt;/span&gt;
87
+ &lt;/div&gt;
88
+ );
89
+ &#125;
90
+ &#125;
91
+ </code></pre>
92
+ <h3 id="1-如何改写为-Hooks-组件?"><a href="#1-如何改写为-Hooks-组件?" class="headerlink" title="1. 如何改写为 Hooks 组件?"></a>1. 如何改写为 Hooks 组件?</h3><p>请看动图:</p>
93
+ <p><img src="https://mmbiz.qpic.cn/mmbiz_gif/icnrNBicEhkVWy7FdrmvylE8IOtycZZGJQgAicXrRuE1Eb4ibsYScOcK2LR3g76GrVmSiah9SeBVaqRVYr1DUgpibaLg/640?wx_fmt=gif&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1" alt="xuehuayu.cn"><img src="https://mmbiz.qpic.cn/mmbiz_png/icnrNBicEhkVWy7FdrmvylE8IOtycZZGJQXQ53pH8bZakicdOqaNd4xUgrg8MayiaOoF8XrbC9foKU56fz9sTYkVIQ/640?wx_fmt=png&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="xuehuayu.cn"></p>
94
+ <h3 id="2-改写组件"><a href="#2-改写组件" class="headerlink" title="2. 改写组件"></a>2. 改写组件</h3><p><code>Hooks</code>版组件属于函数组件,将以上改造:</p>
95
+ <pre><code>import React, &#123; useEffect, useState, useRef &#125; from &quot;react&quot;;
96
+ import PropTypes from &#39;prop-types&#39;;
97
+ import classNames from &#39;classnames&#39;;
98
+ import classList from &#39;../../scss/components/Common/FilesDragAndDrop.scss&#39;;
99
+ const FilesDragAndDrop = (props) =&gt; &#123;
100
+ return (
101
+ &lt;div className=&#39;FilesDragAndDrop__area&#39;&gt;
102
+ 传下文件试试?
103
+ &lt;span
104
+ role=&#39;img&#39;
105
+ aria-label=&#39;emoji&#39;
106
+ className=&#39;area__icon&#39;
107
+ &gt;
108
+ &amp;#128526;
109
+ &lt;/span&gt;
110
+ &lt;/div&gt;
111
+ );
112
+ &#125;
113
+
114
+ FilesDragAndDrop.propTypes = &#123;
115
+ onUpload: PropTypes.func.isRequired,
116
+ children: PropTypes.node.isRequired,
117
+ count: PropTypes.number,
118
+ formats: PropTypes.arrayOf(PropTypes.string)
119
+ &#125;
120
+
121
+ export &#123; FilesDragAndDrop &#125;;
122
+ </code></pre>
123
+ <p><strong>FilesDragAndDrop.scss</strong></p>
124
+ <pre><code>.FilesDragAndDrop &#123;
125
+ .FilesDragAndDrop__area &#123;
126
+ width: 300px;
127
+ height: 200px;
128
+ padding: 50px;
129
+ display: flex;
130
+ align-items: center;
131
+ justify-content: center;
132
+ flex-flow: column nowrap;
133
+ font-size: 24px;
134
+ color: #555555;
135
+ border: 2px #c3c3c3 dashed;
136
+ border-radius: 12px;
137
+
138
+ .area__icon &#123;
139
+ font-size: 64px;
140
+ margin-top: 20px;
141
+ &#125;
142
+ &#125;
143
+ &#125;
144
+ </code></pre>
145
+ <p>然后就可以看到页面:</p>
146
+ <p><img src="https://mmbiz.qpic.cn/mmbiz_png/icnrNBicEhkVWy7FdrmvylE8IOtycZZGJQNLCxJec47zEGicU5fmTQFokLla9I8Qbdeh6hZ1pYUjnEmsBQq9jYgCQ/640?wx_fmt=png&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="xuehuayu.cn"></p>
147
+ <h2 id="2-实现分析"><a href="#2-实现分析" class="headerlink" title="2. 实现分析"></a>2. 实现分析</h2><p>从操作DOM、组件复用、事件触发、阻止默认行为、以及<code>Hooks</code>应用方面分析。</p>
148
+ <h3 id="1-操作DOM:useRef"><a href="#1-操作DOM:useRef" class="headerlink" title="1. 操作DOM:useRef"></a>1. 操作DOM:<code>useRef</code></h3><p>由于需要拖拽文件上传以及操作组件实例,需要用到<code>ref</code>属性。</p>
149
+ <p><code>React Hooks</code>中 新增了<code>useRef API</code><br><strong>语法</strong></p>
150
+ <pre><code>const refContainer = useRef(initialValue);
151
+ </code></pre>
152
+ <ul>
153
+ <li><p><code>useRef</code> 返回一个可变的 <code>ref</code> 对象,。</p>
154
+ </li>
155
+ <li><p>其 <strong>.current</strong> 属性被初始化为传递的参数(<code>initialValue</code>)</p>
156
+ </li>
157
+ <li><p>返回的对象将存留在整个组件的生命周期中。</p>
158
+ <p> …<br> const drop &#x3D; useRef();</p>
159
+ <p> return (<br> <div
160
+ ref={drop}
161
+ className='FilesDragAndDrop'
162
+ /><br> …<br> )</p>
163
+ </li>
164
+ </ul>
165
+ <h3 id="2-事件触发"><a href="#2-事件触发" class="headerlink" title="2. 事件触发"></a>2. 事件触发</h3><p><img src="https://mmbiz.qpic.cn/mmbiz_png/icnrNBicEhkVWy7FdrmvylE8IOtycZZGJQvnn30ACmFzc47kcxnB1awoxeUW2y9dicLSAQRrtiaBpp3tbaO1OLU4vQ/640?wx_fmt=png&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="xuehuayu.cn"><br>完成具有动态交互的拖拽行为并不简单,需要用到四个事件控制:</p>
166
+ <ul>
167
+ <li><p>区域外:<code>dragleave</code>, 离开范围</p>
168
+ </li>
169
+ <li><p>区域内:<code>dragenter</code>,用来确定放置目标是否接受放置。</p>
170
+ </li>
171
+ <li><p>区域内移动:<code>dragover</code>,用来确定给用户显示怎样的反馈信息</p>
172
+ </li>
173
+ <li><p>完成拖拽(落下):<code>drop</code>,允许放置对象。</p>
174
+ </li>
175
+ </ul>
176
+ <p>这四个事件并存,才能阻止 Web 浏览器默认行为和形成反馈。</p>
177
+ <h3 id="3-阻止默认行为"><a href="#3-阻止默认行为" class="headerlink" title="3. 阻止默认行为"></a>3. 阻止默认行为</h3><p>代码很简单:</p>
178
+ <pre><code>e.preventDefault() //阻止事件的默认行为(如在浏览器打开文件)
179
+ e.stopPropagation() // 阻止事件冒泡
180
+ </code></pre>
181
+ <p>每个事件阶段都需要阻止,为啥呢?举个🌰栗子:</p>
182
+ <pre><code>const handleDragOver = (e) =&gt; &#123;
183
+ // e.preventDefault();
184
+ // e.stopPropagation();
185
+ &#125;;
186
+ </code></pre>
187
+ <p><img src="https://mmbiz.qpic.cn/mmbiz_gif/icnrNBicEhkVWy7FdrmvylE8IOtycZZGJQV8pBwsn4AWqE1iaOLqCd8vLFqSvtMx9HnWUIZWoibrt0TPlIXeRNLz8Q/640?wx_fmt=gif&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1" alt="xuehuayu.cn"><br>不阻止的话,就会触发打开文件的行为,这显然不是我们想看到的。<br><img src="https://mmbiz.qpic.cn/mmbiz_png/icnrNBicEhkVWy7FdrmvylE8IOtycZZGJQIxsGsP5FOIn74o42lDBrbOkTiaT98lHpybXia0aXno00JlCTRkTNYFYA/640?wx_fmt=png&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="xuehuayu.cn"></p>
188
+ <h3 id="4-组件内部状态-useState"><a href="#4-组件内部状态-useState" class="headerlink" title="4. 组件内部状态: useState"></a>4. 组件内部状态: useState</h3><p>拖拽上传组件,除了基础的拖拽状态控制,还应有成功上传文件或未通过验证时的消息提醒。<br>状态组成应为:</p>
189
+ <pre><code>state = &#123;
190
+ dragging: false,
191
+ message: &#123;
192
+ show: false,
193
+ text: null,
194
+ type: null,
195
+ &#125;,
196
+ &#125;;
197
+ </code></pre>
198
+ <p>写成对应<code>useState</code>前先回归下写法:</p>
199
+ <pre><code>const [属性, 操作属性的方法] = useState(默认值);
200
+ </code></pre>
201
+ <p>于是便成了:</p>
202
+ <pre><code>const [dragging, setDragging] = useState(false);
203
+ const [message, setMessage] = useState(&#123; show: false, text: null, type: null &#125;);
204
+ </code></pre>
205
+ <h3 id="5-需要第二个叠加层"><a href="#5-需要第二个叠加层" class="headerlink" title="5. 需要第二个叠加层"></a>5. 需要第二个叠加层</h3><p>除了<code>drop</code>事件,另外三个事件都是动态变化的,而在拖动元素时,每隔 <code>350</code> 毫秒会触发 <code>dragover</code>事件。</p>
206
+ <p>此时就需要第二<code>ref</code>来统一控制。</p>
207
+ <p>所以全部的ref为:</p>
208
+ <pre><code>const drop = useRef(); // 落下层
209
+ const drag = useRef(); // 拖拽活动层
210
+ </code></pre>
211
+ <h3 id="6-文件类型、数量控制"><a href="#6-文件类型、数量控制" class="headerlink" title="6. 文件类型、数量控制"></a>6. 文件类型、数量控制</h3><p>我们在应用组件时,<code>prop</code>需要传入类型和数量来控制</p>
212
+ <pre><code>&lt;FilesDragAndDrop
213
+ onUpload=&#123;this.onUpload&#125;
214
+ count=&#123;1&#125;
215
+ formats=&#123;[&#39;jpg&#39;, &#39;png&#39;]&#125;
216
+ &gt;
217
+ &lt;div className=&#123;classList[&#39;FilesDragAndDrop__area&#39;]&#125;&gt;
218
+ 传下文件试试?
219
+ &lt;span
220
+ role=&#39;img&#39;
221
+ aria-label=&#39;emoji&#39;
222
+ className=&#123;classList[&#39;area__icon&#39;]&#125;
223
+ &gt;
224
+ &amp;#128526;
225
+ &lt;/span&gt;
226
+ &lt;/div&gt;
227
+ &lt;/FilesDragAndDrop&gt;
228
+ </code></pre>
229
+ <ul>
230
+ <li><p><code>onUpload</code>:拖拽完成处理事件</p>
231
+ </li>
232
+ <li><p><code>count</code>: 数量控制</p>
233
+ </li>
234
+ <li><p><code>formats</code>: 文件类型。</p>
235
+ </li>
236
+ </ul>
237
+ <p>对应的组件<code>Drop</code>内部事件:<code>handleDrop</code>:</p>
238
+ <pre><code>const handleDrop = (e) =&gt; &#123;
239
+ e.preventDefault();
240
+ e.stopPropagation();
241
+ setDragging(false)
242
+ const &#123; count, formats &#125; = props;
243
+ const files = [...e.dataTransfer.files];
244
+ if (count &amp;&amp; count &lt; files.length) &#123;
245
+ showMessage(`抱歉,每次最多只能上传$&#123;count&#125; 文件。`, &#39;error&#39;, 2000);
246
+ return;
247
+ &#125;
248
+ if (formats &amp;&amp; files.some((file) =&gt; !formats.some((format) =&gt; file.name.toLowerCase().endsWith(format.toLowerCase())))) &#123;
249
+ showMessage(`只允许上传 $&#123;formats.join(&#39;, &#39;)&#125;格式的文件`, &#39;error&#39;, 2000);
250
+ return;
251
+ &#125;
252
+ if (files &amp;&amp; files.length) &#123;
253
+ showMessage(&#39;成功上传!&#39;, &#39;success&#39;, 1000);
254
+ props.onUpload(files);
255
+ &#125;
256
+ &#125;;
257
+ </code></pre>
258
+ <blockquote>
259
+ <p><code>.endsWith</code>是判断字符串结尾,如:<code>&quot;abcd&quot;.endsWith(&quot;cd&quot;); // true</code></p>
260
+ </blockquote>
261
+ <p><code>showMessage</code>则是控制显示文本:</p>
262
+ <pre><code>const showMessage = (text, type, timeout) =&gt; &#123;
263
+ setMessage(&#123; show: true, text, type, &#125;)
264
+ setTimeout(() =&gt;
265
+ setMessage(&#123; show: false, text: null, type: null, &#125;,), timeout);
266
+ &#125;;
267
+ </code></pre>
268
+ <blockquote>
269
+ <p>需要触发定时器来回到初始状态</p>
270
+ </blockquote>
271
+ <h3 id="7-事件在生命周期里的触发与销毁"><a href="#7-事件在生命周期里的触发与销毁" class="headerlink" title="7. 事件在生命周期里的触发与销毁"></a>7. 事件在生命周期里的触发与销毁</h3><p>原本<code>EventListener</code>的事件需要在<code>componentDidMount</code>添加,在<code>componentWillUnmount</code>中销毁:</p>
272
+ <pre><code>componentDidMount () &#123;
273
+ this.drop.addEventListener(&#39;dragover&#39;, this.handleDragOver);
274
+ &#125;
275
+
276
+ componentWillUnmount () &#123;
277
+ this.drop.removeEventListener(&#39;dragover&#39;, this.handleDragOver);
278
+ &#125;
279
+ </code></pre>
280
+ <p>但<code>Hooks</code>中有内部操作方法和对应<code>useEffect</code>来取代上述两个生命周期</p>
281
+ <p><code>useEffect</code>示例:</p>
282
+ <pre><code>useEffect(() =&gt; &#123;
283
+ document.title = `You clicked $&#123;count&#125; times`;
284
+ &#125;, [count]); // 仅在 count 更改时更新
285
+ </code></pre>
286
+ <p>而 <strong>每个<code>effect</code>都可以返回一个清除函数。如此可以将添加(<code>componentDidMount</code>)和移除(<code>componentWillUnmount</code>) 订阅的逻辑放在一起。</strong></p>
287
+ <p>于是上述就可以写成:</p>
288
+ <pre><code>useEffect(() =&gt; &#123;
289
+ drop.current.addEventListener(&#39;dragover&#39;, handleDragOver);
290
+ return () =&gt; &#123;
291
+ drop.current.removeEventListener(&#39;dragover&#39;, handleDragOver);
292
+ &#125;
293
+ &#125;)
294
+ </code></pre>
295
+ <p><img src="https://mmbiz.qpic.cn/mmbiz_png/icnrNBicEhkVWy7FdrmvylE8IOtycZZGJQhAnat3eFjQCk8HYbx6yeDicJzZiatoQn9RcWL18yrTS2NVia4qERFBJSQ/640?wx_fmt=png&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="xuehuayu.cn"><br>这也太香了吧!!!</p>
296
+ <h2 id="3-完整代码:"><a href="#3-完整代码:" class="headerlink" title="3. 完整代码:"></a>3. 完整代码:</h2><p><strong><code>FilesDragAndDropHook.js</code>:</strong></p>
297
+ <pre><code>import React, &#123; useEffect, useState, useRef &#125; from &quot;react&quot;;
298
+ import PropTypes from &#39;prop-types&#39;;
299
+ import classNames from &#39;classnames&#39;;
300
+ import classList from &#39;../../scss/components/Common/FilesDragAndDrop.scss&#39;;
301
+
302
+ const FilesDragAndDrop = (props) =&gt; &#123;
303
+ const [dragging, setDragging] = useState(false);
304
+ const [message, setMessage] = useState(&#123; show: false, text: null, type: null &#125;);
305
+ const drop = useRef();
306
+ const drag = useRef();
307
+ useEffect(() =&gt; &#123;
308
+ // useRef 的 drop.current 取代了 ref 的 this.drop
309
+ drop.current.addEventListener(&#39;dragover&#39;, handleDragOver);
310
+ drop.current.addEventListener(&#39;drop&#39;, handleDrop);
311
+ drop.current.addEventListener(&#39;dragenter&#39;, handleDragEnter);
312
+ drop.current.addEventListener(&#39;dragleave&#39;, handleDragLeave);
313
+ return () =&gt; &#123;
314
+ drop.current.removeEventListener(&#39;dragover&#39;, handleDragOver);
315
+ drop.current.removeEventListener(&#39;drop&#39;, handleDrop);
316
+ drop.current.removeEventListener(&#39;dragenter&#39;, handleDragEnter);
317
+ drop.current.removeEventListener(&#39;dragleave&#39;, handleDragLeave);
318
+ &#125;
319
+ &#125;)
320
+ const handleDragOver = (e) =&gt; &#123;
321
+ e.preventDefault();
322
+ e.stopPropagation();
323
+ &#125;;
324
+
325
+ const handleDrop = (e) =&gt; &#123;
326
+ e.preventDefault();
327
+ e.stopPropagation();
328
+ setDragging(false)
329
+ const &#123; count, formats &#125; = props;
330
+ const files = [...e.dataTransfer.files];
331
+
332
+ if (count &amp;&amp; count &lt; files.length) &#123;
333
+ showMessage(`抱歉,每次最多只能上传$&#123;count&#125; 文件。`, &#39;error&#39;, 2000);
334
+ return;
335
+ &#125;
336
+
337
+ if (formats &amp;&amp; files.some((file) =&gt; !formats.some((format) =&gt; file.name.toLowerCase().endsWith(format.toLowerCase())))) &#123;
338
+ showMessage(`只允许上传 $&#123;formats.join(&#39;, &#39;)&#125;格式的文件`, &#39;error&#39;, 2000);
339
+ return;
340
+ &#125;
341
+
342
+ if (files &amp;&amp; files.length) &#123;
343
+ showMessage(&#39;成功上传!&#39;, &#39;success&#39;, 1000);
344
+ props.onUpload(files);
345
+ &#125;
346
+ &#125;;
347
+
348
+ const handleDragEnter = (e) =&gt; &#123;
349
+ e.preventDefault();
350
+ e.stopPropagation();
351
+ e.target !== drag.current &amp;&amp; setDragging(true)
352
+ &#125;;
353
+
354
+ const handleDragLeave = (e) =&gt; &#123;
355
+ e.preventDefault();
356
+ e.stopPropagation();
357
+ e.target === drag.current &amp;&amp; setDragging(false)
358
+ &#125;;
359
+
360
+ const showMessage = (text, type, timeout) =&gt; &#123;
361
+ setMessage(&#123; show: true, text, type, &#125;)
362
+ setTimeout(() =&gt;
363
+ setMessage(&#123; show: false, text: null, type: null, &#125;,), timeout);
364
+ &#125;;
365
+
366
+ return (
367
+ &lt;div
368
+ ref=&#123;drop&#125;
369
+ className=&#123;classList[&#39;FilesDragAndDrop&#39;]&#125;
370
+ &gt;
371
+ &#123;message.show &amp;&amp; (
372
+ &lt;div
373
+ className=&#123;classNames(
374
+ classList[&#39;FilesDragAndDrop__placeholder&#39;],
375
+ classList[`FilesDragAndDrop__placeholder--$&#123;message.type&#125;`],
376
+ )&#125;
377
+ &gt;
378
+ &#123;message.text&#125;
379
+ &lt;span
380
+ role=&#39;img&#39;
381
+ aria-label=&#39;emoji&#39;
382
+ className=&#123;classList[&#39;area__icon&#39;]&#125;
383
+ &gt;
384
+ &#123;message.type === &#39;error&#39; ? &lt;&gt;&amp;#128546;&lt;/&gt; : &lt;&gt;&amp;#128536;&lt;/&gt;&#125;
385
+ &lt;/span&gt;
386
+ &lt;/div&gt;
387
+ )&#125;
388
+ &#123;dragging &amp;&amp; (
389
+ &lt;div
390
+ ref=&#123;drag&#125;
391
+ className=&#123;classList[&#39;FilesDragAndDrop__placeholder&#39;]&#125;
392
+ &gt;
393
+ 请放手
394
+ &lt;span
395
+ role=&#39;img&#39;
396
+ aria-label=&#39;emoji&#39;
397
+ className=&#123;classList[&#39;area__icon&#39;]&#125;
398
+ &gt;
399
+ &amp;#128541;
400
+ &lt;/span&gt;
401
+ &lt;/div&gt;
402
+ )&#125;
403
+ &#123;props.children&#125;
404
+ &lt;/div&gt;
405
+ );
406
+ &#125;
407
+
408
+ FilesDragAndDrop.propTypes = &#123;
409
+ onUpload: PropTypes.func.isRequired,
410
+ children: PropTypes.node.isRequired,
411
+ count: PropTypes.number,
412
+ formats: PropTypes.arrayOf(PropTypes.string)
413
+ &#125;
414
+
415
+ export &#123; FilesDragAndDrop &#125;;
416
+ </code></pre>
417
+ <p><strong><code>App.js</code>:</strong></p>
418
+ <pre><code>import React, &#123; Component &#125; from &#39;react&#39;;
419
+ import &#123; FilesDragAndDrop &#125; from &#39;../components/Common/FilesDragAndDropHook&#39;;
420
+ import classList from &#39;../scss/components/Common/FilesDragAndDrop.scss&#39;;
421
+
422
+ export default class App extends Component &#123;
423
+ onUpload = (files) =&gt; &#123;
424
+ console.log(files);
425
+ &#125;;
426
+ render () &#123;
427
+ return (
428
+ &lt;FilesDragAndDrop
429
+ onUpload=&#123;this.onUpload&#125;
430
+ count=&#123;1&#125;
431
+ formats=&#123;[&#39;jpg&#39;, &#39;png&#39;, &#39;gif&#39;]&#125;
432
+ &gt;
433
+ &lt;div className=&#123;classList[&#39;FilesDragAndDrop__area&#39;]&#125;&gt;
434
+ 传下文件试试?
435
+ &lt;span
436
+ role=&#39;img&#39;
437
+ aria-label=&#39;emoji&#39;
438
+ className=&#123;classList[&#39;area__icon&#39;]&#125;
439
+ &gt;
440
+ &amp;#128526;
441
+ &lt;/span&gt;
442
+ &lt;/div&gt;
443
+ &lt;/FilesDragAndDrop&gt;
444
+ )
445
+ &#125;
446
+ &#125;
447
+ </code></pre>
448
+ <p><strong><code>FilesDragAndDrop.scss</code>:</strong></p>
449
+ <pre><code>.FilesDragAndDrop &#123;
450
+ position: relative;
451
+
452
+ .FilesDragAndDrop__placeholder &#123;
453
+ position: absolute;
454
+ top: 0;
455
+ left: 0;
456
+ right: 0;
457
+ bottom: 0;
458
+ width: 100%;
459
+ height: 100%;
460
+ z-index: 9999;
461
+ display: flex;
462
+ align-items: center;
463
+ justify-content: center;
464
+ flex-flow: column nowrap;
465
+ background-color: #e7e7e7;
466
+ border-radius: 12px;
467
+ color: #7f8e99;
468
+ font-size: 24px;
469
+ opacity: 1;
470
+ text-align: center;
471
+ line-height: 1.4;
472
+
473
+ &amp;.FilesDragAndDrop__placeholder--error &#123;
474
+ background-color: #f7e7e7;
475
+ color: #cf8e99;
476
+ &#125;
477
+
478
+ &amp;.FilesDragAndDrop__placeholder--success &#123;
479
+ background-color: #e7f7e7;
480
+ color: #8ecf99;
481
+ &#125;
482
+
483
+ .area__icon &#123;
484
+ font-size: 64px;
485
+ margin-top: 20px;
486
+ &#125;
487
+ &#125;
488
+ &#125;
489
+
490
+ .FilesDragAndDrop__area &#123;
491
+ width: 300px;
492
+ height: 200px;
493
+ padding: 50px;
494
+ display: flex;
495
+ align-items: center;
496
+ justify-content: center;
497
+ flex-flow: column nowrap;
498
+ font-size: 24px;
499
+ color: #555555;
500
+ border: 2px #c3c3c3 dashed;
501
+ border-radius: 12px;
502
+
503
+ .area__icon &#123;
504
+ font-size: 64px;
505
+ margin-top: 20px;
506
+ &#125;
507
+ &#125;
508
+ </code></pre>
509
+ <p>然后你就可以拿到文件慢慢耍了。。。<br><img src="https://mmbiz.qpic.cn/mmbiz_gif/icnrNBicEhkVWy7FdrmvylE8IOtycZZGJQhT1icqPQAzib5H0T9ibfvH6dU2jflFBH2SoLibtPDIbj0EfRHGz7xGmXUQ/640?wx_fmt=gif&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1" alt="xuehuayu.cn"><img src="https://mmbiz.qpic.cn/mmbiz_png/icnrNBicEhkVWy7FdrmvylE8IOtycZZGJQMfg7iaWrzllyv91xXqjL5hGicjMsM8M5kicw3YBMkwAtGDZD8cswZFjrQ/640?wx_fmt=png&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="xuehuayu.cn"></p>
510
+ </div><iframe src="/donate/?AliPayQR=https://store.xuehuayu.cn/store/public/alipay_qr.jpg&amp;WeChatQR=https://store.xuehuayu.cn/store/public/wechat_qr.png&amp;UnionPayQR=null&amp;GitHub=null&amp;BTCQR=null&amp;BTCKEY=null&amp;PayPal=https://www.paypal.com/paypalme/OrdinaryPerson" style="overflow-x:hidden; overflow-y:hidden; border:0xp none #fff; min-height:240px; width:100%;" frameborder="0" scrolling="no"></iframe><div><ul class="post-copyright"><li class="post-copyright-author"><strong>本文作者:</strong>雪花雨</li><li class="post-copyright-link"><strong>本文链接:</strong><a href="/article/402.html">https://xuehuayu.cn/article/402.html</a></li><li class="post-copyright-license"><strong>版权声明:</strong>① 标为原创的文章为博主原创,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接。② 转载文章来自网络,已标明出处,<a href="mailto:cainiaoblog@126.com">侵删</a>。</li></ul></div><br><div class="tags"><a href="/tags/%E8%BD%AC%E8%BD%BD/">转载</a></div><div class="post-nav"><a class="pre" href="/article/35397.html">React 开发人员应该掌握的 22 种神奇工具</a><a class="next" href="/article/25318.html">可能是最全的 文本溢出截断省略 方案合集</a></div><div id="vcomment"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@waline/client@v2/dist/waline.min.css"><script src="//cdn.jsdelivr.net/npm/@waline/client@v2/dist/waline.js"></script><script>const origin = window.location.origin
511
+ const serverURL = origin.includes('cainiaoblog') ? 'https://cmts.cainiaoblog.cn' : 'https://cmts.xuehuayu.cn'
512
+ const locale = {
513
+ placeholder: '请正确填写昵称和邮箱,方便接收回复通知~',
514
+ sofa: '沙发空缺中,还不快抢~',
515
+ };
516
+ Waline.init({
517
+ el: '#vcomment',
518
+ serverURL: serverURL,
519
+ pageSize: '20',
520
+ visitor: true, // 阅读量统计
521
+ requiredMeta: ['nick', 'mail'],
522
+ emoji: [
523
+ 'https://cdn.jsdelivr.net/gh/walinejs/emojis@1.0.0/weibo',
524
+ 'https://cdn.jsdelivr.net/gh/walinejs/emojis@1.0.0/qq',
525
+ 'https://cdn.jsdelivr.net/gh/walinejs/emojis@1.0.0/tw-emoji',
526
+ ],
527
+ locale,
528
+ pageview: true
529
+ })
530
+ </script></div></div></div><div class="pure-u-1 pure-u-md-1-4 fixed-search hidden_mid_and_down"><div id="sidebar"><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/search.min.js"></script><div class="widget"><div class="widget-search"><input class="search" type="radio" name="search" value="baidu" id="baidu" checked="checked"/><label class="label" for="baidu" title="百度全站搜索">百度</label><input class="search" type="radio" name="search" value="google" id="google"/><label class="label" for="google" title="谷歌全站搜索">谷歌</label><input class="search" type="radio" name="search" value="self" id="self"/><label class="label" for="self" title="使用站内搜索">站内</label></div><div class="widget" id="search"><form class="search-form" action="//www.baidu.com/baidu" method="get" accept-charset="utf-8" target="_blank"><input type="search" name="word" maxlength="30" placeholder="百度全站搜索"/><input type="hidden" name="si" value="xuehuayu.cn"/><input type="hidden" name="cl" value="3"/><input type="hidden" name="ct" value="2097152"/><input type="hidden" name="s" value="on"/><input class="search-submit" type="submit" value=""/></form></div></div><script>$('input[type=radio][name=search]').change(function() {
531
+ var val = $(this).val()
532
+ var self = '<div class="search-form"><input id="local-search-input" placeholder="站内搜索,首次慢" type="search" name="q" results="0"><input class="search-submit" type="submit" value=""/><div id="local-search-result"></div></div>'
533
+ var google = '<form class="search-form" action="//www.google.com/search" method="get" accept-charset="utf-8" target="_blank"><input type="search" name="q" maxlength="30" placeholder="谷歌全站搜索"><input type="hidden" name="sitesearch" value="xuehuayu.cn"><input class="search-submit" type="submit" value=""/></form>'
534
+ var baidu = '<form class="search-form" action="//www.baidu.com/baidu" method="get" accept-charset="utf-8" target="_blank"><input type="search" name="word" maxlength="30" placeholder="百度全站搜索"><input type="hidden" name="si" value="xuehuayu.cn"><input type="hidden" name="cl" value="3"><input type="hidden" name="ct" value="2097152"><input type="hidden" name="s" value="on"><input class="search-submit" type="submit" value=""/></form>'
535
+
536
+ if (val === 'self') {
537
+ $('#search').html(self)
538
+ var search_path = 'search.xml';
539
+ if (search_path.length == 0) {
540
+ search_path = 'search.xml';
541
+ }
542
+ var path = 'https://cdn.staticaly.com/gh/npljy/npljy.github.io/main/' + search_path;
543
+ searchFunc(path, 'local-search-input', 'local-search-result');
544
+ } else if (val === 'baidu') {
545
+ $('#search').html(baidu)
546
+ } else if (val === 'google') {
547
+ $('#search').html(google)
548
+ }
549
+ })</script><div class="widget widget-wxmp"><img alt="微信公众号" width="100%" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/mp-mini.jpg"/></div><div class="widget widget-categories"><div class="widget-title"><i class="fa fa-folder-o"> 分类</i></div><ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/CDN/">CDN</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/IDE/">IDE</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/git/">git</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/hexo/">hexo</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%85%AC%E5%85%B1%E8%8A%82%E6%97%A5/">公共节日</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%88%86%E4%BA%AB/">分享</a><span class="category-list-count">29</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%89%8D%E7%AB%AF/">前端</a><span class="category-list-count">191</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%89%8D%E7%AB%AF/%E6%B5%8F%E8%A7%88%E5%99%A8/">浏览器</a><span class="category-list-count">1</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%89%8D%E7%AB%AF/%E6%B5%8F%E8%A7%88%E5%99%A8/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE/">网络协议</a><span class="category-list-count">1</span></li></ul></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%8D%9A%E5%AE%A2/">博客</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%B7%A5%E5%85%B7/">工具</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%B9%BF%E5%91%8A%E8%BF%87%E6%BB%A4/">广告过滤</a><span class="category-list-count">8</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%B9%BF%E5%91%8A%E8%BF%87%E6%BB%A4/%E8%A7%86%E9%A2%91%E7%94%B5%E8%A7%86%E5%B0%8F%E8%AF%B4%E6%BC%AB%E7%94%BB%E8%B5%84%E8%AE%AF%E9%9F%B3%E4%B9%90/">视频电视小说漫画资讯音乐</a><span class="category-list-count">2</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E6%AD%A3%E5%88%99/">正则</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E6%B5%8F%E8%A7%88%E5%99%A8/">浏览器</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E7%AE%97%E6%B3%95/">算法</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E8%B5%84%E8%AE%AF/">资讯</a><span class="category-list-count">16</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E8%BD%BB%E6%9D%BE%E4%B8%80%E5%88%BB/">轻松一刻</a><span class="category-list-count">1</span></li></ul></div><div class="widget widget-tags"><div class="widget-title"><i class="fa fa-star-o"> 标签</i></div><div class="tagcloud"><a href="/tags/%E5%8E%9F%E5%88%9B/" style="font-size: 15px;">原创</a> <a href="/tags/%E8%BD%AC%E8%BD%BD/" style="font-size: 15px;">转载</a> <a href="/tags/%E6%89%8B%E5%86%99/" style="font-size: 15px;">手写</a> <a href="/tags/%E7%96%AB%E6%83%85/" style="font-size: 15px;">疫情</a> <a href="/tags/%E5%A8%B1%E4%B9%90/" style="font-size: 15px;">娱乐</a></div></div><div class="widget widget-recent-posts"><div class="widget-title"><i class="fa fa-file-o"> 最近文章</i></div><ul class="post-list"><li class="post-list-item"><a class="post-list-link" href="/article/c5576490.html">面试准备</a></li><li class="post-list-item"><a class="post-list-link" href="/article/84c9ccd6.html">精读《SolidJS》</a></li><li class="post-list-item"><a class="post-list-link" href="/article/53803e6.html">git提交注释规范</a></li><li class="post-list-item"><a class="post-list-link" href="/article/a4145266.html">前端数组拍平flat一行代码</a></li><li class="post-list-item"><a class="post-list-link" href="/article/bedea419.html">一道前端this面试题</a></li><li class="post-list-item"><a class="post-list-link" href="/article/bf7e7421.html">git多账号配置</a></li></ul></div><div class="widget widget-links"><div class="widget-title"><i class="fa fa-external-link"> 友情链接</i></div><ul></ul><a href="https://github.com/npljy?utm_source=xuehuayu.cn" title="GitHub" target="_blank">GitHub</a><ul></ul><a href="https://laonongmin.online?utm_source=xuehuayu.cn" title="看看" target="_blank">看看</a><ul></ul><a href="https://cainiaoblog.cn?utm_source=xuehuayu.cn" title="菜鸟博客" target="_blank">菜鸟博客</a><ul></ul><a href="mailto:cainiaoblog@126.com" title="友链联系" target="_blank">友链联系</a></div></div></div><div class="pure-u-1 pure-u-md-3-4"><div id="footer"><div class="flex-block justify-center align-center flex-wrap"><a class="gxba-link" id="gxba" rel="nofollow" target="_blank" href="http://beian.miit.gov.cn/">京ICP备20007647号-2</a><a class="gaba-link" id="gaba-link" rel="nofollow" target="_blank" href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=11010802031264"><img class="nofancybox" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/gaba.png" alt=""/><span id="gaba">京公网安备 11010802031264号</span><span style="padding-right: 10px;"></span></a><span>Copyright © 2023 </span><a href="/." rel="nofollow">前端壹菜鸟. </a><script>(function(){
550
+ var cnb =window.location.origin.indexOf('cainiaoblog') !==-1
551
+ if (cnb) {
552
+ var gxba =document.getElementById('gxba')
553
+ var gaba =document.getElementById('gaba')
554
+ var gabaLink =document.getElementById('gaba-link')
555
+ gxba.innerText ='京ICP备20007647号-1'
556
+ gaba.innerText ='京公网安备 11010802031254号'
557
+ gabaLink.setAttribute('href','http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=11010802031254')
558
+ }
559
+ })()</script></div><div class="flex-block justify-center align-center flex-wrap"><a rel="nofollow" target="_blank" href="https://v6.51.la/s/Guz3lwHCsVme9Cu"><div class="busuanzi_container" id="busuanzi_container"><span class="busuanzi_container_site_pv" id="busuanzi_container_site_pv">访问量:<span id="busuanzi_value_site_pv"><i class="fa fa-spinner"></i></span></span><span class="busuanzi_container_site_uv" id="busuanzi_container_site_uv">访客数:<span id="busuanzi_value_site_uv"><i class="fa fa-spinner"></i></span></span><span style="padding-right: 10px;"></span></div></a><a rel="nofollow" target="_blank" href="https://www.upyun.com/?utm_source=lianmeng&amp;utm_medium=referral"><span style="font-weight:bold;letter-spacing: 1px;">本网站由 </span><img class="nofancybox" height="32" style="vertical-align: middle" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/upy_logo.min.svg" alt=""/><span style="font-weight:bold;letter-spacing: 1px;">提供CDN加速/云存储服务</span></a><span style="padding-right: 10px;"></span><a rel="nofollow" style="font-size:18px;font-weight:bold;vertical-align: middle" target="_blank" title="注册就送代金券可直接使用" href="https://console.upyun.com/register/?invite=HyDsjZHIL">注册</a></div></div></div></div><a class="show" id="rocket" href="#top"></a><div class="darkmode-toggle">🌓</div><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/totop.min.js" async></script><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/dark.min.js" async></script><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/codeblock-resizer.min.js"></script><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/smartresize.min.js"></script></div></body></html>