安装与调用
引用下面CSS文件:
<link rel="stylesheet" href="https://unpkg.com/lu2/theme/edge/css/common/ui/Tab.css">
引用下面的JS文件:
<script type="module" src="https://unpkg.com/lu2/theme/edge/js/common/ui/Tab.js"></script>
支持es6 import的使用方式:
<script type="module"> import 'https://unpkg.com/lu2/theme/edge/js/common/ui/Tab.js'; </script>
import 'lu2/theme/edge/css/common/ui/Tab.css'; import 'lu2/theme/edge/js/common/ui/Tab.js';
如果 JS import语法报错,试试在业务代码中动态引入。
import('lu2/theme/edge/js/common/ui/Tab.js');
概要
这里的Tab切换本质上是一个切换器,任意1对1的交互效果都支持,例如展开收起、选项卡切换,又或者文档后面演示的轮播效果。
<ui-tab>自定义元素
<ui-tab>
自定义元素可以实现几乎所有常见的切换效果。
实现原理如下:
<ui-tab>
元素点击(或悬停)的时候,判断自身是否有name
属性:- 如果有
name
属性,则同name
属性值的全部<ui-tab>
元素仅当前点击的<ui-tab>
元素保持open状态; - 如果没有
name
属性,则认为是独立的,表现为当前<ui-tab>
元素的open状态在true
和false
之间不断切换。 - 通过
target
属性匹配对应的面板元素,根据<ui-tab>
元素的open状态添加或移除面板元素的.active
类名。
下面通过多个不同类型的案例了解<ui-tab>
自定义元素的功能表现。
1. 展开与收起
点击下面的“更多”。
- 列表1
- 列表2
- 列表3
- 列表4
- 列表5
- 列表6
相关代码如下所示:
<ul id="c1"> <li>列表1</li> <li>列表2</li> <li>列表3</li> <li hidden>列表4</li> <li hidden>列表5</li> <li hidden>列表6</li> <ui-tab target="c1">更多↓</ui-tab> </ul>
ul.active [hidden] { display: list-item; } ul.active ui-tab { -webkit-text-fill-color: transparent; } ul.active ui-tab::before { position: absolute; content: '收起↑'; -webkit-text-fill-color: currentColor; }
在本例中,“更多↓”所在的<ui-tab>
元素没有name
属性值,属于A/B切换效果,因此,随着点击行为的触发,当前<ui-tab>
元素会不断切换open
属性;同时target
属性所匹配的元素'c1'
也会不断切换类名'active'
。
配合相关的CSS就可以控制元素的显隐了。
2. 手风琴效果
左侧列表没有name
属性,每个标题展开收起都是独立的;右侧列表有name
属性,标题展开与收起是联动的。
标题A - 内容1
- 内容2
标题B - 内容1
- 内容2
标题C - 内容1
- 内容2
标题A - 内容1
- 内容2
标题B - 内容1
- 内容2
标题C - 内容1
- 内容2
HTML代码如下:
<div class="accordion"> <dl> <dt id="dt1"><ui-tab target="dt1">标题A</ui-tab></dt> <dd>内容1</dd> <dd>内容2</dd> <dt id="dt2"><ui-tab target="dt2">标题B</ui-tab></dt> <dd>内容1</dd> <dd>内容2</dd> <dt id="dt3"><ui-tab target="dt3">标题C</ui-tab></dt> <dd>内容1</dd> <dd>内容2</dd> </dl> <dl> <dt id="dt4"><ui-tab target="dt4" name="dt">标题A</ui-tab></dt> <dd>内容1</dd> <dd>内容2</dd> <dt id="dt5"><ui-tab target="dt5" name="dt">标题B</ui-tab></dt> <dd>内容1</dd> <dd>内容2</dd> <dt id="dt6"><ui-tab target="dt6" name="dt">标题C</ui-tab></dt> <dd>内容1</dd> <dd>内容2</dd> </dl> </div>
关键CSS如下:
.accordion dd { display: none; } .accordion .active + dd, .accordion .active + dd + dd { display: block; }
3. 选项卡效果
我是选项卡1对应的图片
我是选项卡2对应的图片
我是选项卡3对应的图片
主要看下HTML代码:
<div class="tab-x"> <div class="tab"> <ui-tab class="tab-label" name="s-tab" target="t1" open>选项卡1</ui-tab> <ui-tab class="tab-label" name="s-tab" target="t2">选项卡2</ui-tab> <ui-tab class="tab-label" name="s-tab" target="t3">选项卡3</ui-tab> </div> <div id="t1" class="tab-content active"> <p>我是选项卡1对应的图片</p> <img src="1.jpg" /> </div> <div id="t2" class="tab-content"> <p>我是选项卡2对应的图片</p> <img src="2.jpg" /> </div> <div id="t3" class="tab-content"> <p>我是选项卡3对应的图片</p> <img src="3.jpg" /> </div> </div>
本组件内置了一套选项卡UI样式,效果如下所示:
点击上方的选项卡按钮,可以看到切换效果。
相关的HTML样式和结构如下所示:
<div class="ui-tab-tabs"> <ui-tab target="tabTarget1" name="tabgroup" class="ui-tab-tab" open>选项卡文档</ui-tab> <ui-tab target="tabTarget2" name="tabgroup" class="ui-tab-tab">业务JS分离演示</ui-tab> </div> <div class="ui-tab-contents"> <div id="tabTarget1" class="ui-tab-content active"></div> <div id="tabTarget2" class="ui-tab-content"></div> </div>
其中的类名ui-tab-tabs
、ui-tab-tab
、ui-tab-contents
、ui-tab-content
对应的样式与标签无关,因此,如果当前选项卡就是普通的链接跳转,替换成<a>
元素即可。
<div class="ui-tab-tabs"> <a href="/a/" class="ui-tab-tab" open>选项卡1</a> <a href="/b/" class="ui-tab-tab">选项卡2</a> </div>
每次进来,图片会重载一次,高度随机。演示选项卡切换事件是如何触发的。
代码如下:
// 点击第2个选项卡
// 这里'show'事件也可以换成'click'事件
document.querySelector('ui-tab[target="tabTarget2"]').addEventListener('show', function () {
eleImgX.innerHTML = '<img src="some.jpg" height="' + Math.round(100 + 100 * Math.random()) + '">';
});
is-tab属性
本组件还支持在普通HTML元素上使用应用切换效果,方法是添加is-tab
属性。
切换对象使用data-target
属性指定,对于<a>
元素,也可以使用href
属性指定(此时需要前面加'#'
)。
例如上面提到的展开收起效果也可以使用如下所示的HTML结构:
<ul id="c2"> <li>列表1</li> <li>列表2</li> <li>列表3</li> <li hidden>列表4</li> <li hidden>列表5</li> <li hidden>列表6</li> <a href="#c2" class="blue" is-tab>更多↓</a> <!-- 或者 --> <!-- <a href="javascript:" class="blue" is-tab="c2"></a> --> </ul>
实时效果如下:
- 列表1
- 列表2
- 列表3
- 列表4
- 列表5
- 列表6 更多↓
亦或者选项卡效果(同样使用name
属性进行分组),这里使用<button>
元素示意下:
<div class="ui-tab-tabs"> <button data-target="p1" name="tab-button" class="ui-tab-tab" is-tab open>选项卡1</button> <button data-target="p2" name="tab-button" class="ui-tab-tab" is-tab>选项卡2</button> </div> <div id="p1" class="ui-tab-content active"> <p>我是选项卡1对应的图片</p> <img src="1.jpg" /> </div> <div id="p2" class="ui-tab-content"> <p>我是选项卡2对应的图片</p> <img src="2.jpg" /> </div>
我是选项卡1对应的图片
我是选项卡2对应的图片
设置了is-tab
属性的DOM元素的切换效果底层还是借助<ui-tab>
元素实现的,该<ui-tab>
元素可以使用下面的语法获得:
dom['ui-tab']; // 返回对应的<ui-tab>元素
另外,is-tab="prev"
和is-tab="next"
元素在点击的时候,可以触发选项卡的上一项和下一项的切换效果,前提是使用data-name
属性指向选项卡元素的name
属性值,本文档最后的扩展效果有使用示意。
NodeList.tab()方法
本组件还支持手动绑定切换行为,同样针对普通元素元素。假设有如下所示的HTML代码:
<div id="myTabs" class="ui-tab-tabs"> <button data-target="p3" class="ui-tab-tab" open>选项卡1</button> <button data-target="p4" class="ui-tab-tab">选项卡2</button> </div> <div id="p3" class="ui-tab-content active">...</div> <div id="p4" class="ui-tab-content">...</div>
则执行下面的JavaScript代码就可以有选项卡切换效果了:
document.querySelectorAll('#myTabs button').tab();
我是选项卡1对应的图片
我是选项卡2对应的图片
语法和参数
对于<ui-tab>
自定义元素,支持下面这些自定义参数。
参数名称 | 支持类型 | 默认值 | 释义 |
---|---|---|---|
target | String | '' | 可选。表示切换效果对应的元素的id值。 |
name | String | '' | 可选。表示分组名。如果不设置,或者为空,则表示当前切换是不断循环的A/B切换效果。 |
event |
String | 'click' | 可选。表示事件类型。默认为点击事件。还支持'mouseover' 'mouseenter' 等事件。值'hover' 会按照'mouseenter' 事件处理。
|
history | Boolean | false | 可选。表示是否通过给url添加查询字符串记录选项卡的选中状态。默认值为false 表示切换时候查询地址无变化。此参数生效需要name值必须存在。 |
autoplay | Integer | 3000 | 可选。表示是否自动播放。如果不设置,表示不自动播放。如果设置,则只要参数值不是整数,均采用默认的自动播放时间3000ms。autoplay 自动播放时间是独立的,不同选项卡按钮可以有不同的自动播放时间。 |
history参数效果示意
鼠标经过下面的选项卡,同时观察URL地址的变化。
我是选项卡1对应的图片
我是选项卡2对应的图片
相关HTML如下所示:
<div class="ui-tab-tabs"> <ui-tab target="tt1" name="rel" class="ui-tab-tab" history="true" eventtype="hover" open>选项卡1</ui-tab> <ui-tab target="tt2" name="rel" class="ui-tab-tab" history="true" eventtype="hover">选项卡2</ui-tab> </div> <div id="tt1" class="ui-tab-content active">...</div> <div id="tt2" class="ui-tab-content">...</div>
可以看到name属性作为了查询字符串的key值,target属性值作为了查询字符串的value值。
虽然页面刷新的时候,选项卡会自动定位到上一个选中的选项卡元素上,但是这个过程是异步后执行的,用户会看到选项卡变化的过程,体验并不一定完美,因此建议页面直出的时候直接根据URL查询内容进行open属性和active类名的设置。
普通元素中的参数设置
普通元素中的参数设置与<ui-tab>
自定义元素类似,区别在于需要在前面添加data-
前缀(name
参数除外),以及注意保持小写。
例如:
<button data-target="someId" data-history="true" data-eventtype="hover" is-tab open>选项卡1</button>
其中,对于<a>
元素,可以使用href
属性代替data-target
,不过需要在前面添加一个井号#
,例如:
<a href="#c2" class="blue" is-tab>更多↓</a>
Nodelist.tab()的语法和参数
语法如下:
Nodelist.tab(options);
其中options
是可选参数,支持这3个参数:name
、eventType
、history
和autoplay
。
例如下面这个效果:
内容1内容2
相关HTML和JS代码使用示意:
<button data-target="t-1">经过我-1</button> <button data-target="t-2">经过我-2</button> <p> <mark id="t-1" class="ui-tab-content">内容1</mark> <mark id="t-2" class="ui-tab-content">内容2</mark> </p>
document.querySelectorAll('button[data-target^="t-"]').tab({ name: 'free', history: true, eventType: 'hover' });
new Tab()的语法和参数
对于单个普通HTML元素,也可以使用new Tab()
语法进行构造。
new Tab()
本质上是创建<ui-tab>
自定义元素的快捷语法,底层通过for
属性机制和普通HTML产生状态关联。
语法如下:
let eleTab = new Tab(trigger, options);
其中:
- trigger
- 必需。String|Element。表示切换按钮元素。如果是字符串类型,则表示切换按钮元素。
- options
- 可选。Object。表示可选参数,仅支持
eventType
、history
和autoplay
的设置。
事件与回调
仅在<ui-tab>
元素中有自定义的事件支持,包括'show'
、'hide'
和'switch'
这3个自定义事件。
其中:
- show
- 切换显示的时候触发。使用示意:
tab.addEventListener('show', _ => {});
- hide
- 切换隐藏的时候触发。使用示意:
tab.addEventListener('hide', _ => {});
- switch
- 切换状态变化的时候触发。使用示意:
tab.addEventListener('switch', event => { console.log(this.open); });
对于普通元素的切换,可以使用原生事件进行处理,例如,点击某个选项卡之后你希望做些事情,可以:
tab.addEventListener('click', _ => {});
扩展:广告图轮播实现
Tab组件本质上是个切换器,因此,也是可以用来实现轮播图效果的,使用autoplay
参数即可触发自动播放:
样式需要重写,LuLu UI不提供,源码示意:
CSS部分:
.slide-container { position: relative; width: 350px; height: 105px; border: 1px solid #ddd; } .slide-a { position: absolute; transition: opacity .2s; } .slide-a:not(.active) { opacity: 0; visibility: hidden; transition: opacity .2s, visibility .01s .2s; } .slide-img { display: block; width: 100%; height: 105px; } .slide-dot-x { width: 350px; text-align: center; position: relative; margin-top: -25px; } .slide-dot { display: inline-block; width: 10px; height: 10px; border: 4px solid transparent; background-color: #fff; background-clip: content-box; border-radius: 50%; } .slide-dot[open] { background-color: #cd0000; } .slide-prev, .slide-next { position: absolute; width: 24px; height: 24px; border: 2px solid #fff; color: #fff; border-radius: 100%; top: -40px; display: grid; place-items: center; font-size: 14px; font-family: system-ui; cursor: pointer; background-color: #fff1; } .slide-prev { left: 20px; } .slide-next { right: 20px; }
HTML部分:
<div id="slideContainer" class="slide-container"> <a href id="slideLi1" class="slide-a active"> <img src="1.jpg" class="slide-img"> </a> <a href id="slideLi2" class="slide-a"> <img src="2.jpg" class="slide-img"> </a> <a href id="slideLi3" class="slide-a"> <img src="3.jpg" class="slide-img"> </a> </div> <div id="slideDot" class="slide-dot-x"> <ui-tab eventtype="mouseover" name="sliderDot" class="slide-dot" autoplay open target="slideLi1"></ui-tab> <ui-tab eventtype="mouseover" name="sliderDot" class="slide-dot" autoplay="4000" target="slideLi2"></ui-tab> <ui-tab eventtype="mouseover" name="sliderDot" class="slide-dot" autoplay="5000" target="slideLi3"></ui-tab> <!-- 前后切换 --> <span class="slide-prev" is-tab="prev" data-name="sliderDot">◀</span> <span class="slide-next" is-tab="next" data-name="sliderDot">▶</span> </div>
3个广告图自动播放时间分别是3s,4s和5s。