先声明,要看懂这篇博客要求你具备少量基础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 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>
忽然发现这个并不是纯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"}
嗯?这个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
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>
效果
好的,你应该可以打出自己的Menu组件了,当然我也不介意你使用我的代码
补充:使用customElement来写每个菜单子项也不错
关于上面我所有的代码如果有问题请联系我
或者你有更好的方法也请不吝赐教。
愿意交流我也随时恭候。
期待我的下篇博客就收藏吧