Tabs

更新时间:
复制 MD 格式

Switches between same-level content groups, typically at the top of forms or standard list interfaces.

Important
  • Currently, only one Tabs component can be used on a single page.

  • In base libraries 2.x, an embedded scroll-view may become unscrollable. To fix this, prevent touch events from bubbling up from the scroll-view using `catchTouchStart` and `catchTouchMove`.

  • Tabs use the transform style internally for the carousel effect. This can cause display issues with nested pop-up layers. Avoid nesting components that contain pop-up layers. Alternatively, you can use the `fallback` property to implement a simple version of the carousel yourself. For more information, see the fallback demo below.

Properties

Tabs

Property

Type

Required

Default

Description

adjustHeight

string

No

'current'

Automatically sets the container height to the height of the specified panel.

activeClass

string

No

''

The class of the swiper-item when it is visible.

animation

boolean

No

false

Whether to use a transition animation.

className

string

No

-

The class name.

easingFunction

string

No

'default'

The easing animation type for tab switching.

index

number

No

0

The active index.

nextMargin

string

No

'0px'

The next margin. The unit is px. In version 1.9.0, only the horizontal direction is supported.

plus

string | slot

No

-

Custom action button in the upper-right corner.

previousMargin

string

No

'0px'

The previous margin. The unit is px. In version 1.9.0, only the horizontal direction is supported.

snapToEdge

boolean

No

false

When there are two or more swiper-items, `circular` is off, and `previous-margin` or `next-margin` is on, this specifies if the margin applies to the first and last items.

sticky

boolean

No

false

Whether to enable the sticky header effect.

swipeRatio

number

No

0.2

The threshold for triggering a tab switch with a horizontal swipe gesture. The swiper-item switches when the swipe distance exceeds this threshold.

swipeSpeed

number

No

0.05

Controls the swipe distance of the swiper-item relative to the user's gesture. A smaller value means the swiper-item moves less for the same gesture distance.

swipeable

boolean

No

false

Whether to allow switching tabs with swipe gestures.

title

slot-scope

No

-

Customizes the tab title style. This is available only when `type` is set to `basis`.

touchAngle

number

No

45

The swipe angle at which a horizontal swipe gesture takes effect. The angle is calculated based on the coordinates of the `touchstart` event and the first `touchmove` event. A smaller value requires a more precise horizontal swipe direction from the user.

type

'basis' | 'capsule' | 'mixin'

No

'basis'

The type.

  • Basis

  • Capsule

  • Mix-in

TabItem

Property

Type

Required

Default

Description

tab

{title: string; subTitle?: string; badge?: number; disabled?: boolean}[]

Yes

-

The content of each tab.

className

string

No

-

The class name.

Events

Event name

Description

Type

onChange

Triggered when the active panel changes.

(index: number) => void

onAnimationEnd

The `onAnimationEnd` event of the internal swiper component. Available in base library 1.50.0 and later.

(e: any) => void

onTouchStart

The `onTouchStart` event of the internal swiper component. Available in base library 2.x and later.

(e: any) => void

onTransition

The `onTransition` event of the internal swiper component. Available in base library 2.x and later.

(e: any) => void

Slots

Tabs

Name

Description

plus

Extra content for the form item.

Scoped slots

Tabs

Name

Description

title

Customizes the tab title style.

Style classes

Tabs

Class name

Description

amd-tabs

The overall style.

amd-tabs-bar

The style of the title area at the top.

amd-tabs-bar-active

The style of the title area when it is active.

amd-tabs-bar-active:after

The style of the indicator when the title area is active.

amd-tabs-bar

The style of the title area at the top.

amd-tabs-bar-sticky

The style for the sticky state.

amd-tabs-bar-plus

Tag style in the top-right corner.

amd-tabs-bar-fade

The style for the fade effect on both sides.

amd-tabs-bar-fade-left

The style for the fade effect on the left.

amd-tabs-bar-fade-right

