共计 3541 个字符,预计需要花费 9 分钟才能阅读完成。
前置
本文需要对 CSS,Vue,ElementUI 有基本的了解。
本文以 ElementUI 提供的导航菜单组件为基础。
本文希望能在此组件基础上实现以下内容:
- 中间一段空白把导航栏分为左右两个部分
- 在导航栏上加上一个搜索框,但不被 el-menu-item 的样式污染。
先研究清楚 ElementUI 的 css 样式
创建一个简单的网页,在其中使用 ElementUI 的导航菜单组件。
用 Chrome 之类的工具对网页检查(F12/Ctrl+Shift+I)后,从 Elements 标签页中定位到导航菜单组件在网页中最后的实现元素。在检查工具下方有 Styles 工具会显示选中的元素的相关样式。提取其中对元素位置有影响以及我不太熟悉的属性。
el-menu
提取后发现有这些和元素位置相关的设置
margin: 0;
padding-left: 0;
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0px;
margin-inline-end: 0px;
padding-inline-start: 40px;
border-bottom: solid 1px #color;
border-right: none;
display:block;
position: relative;
-webkit-box-direction: normal;
list-style:none;
// 使用了::before 和::after 创建了伪元素(注意,不是伪类。)::before {
display: table;
content: "";
}
::after {
display: table;
content: "";
clear: both;
}
对于出现在以上代码中的但不熟悉不确认作用的属性,以其为关键词(记得加引号以避免搜索引擎错误解析)加 css 进行搜索,基本上就能找到满意的答案。
margin-block-start 等属性的作用 —— 影响不大
::before 和 ::after —— 伪类
clear:both
搞明白了这里为什么要使用一个::after 的伪元素,可以预测该元素下的子元素全都是浮动元素。因此如果放任不管的话,会造成浮动元素的高度不被父元素计算而导致父元素高度为零直接崩掉。所以使用这样一个伪类,由于这个伪类不能允许左右有浮动元素,所以它会使自己的上外边界碰着浮动元素(理想状况下应该排成一行)的那一行的下边界,而这一行的高度(也即浮动元素的高度)就会被计算为父元素的高度了。实际上如果这个伪类自己有高度比如 60px, 浮动元素那一行的最大高度为 60px,则父元素的高度就会是 120px 了。
box-direction —— 影响不大
在解决了有问题的样式属性后发现,其实整个 el-menu 的最终实现很简单:使用 positive:relative
但并不带有 left
top
这一类设置的属性,所以说元素还是留在原地。这里设置positive
为relative
的理由应当是辅助之后的子元素即导航栏内部的 item 的定位(position:absolute
时相对的元素若是 position:static
这一默认值是会被无视的)。
el-menu-item
float: left;
position: relative;
display: list-item;
margin: 0;
padding: 0 20px;
height: 60px;
line-height: 60px;
font-size:14px;
box-sizing: border-box;
text-align: -webkit-match-parent;
white-space: nowrap;
cursor: pointer;
float:left
和 display:list-item
同时使用第一时间可能想不明白,但经过自己创建更简单的样例进行测试,可以这么理解:float:left
先执行确定下自己的位置,然后执行 position:relative
,即relative
的相对定位相对的“原本的位置”是 float:left
之后的位置。而之类由于又没有设置top
left
之类的属性,可以认为这是为了在其内部再放其它组件的话辅助定位用的。
display: list-item —— 从官方文档来看意思就是说配置这个 list-item
这个 display
属性的元素表现出 <ul>
的子元素 <li>
的样式,从而可以为它配置 list-style
,并且这是在没有<ul>
这种 display
的父元素的基础上的。实际上它的父元素也确实是display:block
。
white-space —— white-space CSS 属性是用来设置如何处理元素中的空白。
cursor —— cursor 属性规定要显示的光标的类型(形状)。
那么最基本的两个组件最终生成的元素的 CSS 已经分析完了。动手试试我们一开始的目标吧。
目标
- 中间一段空白把导航栏分为左右两个部分
- 在导航栏上加上一个搜索框,但不被 el-menu-item 的样式污染。
目标 1
我的第一个想法是创建一个 el-menu-item 给它宽度但是不给它内容同时让它disable="true"
<el-menu-item index="1" v-show="!logined"> 淘宝网 </el-menu-item>
<el-menu-item index=""disabled="true"id="el-menu-item-placeholder1"></el-menu-item>
<el-menu-item index="2"> 登录 </el-menu-item>
<el-menu-item index="3"> 注册 </el-menu-item>
#el-menu-item-placeholder1 {width: 80%;}
在此状态下创建的导航栏中间确实有了很大一块空白作为区隔,但仍然有如下问题:
- 鼠标悬停在空白上时因为
:disabled="true"
导致鼠标会变成一个禁止通行的图标。 - 页面缩小到 1000px 左右时就已经会让右边的“登录”“注册”新开一行,把整个布局弄得很糟糕。
对于第一个问题,可以通过 cursor
属性解决?设置 cursor: default;
于我们自定义的作为占位符的空白格 el-menu-item 样式中,就解决了。
对于第二个问题,三个组件总共宽度为 218px,占据 20% 的宽度,则要求 100% 宽度大于 1090px 才会不崩盘。所以可以设置 el-menu 的类的样式解决这个问题
.el-menu {min-width: 1090px;}
#el-menu-item-placeholder1 {
width: 80%;
max-width: 80%;
cursor: default;
}
目标 2
在解决目标 1 的基础上,其实已经有了目标 2 的思路:设置一个 :disable="true"
的 el-menu-item 来放置一个 el-input 输入框。对这个 el-menu-item 标记 id 属性,然后通过 id 选择器设置cursor:default
。
实际测试时发现整个输入框被导航栏的背景色给灰蒙蒙地上了一层。显然这一副作用是由于将起禁用而导致的。(对比不禁用时的输入框很正常)。所以用检查工具查看此时的元素,发现其 class
属性多了一个is-disabled
,从而引入了 ElementUI 自带的样式中的 opacity: 0.25
才导致的。那通过 id 选择器进一步将其覆盖即可。
最终代码如下:
<el-menu-item index="1" v-show="!logined"> 淘宝网 </el-menu-item>
<el-menu-item :disabled="true" id="el-menu-item-placeholder1"></el-menu-item>
<el-menu-item id="el-menu-item-searchinput-container" :disabled="true">
<el-input v-model="input" placeholder="搜索栏"></el-input>
</el-menu-item>
<el-menu-item index="2"> 登录 </el-menu-item>
<el-menu-item index="3"> 注册 </el-menu-item>
.el-menu {min-width: 1090px;}
#el-menu-item-placeholder1 {
width: 80%;
max-width: 80%;
cursor: default;
}
#el-menu-item-searchinput-container {
cursor: default;
opacity: 1;
}
最初的两个目标基本都实现了。