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

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

先放一张效果图
         

Part 1:纯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"}
menu label::after{
float:right;
margin: 0 8px 0 16px;
padding:5px;
color:gray;
content:attr(description);
}
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> <menu tabindex="0" oncontextmenu="return false">
<item style="">
<span></span>
<span>文件(F)</span>
<span>File(F)</span>
<submenu>
<item style="" onmouseup="">
<label description="Ctrl+N" en-description="Ctrl+N">
<input type="checkbox">
<span></span>
<span>新建文件</span>
<span>New File</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Alt+N" en-description="Alt+N">
<input type="checkbox">
<span></span>
<span>新建项目</span>
<span>New Project</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="Ctrl+O" en-description="Ctrl+O">
<input type="checkbox">
<span></span>
<span>打开文件</span>
<span>Open File</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Alt+O" en-description="Alt+O">
<input type="checkbox">
<span></span>
<span>打开文件夹</span>
<span>Open Folder</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Shift+O" en-description="Shift+O">
<input type="checkbox">
<span></span>
<span>导入云端项目</span>
<span>Open Cloud Project</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Shift+G" en-description="Shift+G">
<input type="checkbox">
<span></span>
<span>导入github项目</span>
<span>Open Github Project</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Shift+Alt+O" en-description="Shift+Alt+O">
<input type="checkbox">
<span></span>
<span>导入其他云项目</span>
<span>Open Other Cloud Project</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="Ctrl+S" en-description="Ctrl+S">
<input type="checkbox">
<span></span>
<span>本地保存</span>
<span>Save Locally</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Shift+S" en-description="Shift+S">
<input type="checkbox">
<span></span>
<span>云端保存</span>
<span>Save to Cloud</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Shift+Alt+S" en-description="Shift+Alt+S">
<input type="checkbox">
<span></span>
<span>保存为模板</span>
<span>Save As Template</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="即时云端缓存代码" en-description="Instant cloud caching code">
<input type="checkbox" used="">
<span></span>
<span>禁用数据同步</span>
<span>forbidden DS</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="Alt+S" en-description="Alt+S">
<input type="checkbox">
<span></span>
<span>设置</span>
<span>Settings</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="Shift+Z" en-description="Shift+Z">
<input type="checkbox">
<span></span>
<span>还原云端文件</span>
<span>Recovery File From Cloud</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Ctrl+F4" en-description="Ctrl+F4">
<input type="checkbox">
<span></span>
<span>关闭文件</span>
<span>Close File</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Ctrl+Shift+F4" en-description="Ctrl+Shift+F4">
<input type="checkbox">
<span></span>
<span>关闭文件夹</span>
<span>Close Folder</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Ctrl+Alt+F4" en-description="Ctrl+Alt+F4">
<input type="checkbox">
<span></span>
<span>关闭项目</span>
<span>Close Project</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="Shift+Alt+F4" en-description="Shift+Alt+F4">
<input type="checkbox">
<span></span>
<span>退出</span>
<span>Exit</span>
</label>
</item>
</submenu>
</item>
<item style="">
<span></span>
<span>编辑(E)</span>
<span>Edit(E)</span>
<submenu>
<item style="" onmouseup="{}">
<label description="Ctrl+Z" en-description="Ctrl+Z">
<input type="checkbox">
<span></span>
<span>撤销</span>
<span>Undo</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Ctrl+Y" en-description="Ctrl+Y">
<input type="checkbox">
<span></span>
<span>重做</span>
<span>Redo</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="Ctrl+X" en-description="Ctrl+X">
<input type="checkbox">
<span></span>
<span>剪切</span>
<span>Cut</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Ctrl+C" en-description="Ctrl+C">
<input type="checkbox">
<span></span>
<span>复制</span>
<span>Copy</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Ctrl+V" en-description="Ctrl+V">
<input type="checkbox">
<span></span>
<span>粘贴</span>
<span>Paste</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="Ctrl+A" en-description="Ctrl+A">
<input type="checkbox">
<span></span>
<span>全选</span>
<span>Select All</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="" en-description="">
<input type="checkbox">
<span></span>
<span>"Ctrl+单击"跳转到定义</span>
<span>"Ctrl+Click"Jump to definition</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="" en-description="">
<input type="checkbox" used="">
<span></span>
<span>"Alt+单击"进行多光标功能</span>
<span>"Ctrl+Click"Multiple Cursors For Edit</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="Ctrl+F" en-description="Ctrl+F">
<input type="checkbox">
<span></span>
<span>查找</span>
<span>Find</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Ctrl+H" en-description="Ctrl+H">
<input type="checkbox">
<span></span>
<span>替换</span>
<span>Replace</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="Ctrl+Shift+F" en-description="Ctrl+Shift+F">
<input type="checkbox">
<span></span>
<span>打开文件中查找</span>
<span>Find in Opened Files</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Ctrl+Shift+H" en-description="Ctrl+Shift+H">
<input type="checkbox">
<span></span>
<span>打开文件中替换</span>
<span>Replace in Opened Files</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Ctrl+Alt+F" en-description="Ctrl+Alt+F">
<input type="checkbox">
<span></span>
<span>所有文件中查找</span>
<span>Find in All Files</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Ctrl+Alt+H" en-description="Ctrl+Alt+H">
<input type="checkbox">
<span></span>
<span>所有文件中替换</span>
<span>Replace in All Files</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="Ctrl+/" en-description="Ctrl+/">
<input type="checkbox">
<span></span>
<span>切换行注释</span>
<span>Toggle line Comment</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Ctrl+." en-description="Ctrl+.">
<input type="checkbox">
<span></span>
<span>切换块注释</span>
<span>Toggle Block Comment</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="Ctrl+M" en-description="Ctrl+M">
<input type="checkbox">
<span></span>
<span>代码格式化</span>
<span>Code Formatter</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Ctrl+J" en-description="Ctrl+J">
<input type="checkbox">
<span></span>
<span>全部折叠</span>
<span>Collapse All</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Ctrl+K" en-description="Ctrl+K">
<input type="checkbox">
<span></span>
<span>全部展开</span>
<span>Uncollapse All</span>
</label>
</item>
</submenu>
</item>
<item style="">
<span></span>
<span>视图(V)</span>
<span>View(V)</span>
<submenu>
<item style="" onmouseup="{}">
<label description="Alt+C" en-description="Alt+C">
<input type="checkbox">
<span></span>
<span>命令面板</span>
<span>Command Panel</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Alt+X" en-description="Alt+X">
<input type="checkbox">
<span></span>
<span>打开视图</span>
<span>View Panel</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="F3" en-description="F3">
<input type="checkbox">
<span></span>
<span>搜索文件</span>
<span>Search File</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Shift+T" en-description="Shift+T">
<input type="checkbox">
<span></span>
<span>源代码管理</span>
<span>Source Code Manager</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Alt+T" en-description="Alt+T">
<input type="checkbox">
<span></span>
<span>资源管理器</span>
<span>Resource Manager</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Alt+Y" en-description="Alt+Y">
<input type="checkbox">
<span></span>
<span>代码定义</span>
<span>Code definition Show</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Alt+U" en-description="Alt+U">
<input type="checkbox">
<span></span>
<span>调试面板</span>
<span>Debug Panel</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="F12" en-description="F12">
<input type="checkbox">
<span></span>
<span>拓展</span>
<span>Extension</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="Alt+J" en-description="Alt+J">
<input type="checkbox">
<span></span>
<span>输出</span>
<span>Output</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Alt+K" en-description="Alt+K">
<input type="checkbox">
<span></span>
<span>问题</span>
<span>Problem</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Alt+L" en-description="Alt+L">
<input type="checkbox">
<span></span>
<span>调试控制台</span>
<span>Debug Console</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Alt+`" en-description="Alt+`">
<input type="checkbox">
<span></span>
<span>集成终端</span>
<span>Integrated Terminal</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="F11" en-description="F11">
<input type="checkbox">
<span></span>
<span>切换全屏</span>
<span>Toggle Fullscreen</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Alt+Shift+M" en-description="Alt+Shift+M">
<input type="checkbox">
<span></span>
<span>切换菜单栏</span>
<span>Toggle Menu</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="Alt+Shift+Z" en-description="Alt+Shift+Z">
<input type="checkbox">
<span></span>
<span>切换活动栏</span>
<span>Toggle Activity Panel</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Alt+Shift+X" en-description="Alt+Shift+X">
<input type="checkbox">
<span></span>
<span>切换侧边栏</span>
<span>Toggle Aside Panel</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Alt+Shift+C" en-description="Alt+Shift+C">
<input type="checkbox">
<span></span>
<span>切换侧边栏左右位置</span>
<span>Toggle Aside Panel Left Or Right</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Alt+Shift+V" en-description="Alt+Shift+V">
<input type="checkbox">
<span></span>
<span>切换输出控制台</span>
<span>Toggle Output Console</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Alt+Shift+B" en-description="Alt+Shift+B">
<input type="checkbox">
<span></span>
<span>切换状态栏</span>
<span>Toggle Status Bar</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="Alt+\" en-description="Alt+\">
<input type="checkbox">
<span></span>
<span>拆分编辑器</span>
<span>Split Editor</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Alt+Q" en-description="Alt+Q">
<input type="checkbox">
<span></span>
<span>切换小窗口</span>
<span>Toggle Small Window</span>
</label>
</item>
</submenu>
</item>
<item style="">
<span></span>
<span>运行(R)</span>
<span>Run(R)</span>
<submenu>
<item style="" onmouseup="{}">
<label description="F8" en-description="F8">
<input type="checkbox">
<span></span>
<span>编译</span>
<span>Compile</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="F9" en-description="F9">
<input type="checkbox">
<span></span>
<span>运行</span>
<span>Run</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="F10" en-description="F10">
<input type="checkbox">
<span></span>
<span>编译运行</span>
<span>Compile And Run</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="Alt+A" en-description="Alt+A">
<input type="checkbox">
<span></span>
<span>性能分析</span>
<span>Performance analysis</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="F5" en-description="F5">
<input type="checkbox">
<span></span>
<span>调试</span>
<span>Debug</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="F6" en-description="F6">
<input type="checkbox">
<span></span>
<span>停止调试</span>
<span>Stop Debug</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="F7" en-description="F7">
<input type="checkbox">
<span></span>
<span>添加断点</span>
<span>Add Breakpoint</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Shift+Q" en-description="Shift+Q">
<input type="checkbox">
<span></span>
<span>下一条语句</span>
<span>Next Command</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Shift+W" en-description="Shift+W">
<input type="checkbox">
<span></span>
<span>下一行</span>
<span>Next Line</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Shift+E" en-description="Shift+E">
<input type="checkbox" used="">
<span></span>
<span>继续</span>
<span>Continue</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="Shift+\" en-description="Shift+\">
<input type="checkbox">
<span></span>
<span>提交调试信息</span>
<span>Push debug information</span>
</label>
</item>
</submenu>
</item>
<item style="">
<span></span>
<span>帮助(H)</span>
<span>Help(H)</span>
<submenu>
<item style="" onmouseup="{}">
<label description="F1" en-description="F1">
<input type="checkbox">
<span></span>
<span>交互教程</span>
<span>Interactive Tutorials</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Alt+D" en-description="Alt+D">
<input type="checkbox">
<span></span>
<span>说明文档</span>
<span>Description document</span>
</label>
</item>
<item style="" onmouseup="{}">
<label description="Alt+B" en-description="Alt+B">
<input type="checkbox">
<span></span>
<span>发行说明</span>
<span>Issuance Instructions</span>
</label>
</item>
<hr>
<item style="" onmouseup="{}">
<label description="Alt+/" en-description="Alt+/">
<input type="checkbox">
<span></span>
<span>关于</span>
<span>About</span>
</label>
</item>
</submenu>
</item>
</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"}
 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来写每个菜单子项也不错

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

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

