tab.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. <template>
  2. <div v-if='showTabs'>
  3. <div class="nut-tab" :class="{'nut-tab-leftnav' : positionNavCss}">
  4. <template v-if="positionNav=='top'">
  5. <div :class="['nut-tab-title',tabType]">
  6. <b class="nav-bar" :style="[{transform:'translateX('+initX+'px)'},{width:navWidth+'px'}]"></b>
  7. <span v-for="(value,index) in tabTitleList"
  8. v-bind:key="index"
  9. v-on:click="switchTab(index,$event,value.disable)" class="nut-title-nav-list"
  10. :class="['nut-title-nav',{'nut-tab-disable':value.disable},{'nut-tab-active' : activeIndex == index}]"
  11. >
  12. <b v-if='closable' class="close-btn" v-on:click="closeItem(value)">x</b>
  13. <a :href="value.href" :clstag="value.clstag" class="nut-tab-link" v-on:click="switchTabLink(index,$event,value.disable)">
  14. <i class="nut-tab-icon" :style="{backgroundImage: 'url('+value.iconUrl+')'}" v-if="value.iconUrl"></i>
  15. {{value.tabTitle}}
  16. </a>
  17. </span>
  18. </div>
  19. <div class="nut-tab-item" v-show="contentShow">
  20. <slot></slot>
  21. </div>
  22. </template>
  23. <template v-else-if="positionNav=='left'">
  24. <div :class="['nut-tab-title-leftnav',tabType]">
  25. <b class="nav-bar-left" :style="[{transform:'translateY('+initX+'px)'},{height:navWidth+'px'}]"></b>
  26. <span v-for="(value,index) in tabTitleList"
  27. v-bind:key="index"
  28. v-on:click="switchTab(index,$event,value.disable)" class="nut-title-nav-leftnav"
  29. :class="['nut-title-nav',{'nut-tab-disable':value.disable},{'nut-tab-active' : activeIndex == index}]"
  30. >
  31. <b v-if='closable' class="close-btn" v-on:click="closeItem(value)">x</b>
  32. <a :href="value.href" :clstag="value.clstag" class="nut-tab-link" v-on:click="switchTabLink(index,$event,value.disable)">
  33. <i class="nut-tab-icon" :style="{backgroundImage: 'url('+value.iconUrl+')'}" v-if="value.iconUrl"></i>
  34. {{value.tabTitle}}
  35. </a>
  36. </span>
  37. </div>
  38. <div class="nut-tab-item" v-show="contentShow">
  39. <slot></slot>
  40. </div>
  41. </template>
  42. <template v-else-if="positionNav=='right'">
  43. <div class="nut-tab-item" v-show="contentShow">
  44. <slot></slot>
  45. </div>
  46. <div :class="['nut-tab-title-rightnav',tabType]">
  47. <b class="nav-bar-right" :style="[{transform:'translateY('+initX+'px)'},{height:navWidth+'px'}]"></b>
  48. <span v-for="(value,index) in tabTitleList"
  49. v-bind:key="index"
  50. v-on:click="switchTab(index,$event,value.disable)" class="nut-title-nav-rightnav"
  51. :class="['nut-title-nav',{'nut-tab-disable':value.disable},{'nut-tab-active' : activeIndex == index}]"
  52. >
  53. <b v-if='closable' class="close-btn" v-on:click="closeItem(value)">x</b>
  54. <a :href="value.href" :clstag="value.clstag" class="nut-tab-link" v-on:click="switchTabLink(index,$event,value.disable)">
  55. {{value.tabTitle}}
  56. <i class="nut-tab-icon" :style="{backgroundImage: 'url('+value.iconUrl+')'}" v-if="value.iconUrl"></i>
  57. </a>
  58. </span>
  59. </div>
  60. </template>
  61. <template v-else-if="positionNav=='bottom'">
  62. <div class="nut-tab-item" v-show="contentShow">
  63. <slot></slot>
  64. </div>
  65. <div :class="['nut-tab-title-bottomnav',tabType]">
  66. <b class="nav-bar-bottom" :style="[{transform:'translateX('+initX+'px)'},{width:navWidth+'px'}]"></b>
  67. <span v-for="(value,index) in tabTitleList"
  68. v-bind:key="index"
  69. v-on:click="switchTab(index,$event,value.disable)" class="nut-title-nav-list"
  70. :class="['nut-title-nav',{'nut-tab-disable':value.disable},{'nut-tab-active' : activeIndex == index}]"
  71. >
  72. <b v-if='closable' class="close-btn" v-on:click="closeItem(value)">x</b>
  73. <a :href="value.href" :clstag="value.clstag" class="nut-tab-link" v-on:click="switchTabLink(index,$event,value.disable)">
  74. <i class="nut-tab-icon" :style="{backgroundImage: 'url('+value.iconUrl+')'}" v-if="value.iconUrl"></i>
  75. {{value.tabTitle}}
  76. </a>
  77. </span>
  78. </div>
  79. </template>
  80. </div>
  81. </div>
  82. </template>
  83. <script>
  84. export default {
  85. name:'nut-tab',
  86. props: {
  87. 'type':{
  88. type:String,
  89. default:'based',
  90. },
  91. 'defIndex':{
  92. type:Number,
  93. default:0,
  94. },
  95. 'contentShow':{
  96. type:Boolean,
  97. default:true,
  98. },
  99. 'positionNav':{
  100. type:String,
  101. default:'top',
  102. },
  103. 'closable':{
  104. type:Boolean,
  105. default:false,
  106. },
  107. 'initData':{
  108. type:Array,
  109. default:function(){
  110. return [];
  111. }
  112. }
  113. },
  114. data() {
  115. return {
  116. tabTitleList:[],
  117. activeIndex:this.defIndex,
  118. initIndex:0,
  119. showTabs:true,
  120. initX:'0px',
  121. navWidth:0,
  122. };
  123. },
  124. watch:{
  125. defIndex(){
  126. this.updeteTab();
  127. },
  128. initData:{
  129. handler(){
  130. this.updeteTab();
  131. },
  132. deep:true
  133. }
  134. },
  135. computed:{
  136. tabType:function(){
  137. return this.type;
  138. },
  139. positionNavCss:function(){
  140. if(this.positionNav=='top' || this.positionNav=='bottom'){
  141. return false;
  142. }else{
  143. return true;
  144. }
  145. },
  146. },
  147. mounted() {
  148. this.$nextTick(()=>{
  149. this.$slots.default && this.initTab(this.$slots.default);
  150. })
  151. },
  152. methods: {
  153. updeteTab:function(){
  154. setTimeout(()=>{
  155. let slot = [...this.$slots.default];
  156. this.tabTitleList = [];
  157. this.activeIndex = this.defIndex;
  158. this.initTab(slot);
  159. },100);
  160. },
  161. closeItem:function(value){
  162. this.$emit('tab-remove',value);
  163. setTimeout(()=>{
  164. this.tabTitleList=[];
  165. if(this.$slots.default){
  166. let slot = [...this.$slots.default];
  167. this.initTab(slot);
  168. }else{
  169. this.showTabs = false;
  170. }
  171. },10);
  172. },
  173. initTab:function(params){
  174. let slot = params;
  175. for(let i = 0; i < slot.length; i++) {
  176. let aa = slot[i].tag;
  177. if(typeof(aa)=='string'){
  178. if(slot[i].tag.indexOf('nut-tab-panel') != -1) {
  179. let item ={
  180. 'tabTitle':slot[i].data.attrs.tabTitle,
  181. 'disable':slot[i].data.attrs.disable==''?true:false,
  182. 'iconUrl':slot[i].data.attrs.iconUrl,
  183. 'clstag': slot[i].data.attrs.clstag,
  184. 'href':slot[i].data.attrs.tabLink?slot[i].data.attrs.tabLink:'javascript:void(0)',
  185. }
  186. this.tabTitleList.push(item);
  187. let slotElm = slot[i].elm;
  188. if(slotElm){
  189. this.addClass(slotElm,'hide');
  190. if(this.activeIndex == i) {
  191. this.removeClass(slotElm,'hide')
  192. }
  193. }
  194. }
  195. }
  196. }
  197. setTimeout(()=>{
  198. this.getTabWidth();
  199. },0);
  200. },
  201. getStyle:function(obj,styleName){
  202. if(obj.currentStyle){
  203. return obj.currentStyle[styleName];
  204. }else{
  205. return getComputedStyle(obj,null)[styleName];
  206. }
  207. },
  208. getTabWidth:function(){
  209. if(this.positionNav=='top' || this.positionNav=='bottom'){
  210. let tabTitle = document.querySelector('.nut-tab-title');
  211. let tabWidth = this.getStyle(tabTitle,'width');
  212. let tabWidthNum = tabWidth.substring(0,tabWidth.length-2);
  213. let navBarWidth = (tabWidthNum/this.tabTitleList.length);
  214. this.navWidth = navBarWidth;
  215. this.initX= parseInt(this.navWidth * this.defIndex);
  216. }else{
  217. let tabTitle = document.querySelector('.nut-tab-title-leftnav')||document.querySelector('.nut-tab-title-rightnav');
  218. let tabWidth = this.getStyle(tabTitle,'height');
  219. let tabWidthNum = tabWidth.substring(0,tabWidth.length-2);
  220. let navBarWidth = (tabWidthNum/this.tabTitleList.length);
  221. this.navWidth = navBarWidth;
  222. this.initX= parseInt(this.navWidth * this.defIndex);
  223. }
  224. },
  225. hasClass:function( elements,cName ){
  226. return !!elements.className.match( new RegExp( "(\\s|^)" + cName + "(\\s|$)") ); // ( \\s|^ ) 判断前面是否有空格 (\\s | $ )判断后面是否有空格 两个感叹号为转换为布尔值 以方便做判断
  227. },
  228. addClass:function( elements,cName ){
  229. if(!this.hasClass( elements,cName ) ){
  230. elements.className += " " + cName;
  231. };
  232. },
  233. removeClass:function ( elements,cName ){
  234. if( this.hasClass( elements,cName ) ){
  235. elements.className = elements.className.replace( new RegExp( "(\\s|^)" + cName + "(\\s|$)" )," " ); // replace方法是替换
  236. };
  237. },
  238. switchTabLink:function(index,event,disable){
  239. if(!disable){
  240. event.target.parentNode.click();
  241. }
  242. },
  243. switchTab:function(index,event,disable){
  244. if(!disable && event.target.className.indexOf('nut-title-nav')!==-1){
  245. this.activeIndex=index;
  246. this.initX= parseInt(this.navWidth * index);
  247. let nutTab = event.target.parentNode.parentNode;
  248. let items = this.positionNav=='bottom' || this.positionNav=='right' ?nutTab.children[0].children : nutTab.children[1].children;
  249. for(let i=0;i<items.length;i++){
  250. if(i==index){
  251. this.removeClass(items[i],'hide');
  252. }else{
  253. this.addClass(items[i],'hide');
  254. }
  255. }
  256. this.$emit('tab-switch',index,event);
  257. }
  258. }
  259. },
  260. }
  261. </script>