tab.vue 11 KB

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