如何在微信原生小程序中使用van-tabbar 实现:自定义底部导航栏

創建於:2025年2月17日

使用 O1 回答 Chat01

問題

如何在微信原生小程序中使用van-tabbar 实现:自定义底部导航栏

思考

Integrating Van-Tabbar

I'm clarifying steps to integrate Van-Tabbar from Vant WeApp into a WeChat mini-program, covering installing the library, importing the tabbar component, referencing it in JSON, adjusting its configuration, and customizing tabbars.

Integrating the snippet

I provided a code snippet for integrating Van-Tabbar in a WeChat mini-program, including JSON updates, WXML structure, and JavaScript handling, and suggested custom tabbar options.

Reasoned for 13 seconds

回答

下面给出一个在微信原生小程序中使用 Vant Weapp 的 van-tabbar 组件,自定义底部导航栏的示例步骤。假设你已经能够在项目中正常安装和使用 Vant Weapp,如果没有,可以参考下面的简要安装步骤。


1. 安装或引入 Vant Weapp

方法一:使用 npm + 小程序第三方依赖管理

  1. 在小程序开发者工具中,开启“使用 npm 模块”选项。
  2. 在项目根目录下执行:
    bash
    npm init -y npm install @vant/weapp --save
  3. 打开小程序开发者工具,“工具” -> “构建 npm”,构建完成后即可使用。
  4. 也可在项目根目录添加/修改 mini.project.json 文件:
    json
    { "setting": { "packNpmManually": true, "packNpmRelationList": [ { "packageJsonPath": "./package.json", "miniprogramNpmDistDir": "./miniprogram_npm" } ] } }

方法二:下载源代码引入

如果不方便使用 npm,可以直接下载 Vant Weapp 仓库,然后将 dist 目录拷贝到小程序目录中。例如放到 components/vant-weapp 下面,然后使用相对路径引用。


2. 确保隐藏或不使用原生 tabBar

如果你想完全自定义底部导航栏,需要在 app.json 里去掉/注释掉原生 tabBar 的相关配置。一般情况下,不配置 tabBar 即可。如果你已经配置过,需要删除或者改成自定义组件的方式。


3. 在页面或自定义组件中引入 van-tabbar、van-tabbar-item

你可以将自定义的底部导航写在每个页面的 WXML 中,也可以封装成一个公共的自定义组件,然后在各页面中直接引用。这里演示的是最简形式,直接写在某个页面里(比如 pages/index/index):

3.1 在该页面的 JSON 配置中引入组件

假设你是通过 npm 的方式安装,并且使用自动构建,这时引入路径一般是:

json
{ "usingComponents": { "van-tabbar": "@vant/weapp/tabbar/index", "van-tabbar-item": "@vant/weapp/tabbar-item/index" } }

如果你是直接复制的 dist 文件夹,则引入路径参考你放置的真实位置,示例:

json
{ "usingComponents": { "van-tabbar": "/components/vant-weapp/tabbar/index", "van-tabbar-item": "/components/vant-weapp/tabbar-item/index" } }

3.2 在页面的 WXML 中使用 van-tabbar

html
<!-- pages/index/index.wxml --> <view class="container"> <!-- 其他内容 --> <van-tabbar active="{{ active }}" bind:change="onChange" safe-area-inset-bottom > <van-tabbar-item icon="home-o" name="home">首页</van-tabbar-item> <van-tabbar-item icon="search" name="search">搜索</van-tabbar-item> <van-tabbar-item icon="friends-o" name="friends">好友</van-tabbar-item> <van-tabbar-item icon="setting-o" name="settings">设置</van-tabbar-item> </van-tabbar> </view>

说明:

  • active="{{ active }}" 用于控制当前选中的 tab。
  • bind:change="onChange" 是当用户点击切换 tab 时的事件回调。
  • safe-area-inset-bottom 属性可以兼容 iPhone X 系列等带有底部安全区域的设备,自动给底部留出安全区域。

3.3 在页面的 JS 中处理逻辑