The style for the fade effect on the right.

amd-tabs-bar-scroll-view

The style of the internal ScrollView component.

amd-tabs-bar-wrap

The style of each title.

amd-tabs-bar-item

The style of each title.

amd-tabs-bar-basis

The style of each title when `type` is `basis`.

amd-tabs-bar-capsule

The style of each title when `type` is `capsule`.

amd-tabs-bar-capsule-title

The style of the text inside each title when `type` is `capsule`.

amd-tabs-bar-capsule-badge

The style of the badge inside each title when `type` is `capsule`.

amd-tabs-bar-mixin

The style of each title when `type` is `mixin`.

amd-tabs-bar-mixin-title

The style of the text in each title when `type` is `mixin`.

amd-tabs-bar-mixin-subtitle

The style of the subtitle in each title when `type` is `mixin`.

amd-tabs-bar-disabled

The style of a disabled tab.

TabItem

Class name

Description

amd-tabs-item

The style of the tab menu.

amd-tabs-item-pane

The style of the content panel below the tabs.

Code examples

Basic usage

The following code is an example of `index.axml`:

<view>
  <tabs 
    index="{{index}}" 
    type="{{type}}" 
    animation="{{animation}}" 
    swipeable="{{swipeable}}" 
    sticky="{{sticky}}"
    onChange="handleChangeTab">
    <view a:if="{{plusSlot}}" slot="plus" >
      <icon 
        size="small"
        type="AddOutline" 
        className="plus-icon"
        onTap="handleClickIcon" />
    </view>
    <view 
      a:if="{{titleSlot}}"
      slot-scope="prop" 
      slot="title">
      {{prop.tab.title + ' slot'}}
    </view> 
    <block a:for="{{tabs}}">
      <tab-content 
        a:if="{{index === 1}}" 
        tab="{{item}}">
        <view>
          {{item.title}}
            <view 
              a:for="{{height}}">
              ........Height adapts to content........
            </view>
        </view>
      </tab-content>

      <tab-content 
        a:elif="{{index === 3}}"
        tab="{{item}}">
        <view style="height: 30vh">
          ........{{item.title}}........
          <text>Content with parent-defined height</text>
        </view>
      </tab-content>

      <tab-content tab="{{item}}" a:else badge="{{item.badge}}">
        <view style="height: 20vh">
          ........{{item.title}}........
        </view>
      </tab-content>

    </block>
  </tabs>
  <list radius className="actions">
    <list-item>
      Number of tabs
      <radio-group 
        slot="extra"
        class="radio-group"
        name="tabsNumber" 
        onChange="handleChangeTabNum" >
        <label 
          class="radio" 
          a:for="{{tabsNumber}}">
          <radio 
            value="{{item.name}}" 
            checked="{{item.checked}}" />
          <text 
            class="radio-text">
            {{item.value}}
          </text>
        </label>
      </radio-group>
    </list-item>
    <list-item>
      type
      <radio-group 
        slot="extra"
        class="radio-group" 
        name="tabsType"
        onChange="handleChangeType" >
        <label 
          class="radio" 
          a:for="{{tabsType}}">
          <radio 
            value="{{item.name}}" 
            checked="{{item.checked}}" />
          <text 
            class="radio-text">
            {{item.value}}
          </text>
        </label>
      </radio-group>
    </list-item>
    <list-item>
      Content transition animation<switch checked="{{animation}}" controlled onChange="handleChangeAnimation" slot="extra"/>
    </list-item>
    <list-item>
      Support swipe to switch<switch checked="{{swipeable}}" controlled onChange="handleChangeSwipeable" slot="extra"/>
    </list-item>
    <list-item brief="sticky effect">
      Sticky header<switch checked="{{sticky}}" controlled onChange="handleChangeSticky" slot="extra"/>
    </list-item>
    <list-item brief="Custom tab display, has higher priority than configuration">
      title slot<switch checked="{{titleSlot}}" controlled onChange="handleChangeTitleSlot" slot="extra"/>
    </list-item>
    <list-item brief="Action button in the upper-right corner">
      plus slot<switch checked="{{plusSlot}}" controlled onChange="handleChangePlusSlot" slot="extra"/>
    </list-item>
  </list>
