不久之前,我的一个朋友构建了一个UI组件,用于根据<select>
元素的当前选择来更改页面的内容。 她的代码虽然有效,但是对于JavaScript还是陌生的,她已经在jQuery中构建了该组件,并要求我帮助对其进行优化。
虽然没有完全复制代码,但我创建了以下示例来展示她尝试创建的UI组件的类型:
<div class="select-area">
<select name="choose" id="choose" class="input-select">
<option value="nul" selected>Make a Selection</option>
<option value="opt1">Option 1</option>
<option value="opt2">Option 2</option>
<option value="opt3">Option 3</option>
</select>
</div>
<section class="jqueryOptions opt1">
<div class="content">
<h2>Option 1 Content</h2>
<p>
...
</p>
</div>
</section>
<section class="jqueryOptions opt2">
<div class="content">
<h2>Option 2 Content</h2>
<p>
...
</p>
</div>
</section>
<section class="jqueryOptions opt3">
<div class="content">
<h2>Option 3 Content</h2>
<p>
...
</p>
</div>
</section>
经过一些优化后,这是我们最终用来切换所选内容块的显示状态的jQuery。
$(function() {
$('.jqueryOptions').hide();
$('#choose').change(function() {
$('.jqueryOptions').slideUp();
$('.jqueryOptions').removeClass('current-opt');
$("." + $(this).val()).slideDown();
$("." + $(this).val()).addClass('current-opt');
});
});
那么这是怎么回事?
上面的jQuery函数查找所有具有'jqueryOptions'类的内容块,并默认隐藏它们。
然后,当用户改变所选择的选项select
的输入(其具有的“选择”的ID),则函数关闭使用jQuery的任何潜在的打开内容块.slideUp()
方法,然后与打开所选择的选项slideDown()
它通过获取所选选项的值(称为this
)并使用具有与“ this”中的值匹配的类名的元素来进行此操作。
所以:
<option value="opt1">Option 1</option>
火柴:
<section class="options opt1">
...
</section>
这是一个演示:
请参阅CodePen上带有 SitePoint( @SitePoint )的jQuery的Pen 内容切换组件 。
那还不算难,是吗?
那么,为什么不把它留在那呢?
jQuery解决方案的问题在于,我们仅包含了这小部分功能的jQuery(压缩后为98kb)。 我们可以做得更好。
在不更改标记的情况下,让我们看看如何首先使用原始JavaScript然后仅使用CSS来创建相同的效果。
首先,让我们考虑一下要重新产生这种效果需要发生什么。
- 默认情况下,内容需要隐藏。
- 进行选择后,我们需要显示所选内容。
- 选择新选项时,我们还需要隐藏所有以前打开的内容。
在代码中将对此进行解释,但还有一些其他内容,但这是我们需要牢记的三个主要要点。 其中之一是默认情况下隐藏内容,我们默认情况下可以使用CSS进行设置,所以这是一项无效的规定。 两个要走。
创建Vanilla JavaScript版本
首先,让我们设置一些变量以使我们的生活更轻松。
var selectInput = document.getElementById('choose'),
panels = document.querySelectorAll('.options'),
currentSelect,
i;
现在,我们有了变量,可以轻松访问我们的输入选择( selectInput
),不同的内容面板( panels
),当前选择的占位符以及迭代器。
接下来,我们需要编写一些函数来帮助我们处理上面项目符号列表中的项目。
首先从最后一个项目符号开始,当选择一个新选项时,我们需要确保显示的所有内容都被隐藏。 为此,我们将创建自己的函数:
function clearShow() {
for ( i = 0; i < panels.length; i++ ) {
panels[i].classList.remove('show');
}
}
clearShow()
函数正在做一些事情。 首先,它使用我们的panels
变量(这是页面上所有节点的列表,带有“选项”类),并对其进行迭代(在本例中为三个),并从所有变量中删除“ show”类。
“显示”类使内容在我们的页面上可见。
现在我们有了从每个内容块中删除“显示”类的方法,我们需要一种将“显示”添加到选定面板的方法。
function addShow(showThis) {
var el = document.getElementsByClassName(showThis);
for ( i = 0; i < el.length; i++ ) {
el[i].classList.add('show');
}
}
addShow()
函数接收一个名为showThis
的参数,并将“ show”类添加到具有与select
输入的当前值匹配的类的面板节点。 现在,我们仍然需要另外一块将showThis
值传递给addShow()
。
function vUpdate() {
currentSelect = selectInput.value;
clearShow();
addShow(currentSelect);
}
selectInput.addEventListener('change', vUpdate);
每当更新选择输入(通过change
事件检测到vUpdate()
时,都会执行vUpdate()
函数。 因此,当vUpdate()
运行时,它将执行以下操作:
- 获取
selectInput
的当前值并将其存储在currentSelect
变量中。 - 执行
clearShow
函数以从面板中删除任何.show
痕迹。 - 执行
addShow()
函数,传入currentSelect
以完成该函数的缺失部分 - 将
.show
分配给具有与选择输入的当前值匹配的类的面板。
您可以查看下面的演示以查看其运行情况:
请参阅CodePen上带有 SitePoint( @SitePoint )的原始 JavaScript的Pen 内容切换组件 。
或者,您可以在此处查看整页演示 。
但是在继续之前...如果您从选择输入中选择一个选项,然后刷新页面,则输入的值可能会保留,但不会显示相应的面板。
我们可以通过添加以下内容来解决此问题:
if (selectInput.value !== 'nul') {
currentSelect = selectInput.value;
addShow(currentSelect);
}
if
构造将检查是否selectInput
值不是nul
。 如果是这种情况,它将把当前选择的值传递给addShow()
函数,从而在重新加载页面时触发该事件。 修复页面刷新且select
元素显示一个值但未显示适当内容的罕见情况很方便。
最后,在需要支持Internet Explorer 9或更低版本的情况下,我们不能使用classList()
。 要解决此问题,这里有一些函数可用于添加和删除元素中的类。 上面的CodePen演示正在使用以下功能:
function addClass(elm, newClass) {
elm.className += ' ' + newClass;
}
function removeClass(elm, deleteClass) {
elm.className = elm.className.replace(new RegExp("\\b" + deleteClass + "\\b", 'g'), '').trim();
/* the RegExp here makes sure that only
the class we want to delete, and not
any other potentially matching strings
get deleted.
*/
}
只能用CSS完成吗?
利用我制作的许多组件,我想尝试看看在纯CSS解决方案中复制它们有多接近。 但是,如果jQuery和原始JavaScript解决方案可以基于相同的标记,则仅需修改CSS解决方案。
与先前版本相比,最大,最重要的变化是需要完全替换select
。 在前面的示例依赖于select
元素的值来更改将显示哪个内容面板的情况下,仅CSS并不了解这些值的更改,因此无法利用不同的值来切换不同的选择器链。
select
元素将只需要重新创建,并且要做到这一点,我们将使用所谓的“复选框/单选按钮hack”。
这是我们新的“ select
元素”的标记。
<input type='checkbox' class="invis" id="open_close" />
<input type='radio' name='opts' class="invis" id="opt1" />
<input type='radio' name='opts' class="invis" id="opt2" />
<input type='radio' name='opts' class="invis" id="opt3" />
<header class="header-base">
<div class="content">
<p>
Choose an Option
</p>
<div class="select-area">
<label for="open_close" class="input-select">
...
</label>
<ul class="select-options">
<li>
<label for="opt1">Option 1</label>
</li>
<li>
<label for="opt2">Option 2</label>
</li>
<li>
<label for="opt3">Option 3</label>
</li>
</ul>
</div>
</div>
</header>
基本上,这里所做的就是重新创建select
元素,而HTML和CSS可以在没有JavaScript的任何帮助的情况下尽其所能。 标头上方的输入用作站点上select
面板和内容面板的样式锚的控件。 新的无序列表和标签成为我们的新select
元素。
opt1,opt2和opt3的标签会更改具有相应ID的单选按钮的选中状态。 在CSS中,根据选择了哪个单选按钮,使用通用的同级选择器将相应的面板设置为显示。
#opt1:checked ~ main .opt1,
#opt2:checked ~ main .opt2,
#opt3:checked ~ main .opt3 {
display: block;
height: 100%;
overflow: visible;
visibility: visible;
}
有很多细节可以复制select
元素,这些细节取决于要检查的适当单选按钮和CSS的常规同级选择器。 有关常规兄弟选择器的更多信息以及仅CSS可以完成的其他整洁的事情,您应该查看我的文章CSS可以做到的吗? 和CSS变形菜单 。
这些文章中我没有介绍的是重新创建select
元素的一些较困难的方面。
很简单,我们希望根据所按下的选项立即更新页面的内容。 我们遇到的问题是,如果select
元素和内容块均基于相同的单选按钮,则单击select
元素会使内容消失。 不仅如此,如果打开了select
选项,然后单击其中一个选项,则这些选项将消失,并显示内容块。
为了缓解此UX缺陷,我添加了<input type="checkbox" class="invis" id="open_close" />
。 现在可以同时打开select
元素和当前内容。 缺点是select
元素在单击选项时不会关闭,而是在再次单击时才关闭。 不理想。 但是,我觉得这比我之前提到的要好。 为了吸引人们注意需要再次单击以关闭的select
元素,我在打开元素时将向下箭头更改为X:
#open_close:checked ~ .header-base .select-area .select-options {
opacity: 1;
visibility: visible;
}
#open_close:checked ~ .header-base .select-area:after {
border: none;
content: 'X';
top: -24px;
}
我要重新创建的真正select
元素的另一个功能是,当选择了一个新选项时,主select
元素的文本将变为该选项。 使用:before
伪元素,可以根据选择哪个单选按钮来更改文本:
.input-select:before {
content: 'Make a Selection';
}
#opt1:checked ~ .header-base .input-select:before {
content: 'Option 1';
}
#opt2:checked ~ .header-base .input-select:before {
content: 'Option 2';
}
#opt3:checked ~ .header-base .input-select:before {
content: 'Option 3';
}
通过查看纯CSS的CodePen演示的源代码,可以看到以上内容以及更多内容:
请参阅CodePen上具有 SitePoint( @SitePoint )的纯CSS的Pen 内容切换组件 。
这是完整版 。
最后,简要总结一下优缺点……
我们只是考虑了三种不同的方式来使用jQuery创建相似的接口,然后使用普通JavaScript,然后仅使用CSS。 每种技术都有其优点和缺点。
到目前为止, jQuery解决方案是最容易实现的,几乎没有代码。
jQuery解决方案的缺点是,如果您只需要该接口的库,那么您将添加整个库用于一个目的。
利用CSS转换和过渡的Vanilla JavaScript解决方案非常类似于jQuery解决方案。 最小化它的时钟为486字节-显然比jQuery替代要小得多。
该解决方案的缺点是,并非所有浏览器都支持某些JavaScript,并且要支持这些浏览器,您需要编写其他变通方法(如我所做的那样)。
纯CSS解决方案非常适合那些希望尝试CSS的人或对JavaScript不太熟悉的人。 但是,它需要大量重复的,依赖于标记的CSS才能正常工作,并且可能对网站的可访问性产生负面影响,因为您必须以原本就不应使用的方式使用元素。
无论您偏向哪种解决方案,请务必权衡每种解决方案的利弊,并致力于提供最佳的用户体验。
From: https://www.sitepoint.com/content-switching-component-built-three-ways/