js
// pages/index/index.js Page({ data: { active: 'home' // 默认选中的 tab }, onChange(event) { // event.detail 即当前点击的 tabbar-item 的 name const currentName = event.detail; this.setData({ active: currentName }); // 这里可以做页面跳转 switch (currentName) { case 'home': wx.switchTab({ url: '/pages/home/home' }); break; case 'search': wx.navigateTo({ url: '/pages/search/search' }); break; case 'friends': wx.navigateTo({ url: '/pages/friends/friends' }); break; case 'settings': wx.navigateTo({ url: '/pages/settings/settings' }); break; default: break; } } });

注意:

  • 如果你要用原生的 tabBar 类似 switchTab 跳转,需要先在 app.jsonpages 里注册对应页面,否则会报错。
  • 若你是完全自定义导航,可以使用 navigateToredirectTo 等自定义页面跳转方式。

4. 优化:封装成公共组件

如果项目里多页面都需要相同的底部导航,可以把 van-tabbar 的使用封装到一个自定义组件里,比如 components/custom-tabbar/custom-tabbar,再在各个页面中引入这个自定义组件。这样便于统一管理。例如:

json
// components/custom-tabbar/custom-tabbar.json { "component": true, "usingComponents": { "van-tabbar": "@vant/weapp/tabbar/index", "van-tabbar-item": "@vant/weapp/tabbar-item/index" } }
html
<!-- components/custom-tabbar/custom-tabbar.wxml --> <van-tabbar active="{{ active }}" bind:change="onChange" safe-area-inset-bottom > <van-tabbar-item icon="home-o" name="home">首页</van-tabbar-item> <van-tabbar-item icon="search" name="search">搜索</van-tabbar-item> <van-tabbar-item icon="friends-o" name="friends">好友</van-tabbar-item> <van-tabbar-item icon="setting-o" name="settings">设置</van-tabbar-item> </van-tabbar>
js
// components/custom-tabbar/custom-tabbar.js Component({ properties: { active: { type: String, value: 'home' } }, methods: { onChange(event) { const currentName = event.detail; this.triggerEvent('change', { value: currentName }); } } });

然后在你的页面中使用:

json
// pages/index/index.json { "usingComponents": { "custom-tabbar": "/components/custom-tabbar/custom-tabbar" } }
html
<!-- pages/index/index.wxml --> <view class="container"> <!-- 其他内容 --> <custom-tabbar active="{{ active }}" bind:change="onTabbarChange" /> </view>
js
// pages/index/index.js Page({ data: { active: 'home' }, onTabbarChange(e) { const currentName = e.detail.value; this.setData({ active: currentName }); // 这里做页面跳转等逻辑 // ... } });

这样就可以实现多页面共享同一个底部导航栏的逻辑。


总结

  1. 安装并引入 Vant Weapp:确保在小程序中能正常调用。
  2. 隐藏原生 tabBar:如果想自定义,就别在 app.json 中配置原生 tabBar
  3. 页面中引用 van-tabbar、van-tabbar-item:在页面的 JSON 中声明组件路径,在 WXML 中编写。
  4. 绑定事件和状态:通过 active 属性控制当前选中的标签,在 bind:change 中做页面跳转或逻辑处理。
  5. 可进一步封装成自定义组件:在各页面中复用,减少重复代码。

通过以上步骤,就可以在微信原生小程序中使用 Vant Weapp 的 van-tabbar 实现自定义底部导航栏。这样可以自由定制图标、文字、交互逻辑等,也可以结合小程序本身的页面路由进行跳转。希望能帮你快速上手!

問題

需求完善:
1.导航栏 tab数量:固定是4个
2.每个tab 显示名称和 url和icon不同
3.用函数方式实现控制:入参:lx(0/经销商 1/甲方 2/护工 3/用户)
函数放置在app.js中

<!-- 底部 自定义导航栏 start-->

<van-tabbar active="{{ active }}" bind:change="onChange" safe-area-inset-bottom>
<van-tabbar-item icon="home-o" name="home">首页</van-tabbar-item>
<van-tabbar-item icon="search" name="search">搜索</van-tabbar-item>
<van-tabbar-item icon="friends-o" name="friends">好友</van-tabbar-item>
<van-tabbar-item icon="setting-o" name="settings">设置</van-tabbar-item>
</van-tabbar>

<!-- 底部 自定义导航栏 end-->