</view>

The following code is an example of `index.js`:

Page({
  data: {
    index: 0,
    height: 30,
    type: 'basis',
    animation: true,
    swipeable: true,
    titleSlot: false,
    plusSlot: true,
    sticky: false,
    tabs: [
      {
        title: 'Tab 1',
        subTitle: 'Description',
      },
      {
        title: 'Tab 2',
        subTitle: 'Description text',
      },
      {
        title: 'Tab 3',
        subTitle: 'Description',
      },
    ],
    tabsType: [
      { name: 'basis', value: 'Basic', checked: true },
      { name: 'capsule', value: 'Capsule' },
      { name: 'mixin', value: 'With description' },
    ],
    tabsNumber: [
      { name: '1', value: 'One' },
      { name: '2', value: 'Two' },
      { name: '3', value: 'Three', checked: true },
      { name: '-1', value: 'Many' },
    ],
  },
  handleChangeAnimation(checked) {
    this.setData({ animation: checked });
  },
  handleChangeSwipeable(checked) {
    this.setData({ swipeable: checked });
  },
  handleChangeSticky(checked) {
    this.setData({ sticky: checked });
  },
  handleChangeTitleSlot(checked) {
    this.setData({ titleSlot: checked });
  },
  handleChangePlusSlot(checked) {
    this.setData({ plusSlot: checked });
  },
  handleChangeType(e) {
    this.setData({
      type: e.detail.value,
    });
  },
  // Callback for tab clicks
  handleChangeTab(e) {
    this.setData({
      index: e,
    });
  },
  // Click event for the plus area in the upper-right corner
  handleClickIcon() {
    my.alert({
      title: 'slot="plus"',
      content: 'The icon in the custom slot was clicked',
    });
  },
  handleChangeTabNum(e) {
    if (e.detail.value === '1') {
      this.setData({
        tabs: [
          {
            title: 'Tab',
            subTitle: 'Description',
            badge: 6,
          },
        ],
      });
    } else if (e.detail.value === '2') {
      this.setData({
        tabs: [
          {
            title: 'Tab',
            subTitle: 'Description',
          },
          {
            title: 'Tab 2',
            subTitle: 'Description text',
          },
        ],
      });
    } else if (e.detail.value === '3') {
      this.setData({
        tabs: [
          {
            title: 'Tab 1',
            subTitle: 'Description',
          },
          {
            title: 'Tab 2',
            subTitle: 'Description text',
          },
          {
            title: 'Tab 3',
            subTitle: 'Description',
          },
        ],
      });
    } else {
      this.setData({
        tabs: [
          {
            title: 'Tab 1',
            subTitle: 'Description',
          },
          {
            title: 'Tab 2',
            subTitle: 'Description text',
          },
          {
            title: 'Tab 3',
            subTitle: 'Description',
          },
          {
            title: '4 Tab',
            subTitle: 'Description',
            showBadge: true,
            badge: 1,
          },
          {
            title: '5 Tab',
            subTitle: 'Description',
            badge: 999,
          },
          {
            title: '3 Tab',
            subTitle: 'Description',
          },
          {
            title: '4 Tab',
            subTitle: 'Description',
          },
          {
            title: '151111 Tab',
            subTitle: 'Description',
          },
          {
            title: '42345 Tab',
            subTitle: 'Description',
          },
          {
            title: '1511116787 Tab',
            subTitle: 'Description',
          },
          {
            title: '42452 Tab',
            subTitle: 'Description',
          },
          {
            title: '15451111 Tab',
          },
          {
            title: '4234 Tab',
            subTitle: 'Description',
          },
          {
            title: '11251111 Tab',
            subTitle: 'Description',
          },
          {
            title: '44123 Tab',
          },
          {
            title: '1531111 Tab',
            subTitle: 'Description',
          },
          {
            title: '41 Tab',
          },
          {
            title: '15111111 Tab',
          },
        ],
      });
    }
  },
});

The following code is an example of `index.acss`:

.actions {
  margin-top: 24px;
}
.amd-tabs-item-pane view {
  background-color: #fff;
  padding: 24rpx;
}

.plus-icon {
  font-size: 48rpx;
}

The following code is an example of `index.json`:

{
  "defaultTitle": "Tabs",
  "usingComponents": {
    "tabs": "antd-mini/es/Tabs/index",
    "tab-content": "antd-mini/es/Tabs/TabItem/index",
    "icon": "antd-mini/es/Icon/index",
    "list": "antd-mini/es/List/index",
    "list-item": "antd-mini/es/List/ListItem/index",
    "switch": "antd-mini/es/Switch/index",
    "demo-block": "../../components/DemoBlock/index"
  }
}

fallback

The following code is an example of `index.axml`:

<tabs 
  index="{{curIdx}}" 
  type="{{type}}" 
  fallback="{{true}}" 
  sticky="{{sticky}}"
  onChange="changeTab">
  <block a:for="{{tabs}}">
    <tab-content 
      style="{{curIdx===index ? '' : 'display:none'}}"
      tab="{{item}}">
      <view>
        {{item.title}}
          <view 
            a:for="{{height}}">
            ........Height adapts to content........
          </view>
      </view>
    </tab-content>
  </block>
</tabs>

The following code is an example of `index.js`:

const component2 = my.canIUse('component2');

Page({
  data: {
    curIdx: 2,
    height: 30,
    type: 'basis',
    animation: false,
    swipeable: false,
    titleSlot: false,
    plusSlot: true,
    sticky: false,
    tabs: [
      {
        title: 'Tab 1',
        subTitle: 'Description',
        corner: true,
      },
      {
        title: 'Tab 2',
        subTitle: 'Description text',
      },
      {
        title: 'Tab 3',
        subTitle: 'Description',
      },
    ],
    tabsType: [
      { name: 'basis', value: 'Basic', checked: true },
      { name: 'capsule', value: 'Capsule' },
      { name: 'mixin', value: 'With description' },
    ],
    tabsNumber: [
      { name: '1', value: 'One' },
      { name: '2', value: 'Two' },
      { name: '3', value: 'Three' },
      { name: '-1', value: 'Many', checked: true },
    ],
    tabsAnimation: [
      { name: true, value: 'true' },
      { name: false, value: 'false', checked: true },
    ],
    tabsSwipeable: [
      { name: true, value: 'true' },
      { name: false, value: 'false', checked: true },
    ],
    tabsTitleSlotScope: [
      { name: true, value: 'true' },
      { name: false, value: 'false', checked: true },
    ],
    tabsSticky: [
      { name: true, value: 'true' },
      { name: false, value: 'false', checked: true },
    ],
    tabsPlusSlotScope: [
      { name: true, value: 'true', checked: true },
      { name: false, value: 'false' },
    ],
    canSwipe: true,
  },
  onLoad() {
    if (!component2) {
      this.setData({
        canSwipe: component2,
      });
    }
  },
  // Callback for tab clicks
  changeTab(e) {
    this.setData({
      curIdx: e,
    });
  },
  // Click event for the plus area in the upper-right corner
  iconClick() {
    my.alert({
      title: 'slot="plus"',
      content: 'The icon in the custom slot was clicked',
    });
  },
});

The following code is an example of `index.json`:

{
    "defaultTitle": "Tabs",
    "usingComponents": {
      "tabs": "antd-mini/es/Tabs/index",
      "tab-content": "antd-mini/es/Tabs/TabItem/index",
      "icon": "antd-mini/es/Icon/index"
    }
  }