1. 项目概述:为什么选择Vant作为Vue项目的UI基石
在Vue生态里做移动端项目,UI组件库的选择往往是第一个要过的坎。市面上选择不少,有Vant、NutUI、Mint UI等等,但如果你要问我哪个在移动端H5开发里最“能打”,我的答案很明确:Vant。这不是空口无凭,而是基于我经手过十几个中大型移动端项目后得出的结论。Vant的核心优势在于它的“克制”与“务实”——它不追求大而全,而是精准覆盖了移动端高频使用的组件,比如地址编辑、商品卡片、优惠券、提交订单栏这些电商场景的刚需,并且设计风格高度贴合主流审美,开箱即用。
很多新手拿到一个Vue项目,看到package.json里一堆依赖就发怵,对于如何引入一个UI库更是摸不着头脑。常见的困惑包括:是用npm安装还是CDN引入?按需引入和全局引入到底差在哪?为什么我的样式没生效?组件为什么渲染不出来?这些问题看似基础,但每一步踩坑都可能浪费半天时间。这篇文章,我就以一个老司机的视角,带你从零开始,把Vant在Vue项目(包括Vue 2和Vue 3)里安装、引入、使用的全链路走通,不仅告诉你“怎么做”,更会讲清楚“为什么这么做”,以及那些官方文档里不会写的“坑”在哪里。
2. 环境准备与安装策略解析
在动手安装Vant之前,确保你的开发环境是就绪的,这能避免很多因环境问题导致的诡异错误。
2.1 基础环境确认
首先,打开你的终端(命令行),依次运行以下命令来检查核心工具的版本:
node -v npm -v对于Vue 2项目,我推荐使用Node.js 14.x 或 16.x LTS版本,npm版本在6.x以上即可。如果是Vue 3项目,建议使用Node.js 16.x或更高版本。版本不匹配有时会导致依赖安装失败或构建错误。
接下来,确认你的项目是基于Vue CLI、Vite还是其他构建工具创建的。这决定了后续的配置方式。
- Vue CLI项目:查看根目录下是否有
vue.config.js文件。 - Vite项目:查看根目录下是否有
vite.config.js或vite.config.ts文件。 - 其他或老旧项目:可能直接使用webpack配置,查看是否有
webpack.config.js。
2.2 Vant安装:NPM vs Yarn vs PNPM
安装Vant最主流、最推荐的方式是通过包管理器。根据你的项目使用的包管理器,选择对应的命令。
对于Vue 2项目,你需要安装 Vant 2.x 版本:
# 使用 npm npm i vant@latest-v2 -S # 使用 yarn yarn add vant@latest-v2 # 使用 pnpm pnpm add vant@latest-v2对于Vue 3项目,你需要安装 Vant 3.x 或 4.x 版本:
# 使用 npm npm i vant -S # 使用 yarn yarn add vant # 使用 pnpm pnpm add vant注意:
-S参数是--save的缩写,表示将依赖写入package.json的dependencies中,这是默认行为,现在可以省略。但明确写上是个好习惯,尤其是需要区分dependencies和devDependencies时。
为什么强烈推荐NPM/Yarn/PNPM安装,而不是CDN?CDN引入方式看似简单,直接在HTML里加个<script>标签就行,但它有几个致命缺点:1) 无法享受Tree Shaking(按需引入)带来的体积优化,会引入整个库;2) 版本管理不便,容易造成生产环境和开发环境不一致;3) 依赖网络,影响加载速度和稳定性。而通过包管理器安装,可以与你的项目构建流程深度集成,是工程化的标准做法。
包管理器选择建议:新项目我强烈推荐使用PNPM。它通过硬链接和符号链接来管理node_modules,安装速度极快,并且能严格避免幽灵依赖(phantom dependencies)问题,让依赖结构更清晰。Yarn和NPM也是完全可行的选择。
安装完成后,你的package.json文件中会新增一条类似于"vant": "^3.6.0"的记录。
3. 引入方式深度对比与选型
安装完Vant只是第一步,如何将它引入到你的项目中,是影响项目体积和性能的关键决策。主要有三种方式:全局完整引入、按需引入、以及通过插件自动按需引入。我们来逐一拆解。
3.1 全局完整引入:快速但笨重
这种方式最简单粗暴,适合快速原型验证或极其小型的项目。你只需要在主入口文件(通常是src/main.js或src/main.ts)中一次性导入所有组件和样式。
// src/main.js (Vue 2 示例) import Vue from 'vue'; import Vant from 'vant'; import 'vant/lib/index.css'; // 引入全部样式 Vue.use(Vant); new Vue({ // ... 你的配置 }).$mount('#app');// src/main.ts (Vue 3 示例) import { createApp } from 'vue'; import Vant from 'vant'; import 'vant/lib/index.css'; // 引入全部样式 const app = createApp(App); app.use(Vant); app.mount('#app');优点:代码最少,所有组件无需单独导入即可在模板中直接使用。致命缺点:无论你的项目实际使用了多少个Vant组件,最终打包的bundle都会包含整个Vant库的代码和样式。对于一个中型项目,这可能会额外增加100KB甚至更多的体积,严重影响首屏加载时间。在绝大多数生产项目中,不推荐使用此方式。
3.2 手动按需引入:精准控制体积
这是最推荐的方式,也是Vant官方主推的。原理是只引入你真正用到的组件。这需要配合一个Babel插件(对于Vue CLI项目)或直接使用ES模块的Tree Shaking(对于Vite项目)。
首先,你需要安装一个核心插件:babel-plugin-import。这个插件会在编译过程中,自动将类似import { Button } from 'vant';的语句,转换为按需引入的格式。
npm i babel-plugin-import -D # 或 yarn add babel-plugin-import -D # 或 pnpm add -D babel-plugin-import然后,进行Babel配置(Vue CLI项目):在项目根目录下的babel.config.js文件中进行配置。
// babel.config.js module.exports = { plugins: [ [ 'import', { libraryName: 'vant', libraryDirectory: 'es', style: true, // 设置为 `true` 表示引入组件的CSS,也可以设置为 `'css'` }, 'vant', ], ], };配置好后,你就可以在具体的Vue组件中,按需引入并使用组件了:
<template> <div> <van-button type="primary">主要按钮</van-button> <van-cell title="单元格" value="内容" /> </div> </template> <script> // 手动引入需要用到的组件 import { Button, Cell } from 'vant'; export default { components: { // 在组件内局部注册 [Button.name]: Button, [Cell.name]: Cell, }, // ... 其他选项 }; </script>为什么推荐这种方式?
- 极致的体积优化:打包时只包含你用到的Button和Cell的代码,其他几十个组件都不会被打进来。
- 清晰的依赖关系:在组件顶部一眼就能看出它依赖了哪些Vant组件,便于维护。
- 灵活性高:每个组件独立注册,互不影响。
实操心得:在配置babel-plugin-import时,libraryDirectory参数非常关键。对于Vant,必须设置为'es',这指向Vant的ES模块入口,这样才能被Tree Shaking。style: true会自动引入对应组件的样式文件,无需你再手动import 'vant/lib/button/style',非常方便。
3.3 使用Vite插件自动按需引入(Vue 3推荐)
如果你使用Vite构建Vue 3项目,那么你有更优雅的选择——使用Vant官方提供的Vite插件@vant/auto-import-resolver(Vant 4+)或配合unplugin-vue-components。
这是目前Vue 3生态中最流行的方式,它可以让你在模板中直接使用组件,而无需在<script>中手动导入和注册,插件会在编译时自动帮你完成这些工作。
首先,安装必要的插件:
npm i unplugin-vue-components unplugin-auto-import -D # 或 pnpm add -D unplugin-vue-components unplugin-auto-import然后,在vite.config.ts中配置:
// vite.config.ts import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import Components from 'unplugin-vue-components/vite'; import { VantResolver } from 'unplugin-vue-components/resolvers'; export default defineConfig({ plugins: [ vue(), Components({ resolvers: [VantResolver()], // 自动解析 Vant 组件 }), ], });配置完成后,你就可以在任意Vue组件的模板中,直接使用van-前缀的Vant组件,无需任何import语句:
<template> <!-- 直接使用,无需导入和注册 --> <van-button type="primary">神奇按钮</van-button> <van-field label="用户名" placeholder="请输入用户名" /> </template> <script setup> // 这里完全不需要 import { Button, Field } from 'vant'; // 也不需要 components: { ... } 注册 </script>这种方式的好处是革命性的:它极大提升了开发体验,让你几乎感觉不到UI库的存在,就像在使用原生HTML标签一样。同时,它底层依然是按需引入,打包体积最优。
注意事项:使用自动导入时,你的代码编辑器(如VSCode)可能需要一点时间来识别这些自动生成的组件,有时会有短暂的“未找到组件”的提示,这属于正常现象,保存文件或重启语言服务通常能解决。确保你安装了Volar(Vue 3官方推荐扩展)以获得最好的TypeScript支持。
4. 样式处理与主题定制实战
引入组件后,样式是下一个重点。Vant提供了一套默认的、符合移动端设计规范的样式,但几乎每个项目都需要进行一定程度的定制。
4.1 基础样式引入
无论采用哪种引入方式,样式文件都必须被正确引入。
- 全局引入时,你已经通过
import 'vant/lib/index.css'引入了全部样式。 - 手动按需引入时,
babel-plugin-import的style: true选项会自动处理。 - Vite插件自动引入时,插件同样会自动处理样式的按需加载。
你需要确保项目能处理CSS文件。通常,Vue CLI和Vite项目已经配置好了相关的CSS加载器(如postcss,sass-loader等)。
4.2 定制主题:覆盖CSS变量
Vant 3.x/4.x 使用了CSS Custom Properties(CSS变量)来定义主题样式,这使得主题定制变得异常简单。你不再需要繁琐地覆盖具体组件的类名,只需在根元素或特定区域重新定义这些变量即可。
Vant的所有主题变量都可以在官方文档的“定制主题”部分找到。常见的定制需求包括品牌主色、边框圆角、字体等。
全局定制示例(在项目的入口CSS文件,如src/styles/index.css或src/App.vue的<style>中):
/* 在 :root 选择器中覆盖变量,影响全局 */ :root { /* 将品牌主色改为 #07c160 */ --van-primary-color: #07c160; /* 修改按钮的圆角 */ --van-button-border-radius: 8px; /* 修改单元格上下内边距 */ --van-cell-vertical-padding: 14px; /* 修改全局字体 */ --van-font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif; }局部定制示例(只影响特定组件或区域):
<template> <div class="custom-theme-area"> <van-button type="primary">这个按钮是自定义颜色</van-button> </div> <div> <van-button type="primary">这个按钮还是默认颜色</van-button> </div> </template> <style scoped> .custom-theme-area { /* 在这个类的作用域内覆盖变量 */ --van-primary-color: #ff6b6b; } </style>实操心得:在覆盖变量时,最好先去Vant的源码或文档里找到准确的变量名。变量名通常遵循--van-组件名-属性名的格式。使用浏览器的开发者工具,直接检查Vant组件的元素,可以快速看到它应用了哪些CSS变量,这是最直接的调试方法。
4.3 处理REM适配与Viewport布局
移动端项目离不开适配。Vant默认使用px作为样式单位,并提供了两种主流的适配方案供你选择:
方案一:使用postcss-pxtorem插件(推荐)这是最通用和灵活的方案。它会自动将你代码中的px单位转换为rem单位,基于你在html元素上设置的font-size。
安装插件:
npm install postcss-pxtorem -D配置 PostCSS: 在项目根目录创建
postcss.config.js文件,或修改已有的配置文件。// postcss.config.js module.exports = { plugins: { 'postcss-pxtorem': { rootValue: 37.5, // 设计稿宽度 / 10。例如设计稿是375px,则设为37.5 propList: ['*'], // 需要转换的属性列表,* 表示所有 selectorBlackList: ['.norem'], // 忽略的类名,带有 .norem 类的元素不会转换 }, }, };动态设置HTML的font-size: 通常会在入口文件或一个工具脚本中,根据屏幕宽度动态计算并设置
html元素的font-size。// utils/rem.js 或直接在 main.js 中 function setRemUnit() { const docEl = document.documentElement; const width = docEl.clientWidth || 375; // 默认375 const rem = width / 10; // 将屏幕宽度分为10份,1rem = 1/10 screen width docEl.style.fontSize = rem + 'px'; } setRemUnit(); window.addEventListener('resize', setRemUnit);
方案二:使用viewport布局 (Vant 官方也支持)Vant 4.x 推荐使用viewport单位 (vw,vh) 进行适配,无需rem转换。你可以通过配置PostCSS插件postcss-px-to-viewport来实现。
选择建议:对于新项目,尤其是Vant 4.x,可以尝试
viewport方案,它更符合现代CSS标准。但对于需要兼容老旧方案或与其他使用rem的库集成的项目,postcss-pxtorem方案更稳妥。我个人在大多数项目中仍使用rem方案,因为其生态更成熟,遇到问题也更容易搜索到解决方案。
5. 核心组件使用详解与避坑指南
安装和引入只是基础,真正用好Vant在于理解其核心组件的特性和使用场景。这里我挑几个最常用也最容易踩坑的组件,结合实战经验深入讲解。
5.1 表单组件:Field, Checkbox, Radio, Picker
表单是交互的重灾区。Vant的van-field组件功能强大,但有些细节需要注意。
van-field输入框的v-model与格式化:
<van-field v-model="username" label="用户名" placeholder="请输入用户名" :error-message="usernameError" clearable @clear="handleClear" />clearable属性:在右侧显示清除图标。注意,点击清除图标触发@clear事件后,组件内部会清空输入框的值,你的v-model绑定的数据也会同步更新。你不需要在handleClear方法里手动设置this.username = ''。- 输入格式化:如果需要限制输入格式(如手机号、身份证号),不要尝试用
@input事件和正则表达式粗暴地替换v-model的值,这会导致光标跳动。推荐使用van-field的formatter属性。<van-field v-model="phone" label="手机号" placeholder="请输入手机号" :formatter="formatterPhone" />methods: { formatterPhone(value) { // 格式化为 138-xxxx-xxxx 的形式,仅影响显示,不影响实际绑定值 return value.replace(/(\d{3})(\d{0,4})(\d{0,4})/, '$1-$2-$3').replace(/-+$/g, ''); } } - 与校验库结合:强烈建议将Vant表单组件与校验库(如
vee-validate或async-validator)结合使用。van-form组件提供了validate、submit等方法,能很好地组织表单校验。
van-picker选择器的数据绑定:van-picker(包括多列选择器van-picker-column)的v-model绑定的是选中值在选项数组中的索引(一个数字或数组),而不是选项对象本身。这是新手最容易混淆的地方。
<van-picker title="城市选择" :columns="columns" v-model="selectedIndex" <!-- 这里绑定的是索引,例如 0 --> @confirm="onConfirm" />data() { return { columns: ['杭州', '宁波', '温州', '嘉兴', '湖州'], selectedIndex: 0, // 默认选中第一个 }; }, methods: { onConfirm(value, index) { // value 是选中的文本,index 是选中的索引 console.log(`选中了: ${value}, 索引是: ${index}`); this.selectedCity = value; // 通常我们会保存选中的文本 } }5.2 反馈组件:Dialog, Toast, Notify
这些轻量级的交互组件使用频率极高,关键在于理解它们的调用方式。
Dialog对话框:它既可以通过组件形式使用,也可以通过函数式调用。对于简单的确认/取消弹窗,函数式调用更简洁。// 函数式调用 import { Dialog } from 'vant'; Dialog.confirm({ title: '确认删除', message: '确定要删除这条记录吗?此操作不可撤销。', }) .then(() => { // 用户点击了确认 this.doDelete(); }) .catch(() => { // 用户点击了取消或关闭 console.log('取消删除'); });注意:函数式调用创建的Dialog实例是独立于当前Vue组件上下文的。这意味着在Dialog的回调函数(如
.then)中,this不再指向你的Vue组件。如果你需要在回调中访问组件的数据或方法,请务必使用箭头函数或在外部先将this保存到一个变量(例如const that = this;)。Toast轻提示:用于显示成功、失败、加载中的轻量级提示。切记,Toast默认是单例的。这意味着在同一时间,只能有一个Toast显示。如果你在短时间内连续调用Toast.loading()和Toast.success(),可能会出现提示闪烁或覆盖的问题。正确的做法是,在显示下一个Toast前,先关闭前一个。import { Toast } from 'vant'; const loadingToast = Toast.loading({ message: '加载中...', forbidClick: true, // 加载时禁止背景点击 duration: 0, // 持续显示,直到手动清除 }); // 模拟异步操作 setTimeout(() => { loadingToast.clear(); // 先清除加载提示 Toast.success('操作成功!'); }, 2000);
5.3 布局与导航组件:Tabbar, NavBar, List, PullRefresh
这些组件构成了移动端应用的基本骨架。
van-tabbar底部导航:路由切换是其核心。你需要将van-tabbar-item的to属性或@click事件与Vue Router的路由跳转绑定。<van-tabbar v-model="active" route> <van-tabbar-item icon="home-o" to="/">首页</van-tabbar-item> <van-tabbar-item icon="search" to="/search">搜索</van-tabbar-item> <van-tabbar-item icon="cart-o" :badge="cartCount" to="/cart">购物车</van-tabbar-item> <van-tabbar-item icon="user-o" to="/mine">我的</van-tabbar-item> </van-tabbar>route属性开启后,点击tabbar-item会自动调用router.push()进行路由跳转,并且active会与当前路由路径同步。badge属性可以方便地显示小红点或数字角标。van-list列表滚动加载:这是实现无限滚动加载的核心组件。其工作原理是监听滚动,当列表滚动到底部阈值(offset)时,触发你定义的@load事件。<van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="onLoad" :immediate-check="false" > <van-cell v-for="item in list" :key="item.id" :title="item.title" /> </van-list>data() { return { list: [], loading: false, finished: false, page: 1, }; }, methods: { async onLoad() { if (this.finished || this.loading) return; this.loading = true; try { const { data, hasMore } = await fetchListApi(this.page); this.list.push(...data); this.page++; this.finished = !hasMore; } catch (error) { console.error('加载失败', error); } finally { this.loading = false; // 无论成功失败,都必须将loading设为false } }, }, mounted() { // 如果immediate-check为false,需要手动触发首次加载 this.onLoad(); }关键点:
loading状态必须正确管理。在加载开始前设为true,加载结束后(无论成功失败)必须设为false,否则@load事件不会再触发。finished状态在服务器返回没有更多数据时设为true。immediate-check属性控制组件在初始化时是否立即检查位置并触发load。如果列表初始为空且高度不足以触发滚动,建议设为false,并在mounted中手动调用一次加载函数。
6. 进阶配置与工程化实践
当项目规模增长,就需要更工程化的手段来管理Vant的使用。
6.1 自定义组件注册器
如果你不喜欢在每个组件里都写一堆import和components注册,但又不想用全自动的Vite插件,可以创建一个全局的组件注册器文件。
// src/plugins/vant.js import { Button, Cell, CellGroup, Icon, Field, Form, Toast, Dialog } from 'vant'; // 你可以在这里集中管理所有需要全局注册的Vant组件 const components = [Button, Cell, CellGroup, Icon, Field, Form]; export default { install(Vue) { components.forEach(component => { Vue.component(component.name, component); }); // 将函数式组件挂载到Vue原型上,方便使用 this.$toast, this.$dialog Vue.prototype.$toast = Toast; Vue.prototype.$dialog = Dialog; }, };然后在main.js中使用:
import Vant from '@/plugins/vant'; Vue.use(Vant);这样,components数组里的组件就可以在任何地方直接使用,无需再单独引入。Toast和Dialog也可以通过this.$toast调用。这是一种介于全局引入和完全按需引入之间的折中方案,适合组件使用频率非常高的项目。
6.2 类型支持(TypeScript项目)
对于TypeScript项目,获得良好的类型提示至关重要。
- 手动按需引入:TypeScript能自动推导出类型,无需额外配置。
- Vite插件自动引入:
unplugin-vue-components插件会在编译时生成一个components.d.ts文件,自动声明全局组件。你需要在tsconfig.json中将其包含进来:
这样,在模板中使用{ "include": [ "src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", // 添加这行 "./components.d.ts" ] }<van-button>时,Volar就能提供完整的类型提示和跳转。
6.3 按需引入样式文件的深度优化
在某些极端性能敏感的场景,你甚至希望样式也能做到更极致的按需。babel-plugin-import的style: true配置已经很好,但它是按组件引入整个组件的CSS。如果你使用的是支持Tree Shaking CSS的构建工具(如Vite + PostCSS),可以尝试配置style: 'css',并确保你的构建流程能处理CSS的Tree Shaking。不过,对于绝大多数项目,style: true已经足够优化,不必过度追求这一点。
7. 常见问题排查与解决方案实录
在实际开发中,你一定会遇到各种各样的问题。下面是我总结的一些高频问题及其解决方案。
7.1 组件渲染异常或样式丢失
- 问题描述:组件显示为原生HTML标签(如
<van-button>直接显示在页面上),或者没有样式。 - 排查步骤:
- 检查组件是否正确定义/注册:对于手动引入,检查
components选项里是否注册了组件。对于自动引入,检查Vite插件配置是否正确,并查看终端是否有构建错误。 - 检查样式是否引入:确认CSS文件被正确引入。检查浏览器开发者工具的“网络”选项卡,看对应的Vant CSS文件是否成功加载。检查“元素”选项卡,看组件元素上是否应用了Vant的CSS类名。
- 检查Vant版本与Vue版本是否匹配:Vue 2项目必须使用Vant 2.x,Vue 3项目必须使用Vant 3.x/4.x。版本不匹配会导致无法注册或渲染错误。
- 检查构建工具配置:特别是
babel.config.js中babel-plugin-import的配置,libraryDirectory必须是'es'。
- 检查组件是否正确定义/注册:对于手动引入,检查
7.2 图标不显示
Vant 4.x 默认使用了图标字体,而 Vant 3.x 及之前版本使用的是内置的SVG图标。图标不显示通常有以下原因:
- 未引入图标样式/组件:Vant 4.x 需要单独引入图标样式或使用
@vant/icons组件库。如果你使用的是按需引入且需要图标,请确保引入了Icon组件,并在使用icon属性时传入了正确的图标名称。# Vant 4 需要安装图标包 npm i @vant/icons<van-button icon="star-o">收藏</van-button> <!-- 需要确保 Icon 组件被引入 --> - 图标名称错误:图标名称是字符串,如
'star-o',注意大小写和短横线。最好去Vant官方图标库页面复制名称。 - 自定义图标未正确配置:如果使用
van-icon组件的tag属性或插槽来自定义图标,请确保自定义的SVG或图片资源路径正确。
7.3 移动端点击延迟与FastClick
在早期移动端浏览器中,点击事件会有300ms的延迟(用于判断是否是双击)。虽然现代浏览器已经优化了这个问题,但在一些旧版WebView或特定场景下可能仍需处理。
Vant组件内部已经处理了大部分点击交互。如果你的项目仍有明显的点击延迟感,可以考虑引入fastclick库(注意其已不再维护),或者使用Vue的@touchstart和@touchend事件自行模拟更快的点击反馈。更现代的做法是使用CSS的touch-action: manipulation;属性,它告诉浏览器可以优化触摸操作(如双击缩放),通常能消除延迟。
7.4 打包后样式丢失或顺序错乱
这个问题在复杂构建配置中可能出现。
- 样式丢失:检查是否在按需引入时漏掉了样式。确保
babel-plugin-import的style选项为true或'css'。检查生产环境构建命令是否与开发环境有差异。 - 样式顺序错乱导致覆盖失效:这通常是因为多个CSS文件引入顺序问题,或者CSS Modules、Scoped CSS的影响。确保你的全局样式(如主题变量覆盖)在Vant样式之后引入。在
main.js中,调整import顺序:
如果使用Vite,可以在import 'vant/lib/index.css'; // 先引入Vant样式 import './styles/index.css'; // 再引入你的全局覆盖样式vite.config.ts中通过css.postcss或调整CSS文件的引入顺序来控制。
7.5 与第三方库或自定义样式冲突
Vant的CSS使用了命名空间(van-前缀),冲突概率较低,但仍有可能。
- 全局样式污染:避免在全局样式中使用过于宽泛的选择器(如
div { ... },button { ... })来覆盖样式,这可能会意外影响Vant组件。应该使用Vant提供的CSS变量或更具体的选择器(如.my-container .van-button)进行覆盖。 - CSS权重问题:如果你的自定义样式没有生效,打开开发者工具检查元素,看你的样式是否被Vant的默认样式覆盖了。可能需要通过增加选择器特异性(如添加父级类名)或使用
!important(不推荐,作为最后手段)来解决。
最后,遇到任何奇怪的问题,第一反应应该是打开浏览器的开发者工具。查看Console是否有错误,查看Elements面板确认DOM结构是否正确、CSS类名和样式是否被应用,查看Network面板确认资源是否加载成功。这能解决你90%以上的问题。如果问题依旧,去Vant的GitHub仓库的Issues里搜索,你很可能不是第一个遇到它的人。