思考

Crafting a tailored tab

I’m thinking through a personalized van-tabbar with four tabs, each dynamically displaying text, icons, and urls based on the lx parameter, representing various roles.

Setting up dynamic tab bars

I’m creating a dynamic van-tabbar by establishing a config function in app.js, integrating role-based parameters, and leveraging WXML for UI, enabling adaptable navigation icons and labels.

Crafting the approach

I'm considering a role-based config array or a dynamic single array for van-tabbar items. The onChange method will handle page navigation, with a complete setup example provided.

Configuring tabs

I’m detailing the getTabbarListByType function in app.js to generate dynamic van-tabbar items based on the lx parameter. The onLoad method ensures the correct tabs are displayed.

Navigating options

I'm detailing how to bind the onChange method to the van-tabbar, using either a numeric index or names like {{index}} or {{item.name}} for clarity.

Finalizing the design

Wrapping up the van-tabbar setup with WXML, JSON, and JS, ensuring dynamic navigation based on roles, and integrating the getTabbarConfig function to manage tabs effectively.

Reasoned for 33 seconds

回答

下面演示一个思路:

  • app.js 中编写一个函数,根据不同用户类型(0/1/2/3)返回对应的 4 个 Tab 配置(文本、图标、跳转 URL 等)。
  • 在页面(或自定义组件)中,通过 getApp() 调用这个函数获得 Tab 配置,使用 van-tabbar + van-tabbar-item 动态渲染。
  • bind:change 回调里,根据选中的 tab 执行不同的跳转逻辑。

下面给出一个完整的示例供你参考。


一、在 app.js 中定义函数

在小程序根目录下的 app.js 中,添加一个方法 getTabbarConfig(lx),用来返回对应角色(lx)下的 4 个 Tab 数据。

js
// app.js App({ onLaunch() { // ... }, /** * 根据不同用户类型,返回对应的 Tab 配置 * lx: 0(经销商), 1(甲方), 2(护工), 3(用户) */ getTabbarConfig(lx) { switch (lx) { case 0: // 经销商 return [ { name: 'home', text: '首页', icon: 'home-o', url: '/pages/dealer/home/home' }, { name: 'order', text: '订单', icon: 'orders-o', url: '/pages/dealer/order/order' }, { name: 'friends', text: '好友', icon: 'friends-o', url: '/pages/dealer/friends/friends' }, { name: 'profile', text: '我的', icon: 'setting-o', url: '/pages/dealer/profile/profile' }, ]; case 1: // 甲方 return [ { name: 'home', text: '首页', icon: 'home-o', url: '/pages/client/home/home' }, { name: 'bill', text: '账单', icon: 'bill-o', url: '/pages/client/bill/bill' }, { name: 'search', text: '搜索', icon: 'search', url: '/pages/client/search/search' }, { name: 'profile', text: '我的', icon: 'setting-o', url: '/pages/client/profile/profile' }, ]; case 2: // 护工 return [ { name: 'home', text: '首页', icon: 'home-o', url: '/pages/nurse/home/home' }, { name: 'task', text: '任务', icon: 'todo-list-o', url: '/pages/nurse/task/task' }, { name: 'friends', text: '好友', icon: 'friends-o', url: '/pages/nurse/friends/friends' }, { name: 'profile', text: '我的', icon: 'setting-o', url: '/pages/nurse/profile/profile' }, ]; case 3: // 普通用户 return [ { name: 'home', text: '首页', icon: 'home-o', url: '/pages/user/home/home' }, { name: 'search', text: '发现', icon: 'search', url: '/pages/user/discover/discover' }, { name: 'cart', text: '购物车', icon: 'shopping-cart-o', url: '/pages/user/cart/cart' }, { name: 'profile', text: '个人', icon: 'setting-o', url: '/pages/user/profile/profile' }, ]; default: // 其他或默认 return [ { name: 'home', text: '首页', icon: 'home-o', url: '/pages/home/home' }, { name: 'search', text: '搜索', icon: 'search', url: '/pages/search/search' }, { name: 'friends', text: '好友', icon: 'friends-o', url: '/pages/friends/friends' }, { name: 'settings', text: '设置', icon: 'setting-o', url: '/pages/settings/settings' }, ]; } } });
  • 你可以根据自己的路由结构修改 url
  • icon 可以用 Vant Weapp 内置的 icon 名称(如 home-osearchfriends-osetting-o 等),也可以用自定义图标。

