tabs
							parent
							
								
									b0a21a5b08
								
							
						
					
					
						commit
						3b6008151b
					
				| 
						 | 
				
			
			@ -23,3 +23,5 @@ export { default as Tag } from './tag'
 | 
			
		|||
export { default as Avatar } from './avatar'
 | 
			
		||||
 | 
			
		||||
export { default as Badge } from './badge'
 | 
			
		||||
 | 
			
		||||
export { default as Tabs } from './tabs'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,3 +8,4 @@ import './rate/style'
 | 
			
		|||
import './pagination/style'
 | 
			
		||||
import './avatar/style'
 | 
			
		||||
import './badge/style'
 | 
			
		||||
import './tabs/style'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
export default {
 | 
			
		||||
  /**
 | 
			
		||||
   * LEFT
 | 
			
		||||
   */
 | 
			
		||||
  LEFT: 37, // also NUM_WEST
 | 
			
		||||
  /**
 | 
			
		||||
   * UP
 | 
			
		||||
   */
 | 
			
		||||
  UP: 38, // also NUM_NORTH
 | 
			
		||||
  /**
 | 
			
		||||
   * RIGHT
 | 
			
		||||
   */
 | 
			
		||||
  RIGHT: 39, // also NUM_EAST
 | 
			
		||||
  /**
 | 
			
		||||
   * DOWN
 | 
			
		||||
   */
 | 
			
		||||
  DOWN: 40, // also NUM_SOUTH
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
export default {
 | 
			
		||||
  saveRef (name) {
 | 
			
		||||
    return node => {
 | 
			
		||||
      this[name] = node
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,75 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <button :class="classes" :disabled="disabled"
 | 
			
		||||
    @click="handleClick" @mouseout="mouseout" @mouseover="mouseover">
 | 
			
		||||
    {{tab}}
 | 
			
		||||
  </button>
 | 
			
		||||
</template>
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'TabBar',
 | 
			
		||||
  props: {
 | 
			
		||||
    prefixCls: {
 | 
			
		||||
      default: 'ant-tabs',
 | 
			
		||||
      type: String,
 | 
			
		||||
    },
 | 
			
		||||
    tabBarPosition: {
 | 
			
		||||
      default: 'top',
 | 
			
		||||
      validator (value) {
 | 
			
		||||
        return ['top', 'bottom'].includes(value)
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    disabled: Boolean,
 | 
			
		||||
    onKeyDown: Function,
 | 
			
		||||
    onTabClick: Function,
 | 
			
		||||
    activeKey: String,
 | 
			
		||||
    tab: String,
 | 
			
		||||
  },
 | 
			
		||||
  data () {
 | 
			
		||||
    return {
 | 
			
		||||
      sizeMap: {
 | 
			
		||||
        large: 'lg',
 | 
			
		||||
        small: 'sm',
 | 
			
		||||
      },
 | 
			
		||||
      clicked: false,
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    classes () {
 | 
			
		||||
      const { prefixCls, type, shape, size, loading, ghost, clicked, sizeMap } = this
 | 
			
		||||
      const sizeCls = sizeMap[size] || ''
 | 
			
		||||
      return {
 | 
			
		||||
        [`${prefixCls}`]: true,
 | 
			
		||||
        [`${prefixCls}-${type}`]: type,
 | 
			
		||||
        [`${prefixCls}-${shape}`]: shape,
 | 
			
		||||
        [`${prefixCls}-${sizeCls}`]: sizeCls,
 | 
			
		||||
        [`${prefixCls}-loading`]: loading,
 | 
			
		||||
        [`${prefixCls}-clicked`]: clicked,
 | 
			
		||||
        [`${prefixCls}-background-ghost`]: ghost || type === 'ghost',
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    handleClick (event) {
 | 
			
		||||
      if (this.clicked) {
 | 
			
		||||
        return
 | 
			
		||||
      }
 | 
			
		||||
      this.clicked = true
 | 
			
		||||
      clearTimeout(this.timeout)
 | 
			
		||||
      this.timeout = setTimeout(() => (this.clicked = false), 500)
 | 
			
		||||
      this.$emit('click', event)
 | 
			
		||||
    },
 | 
			
		||||
    mouseover (event) {
 | 
			
		||||
      this.$emit('mouseover', event)
 | 
			
		||||
    },
 | 
			
		||||
    mouseout (event) {
 | 
			
		||||
      this.$emit('mouseout', event)
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  beforeDestroy () {
 | 
			
		||||
    if (this.timeout) {
 | 
			
		||||
      clearTimeout(this.timeout)
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,66 @@
 | 
			
		|||
<script>
 | 
			
		||||
import {
 | 
			
		||||
  getTransformByIndex,
 | 
			
		||||
  getActiveIndex,
 | 
			
		||||
  getTransformPropValue,
 | 
			
		||||
  getMarginStyle,
 | 
			
		||||
} from './utils'
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'TabContent',
 | 
			
		||||
  props: {
 | 
			
		||||
    animated: { type: Boolean, default: true },
 | 
			
		||||
    animatedWithMargin: { type: Boolean, default: true },
 | 
			
		||||
    prefixCls: {
 | 
			
		||||
      default: 'ant-tabs',
 | 
			
		||||
      type: String,
 | 
			
		||||
    },
 | 
			
		||||
    activeKey: String,
 | 
			
		||||
    tabBarPosition: String,
 | 
			
		||||
  },
 | 
			
		||||
  data () {
 | 
			
		||||
    return {
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    classes () {
 | 
			
		||||
      const { animated, prefixCls } = this
 | 
			
		||||
      return {
 | 
			
		||||
        [`${prefixCls}-content`]: true,
 | 
			
		||||
        [animated
 | 
			
		||||
          ? `${prefixCls}-content-animated`
 | 
			
		||||
          : `${prefixCls}-content-no-animated`]: true,
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
  },
 | 
			
		||||
  render () {
 | 
			
		||||
    const {
 | 
			
		||||
      activeKey,
 | 
			
		||||
      tabBarPosition, animated, animatedWithMargin, classes,
 | 
			
		||||
    } = this
 | 
			
		||||
    let style = {}
 | 
			
		||||
    if (animated && this.$slots.default) {
 | 
			
		||||
      const activeIndex = getActiveIndex(this.$slots.default, activeKey)
 | 
			
		||||
      if (activeIndex !== -1) {
 | 
			
		||||
        const animatedStyle = animatedWithMargin
 | 
			
		||||
          ? getMarginStyle(activeIndex, tabBarPosition)
 | 
			
		||||
          : getTransformPropValue(getTransformByIndex(activeIndex, tabBarPosition))
 | 
			
		||||
        style = animatedStyle
 | 
			
		||||
      } else {
 | 
			
		||||
        style = {
 | 
			
		||||
          display: 'none',
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return (
 | 
			
		||||
      <div
 | 
			
		||||
        class={classes}
 | 
			
		||||
        style={style}
 | 
			
		||||
      >
 | 
			
		||||
        {this.$slots.default}
 | 
			
		||||
      </div>
 | 
			
		||||
    )
 | 
			
		||||
  },
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,48 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div
 | 
			
		||||
    role="tabpanel"
 | 
			
		||||
    :aria-hidden="active ? 'false' : 'true'"
 | 
			
		||||
    :class="classes"
 | 
			
		||||
  >
 | 
			
		||||
    <slot v-if="isRender || forceRender">
 | 
			
		||||
    </slot>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'TabPane',
 | 
			
		||||
  props: {
 | 
			
		||||
    pKey: [String, Number],
 | 
			
		||||
    forceRender: Boolean,
 | 
			
		||||
    // placeholder: [Function, String, Number],
 | 
			
		||||
  },
 | 
			
		||||
  data () {
 | 
			
		||||
    const { prefixCls, destroyInactiveTabPane, activeKey } = this.$parent
 | 
			
		||||
    return {
 | 
			
		||||
      rootPrefixCls: prefixCls,
 | 
			
		||||
      destroyInactiveTabPane,
 | 
			
		||||
      active: this.pKey === activeKey,
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    classes () {
 | 
			
		||||
      const { rootPrefixCls, active } = this
 | 
			
		||||
      const prefixCls = `${rootPrefixCls}-tabpane`
 | 
			
		||||
      return {
 | 
			
		||||
        [`${prefixCls}`]: true,
 | 
			
		||||
        [`${prefixCls}-inactive`]: !active,
 | 
			
		||||
        [`${prefixCls}-active`]: active,
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    isRender () {
 | 
			
		||||
      const {
 | 
			
		||||
        destroyInactiveTabPane, active,
 | 
			
		||||
      } = this
 | 
			
		||||
      this._isActived = this._isActived || active
 | 
			
		||||
      return destroyInactiveTabPane ? active : this._isActived
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
  },
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,174 @@
 | 
			
		|||
<script>
 | 
			
		||||
import Icon from '../icon'
 | 
			
		||||
import KeyCode from './KeyCode'
 | 
			
		||||
import TabBar from './TabBar'
 | 
			
		||||
import TabContent from './TabContent'
 | 
			
		||||
function getDefaultActiveKey (t) {
 | 
			
		||||
  let activeKey
 | 
			
		||||
  t.$slot.default.forEach((child) => {
 | 
			
		||||
    if (child && !activeKey && !child.disabled) {
 | 
			
		||||
      activeKey = child.pKey
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
  return activeKey
 | 
			
		||||
}
 | 
			
		||||
function activeKeyIsValid (t, key) {
 | 
			
		||||
  const keys = t.$slot.default.map(child => child && child.pKey)
 | 
			
		||||
  return keys.indexOf(key) >= 0
 | 
			
		||||
}
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'Tabs',
 | 
			
		||||
  components: { Icon },
 | 
			
		||||
  props: {
 | 
			
		||||
    prefixCls: {
 | 
			
		||||
      default: 'ant-tabs',
 | 
			
		||||
      type: String,
 | 
			
		||||
    },
 | 
			
		||||
    tabBarPosition: {
 | 
			
		||||
      default: 'top',
 | 
			
		||||
      validator (value) {
 | 
			
		||||
        return ['top', 'bottom'].includes(value)
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    destroyInactiveTabPane: Boolean,
 | 
			
		||||
    activeKey: String,
 | 
			
		||||
    defaultActiveKey: String,
 | 
			
		||||
  },
 | 
			
		||||
  data () {
 | 
			
		||||
    return {
 | 
			
		||||
      stateActiveKey: this.getStateActiveKey(),
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    classes () {
 | 
			
		||||
      const { prefixCls, tabBarPosition } = this
 | 
			
		||||
      return {
 | 
			
		||||
        [`${prefixCls}`]: true,
 | 
			
		||||
        [`${prefixCls}-${tabBarPosition}`]: true,
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  beforeUpdate () {
 | 
			
		||||
    if ('activeKey' in this) {
 | 
			
		||||
      this.stateActiveKey = this.activeKey
 | 
			
		||||
    } else if (!activeKeyIsValid(this, this.stateActiveKey)) {
 | 
			
		||||
      this.stateActiveKey = getDefaultActiveKey(this)
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    getStateActiveKey () {
 | 
			
		||||
      let activeKey
 | 
			
		||||
      if ('activeKey' in this) {
 | 
			
		||||
        activeKey = this.activeKey
 | 
			
		||||
      } else if ('defaultActiveKey' in this) {
 | 
			
		||||
        activeKey = this.defaultActiveKey
 | 
			
		||||
      } else {
 | 
			
		||||
        activeKey = getDefaultActiveKey(this)
 | 
			
		||||
      }
 | 
			
		||||
      return activeKey
 | 
			
		||||
    },
 | 
			
		||||
    onTabClick (activeKey) {
 | 
			
		||||
      if (this.tabBar.props.onTabClick) {
 | 
			
		||||
        this.tabBar.props.onTabClick(activeKey)
 | 
			
		||||
      }
 | 
			
		||||
      this.setActiveKey(activeKey)
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onNavKeyDown (e) {
 | 
			
		||||
      const eventKeyCode = e.keyCode
 | 
			
		||||
      if (eventKeyCode === KeyCode.RIGHT || eventKeyCode === KeyCode.DOWN) {
 | 
			
		||||
        e.preventDefault()
 | 
			
		||||
        const nextKey = this.getNextActiveKey(true)
 | 
			
		||||
        this.onTabClick(nextKey)
 | 
			
		||||
      } else if (eventKeyCode === KeyCode.LEFT || eventKeyCode === KeyCode.UP) {
 | 
			
		||||
        e.preventDefault()
 | 
			
		||||
        const previousKey = this.getNextActiveKey(false)
 | 
			
		||||
        this.onTabClick(previousKey)
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setActiveKey (activeKey) {
 | 
			
		||||
      if (this.stateActiveKey !== activeKey) {
 | 
			
		||||
        if (!('activeKey' in this)) {
 | 
			
		||||
          this.stateActiveKey = activeKey
 | 
			
		||||
        }
 | 
			
		||||
        this.$emit('change', activeKey)
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getNextActiveKey (next) {
 | 
			
		||||
      const activeKey = this.stateActiveKey
 | 
			
		||||
      const children = []
 | 
			
		||||
      this.$slot.default.forEach((c) => {
 | 
			
		||||
        if (c && !c.disabled) {
 | 
			
		||||
          if (next) {
 | 
			
		||||
            children.push(c)
 | 
			
		||||
          } else {
 | 
			
		||||
            children.unshift(c)
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
      const length = children.length
 | 
			
		||||
      let ret = length && children[0].key
 | 
			
		||||
      children.forEach((child, i) => {
 | 
			
		||||
        if (child.pKey === activeKey) {
 | 
			
		||||
          if (i === length - 1) {
 | 
			
		||||
            ret = children[0].key
 | 
			
		||||
          } else {
 | 
			
		||||
            ret = children[i + 1].key
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
      return ret
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  beforeDestroy () {
 | 
			
		||||
  },
 | 
			
		||||
  render () {
 | 
			
		||||
    const {
 | 
			
		||||
      prefixCls,
 | 
			
		||||
      tabBarPosition,
 | 
			
		||||
      destroyInactiveTabPane,
 | 
			
		||||
      onNavKeyDown,
 | 
			
		||||
      onTabClick,
 | 
			
		||||
      stateActiveKey,
 | 
			
		||||
      classes,
 | 
			
		||||
      setActiveKey,
 | 
			
		||||
      $slots,
 | 
			
		||||
    } = this
 | 
			
		||||
    const hasSlot = !!$slots.default
 | 
			
		||||
    const tabBarProps = []
 | 
			
		||||
    if (hasSlot) {
 | 
			
		||||
      $slots.default.forEach(tab => {
 | 
			
		||||
        tab.data && tabBarProps.push(
 | 
			
		||||
          <TabBar
 | 
			
		||||
            {...tab.data}
 | 
			
		||||
            prefixCls={prefixCls}
 | 
			
		||||
            onKeyDown={onNavKeyDown}
 | 
			
		||||
            tabBarPosition={tabBarPosition}
 | 
			
		||||
            onTabClick={onTabClick}
 | 
			
		||||
            activeKey={stateActiveKey} />)
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
    const tabContentProps = {
 | 
			
		||||
      props: {
 | 
			
		||||
        prefixCls,
 | 
			
		||||
        tabBarPosition,
 | 
			
		||||
        activeKey: stateActiveKey,
 | 
			
		||||
        destroyInactiveTabPane,
 | 
			
		||||
        onChange: setActiveKey,
 | 
			
		||||
        key: 'tabContent',
 | 
			
		||||
      }}
 | 
			
		||||
    return (
 | 
			
		||||
      <div
 | 
			
		||||
        class={classes}
 | 
			
		||||
      >
 | 
			
		||||
        {tabBarProps}
 | 
			
		||||
        <TabContent {...tabContentProps}>
 | 
			
		||||
          {$slots.default}
 | 
			
		||||
        </TabContent>
 | 
			
		||||
      </div>
 | 
			
		||||
    )
 | 
			
		||||
  },
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <Tabs activeKey="test1">
 | 
			
		||||
      <TabPane pKey="test1" tab="tab1">hello</TabPane>
 | 
			
		||||
      <TabPane pKey="test2" tab="tab2">world</TabPane>
 | 
			
		||||
    </Tabs>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<script>
 | 
			
		||||
import { Tabs } from 'antd'
 | 
			
		||||
export default {
 | 
			
		||||
  components: {
 | 
			
		||||
    Tabs,
 | 
			
		||||
    TabPane: Tabs.TabPane,
 | 
			
		||||
  },
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
import Tabs from './Tabs'
 | 
			
		||||
import TabPane from './TabPane'
 | 
			
		||||
import TabContent from './TabContent'
 | 
			
		||||
 | 
			
		||||
// import TabContent from './TabContent'
 | 
			
		||||
Tabs.TabPane = TabPane
 | 
			
		||||
export default Tabs
 | 
			
		||||
export { TabPane, TabContent }
 | 
			
		||||
export { TabPane }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,29 @@
 | 
			
		|||
export function toArray (children) {
 | 
			
		||||
  // allow [c,[a,b]]
 | 
			
		||||
  const c = []
 | 
			
		||||
  children.forEach(child => {
 | 
			
		||||
    if (child.data) {
 | 
			
		||||
      c.push(child)
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
  return c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getActiveIndex (children, activeKey) {
 | 
			
		||||
  const c = toArray(children)
 | 
			
		||||
  for (let i = 0; i < c.length; i++) {
 | 
			
		||||
    const pKey = c[i].pKey || c[i].componentOptions.propsData.pKey
 | 
			
		||||
    if (pKey === activeKey) {
 | 
			
		||||
      return i
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return -1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getActiveKey (children, index) {
 | 
			
		||||
  const c = toArray(children)
 | 
			
		||||
  return c[index].pKey
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function setTransform (style, v) {
 | 
			
		||||
  style.transform = v
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue