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

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

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

 

先放一张效果图
纯CSS菜单样式,及其Shadow DOM,Json接口 实现_第1张图片         
纯CSS菜单样式,及其Shadow DOM,Json接口 实现_第2张图片

 

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 Filespan>
 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 Projectspan>
 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 Filespan>
 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 Folderspan>
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 Projectspan>
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 Projectspan>
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 Projectspan>
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 Locallyspan>
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 Cloudspan>
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 Templatespan>
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 DSspan>
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>Settingsspan>
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 Cloudspan>
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 Filespan>
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 Folderspan>
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 Projectspan>
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>Exitspan>
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>Undospan>
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>Redospan>
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>Cutspan>
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>Copyspan>
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>Pastespan>
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 Allspan>
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 definitionspan>
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 Editspan>
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>Findspan>
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>Replacespan>
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 Filesspan>
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 Filesspan>
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 Filesspan>
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 Filesspan>
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 Commentspan>
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 Commentspan>
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 Formatterspan>
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 Allspan>
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 Allspan>
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 Panelspan>
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 Panelspan>
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 Filespan>
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 Managerspan>
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 Managerspan>
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 Showspan>
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 Panelspan>
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>Extensionspan>
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>Outputspan>
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>Problemspan>
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 Consolespan>
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 Terminalspan>
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 Fullscreenspan>
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 Menuspan>
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 Panelspan>
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 Panelspan>
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 Rightspan>
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 Consolespan>
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 Barspan>
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 Editorspan>
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 Windowspan>
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>Compilespan>
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>Runspan>
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 Runspan>
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 analysisspan>
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>Debugspan>
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 Debugspan>
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 Breakpointspan>
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 Commandspan>
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 Linespan>
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>Continuespan>
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 informationspan>
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 Tutorialsspan>
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 documentspan>
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 Instructionsspan>
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>Aboutspan>
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即可

纯CSS菜单样式,及其Shadow DOM,Json接口 实现_第3张图片

对,就是这个参数,原来用来控制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>

效果

纯CSS菜单样式,及其Shadow DOM,Json接口 实现_第4张图片

 

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

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 += "|" }
      } 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>${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 <template> and <slot>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><template>code> and <code><slot>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"><<slot name="element-name">NEED NAMEslot>>code>
            <i class="desc"><slot name="description">NEED DESCRIPTIONslot>i>
          span>
        summary>
        <div class="attributes">
          <h4><span>Attributesspan>h4>
          <slot name="attributes"><p>Nonep>slot>
        div>
      details>
      <hr>
    template>

    <element-details>
      <span slot="element-name">slotspan>
      <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>namedt>
        <dd>The name of the slot.dd>
      dl>
    element-details>

    <element-details>
      <span slot="element-name">templatespan>
      <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>

 效果

纯CSS菜单样式,及其Shadow DOM,Json接口 实现_第5张图片

 

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

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

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

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

愿意交流我也随时恭候。

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

 

转载于:https://www.cnblogs.com/CrossGod/p/CSS_Menu_And_It-s_Shadow_Dom_Json_Realization.html

你可能感兴趣的:(纯CSS菜单样式,及其Shadow DOM,Json接口 实现)