愿意交流我也随时恭候。

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

 

纯CSS菜单样式,及其Shadow DOM,Json接口 实现的更多相关文章

  1. HTML自定义radio单选按钮(纯css版,样式可以随意改变)

    html: <div> <input id="item1" type="radio" name="item" value= ...

  2. 常见Z纯CSS小样式合集(三角形)

    三角形 .sanjiao{ width:0px; height: 0px; overflow: hidden; border-width: 100px; border-color: transpare ...

  3. 纯CSS实现二级下拉导航菜单

    这是一款纯CSS菜单,二级下拉导航效果,是最简洁的CSS导航菜单,兼容性也很棒,IE7/8.火狐等都支持,而且它还是学习CSS菜单编写的典型教程,让你学会很多CSS技巧. 运行效果截图如下: < ...

  4. 【Web技术】400- 浅谈Shadow DOM

    编者按:本文作者:刘观宇,360 奇舞团高级前端工程师.技术经理,W3C CSS 工作组成员. 为什么会有Shadow DOM 你在实际的开发中很可能遇到过这样的需求:实现一个可以拖拽的滑块,以实现范 ...

  5. shadow dom

    初识shadow dom 我们先看个input="range"的表现: what amazing ! 一个dom能表现出这么多样式嘛? 无论是初学者和老鸟都是不肯相信的,于是在好奇 ...

  6. 纯CSS箭头,气泡

    原文地址: CSS Triangles 演示地址:CSS Triangles Demo 原文日期: 2013年8月5日 翻译日期: 2013年8月9日 本文两种实现方式: 使用或不使用 before ...

  7. JavaScript 是如何工作:Shadow DOM 的内部结构 + 如何编写独立的组件!

    这是专门探索 JavaScript 及其所构建的组件的系列文章的第 17 篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述! Jav ...

  8. 究竟什么是Shadow DOM?

    shadow dom 是什么? 顾名思义,shadow dom直译的话就是影子dom,但我更愿把它理解为DOM中的DOM.因为他能够为Web组件中的 DOM和 CSS提供了封装,实际上是在浏览器渲染文 ...

  9. 一个常见下拉菜单的样式:一体化小三角(纯css手写解决)

    类似下拉菜单2个一体化小三角,习惯上用字体图标加jQuery处理,比较方便,但是下面纯css手写解决方式,效果也还不错,对CSS知识也是一个比较好的孔固. 小三角用了2种不同处理方式:1.利用bord ...

随机推荐

  1. mongodb聚合的使用

    聚合: 主要用于计算和统计等,类似sql种的sum() avg() db.集合.aggregate( { 管道:{表达式} } ) 常用的管道: $group:将集合中的文档按照字段进行分组 $mat ...

  2. JavaScript的对象/下

    JavaScript的对象 一.BOM对象 BOM----browser object model 1.window对象 所有浏览器都支持window对象. 概念上讲,一个html文档对应一个wind ...

  3. VueJs(2)---VueJs开发环境的搭建和讲解index.html如何被渲染

    VueJs开发环境的搭建和讲解初始框架 有关如何搭建vue.js框架我这看了一篇文章,自己也根据它进行搭建环境. 文章地址:vue.js2.0实战(1):搭建开发环境及构建项目 接下来对初始的框架进行 ...

  4. 创建第一个Django项目

    第一个Django项目 命令行下使用如下命令创建一个名为"mysite"的Django项目: django-admin startproject mysite 这将会在当前位置创建 ...

  5. TP-LINK | TL-WR842N设置无线转有线

    首先点击右上角的"高级设置". 点击左侧的"无线设置"栏,点击"WDS无线桥接",然后一步步设置可以使路由器连接到当前的一个无线网络. 然后 ...

  6. nginx location的命中过程

    1 先判断精准命中,立即返回结果并结束解析过程 2 判断普通命中,如果有多个命中,"记录"下"最长"的命中结果(注意:记录但不结束,最长的为准) 3 继续判断正 ...

  7. web攻击和防御措施

    1.SQL注入:参照下面的链接 http://www.cnblogs.com/chenhaoyu/p/8758888.html 2.跨网站脚本攻击(Cross Site Scripting, XSS) ...

  8. 四,前端---constructor与prototype

    这里对于constructor 和 prototype做一个简单的介绍,旨在让大家有一个简单的了解与认识 1:定义与用法 prototype:属性使您有能力向对象添加属性和方法. constructo ...

  9. BST讲解

    BST 第一步,什么是BST,所谓BST就是满足一种特定性质的二叉树,这个性质一般情况是当前节点的权值比他的左子树的所有点的权值大,比他的右子树的所有点的权值小,满足这样性质的二叉树就称为BST,下面 ...

  10. [LeetCode] Stickers to Spell Word 贴片拼单词

    We are given N different types of stickers. Each sticker has a lowercase English word on it. You wou ...