Vue.js组件——标签页组件
来源:互联网 发布:python bt文件下载 编辑:程序博客网 时间:2024/06/05 15:09
按照《Vue.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){ 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中对应的内容也隐藏 //可以通过改变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(); }});
阅读全文
0 0
- Vue.js组件——标签页组件
- 【16】vue.js — 组件
- vue.js原生组件化开发——父子组件
- Vue.js组件——组件通信小demo
- Vue.js组件——组件的基础知识
- VUE.JS——组件基础
- Vue.js——组件入门
- VUE.JS——组件基础
- Vue.js知识总结——组件
- Vue.js组件——slot杂记
- 【17】vue.js — 组件(模板)
- 【18】vue.js — 动态组件
- 【19】vue.js — 父子组件
- 【Vue.js】-Vue.js组件
- Vue——组件
- Vue.js组件—父组件与子组件之间的数据联系
- Vue.js组件
- Vue.js笔记-组件
- Fatal signal 11 (SIGSEGV), code 2调试方法
- python简单的爬虫程序
- hibernate框架一对多级联删除例子(十三)
- 0、slam基础
- Matlab2017a安装教程及语言设置
- Vue.js组件——标签页组件
- gem5跑linux或安卓bench
- 如何成为一名全栈语音识别工程师?
- 模板的类型萃取
- Sublime Text2 多行编辑快捷键
- hdu 4259 置换入门题
- php7安装redis 扩展
- 2-3 triangle
- 2017ACM-ICPC香港区域赛赛后感