当前位置: 首页 > Web前端 > vue.js

教你用原生JavaScript造轮子(四)——Tabstab

时间:2023-04-01 10:28:09 vue.js

Tabs标签文档:Tabs源码:tiny-wheels觉得好用的就点个Star吧~(〃'▽'〃)这个组件的难点在于控制每个tabitem底栏的移动和相应面板的移动。最常见的方式就是通过transform来改变元素的位置,废话不多说,直接上传代码实现文章只列出了关键部分的代码,其余逻辑可以自行研究。项目中源码的Tabs组件需要让用户自定义内容,所以有些配置是通过HTML的自定义属性实现的(目前自定义标签的兼容性不是很好,暂不考虑).组件的HTML结构如下:内容1

内容2
内容3
内容4
文档中已经说明了各个属性的具体用法,组件结构的渲染这里不再赘述源码已经有了,最终渲染出来的HTML结构是这样的:标签1选项卡2选项卡3选项卡4内容1内容2content3content4根据用户设置的tab内容,我们可以渲染相应数量的tab-items,而tab-item的位置和宽度的计算可以通过offsetLeft和offsetWidth得到,然后改变相应的样式即可:setTabs(){this.$$tabItems=this.$container.querySelectorAll('.tab-item')this.$tabLine=this.$container.querySelector('.tab-line')这个。setTabStatus()consttabIndex=this.getTabIndex()?this.getTabIndex():0如果(this.$$tabItems[tabIndex]){const{offsetWidth,offsetLeft}=this.$$tabItems[tabIndex]this.setTabItem(this.$$tabItems[tabIndex])this.setTabLine(offsetWidth,offsetLeft)this.setTabPanel(this.$$tabPanels[tabIndex],tabIndex)}}setTabLine(width,left){this.$tabLine.style.width=`${width}px`this.$tabLine.style.transform=`translateX(${left}px)`}tab-panel设置相同:setTabPanel($panel,index){this.$tabPanelContainer.style.transform=`translateX(-${index*100}%)`this.$$tabPanels.forEach($panel=>$panel.classList.remove('active'))$panel.classList.add('active')setTimeout(()=>{if(this.options.animated){this.$tabPanelContainer.classList.add('animated')}})}需要注意的是,第一次加载组件时,我们不希望tab-panel有滑动效果,所以这里需要使用setTimeout延迟加载过渡动画样式的核心逻辑Tabs组件,剩下的就是一些配置属性和事件绑定的实现:getTabIndex(){consttabKey=this.$container.dataset.tabActivelettabIndex=tabKeyif(tabKey){this.$$tabPanels.forEach(($panel,index)=>{if($panel.dataset.tabKey===tabKey){tabIndex=index}})}returntabIndex}setTabStatus(){consttabKey=this.$container.dataset.tabDisabledif(tabKey){this.$$tabPanels.forEach(($panel,index)=>{if($panel.dataset.tabKey===tabKey){this.$$tabItems[index].classList.add('disabled')}})}}bindTabs(){this.$$tabItems.forEach($tab=>{$tab.addEventListener('click',()=>{if(!$tab.classList.contains('disabled')){constindex=[...this.$$tabItems].indexOf($tab)this.setTabItem($tab)this.setTabLine($tab.offsetWidth,$tab.offsetLeft)this.setTabPanel(this.$$tabPanels[index],index)this.options.callback.call(null,$tab,this.$$tabPanels[index].dataset.tabKey)}})})}tab-active(初始激活项)和tab-disabled(初始禁用项)都是通过dataset的API获取对应的属性值,然后遍历找到需要设置的item;绑定事件时,需要将当前元素的引用、tab-key等参数传入回调函数。至此Tabs组件的基本功能已经完成。当然也可以实现一些更复杂的功能:tab的增删改查、响应式显示tab-item、卡片式tabs等,这些功能在element-ui、iview、ant-design中都有实现。可以参考他们的效果自己展开~用Vue或者React来封装这样的组件无非就是省略了DOM操作,简化了组件属性的配置。一些内部核心实现原则是通用的。比如用vue来写组件的结构,可能会变成这样:itemname="one"disabled>Tab1Tab2Tab3内容1内容2内容3可以看到,属性的配置简化了很多,组件结构为类似于我们用原生HTML渲染出来的结果也差不多(其实原生的自定义标签也可以模拟这样的效果,只是目前的浏览器兼容性还是比较差),tabs组件的样式实现还是需要计算offsetWidth、offsetLeft等属性,换汤不换药。有兴趣的可以用vue重写,这里就不啰嗦了~未完待续...

最新推荐
猜你喜欢