二、页面中引用并渲染

下面以某个页面(比如 pages/index/index)为例,说明如何动态渲染并响应点击事件。

1. 引入 van-tabbar & van-tabbar-item 组件

先在 pages/index/index.json 中引入 Vant Weapp 组件:

json
{ "usingComponents": { "van-tabbar": "@vant/weapp/tabbar/index", "van-tabbar-item": "@vant/weapp/tabbar-item/index" } }

如果你是通过拷贝 dist 方式引入,需要把路径改成相对路径:

json
{ "usingComponents": { "van-tabbar": "/components/vant-weapp/tabbar/index", "van-tabbar-item": "/components/vant-weapp/tabbar-item/index" } }

2. 页面 WXML 中循环渲染 4 个 Tab

示例 pages/index/index.wxml

html
<view class="container"> <!-- 其他页面内容 --> <!-- 自定义底部导航栏 --> <van-tabbar active="{{ activeIndex }}" bind:change="onChange" safe-area-inset-bottom > <block wx:for="{{ tabList }}" wx:key="name"> <!-- 使用 tab 的 icon、text、name 动态渲染 --> <van-tabbar-item icon="{{ item.icon }}" name="{{ item.name }}"> {{ item.text }} </van-tabbar-item> </block> </van-tabbar> </view>
  • active="{{ activeIndex }}" 表示当前选中的 tab 索引或名称。这里我们演示用“名称(name)”来区分。
  • 通过 wx:for 遍历在 data.tabList 中的 4 个 tab 配置,动态生成 van-tabbar-item

3. 页面 JS 中获取配置并处理点击事件

示例 pages/index/index.js:

