纯CSS菜单样式,及其Shadow DOM,Json接口 实现

先声明,要看懂这篇博客要求你具备少量基础CSS知识,

当然如果你只是要用的话就随便了,不用了解任何知识

 

先放一张效果图
         

 

Part 1:纯CSS菜单样式

先放样式代码

  1 <style>
  2   *:focus{outline:none}
  3   menu{
  4     display:none;
  5     position:absolute;
  6     margin-top:0;
  7     top:0;
  8     margin-left:0;
  9     left:0;
 10     margin-right:0;
 11     right:0;
 12     height:21px;
 13     padding-left:1px;
 14     white-space:nowrap;
 15     background-color:#f0f0f0;
 16     user-select:none;
 17     cursor:default;
 18     }
 19   menu item{
 20     display:inline-block;
 21     padding:3px 6px 2px 6px;
 22     font-size:12px;
 23     vertical-align:top;
 24   }
 25   menu submenu{
 26     position:absolute;
 27     display:none;
 28     width:auto;
 29     margin-left:-6px;
 30     background-color:#fff;
 31     font-size:16px;
 32     box-shadow:1px 1px 16px #aaa;
 33   }
 34   menu item:hover{background-color:#ddd}
 35   menu:focus item:hover submenu{display:block}
 36   menu delims{display:inline;position:absolute;margin:-2px 2px}
 37   menu submenu item{display:block;width:auto}
 38   menu submenu label{display:block;margin:-4px 4px}
 39   menu submenu hr{display:inline-block;width:100%;margin:0}
 40   menu input{display:inline-block;width:0}
 41   menu span{display:inline-block;margin-left:-6px}
 42   menu span + span{margin-left:6px}
 43   menu submenu span + span{padding:6px}
 44   menu input + span{width:9px}
 45   menu input[used]:checked + span::before{content:"\2713"}
 46   menu label::after{
 47     float:right;
 48     margin: 0 8px 0 16px;
 49     padding:5px;
 50     color:gray;
 51     content:attr(description);
 52     }
 53   menu label:hover::after{color:#000}
 54   :host(.show) menu{display:block}
 55   :host(.night) menu{color:#eee;background-color:#2d2d30}
 56   :host(.night) menu item:hover{background-color:#555}
 57   :host(.night) menu delims{color:#aaa}
 58   :host(.night) menu submenu{background-color:#2d2d30;box-shadow:1px 1px 16px #fff}
 59   :host(.night) menu label::after{color:#fff}
 60   menu span + span + span{display:none}
 61   :host(.EN) menu span + span{display:none}
 62   :host(.EN) menu span + span + span{display:inline-block}
 63   :host(.EN) menu label:after{content:attr(EN-description)}
 64   :host(.english) menu span + span{display:none}
 65   :host(.english) menu span + span + span{display:inline-block}
 66   :host(.english) menu label:after{content:attr(EN-description)}
 67 </style>
 68 
 69 <menu tabindex="0" oncontextmenu="return false">
 70   <item style="">
 71     <span></span>
 72     <span>文件(F)</span>
 73     <span>File(F)</span>
 74     <submenu>
 75       <item style="" onmouseup="">
 76         <label description="Ctrl+N" en-description="Ctrl+N">
 77           <input type="checkbox">
 78           <span></span>
 79           <span>新建文件</span>
 80           <span>New File</span>
 81         </label>
 82       </item>
 83       <item style="" onmouseup="{}">
 84         <label description="Alt+N" en-description="Alt+N">
 85           <input type="checkbox">
 86           <span></span>
 87           <span>新建项目</span>
 88           <span>New Project</span>
 89         </label>
 90       </item>
 91       <hr>
 92       <item style="" onmouseup="{}">
 93         <label description="Ctrl+O" en-description="Ctrl+O">
 94           <input type="checkbox">
 95           <span></span>
 96           <span>打开文件</span>
 97           <span>Open File</span>
 98         </label>
 99       </item>
100       <item style="" onmouseup="{}">
101         <label description="Alt+O" en-description="Alt+O">
102           <input type="checkbox">
103           <span></span>
104           <span>打开文件夹</span>
105           <span>Open Folder</span>
106         </label>
107       </item>
108       <item style="" onmouseup="{}">
109         <label description="Shift+O" en-description="Shift+O">
110           <input type="checkbox">
111           <span></span>
112           <span>导入云端项目</span>
113           <span>Open Cloud Project</span>
114         </label>
115       </item>
116       <item style="" onmouseup="{}">
117         <label description="Shift+G" en-description="Shift+G">
118           <input type="checkbox">
119           <span></span>
120           <span>导入github项目</span>
121           <span>Open Github Project</span>
122         </label>
123       </item>
124       <item style="" onmouseup="{}">
125         <label description="Shift+Alt+O" en-description="Shift+Alt+O">
126           <input type="checkbox">
127           <span></span>
128           <span>导入其他云项目</span>
129           <span>Open Other Cloud Project</span>
130         </label>
131       </item>
132       <hr>
133       <item style="" onmouseup="{}">
134         <label description="Ctrl+S" en-description="Ctrl+S">
135           <input type="checkbox">
136           <span></span>
137           <span>本地保存</span>
138           <span>Save Locally</span>
139         </label>
140       </item>
141       <item style="" onmouseup="{}">
142         <label description="Shift+S" en-description="Shift+S">
143           <input type="checkbox">
144           <span></span>
145           <span>云端保存</span>
146           <span>Save to Cloud</span>
147         </label>
148       </item>
149       <item style="" onmouseup="{}">
150         <label description="Shift+Alt+S" en-description="Shift+Alt+S">
151           <input type="checkbox">
152           <span></span>
153           <span>保存为模板</span>
154           <span>Save As Template</span>
155         </label>
156       </item>
157       <hr>
158       <item style="" onmouseup="{}">
159         <label description="即时云端缓存代码" en-description="Instant cloud caching code">
160           <input type="checkbox" used="">
161           <span></span>
162           <span>禁用数据同步</span>
163           <span>forbidden DS</span>
164         </label>
165       </item>
166       <hr>
167       <item style="" onmouseup="{}">
168         <label description="Alt+S" en-description="Alt+S">
169           <input type="checkbox">
170           <span></span>
171           <span>设置</span>
172           <span>Settings</span>
173         </label>
174       </item>
175       <hr>
176       <item style="" onmouseup="{}">
177         <label description="Shift+Z" en-description="Shift+Z">
178           <input type="checkbox">
179           <span></span>
180           <span>还原云端文件</span>
181           <span>Recovery File From Cloud</span>
182         </label>
183       </item>
184       <item style="" onmouseup="{}">
185         <label description="Ctrl+F4" en-description="Ctrl+F4">
186           <input type="checkbox">
187           <span></span>
188           <span>关闭文件</span>
189           <span>Close File</span>
190         </label>
191       </item>
192       <item style="" onmouseup="{}">
193         <label description="Ctrl+Shift+F4" en-description="Ctrl+Shift+F4">
194           <input type="checkbox">
195           <span></span>
196           <span>关闭文件夹</span>
197           <span>Close Folder</span>
198         </label>
199       </item>
200       <item style="" onmouseup="{}">
201         <label description="Ctrl+Alt+F4" en-description="Ctrl+Alt+F4">
202           <input type="checkbox">
203           <span></span>
204           <span>关闭项目</span>
205           <span>Close Project</span>
206         </label>
207       </item>
208       <hr>
209       <item style="" onmouseup="{}">
210         <label description="Shift+Alt+F4" en-description="Shift+Alt+F4">
211           <input type="checkbox">
212           <span></span>
213           <span>退出</span>
214           <span>Exit</span>
215         </label>
216       </item>
217     </submenu>
218   </item>
219   <item style="">
220     <span></span>
221     <span>编辑(E)</span>
222     <span>Edit(E)</span>
223     <submenu>
224       <item style="" onmouseup="{}">
225         <label description="Ctrl+Z" en-description="Ctrl+Z">
226           <input type="checkbox">
227           <span></span>
228           <span>撤销</span>
229           <span>Undo</span>
230         </label>
231       </item>
232       <item style="" onmouseup="{}">
233         <label description="Ctrl+Y" en-description="Ctrl+Y">
234           <input type="checkbox">
235           <span></span>
236           <span>重做</span>
237           <span>Redo</span>
238         </label>
239       </item>
240       <hr>
241       <item style="" onmouseup="{}">
242         <label description="Ctrl+X" en-description="Ctrl+X">
243           <input type="checkbox">
244           <span></span>
245           <span>剪切</span>
246           <span>Cut</span>
247         </label>
248       </item>
249       <item style="" onmouseup="{}">
250         <label description="Ctrl+C" en-description="Ctrl+C">
251           <input type="checkbox">
252           <span></span>
253           <span>复制</span>
254           <span>Copy</span>
255         </label>
256       </item>
257       <item style="" onmouseup="{}">
258         <label description="Ctrl+V" en-description="Ctrl+V">
259           <input type="checkbox">
260           <span></span>
261           <span>粘贴</span>
262           <span>Paste</span>
263         </label>
264       </item>
265       <hr>
266       <item style="" onmouseup="{}">
267         <label description="Ctrl+A" en-description="Ctrl+A">
268           <input type="checkbox">
269           <span></span>
270           <span>全选</span>
271           <span>Select All</span>
272         </label>
273       </item>
274       <hr>
275       <item style="" onmouseup="{}">
276         <label description="" en-description="">
277           <input type="checkbox">
278           <span></span>
279           <span>"Ctrl+单击"跳转到定义</span>
280           <span>"Ctrl+Click"Jump to definition</span>
281         </label>
282       </item>
283       <item style="" onmouseup="{}">
284         <label description="" en-description="">
285           <input type="checkbox" used="">
286           <span></span>
287           <span>"Alt+单击"进行多光标功能</span>
288           <span>"Ctrl+Click"Multiple Cursors For Edit</span>
289         </label>
290       </item>
291       <hr>
292       <item style="" onmouseup="{}">
293         <label description="Ctrl+F" en-description="Ctrl+F">
294           <input type="checkbox">
295           <span></span>
296           <span>查找</span>
297           <span>Find</span>
298         </label>
299       </item>
300       <item style="" onmouseup="{}">
301         <label description="Ctrl+H" en-description="Ctrl+H">
302           <input type="checkbox">
303           <span></span>
304           <span>替换</span>
305           <span>Replace</span>
306         </label>
307       </item>
308       <hr>
309       <item style="" onmouseup="{}">
310         <label description="Ctrl+Shift+F" en-description="Ctrl+Shift+F">
311           <input type="checkbox">
312           <span></span>
313           <span>打开文件中查找</span>
314           <span>Find in Opened Files</span>
315         </label>
316       </item>
317       <item style="" onmouseup="{}">
318         <label description="Ctrl+Shift+H" en-description="Ctrl+Shift+H">
319           <input type="checkbox">
320           <span></span>
321           <span>打开文件中替换</span>
322           <span>Replace in Opened Files</span>
323         </label>
324       </item>
325       <item style="" onmouseup="{}">
326         <label description="Ctrl+Alt+F" en-description="Ctrl+Alt+F">
327           <input type="checkbox">
328           <span></span>
329           <span>所有文件中查找</span>
330           <span>Find in All Files</span>
331         </label>
332       </item>
333       <item style="" onmouseup="{}">
334         <label description="Ctrl+Alt+H" en-description="Ctrl+Alt+H">
335           <input type="checkbox">
336           <span></span>
337           <span>所有文件中替换</span>
338           <span>Replace in All Files</span>
339         </label>
340       </item>
341       <hr>
342       <item style="" onmouseup="{}">
343         <label description="Ctrl+/" en-description="Ctrl+/">
344           <input type="checkbox">
345           <span></span>
346           <span>切换行注释</span>
347           <span>Toggle line Comment</span>
348         </label>
349       </item>
350       <item style="" onmouseup="{}">
351         <label description="Ctrl+." en-description="Ctrl+.">
352           <input type="checkbox">
353           <span></span>
354           <span>切换块注释</span>
355           <span>Toggle Block Comment</span>
356         </label>
357       </item>
358       <hr>
359       <item style="" onmouseup="{}">
360         <label description="Ctrl+M" en-description="Ctrl+M">
361           <input type="checkbox">
362           <span></span>
363           <span>代码格式化</span>
364           <span>Code Formatter</span>
365         </label>
366       </item>
367       <item style="" onmouseup="{}">
368         <label description="Ctrl+J" en-description="Ctrl+J">
369           <input type="checkbox">
370           <span></span>
371           <span>全部折叠</span>
372           <span>Collapse All</span>
373         </label>
374       </item>
375       <item style="" onmouseup="{}">
376         <label description="Ctrl+K" en-description="Ctrl+K">
377           <input type="checkbox">
378           <span></span>
379           <span>全部展开</span>
380           <span>Uncollapse All</span>
381         </label>
382       </item>
383     </submenu>
384   </item>
385   <item style="">
386     <span></span>
387     <span>视图(V)</span>
388     <span>View(V)</span>
389     <submenu>
390       <item style="" onmouseup="{}">
391         <label description="Alt+C" en-description="Alt+C">
392           <input type="checkbox">
393           <span></span>
394           <span>命令面板</span>
395           <span>Command Panel</span>
396         </label>
397       </item>
398       <item style="" onmouseup="{}">
399         <label description="Alt+X" en-description="Alt+X">
400           <input type="checkbox">
401           <span></span>
402           <span>打开视图</span>
403           <span>View Panel</span>
404         </label>
405       </item>
406       <hr>
407       <item style="" onmouseup="{}">
408         <label description="F3" en-description="F3">
409           <input type="checkbox">
410           <span></span>
411           <span>搜索文件</span>
412           <span>Search File</span>
413         </label>
414       </item>
415       <item style="" onmouseup="{}">
416         <label description="Shift+T" en-description="Shift+T">
417           <input type="checkbox">
418           <span></span>
419           <span>源代码管理</span>
420           <span>Source Code Manager</span>
421         </label>
422       </item>
423       <item style="" onmouseup="{}">
424         <label description="Alt+T" en-description="Alt+T">
425           <input type="checkbox">
426           <span></span>
427           <span>资源管理器</span>
428           <span>Resource Manager</span>
429         </label>
430       </item>
431       <item style="" onmouseup="{}">
432         <label description="Alt+Y" en-description="Alt+Y">
433           <input type="checkbox">
434           <span></span>
435           <span>代码定义</span>
436           <span>Code definition Show</span>
437         </label>
438       </item>
439       <item style="" onmouseup="{}">
440         <label description="Alt+U" en-description="Alt+U">
441           <input type="checkbox">
442           <span></span>
443           <span>调试面板</span>
444           <span>Debug Panel</span>
445         </label>
446       </item>
447       <item style="" onmouseup="{}">
448         <label description="F12" en-description="F12">
449           <input type="checkbox">
450           <span></span>
451           <span>拓展</span>
452           <span>Extension</span>
453         </label>
454       </item>
455       <hr>
456       <item style="" onmouseup="{}">
457         <label description="Alt+J" en-description="Alt+J">
458           <input type="checkbox">
459           <span></span>
460           <span>输出</span>
461           <span>Output</span>
462         </label>
463       </item>
464       <item style="" onmouseup="{}">
465         <label description="Alt+K" en-description="Alt+K">
466           <input type="checkbox">
467           <span></span>
468           <span>问题</span>
469           <span>Problem</span>
470         </label>
471       </item>
472       <item style="" onmouseup="{}">
473         <label description="Alt+L" en-description="Alt+L">
474           <input type="checkbox">
475           <span></span>
476           <span>调试控制台</span>
477           <span>Debug Console</span>
478         </label>
479       </item>
480       <item style="" onmouseup="{}">
481         <label description="Alt+`" en-description="Alt+`">
482           <input type="checkbox">
483           <span></span>
484           <span>集成终端</span>
485           <span>Integrated Terminal</span>
486         </label>
487       </item>
488       <hr>
489       <item style="" onmouseup="{}">
490         <label description="F11" en-description="F11">
491           <input type="checkbox">
492           <span></span>
493           <span>切换全屏</span>
494           <span>Toggle Fullscreen</span>
495         </label>
496       </item>
497       <item style="" onmouseup="{}">
498         <label description="Alt+Shift+M" en-description="Alt+Shift+M">
499           <input type="checkbox">
500           <span></span>
501           <span>切换菜单栏</span>
502           <span>Toggle Menu</span>
503         </label>
504       </item>
505       <hr>
506       <item style="" onmouseup="{}">
507         <label description="Alt+Shift+Z" en-description="Alt+Shift+Z">
508           <input type="checkbox">
509           <span></span>
510           <span>切换活动栏</span>
511           <span>Toggle Activity Panel</span>
512         </label>
513       </item>
514       <item style="" onmouseup="{}">
515         <label description="Alt+Shift+X" en-description="Alt+Shift+X">
516           <input type="checkbox">
517           <span></span>
518           <span>切换侧边栏</span>
519           <span>Toggle Aside Panel</span>
520         </label>
521       </item>
522       <item style="" onmouseup="{}">
523         <label description="Alt+Shift+C" en-description="Alt+Shift+C">
524           <input type="checkbox">
525           <span></span>
526           <span>切换侧边栏左右位置</span>
527           <span>Toggle Aside Panel Left Or Right</span>
528         </label>
529       </item>
530       <item style="" onmouseup="{}">
531         <label description="Alt+Shift+V" en-description="Alt+Shift+V">
532           <input type="checkbox">
533           <span></span>
534           <span>切换输出控制台</span>
535           <span>Toggle Output Console</span>
536         </label>
537       </item>
538       <item style="" onmouseup="{}">
539         <label description="Alt+Shift+B" en-description="Alt+Shift+B">
540           <input type="checkbox">
541           <span></span>
542           <span>切换状态栏</span>
543           <span>Toggle Status Bar</span>
544         </label>
545       </item>
546       <hr>
547       <item style="" onmouseup="{}">
548         <label description="Alt+\" en-description="Alt+\">
549           <input type="checkbox">
550           <span></span>
551           <span>拆分编辑器</span>
552           <span>Split Editor</span>
553         </label>
554       </item>
555       <item style="" onmouseup="{}">
556         <label description="Alt+Q" en-description="Alt+Q">
557           <input type="checkbox">
558           <span></span>
559           <span>切换小窗口</span>
560           <span>Toggle Small Window</span>
561         </label>
562       </item>
563     </submenu>
564   </item>
565   <item style="">
566     <span></span>
567     <span>运行(R)</span>
568     <span>Run(R)</span>
569     <submenu>
570       <item style="" onmouseup="{}">
571         <label description="F8" en-description="F8">
572           <input type="checkbox">
573           <span></span>
574           <span>编译</span>
575           <span>Compile</span>
576         </label>
577       </item>
578       <item style="" onmouseup="{}">
579         <label description="F9" en-description="F9">
580           <input type="checkbox">
581           <span></span>
582           <span>运行</span>
583           <span>Run</span>
584         </label>
585       </item>
586       <item style="" onmouseup="{}">
587         <label description="F10" en-description="F10">
588           <input type="checkbox">
589           <span></span>
590           <span>编译运行</span>
591           <span>Compile And Run</span>
592         </label>
593       </item>
594       <hr>
595       <item style="" onmouseup="{}">
596         <label description="Alt+A" en-description="Alt+A">
597           <input type="checkbox">
598           <span></span>
599           <span>性能分析</span>
600           <span>Performance analysis</span>
601         </label>
602       </item>
603       <hr>
604       <item style="" onmouseup="{}">
605         <label description="F5" en-description="F5">
606           <input type="checkbox">
607           <span></span>
608           <span>调试</span>
609           <span>Debug</span>
610         </label>
611       </item>
612       <item style="" onmouseup="{}">
613         <label description="F6" en-description="F6">
614           <input type="checkbox">
615           <span></span>
616           <span>停止调试</span>
617           <span>Stop Debug</span>
618         </label>
619       </item>
620       <item style="" onmouseup="{}">
621         <label description="F7" en-description="F7">
622           <input type="checkbox">
623           <span></span>
624           <span>添加断点</span>
625           <span>Add Breakpoint</span>
626         </label>
627       </item>
628       <item style="" onmouseup="{}">
629         <label description="Shift+Q" en-description="Shift+Q">
630           <input type="checkbox">
631           <span></span>
632           <span>下一条语句</span>
633           <span>Next Command</span>
634         </label>
635       </item>
636       <item style="" onmouseup="{}">
637         <label description="Shift+W" en-description="Shift+W">
638           <input type="checkbox">
639           <span></span>
640           <span>下一行</span>
641           <span>Next Line</span>
642         </label>
643       </item>
644       <item style="" onmouseup="{}">
645         <label description="Shift+E" en-description="Shift+E">
646           <input type="checkbox" used="">
647           <span></span>
648           <span>继续</span>
649           <span>Continue</span>
650         </label>
651       </item>
652       <hr>
653       <item style="" onmouseup="{}">
654         <label description="Shift+\" en-description="Shift+\">
655           <input type="checkbox">
656           <span></span>
657           <span>提交调试信息</span>
658           <span>Push debug information</span>
659         </label>
660       </item>
661     </submenu>
662   </item>
663   <item style="">
664     <span></span>
665     <span>帮助(H)</span>
666     <span>Help(H)</span>
667     <submenu>
668       <item style="" onmouseup="{}">
669         <label description="F1" en-description="F1">
670           <input type="checkbox">
671           <span></span>
672           <span>交互教程</span>
673           <span>Interactive Tutorials</span>
674         </label>
675       </item>
676       <item style="" onmouseup="{}">
677         <label description="Alt+D" en-description="Alt+D">
678           <input type="checkbox">
679           <span></span>
680           <span>说明文档</span>
681           <span>Description document</span>
682         </label>
683       </item>
684       <item style="" onmouseup="{}">
685         <label description="Alt+B" en-description="Alt+B">
686           <input type="checkbox">
687           <span></span>
688           <span>发行说明</span>
689           <span>Issuance Instructions</span>
690         </label>
691       </item>
692       <hr>
693       <item style="" onmouseup="{}">
694         <label description="Alt+/" en-description="Alt+/">
695           <input type="checkbox">
696           <span></span>
697           <span>关于</span>
698           <span>About</span>
699         </label>
700       </item>
701     </submenu>
702   </item>
703 </menu>
View Code

忽然发现这个并不是纯CSS版本,这是我封装后生成的代码,因为我没有保存,又懒得再打,就用这个讲吧

不过我会分析代码,相信你认真看完完全可以自己打一个纯CSS版本的菜单

当然,如果你复制粘贴运行,会发现没有显示,哈哈,只要令menu的display为block即可,至于为什么要不显示,是我开发中需要这个拓展,就不提了;

纯css版本是怎么运行的呢,无非利用Focus,hover控制menu显示与否,

既如下代码

<style>
Submenu{display:none}
item:hover Submenu{display:block}
</style>

<menu>
<item>
菜单项
<submenu>子菜单项</submenu>
</item>
</menu>

显然就是把鼠标放在菜单项上时显示子菜单

好吧,别着急,别着急,我知道这些你都知道了,那我们就讲讲菜单要什么功能,及其关键代码吧。

首先,肯定不能像这样鼠标放上去就显示子菜单,(有些人喜欢自动显示的,但是,我们这里讲普通菜单),既点击后显示。

然后点击一个菜单项,显示其子菜单,移到另外一个菜单项时,不用点击就自动显示其子菜单,原来的子菜单关闭

菜单可能包括check属性,

(我承认,我这里漏了一些东西,比如鼠标离开菜单,最后一个子菜单应该保持显示,还有为什么我的菜单还可以换语言和颜色,我们先不提,的确有些事我们没有做到,但都是不影响使用的,或者需要之后ShadowDOM知识的)

首先是,点击菜单,显示,点击子菜单项或其他东西,隐藏,

第一种方法

我们在其外面加一个label ,旁边加一个checkbox,

<label><input type="checkbox">###menu###</label>

这样我们就可以通过点击菜单,控制input的check属性,再利用CSS的属性选择器"[ ]"和兄弟选择器"+"即可控制子菜单的显示

<style>
input[check] + menu > submenu{display:block}
</style>

,另外还要隐藏checkbox,这是网上常见的写法

不过,你觉不觉得好麻烦,嗯,我也这样觉得,所以我们还有另外的写法,就是利用Focus,

“什么?不是只有form元素像input才能获得焦点吗”,如果你对html一知半解或者缺乏开发经验你会这样想,

但是我们只要利用一个参数 tabindex即可

对,就是这个参数,原来用来控制Tab导航顺序,事实上,只要赋值0,就可以让任何元素具备被聚焦的能力,尝试运行以下代码

<style>
menu submenu{display:none}
menu:focus item:hover submenu{display:block}
</style>
<menu tabindex="0">
<item>
菜单项1
<submenu>子菜单</submenu>
</item>
<item>
菜单项2
<submenu>子菜单</submenu>
</item>
</menu>

 发现已经做到点击显示,随便还实现了移动到其余菜单项自动显示子菜单的功能

 不过focus到的元素都有outline,只要menu {outline:none}即可,

另外位置不对,因为他们属于同一个流,要脱离文档流,submenu {position:absolute}

“等等,你又说漏一个” ,什么你又发现了?好吧,点击子菜单项之后菜单没有消失。我承认我现在没有办法,

“什么呀。。原来白看这么久吗?”, 等等,别走,再看一句,我下面就有办法了。先实现下面一个功能。

菜单check属性,也很简单,记得我们第一种实现点击显示的方法吗

我们只要让它们display为inline-block,在让他们处于同一个div层,就成为一个带checkbox的菜单项不过。。。这也太丑了吧

 快让它消失,让它成为可设置宽度的inline-block再把宽度设为0

menu input{display:inline-block;width:0}

好的它不见了

我们的样式

menu input[used]:checked + span::before{content:"\2713"}
 menu span{display:inline-block;margin-left:-6px}
 menu input + span{width:9px}

嗯?这个used是什么,废话,不是所有的菜单项都会有check属性啊,used是我随便取得一个变量名,用来标记

保持所有的checkbox以控制菜单整齐,以used属性标记是否显示check状态,实现了部分菜单的check属性

然后,讲完了这个,刚才漏的离开隐藏的实现呢?

记得label将焦点转移给checkbox吗?现在每个子菜单项都有checkbox了,只要submenu的每个item内部套一个label即可

终上所述一个CSS原生菜单样式出现了,

果然还是要再打一遍代码吗!!!要累死我了

        <style>
          *:focus{outline:none}
                    menu{
            display:none;
            position:absolute;
            margin-top:0;
            top:0;
            margin-left:0;
            left:0;
            margin-right:0;
            right:0;
            height:21px;
            padding-left:1px;
            white-space:nowrap;
            background-color:#f0f0f0;
            user-select:none;
            cursor:default;
            }
          menu item{
            display:inline-block;
            padding:3px 6px 2px 6px;
            font-size:12px;
            vertical-align:top;
          }
          menu submenu{
            position:absolute;
            display:none;
            width:auto;
            margin-left:-6px;
            background-color:#fff;
            font-size:16px;
            box-shadow:1px 1px 16px #aaa;
          }
          menu item:hover{background-color:#ddd}
          menu:focus item:hover submenu{display:block}
                    menu delims{display:inline;position:absolute;margin:-2px 2px}
          menu submenu item{display:block;width:auto}
          menu submenu label{display:block;margin:-4px 4px}
          menu submenu hr{display:inline-block;width:100%;margin:0}
          menu input{display:inline-block;width:0}
          menu span{display:inline-block;margin-left:-6px}
          menu span + span{margin-left:6px}
          menu submenu span + span{padding:6px}
          menu input + span{width:9px}
          menu input[used]:checked + span::before{content:"\2713"}
</style>

<menu tabindex="0" oncontextmenu="return false">
  <item>
    <span></span>
    <span>文件(F)</span>
    <submenu>
      <item>
        <label>
          <input type="checkbox">
          <span></span>
          <span>新建文件</span>
        </label>
      </item>
      <item>
        <label>
          <input type="checkbox">
          <span></span>
          <span>新建项目</span>
        </label>
      </item>
      <hr>
      <item>
        <label>
          <input type="checkbox">
          <span></span>
          <span>打开文件</span>
        </label>
      </item>
      <item>
        <label>
          <input type="checkbox">
          <span></span>
          <span>打开文件夹</span>
        </label>
      </item>
      <item>
        <label>
          <input type="checkbox">
          <span></span>
          <span>导入云端项目</span>
        </label>
      </item>
    </submenu>
  </item>
  <item>
    <span></span>
    <span>编辑(E)</span>
    <submenu>
      <item>
        <label>
          <input type="checkbox">
          <span></span>
          <span>撤销</span>
        </label>
      </item>
      <item>
        <label>
          <input type="checkbox">
          <span></span>
          <span>重做</span>
        </label>
      </item>
      <hr>
      <item>
        <label>
          <input type="checkbox">
          <span></span>
          <span>剪切</span>
        </label>
      </item>
    </submenu>
  </item>
</menu>

效果

 

看得见虽然并没有我最开始的那个菜单那么完美,没有变色,没有提示词,没有换语言,但是已经很好看了

Part 2: Shadow DOM

 我们只讲,谈它怎么样只是浪费彼此时间,毕竟我支持ShadowDOM,就一句话“不错”
      let shadow = menuParentElement.attachShadow({ mode: 'open' });
      shadow.innerHTML = style;
      shadow.appendChild(menu); 

这就是我的代码引用shadow的代码,现在只有通过shadow或menuParentElement.shadowRoot才能访问内部,外界其他其他方法都与它无关了

如果mode的值是close就彻底不能修改内部的值了,

我们上面是生成一个菜单项(参考Part1)append进去;于是封装了;

但是ShadowDOM真的只是这样吗?我们的变色,换语言呢?

事实上现在我在ShadowDOM外部留了开关,就是通过:host()选择器;

 

ShadowDOM的内部CSS才能使用的选择器,可以判断外部父元素的值

比如 :host(.night) menu{}就确定了当外部Class 包括"night"时的 menu样式

我上面的换语言和变色都是写好的CSS通过添加删除class(打开关闭,开关)实现的。

<style>
          menu label:hover::after{color:#000}
          :host(.show) menu{display:block}
          :host(.night) menu{color:#eee;background-color:#2d2d30}
          :host(.night) menu item:hover{background-color:#555}
                    :host(.night) menu delims{color:#aaa}
          :host(.night) menu submenu{background-color:#2d2d30;box-shadow:1px 1px 16px #fff}
          :host(.night) menu label::after{color:#fff}
          menu span + span + span{display:none}
          :host(.EN) menu span + span{display:none}
          :host(.EN) menu span + span + span{display:inline-block}
          :host(.EN) menu label:after{content:attr(EN-description)}
          :host(.english) menu span + span{display:none}
          :host(.english) menu span + span + span{display:inline-block}
          :host(.english) menu label:after{content:attr(EN-description)}
</style>

 

至于Json接口

  function createMenu(menuParentElement, menuItemJson, useShadowDOM) {
    let menu = 0;
    let style = 0;
    if (!arguments[3]) {
      menu = document.createElement("menu");
      menu.setAttribute("tabindex", "0");
      menu.setAttribute("oncontextmenu", "return false");
      style = () => {/*
        <style>

        </style>
      */};
      style = style.toString().split(/\n/).slice(1, -1).join('\n');
    } else {
      menu = document.createElement("submenu");
    }
    for (let i = 0; i < menuItemJson.length; i++) {
      if (menuItemJson[i]["label"] == "delims") {
        if (arguments[3]) { menu.appendChild(document.createElement("hr")); }
        else { menu.innerHTML += "<delims>|</delims>" }
      } else if (menuItemJson[i]["submenu"]) {
        if (!menuItemJson[i]["label"]) {
          menu.style.visibility = "hidden";
          createMenu(menu, menuItemJson[i]["submenu"], false, true);
          menu.children[0].setAttribute("tabindex", "0");
          menu.children[0].style.visibility = "visible";
          menu.children[0].style.display = "block";
        } else {
          let item = document.createElement("item");
          item.style = menuItemJson[i]["style"];
          item.innerHTML += `<span></span><span>${menuItemJson[i]["label"]}</span><span>${menuItemJson[i]["EN-label"]?menuItemJson[i]["EN-label"]:menuItemJson[i]["label"]}</span>`;
          createMenu(item, menuItemJson[i]["submenu"], false, true);
          menu.appendChild(item);
        }
      } else {
        menu.innerHTML += `<item style="${menuItemJson[i]["style"] ? menuItemJson[i]["style"] : ""}" onmouseup="${menuItemJson[i]["function"]}"><label description="${menuItemJson[i]["description"] ? menuItemJson[i]["description"] : ""}" EN-description="${menuItemJson[i]["EN-description"] ? menuItemJson[i]["EN-description"] : (menuItemJson[i]["description"] ? menuItemJson[i]["description"] : "")}"><input type="checkbox" ${menuItemJson[i]["checkable"] ? "used" : ""}><span></span><span>${menuItemJson[i]["label"] ? menuItemJson[i]["label"] : ""}</span><span>${menuItemJson[i]["EN-label"] ? menuItemJson[i]["EN-label"] : (menuItemJson[i]["label"] ? menuItemJson[i]["label"] : "")}</span></label></item>`;
      }
    }
    if (useShadowDOM) {
      let shadow = menuParentElement.attachShadow({ mode: 'open' });
      shadow.innerHTML = style;
      shadow.appendChild(menu);
      return menu;
    } else {
      if (!arguments[3]) menuParentElement.innerHTML = style;
      menuParentElement.appendChild(menu);
    }
  }

比较普通,不过整个组件都不需要引入其他库,打算利用onmouseup 直接运行函数 广播事件 ,然后根据事件运行函数。

上面有三个可以注意的点

1.正则表达式避免拼接大段字符串

      style = () => {/*
        <style>
        #######
        </style>
      */};
    style = style.toString().split(/\n/).slice(1, -1).join('\n');
 

2.字符串中${ }可插入表达式和变量

"############${menuItemJson[i]["style"] ? menuItemJson[i]["style"] : ""}###############"

3.函数变量arguments,函数的参数变量名是可有可无的(勿喷)

function a(){
return arguments[0]
}
b=1;
c=a(b)//1

 

Menu之外的话题

1.fetch真好用,如果你还在使用ajax,快放弃它(麻烦,或者依赖时代毒瘤Jq)

fetch一句话调用实例(注意传递的都是Promise)

fetch('menu.json').then((e) => e.json()).then((e) =>console.log(e));

 //我使用Json传输,是为了延迟动态加载,提高主页面的加载速度

 

2.

我们使用ShadowDOM都是先封装进去,后来直接用

不过,其实ShadowDOM内容也并非只能有封装进去的值

就是利用Tamplate的Slot

我们封装进去一个带Slot的template,父元素里对应的slot就可以插入模板并显示出来,

涉及Custom Element,Shadow DOM 

由于我没有用这个功能,我贴下MDN的代码

/*js*/
customElements.define('element-details',
  class extends HTMLElement {
    constructor() {
      super();
      const template = document
        .getElementById('element-details-template')
        .content;
      const shadowRoot = this.attachShadow({mode: 'open'})
        .appendChild(template.cloneNode(true));
  }
});
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>element-details - web component using &lt;template&gt; and &lt;slot&gt;</title>
    <style>
      dl { margin-left: 6px; }
      dt { font-weight: bold; color: #217ac0; font-size: 110% }
      dt { font-family: Consolas, "Liberation Mono", Courier }
      dd { margin-left: 16px }
    </style>
  </head>
  <body>
    <h1>element-details - web component using <code>&lt;template&gt;</code> and <code>&lt;slot&gt;</code></h1>

    <template id="element-details-template">
      <style>
      details {font-family: "Open Sans Light",Helvetica,Arial}
      .name {font-weight: bold; color: #217ac0; font-size: 120%}
      h4 { margin: 10px 0 -8px 0; }
      h4 span { background: #217ac0; padding: 2px 6px 2px 6px }
      h4 span { border: 1px solid #cee9f9; border-radius: 4px }
      h4 span { color: white }
      .attributes { margin-left: 22px; font-size: 90% }
      .attributes p { margin-left: 16px; font-style: italic }
      </style>
      <details>
        <summary>
          <span>
            <code class="name">&lt;<slot name="element-name">NEED NAME</slot>&gt;</code>
            <i class="desc"><slot name="description">NEED DESCRIPTION</slot></i>
          </span>
        </summary>
        <div class="attributes">
          <h4><span>Attributes</span></h4>
          <slot name="attributes"><p>None</p></slot>
        </div>
      </details>
      <hr>
    </template>

    <element-details>
      <span slot="element-name">slot</span>
      <span slot="description">A placeholder inside a web
        component that users can fill with their own markup,
        with the effect of composing different DOM trees
        together.</span>
      <dl slot="attributes">
        <dt>name</dt>
        <dd>The name of the slot.</dd>
      </dl>
    </element-details>

    <element-details>
      <span slot="element-name">template</span>
      <span slot="description">A mechanism for holding client-
        side content that is not to be rendered when a page is
        loaded but may subsequently be instantiated during
        runtime using JavaScript.</span>
    </element-details>

    <script src="main.js"></script>
  </body>
</html>

 效果

 

好的,你应该可以打出自己的Menu组件了,当然我也不介意你使用我的代码

 补充:使用customElement来写每个菜单子项也不错

关于上面我所有的代码如果有问题请联系我

或者你有更好的方法也请不吝赐教。

愿意交流我也随时恭候。

期待我的下篇博客就收藏吧

 
posted @ 2018-04-28 22:28  轻风Blog  阅读(695)  评论(0编辑  收藏  举报