Vue.js组件——标签页组件
2017-11-19 15:47
363 查看
按照《Vue.js实战》的指导,制作了一个标签页的组件,并按照课后练习的要求,添加了一个小功能:
给pane组件新增一个prop:closable的布尔值,支持是否关闭这个pane,如果开启,tabs上会增加一个关闭按钮,可以关闭对应的标签。
做这个练习的时候,主要有两个关键点:
后来查阅书籍,发现
1、删除将navList中对应的元素(navList是标签页标题的集合);
2、通过改变currentValue的值,隐藏标签页对应的内容。
关闭标签页的方法deleteTab的代码如下:
这个组件总共包含如下四个文件:
1、index.html:入口页面;
2、style.csss:样式表;
3、tabs.js:标签页外层的组件tabs,其包含一个标签页标题,一个用于嵌套pane组件的slot;
4、pane.js:标签页嵌套的组件pane,这个组件的作用在于包含具体的标签页的内容。
index.html
style.css
tabs.js
pane.js
给pane组件新增一个prop:closable的布尔值,支持是否关闭这个pane,如果开启,tabs上会增加一个关闭按钮,可以关闭对应的标签。
做这个练习的时候,主要有两个关键点:
1)如何根据closable的值来动态显示/隐藏关闭按钮
解决第一个关键点时,我一开始使用了v-show,如下所示(下面的代码省略了其他不相关的代码),结果不能成功:
Vue.component('tabs',{ template:'\ <div class="tabs">\ <div class="tabs-bar">\ <div\ :class="tabCls(item)"\ v-for="(item,index) in navList"\ @click="handleChange(index)">{{ item.label }} \ <span :v-show="isShown(item)" @click="deleteTab(index,event)">×</span>\ </div>\ </div>\ <div class="tabs-content">\ <slot></slot>\ </div>\ </div>', methods:{ isShown:function(item){ console.log(item.closable); var flag = item.closable == 'true'; console.log("-------------------------"); console.log(flag); return flag; } } });
后来查阅书籍,发现
v-show不能在template中使用。又考虑到这个关闭按钮只会在刚加载时需要渲染,后面都不会改变其显示/隐藏效果,于是决定用
v-if,然后奏效了,代码如下(同样省略了不相关代码):
Vue.component('tabs',{ template:'\ <div class="tabs">\ <div class="tabs-bar">\ <div\ :class="tabCls(item)"\ v-for="(item,index) in navList"\ @click="handleChange(index)">{{ item.label }} \ <span v-if="isShown(item)" @click="deleteTab(index,event)">×</span>\ </div>\ </div>\ <div class="tabs-content">\ <slot></slot>\ </div>\ </div>', methods:{ isShown:function(item){ console.log(item.closable); var flag = item.closable == 'true'; console.log("-------------------------"); console.log(flag); return flag; } } });
2)如何实现关闭标签页的功能
鉴于Vue.js的核心思想是数据驱动DOM,实现关闭标签页的功能,只需要做到两点:1、删除将navList中对应的元素(navList是标签页标题的集合);
2、通过改变currentValue的值,隐藏标签页对应的内容。
关闭标签页的方法deleteTab的代码如下:
deleteTab:function(index,event){ //添加关闭功能,即是将navList中对应的元素删除即可。 //存在一个问题,当关闭了所有的tab后,tab-content中依然会显示内容 //那么,我们不能仅仅只删除navList中对应的元素,还应该将pane中对应的内容也隐藏 //可以通过改变currentValue的值来实现 if(this.navList[index].name === this.currentValue){ if(index > 0){ this.currentValue = this.navList[index - 1].name; this.navList.splice(index,1); event.stopPropagation();//阻止冒泡,避免触发handleChange(index)方法 } else{ this.navList.splice(index,1); event.stopPropagation(); if(this.navList.length > 0){ this.currentValue = this.navList[0].name; } else{ this.currentValue = ''; } } } else{ this.navList.splice(index,1); event.stopPropagation();//阻止冒泡,避免触发handleChange(index)方法 if(this.navList.length === 0){ 4000 this.currentValue = ''; } } }
完整代码
最后,附上完整的代码。这个组件总共包含如下四个文件:
1、index.html:入口页面;
2、style.csss:样式表;
3、tabs.js:标签页外层的组件tabs,其包含一个标签页标题,一个用于嵌套pane组件的slot;
4、pane.js:标签页嵌套的组件pane,这个组件的作用在于包含具体的标签页的内容。
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>标签页组件</title> <link rel="stylesheet" type="text/css" href="../css/style.css"> </head> <body> <h2>练习</h2> <p>给pane组件新增一个prop:closable的布尔值,支持是否关闭这个pane,如果开启,tabs上会增加一个关闭按钮,可以关闭对应的标签</p> <div id="app" v-cloak> <tabs v-model="activeKey" @on-click="doSomeThing"> <pane label="标签一" name="1" closable=true> 标签一的内容 </pane> <pane label="标签二" name="2" closable=true> 标签二的内容 </pane> <pane label="标签三" name="3" closable=false> 标签三的内容 </pane> </tabs> </div> <script src="../js/vue.min.js"></script> <script src="../js/pane.js"></script> <script src="../js/tabs.js"></script> <script type="text/javascript"> var app = new Vue({ el: '#app', data: { activeKey:'1' }, methods:{ doSomeThing:function(){ //console.log("Do something!"); } } }); </script> </body> </html>
style.css
[v-cloak] { display: none; } .tabs { font-size: 14px; color:#657180; } .tabs-bar:after{ content:''; display: block; width: 100%; height: 1px; background: #d7dde4; margin-top:-1px; } .tabs-tab { display: inline-block; padding: 4px 16px; margin-right: 6px; background: #ffffff; border: 1px solid #d7dde4; cursor: pointer; position: relative; } .tabs-tab-active { color: #3399ff; border-top: 1px solid #3399ff; border-bottom: 1px solid #ffffff; } .tabs-tab-active:before { content: ''; display: block; height: 1px; background: #3399ff; position: absolute; top: 0; left: 0; right: 0; } .tabs-content { padding: 8px 0; }
tabs.js
Vue.component('tabs',{ template:'\ <div class="tabs">\ <div class="tabs-bar">\ <div\ :class="tabCls(item)"\ v-for="(item,index) in navList"\ @click="handleChange(index)">{{ item.label }} \ <span v-if="isShown(item)" @click="deleteTab(index,event)">×</span>\ </div>\ </div>\ <div class="tabs-content">\ <slot></slot>\ </div>\ </div>', props:{ value:{ type:[String,Number] }, }, data:function(){ return { currentValue:this.value, navList:[] } }, methods:{ tabCls:function(item){ return [ 'tabs-tab', { 'tabs-tab-active':item.name === this.currentValue } ]; }, getTabs:function(){ return this.$children.filter(function(item){ return item.$options.name === 'pane'; }); }, updateNav:function(){ this.navList = []; var _this = this; this.getTabs().forEach(function(pane,index){ _this.navList.push({ label:pane.label, name:pane.name || index, closable:pane.closable }); if(!pane.name){ pane.name = index; } if(index === 0){ if(!_this.currentValue){ _this.currentValue = pane.name || index; } } }); this.updateStatus(); }, updateStatus: function(){ var tabs = this.getTabs(); var _this = this; tabs.forEach(function(tab){ return tab.show = tab.name === _this.currentValue; }) }, handleChange:function(index){ var nav = this.navList[index]; var name = nav.name; this.currentValue = name; this.$emit('input',name); this.$emit('on-click',name); }, deleteTab:function(index,event){ //添加关闭功能,即是将navList中对应的元素删除即可。 //存在一个问题,当关闭了所有的tab后,tab-content中依然会显示内容 //那么,我们不能仅仅只删除navList中对应的元素,还应该将pane中对应的内容也隐藏 b792 //可以通过改变currentValue的值来实现 if(this.navList[index].name === this.currentValue){ if(index > 0){ this.currentValue = this.navList[index - 1].name; this.navList.splice(index,1); event.stopPropagation();//阻止冒泡,避免触发handleChange(index)方法 } else{ this.navList.splice(index,1); event.stopPropagation(); if(this.navList.length > 0){ this.currentValue = this.navList[0].name; } else{ this.currentValue = ''; } } } else{ this.navList.splice(index,1); event.stopPropagation();//阻止冒泡,避免触发handleChange(index)方法 if(this.navList.length === 0){ this.currentValue = ''; } } }, isShown:function(item){ console.log(item.closable); var flag = item.closable == 'true'; console.log("-------------------------"); console.log(flag); return flag; } }, watch:{ value:function(val){ this.currentValue = val; }, currentValue:function(){ this.updateStatus(); } } });
pane.js
Vue.component('pane',{ name:'pane', template:'\ <div class="pane" v-show="show">\ <slot></slot>\ </div>', props:{ name:{ type:String }, label:{ type:String, default:'' }, closable:{ type:Boolean, default:true } }, data:function(){ return { show:true } }, methods:{ updateNav:function(){ this.$parent.updateNav(); } }, watch:{ label:function(){ this.updateNav(); } }, mounted:function(){ this.updateNav(); } });
相关文章推荐
- Vue.js 组件编码规范
- Vue.js分页组件实现:diVuePagination的使用详解
- Vue.js 组件和组件通信
- require.js+vue开发微信上传图片组件
- Vue.js一个文件对应一个组件实践
- 初探 amaze-vue( 基于vue.js封装的Amaze UI 组件库)
- Vue.js组件tabs实现选项卡切换效果
- vue.js移动端tab组件的封装实践实例
- Vue.js--基于$.ajax获取数据并与组件的data绑定
- Vue.js组件之同级之间的通信
- [vue.js]解决子组件无法获取父组件store中的值的问题
- 《前端福音,vue.js 之豆瓣电影组件大揭秘-video》
- 曹可爱之最可爱-Vue.js入门(十)组件3
- 在 2018 年来临之际,你应该知道的 Vue.js 的 11 个组件库
- Vue.js-组件
- Vuejs——(13)组件——杂项
- vue.js树形组件详解,删除双击增加分支
- Vue.js使用-组件(下篇)
- Vue.js 学习(9) -- 组件*1*
- Vue.js的组件(一)全局组件和局部组件