先声明,要看懂这篇博客要求你具备少量基础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"}
嗯?这个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 += "<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 <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 NAME</slot>></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来写每个菜单子项也不错
关于上面我所有的代码如果有问题请联系我
或者你有更好的方法也请不吝赐教。
愿意交流我也随时恭候。
期待我的下篇博客就收藏吧