js
const app = getApp(); Page({ data: { tabList: [], // 存放4个Tab的数组 activeIndex: '', // 当前激活的Tab名称 userType: 0 // 假设用来存储用户类型(0=经销商,1=甲方,2=护工,3=用户) }, onLoad(options) { // 也可以从 options 或 app.globalData 中获取用户类型 // 这里演示写死 userType = 0 (经销商),实际根据业务修改 const userType = 0; // 或者: const userType = app.globalData.userType; // 调用 app.js 提供的函数,获取该角色的底部导航配置 const tabs = app.getTabbarConfig(userType); // 设置 data this.setData({ userType, tabList: tabs, activeIndex: tabs.length ? tabs[0].name : '' // 默认选中第1个 }); }, // 底部Tab切换时的回调 onChange(event) { // event.detail 即 van-tabbar 传递的 'name' 值 const clickedName = event.detail; this.setData({ activeIndex: clickedName }); // 找到对应的 tab 配置,拿到要跳转的页面 const tabItem = this.data.tabList.find(item => item.name === clickedName); if (tabItem) { // 路由跳转 // 如果这些目标页面是小程序的“tabBar”页面,需要用 wx.switchTab // 否则用 navigateTo / redirectTo 均可 wx.navigateTo({ url: tabItem.url }); } } });

注意

  1. 如果你想使用 switchTab 进行跳转,则需要在小程序 app.json 中的 tabBar -> list 里提前声明那些页面。否则会提示“页面未定义在 tabBar 中”。
  2. 如果你是完全自定义 tabBar,不想用微信原生的 tabBar 配置,就可以使用 navigateToredirectTo 等常规跳转 API。
  3. 代码中的 “默认选中第1个” 只是一种示例,你可以根据实际需要来初始化 activeIndex

三、可选:封装成自定义组件

如果多个页面都需要同样的逻辑,你可以把底部导航封装成一个自定义组件(如 components/custom-tabbar/custom-tabbar),并在组件内写上 “根据用户类型获取 tabList 并渲染” 的逻辑,再在各个页面引用这个组件。

示例结构:

text
components/ └─ custom-tabbar/ ├─ custom-tabbar.js ├─ custom-tabbar.json ├─ custom-tabbar.wxml └─ custom-tabbar.wxss

custom-tabbar.json:

json
{ "component": true, "usingComponents": { "van-tabbar": "@vant/weapp/tabbar/index", "van-tabbar-item": "@vant/weapp/tabbar-item/index" } }

custom-tabbar.wxml:

html
<van-tabbar active="{{ activeIndex }}" bind:change="onChange" safe-area-inset-bottom > <block wx:for="{{ tabList }}" wx:key="name"> <van-tabbar-item icon="{{ item.icon }}" name="{{ item.name }}"> {{ item.text }} </van-tabbar-item> </block> </van-tabbar>

custom-tabbar.js:

js
const app = getApp(); Component({ properties: { // 父级可以传入用户类型,也可以在组件里自己去获取 userType: { type: Number, value: 0 } }, data: { tabList: [], activeIndex: '' }, lifetimes: { attached() { // 根据 userType 获取对应4个Tab const tabs = app.getTabbarConfig(this.data.userType); this.setData({ tabList: tabs, activeIndex: tabs.length ? tabs[0].name : '' }); } }, methods: { onChange(event) { const clickedName = event.detail; this.setData({ activeIndex: clickedName }); const tabItem = this.data.tabList.find(item => item.name === clickedName); if (tabItem) { wx.navigateTo({ url: tabItem.url }); } } } });

然后在页面中使用这个自定义组件:

pages/index/index.json:

json
{ "usingComponents": { "custom-tabbar": "/components/custom-tabbar/custom-tabbar" } }

pages/index/index.wxml:

html
<view class="container"> <!-- 其他内容 --> <!-- 使用自定义底部导航 --> <custom-tabbar user-type="{{ 0 }}"/> </view>

这样就不用在每个页面手写 van-tabbar 标签,统一管理比较方便。


四、小结

  1. app.js 中定义一个“根据用户类型返回 4 个 Tab 配置”的函数,包含文字、图标和跳转 URL 等信息。
  2. 在页面或自定义组件中,通过 getApp() 获取 app 实例,调用该函数拿到所需的 4 个 Tab 配置,然后使用 van-tabbar + wx:for 动态渲染。
  3. bind:change 事件回调中,根据当前点击的 Tab 找到对应的 URL,调用 wx.navigateTowx.switchTab 实现页面跳转。
  4. 为了减少重复,可将底部导航封装成自定义组件,在各个页面中引用并传入“用户类型”即可。

按照以上步骤,即可实现根据不同用户类型,渲染固定 4 个 Tab,并且每个 Tab 的文字、图标和跳转页面都可以灵活配置的功能。这样就可以满足“经销商、甲方、护工、用户”四种角色,底部导航各不相同的需求。

問題

修改:
tab切换时,如果是当前tab,则:
{{ active }} 输出 1
否则输出 0

<van-tabbar active="{{ activeIndex }}" bind:change="tab_onChange" safe-area-inset-bottom>
<block wx:for="{{ tabList }}" wx:key="name">
<!-- 使用 tab 的 icon、text、name 动态渲染 -->
<van-tabbar-item>
<image slot="icon-active" src="/static/footer/{{ item.icon }}{{ active }}.png" mode="aspectFit" style="width: 30px; height: 18px;" />
{{ item.text }}

text
</van-tabbar-item> </block>
</van-tabbar>

思考

Enhancing dynamic icons

I'm updating the code to set the icon dynamically based on the tab's active status. Using slots and Vant's properties, the icon shows "1.png" for active tabs and "0.png" for inactive ones.

Enhancing tab behavior

I'm tweaking the code to ensure the active indicator updates correctly and the static icons display properly. This makes me think about improving user experience in dynamic scenarios.

Adjusting the approach

I'm working through updating the icon suffix conditionally by examining each item and activeIndex. This involves using data keys or WX for precise control.

Implementing dynamic icons

I’m mapping out the solution to use a variable active in WXML to determine if a tab is active. This involves conditional expressions in data or computed functions.

Rethinking icon slots

Using both slot="icon" for inactive and slot="icon-active" for active tabs in WXML simplifies the display logic and ensures updates are concise and efficient.

Balancing efficiency

I’m thinking through the dynamic icon approach, using both slot="icon" and slot="icon-active" in WXML. This method ensures concise and efficient code, providing a balanced solution.

Simplifying icon states

I’m implementing icon and icon-active properties to streamline managing active and inactive tab icons. This method simplifies WXML code, avoiding conditionals.

Opting for simplicity

I'm refining the concept to use icon and icon-active for active and inactive tab icons. This approach ensures the code remains concise and maintainable.

Evaluating options

I’m pulling together two methods: icon and icon-active for active and inactive tabs, or slotted images with dynamic conditions. The former integrates smoothly with built-in features.

Adding missing elements

To ensure both inactive and active icons are shown, I'm including both slot="icon" and slot="icon-active" in the WXML. This approach dynamically offers both icons.

Handling inactive icons

To manage icons for both active and inactive states, I'm combining a conditional expression with slot="icon-active" to dynamically show or hide the inactive icon.

Ensuring visual clarity

OK, let's confirm the inactive tab icon appears in the icon slot. This sets the inactive icon, while the dynamic expression adjusts the active icon as needed.

Clarifying default behavior

I’m thinking through how slot="icon" is typically the default for inactive states, while slot="icon-active" is for active states. This might mean the same icon could represent both states.

Clarifying icon slots

If icon is defined, it represents both states. Adding icon-active distinguishes between active and inactive states. To ensure clarity, using both slots is recommended.

Establishing computed properties

I'm considering computed properties to dynamically assign {{ active }} based on the current tab index. This ensures the icon-changing logic works seamlessly in WXML.

Updating tab states

I’m thinking about setting and updating the active field for each tab in tabList. This ensures the correct icon is shown for each tab state.

Mapping icon logic

I’m detailing how to define the active property in each item and update it in tab_onChange. Typically, both icon states should be defined together.

Updating tab states

I'm showing how to dynamically update the tabList when changing tabs. This prevents inactive tab icons from appearing when the user isn't on the respective tab.

Reasoned for 1m 50s

回答

下面给你演示一种**“在同一个图片文件名里,通过末尾加 0/1 区分是否高亮”**的用法,并配合 Vant Weapp 的 <van-tabbar> 实现“点到当前 Tab 就显示图片名+1.png,否则显示图片名+0.png”的需求。

前提: 你已经在页面中正常引入了 van-tabbarvan-tabbar-item 组件(无论是通过 npm 安装还是拷贝 dist),并且页面 JSON 中有对应的 usingComponents 配置。


核心思路

  1. tabList 数组中,为每个 tab 记录其 nametexticon 等属性。同时,新加一个字段 active,值为 0 或 1,表示“是否高亮”。
  2. activeIndex 用于标识当前选中的 tab(通常是它的 name)。
  3. bind:change 事件中,拿到点击的 tab 名称(event.detail) 后:
    • 更新 activeIndex
    • 遍历 tabList,如果 item.name === activeIndex 就令 item.active=1,否则置 item.active=0
    • 这样就能让“当前 tab 的 active=1,其它 tab 的 active=0
  4. 在 WXML 中,通过 slot 或自定义 icon 的方式,拼接图片路径 "/static/footer/" + item.icon + item.active + ".png",从而达到“当前 tab 用 xxx1.png,非当前 tab 用 xxx0.png”的效果。

示例代码

以下示例假设有四个 Tab:首页(home)、搜索(search)、好友(friends)、设置(settings)。默认第一个 tab 为选中状态,即它的 active=1,其余为 active=0

1. 页面 JS (pages/index/index.js)

js
Page({ data: { // 四个 tab 的初始数据 tabList: [ { name: 'home', text: '首页', icon: 'home', active: 1 }, // 第一个默认选中 { name: 'search', text: '搜索', icon: 'search', active: 0 }, { name: 'friends', text: '好友', icon: 'friends', active: 0 }, { name: 'settings', text: '设置', icon: 'setting', active: 0 } ], // 当前选中的 Tab 名称 activeIndex: 'home' }, onLoad() { // 你也可以在 onLoad 里去获取后端返回的 tabList 或者做一些逻辑 }, // tab 切换事件 tab_onChange(e) { // Vant Weapp 的 van-tabbar,点击后会把当前选中的 name 传到 event.detail const currentName = e.detail; // 更新 activeIndex this.setData({ activeIndex: currentName }); // 遍历 tabList,如果是当前 name,就令 active=1,否则=0 const newList = this.data.tabList.map(item => { if (item.name === currentName) { item.active = 1; } else { item.active = 0; } return item; }); this.setData({ tabList: newList }); // ★ 这里根据实际需要进行页面跳转 // 比如 if (currentName === 'search') wx.navigateTo({ url: '/pages/search/search' }); // ... } });

2. 页面 WXML (pages/index/index.wxml)

html
<view class="container"> <!-- 这里是页面的主要内容 --> <!-- 底部自定义导航栏 --> <van-tabbar active="{{ activeIndex }}" bind:change="tab_onChange" safe-area-inset-bottom > <block wx:for="{{ tabList }}" wx:key="name"> <!-- 如果只定义 slot="icon-active",则只有当 tab 处于“选中”状态时才会显示该图片; 若要在“未选中”时也显示图标,推荐给 slot="icon" 或给 van-tabbar-item 传 icon 属性。 这里演示的是只在激活时的图标。 --> <van-tabbar-item name="{{ item.name }}"> <image slot="icon-active" src="/static/footer/{{ item.icon }}{{ item.active }}.png" mode="aspectFit" style="width: 30px; height: 18px;" /> {{ item.text }} </van-tabbar-item> </block> </van-tabbar> </view>

注意:

  • 上述做法中,你只定义了 slot="icon-active",因此 只在当前 tab(active=1)时显示图标,非当前 tab(active=0)时将没有任何图标。
  • 如果你希望在“未选中”和“选中”两个状态都有图标,只是文件名不同,那么通常的写法是:
    html
    <van-tabbar-item name="{{ item.name }}"> <!-- slot="icon" 用于未选中状态 --> <image slot="icon" src="/static/footer/{{ item.icon }}0.png" mode="aspectFit" style="width: 30px; height: 18px;" /> <!-- slot="icon-active" 用于选中状态 --> <image slot="icon-active" src="/static/footer/{{ item.icon }}1.png" mode="aspectFit" style="width: 30px; height: 18px;" /> {{ item.text }} </van-tabbar-item>
    这样就能分别在“未选中”与“选中”时展示两张不同图标。

关于 icon vs. slot="icon"

  • 在 Vant Weapp 的文档里,我们可以直接对 <van-tabbar-item> 传递 iconicon-active 这两个属性,也可以使用 slot="icon"slot="icon-active"。它们功能类似,都是指定“未选中图标”和“选中图标”。
  • 如果要用自定义图片,用这两种方法都可以:
    1. Props 方式
      html
      <van-tabbar-item name="{{ item.name }}" icon="/static/footer/{{ item.icon }}0.png" icon-active="/static/footer/{{ item.icon }}1.png" > {{ item.text }} </van-tabbar-item>
    2. Slot 方式
      html
      <van-tabbar-item name="{{ item.name }}"> <image slot="icon" src="/static/footer/{{ item.icon }}0.png" /> <image slot="icon-active" src="/static/footer/{{ item.icon }}1.png" /> {{ item.text }} </van-tabbar-item>
    二者本质一致,看你的个人习惯和代码风格即可。

总结

  1. 数据层面:在 tabList 数组里,给每个 tab 携带一个 active 标识(0/1),或在 onChange 时根据当前激活的 name 动态生成想要的图片路径。
  2. 视图层面:通过 <van-tabbar-item> 提供的 icon / icon-active 属性或 slot="icon" / slot="icon-active",分别指定未选中选中时的图标。
  3. 如果你想用一张图片并动态拼出 0/1,则需要在 JS 中或在 WXML 中拼出对应的后缀。这种方式要求你管理好 active 值的更新,否则无法正确显示。
  4. 一般最佳实践:直接使用 icon="/static/footer/xxx0.png" icon-active="/static/footer/xxx1.png",省去手动判断 “0/1” 的步骤,更加直观。

按照上述方式,就可以实现点击某个 Tab 后,若是当前 Tab 则使用 xxx1.png,否则使用 xxx0.png 的自定义底部导航逻辑了。

分享這個問答