一个「钉住」一个「喊话」
移动端页面里有两个高频却常被低估的组件:Sticky 吸顶——让导航条、筛选栏滚动到顶部时钉在屏幕上;NoticeBar 通告栏——用跑马灯循环播放公告。两者经常配合出现在列表页:顶部通告 + 吸顶筛选,信息层次立刻清晰。
Sticky:把任意元素钉在顶部
把需要吸顶的元素包在 van-sticky 里即可,组件会在滚动经过时自动切换为 fixed 定位:
html
page.vue
<template>
<van-nav-bar title="商品列表" />
<!-- 距离顶部 0px 时吸顶 -->
<van-sticky>
<van-dropdown-menu>
<van-dropdown-item v-model="sort" :options="sortOptions" />
<van-dropdown-item v-model="brand" :options="brandOptions" />
</van-dropdown-menu>
</van-sticky>
<van-list ...>列表内容...</van-list>
</template>
<script setup>
import { ref } from "vue";
const sort = ref("hot");
const brand = ref("all");
const sortOptions = [
{ text: "默认排序", value: "hot" },
{ text: "价格从低到高", value: "price" },
];
const brandOptions = [{ text: "全部品牌", value: "all" }];
</script>
offset-top:与其他导航共存
页面顶部已有固定导航栏时,吸顶元素会被遮住,用 offset-top 让它停在导航栏下方:
html
page.vue
<!-- 固定在顶部的导航 -->
<van-nav-bar title="标题" fixed />
<!-- 吸顶时停在导航栏(46px)下方 -->
<van-sticky offset-top="46px">
<van-tabs>
<van-tab title="推荐">内容</van-tab>
<van-tab title="新品">内容</van-tab>
</van-tabs>
</van-sticky>
container 模式:指定吸顶范围
默认 Sticky 一旦吸顶会钉到页面底部。若希望「滚出某个容器就放开」,用 container 属性指定参照容器:
html
section.vue
<template>
<div ref="container" class="section">
<van-sticky :container="container">
<div class="section-title">第一节标题(只在本节范围内吸顶)</div>
</van-sticky>
<div class="section-body">第一节内容...</div>
</div>
</template>
<script setup>
import { ref } from "vue";
const container = ref(null);
</script>
💡 小技巧:Sticky 吸顶时会自动给元素加上
van-sticky--fixed 类,可以借此给吸顶状态加阴影或背景色,强化"钉住"的视觉反馈。NoticeBar:循环播放的公告条
文本超宽时 van-notice-bar 默认以跑马灯形式横向循环,也可以设置可滚动开关、关闭按钮等:
html
demo.vue
<template>
<!-- 跑马灯:文本超宽自动滚动 -->
<van-notice-bar
left-icon="volume-o"
text="618 大促进行中,全场满 300 减 50,活动截止 6 月 20 日,速来抢购!"
/>
<!-- 单行截断 + 可关闭 -->
<van-notice-bar
wrapable
:scrollable="false"
mode="closeable"
text="系统将于今晚 23:00 - 24:00 升级维护,期间可能出现短暂卡顿。"
@close="onClose"
/>
</template>
| 属性 | 说明 |
|---|---|
| scrollable | 是否开启滚动条;false 时文本超宽会截断 |
| wrapable | 是否开启文本换行(与 scrollable 互斥场景) |
| speed | 滚动速度,px/s,默认 60 |
| delay | 动画延迟,秒,默认 1 |
| mode | closeable 显示关闭按钮 / link 显示右侧箭头 |
| color / background | 自定义文字与背景颜色 |
组合实战:公告 + 吸顶筛选列表页
把两者放进同一个列表页:NoticeBar 常驻顶部,下拉菜单吸顶,滚动长列表时筛选始终可用:
html
list-page.vue
<template>
<van-notice-bar
left-icon="volume-o"
:text="announcement"
background="#ecf9ff"
color="#1989fa"
/>
<van-sticky offset-top="46px">
<van-tabs v-model:active="activeTab" sticky>
<van-tab v-for="t in tabs" :key="t" :title="t">
<van-list
v-model:loading="loading"
:finished="finished"
finished-text="没有更多了"
@load="onLoad"
>
<van-cell v-for="i in list" :key="i" :title="`商品 ${i}`" />
</van-list>
</van-tab>
</van-tabs>
</van-sticky>
</template>
<script setup>
import { ref } from "vue";
const announcement = "新品首发专区已上线,前 100 名下单享 5 折优惠!";
const activeTab = ref(0);
const tabs = ["推荐", "数码", "服饰", "食品"];
const list = ref([]);
const loading = ref(false);
const finished = ref(false);
const onLoad = () => {
const start = list.value.length;
for (let i = 1; i <= 20; i++) list.value.push(start + i);
loading.value = false;
if (list.value.length >= 60) finished.value = true;
};
</script>
常见问题排查
Sticky 不吸顶?
- 父容器设置了 overflow: hidden / auto,会破坏 fixed 定位的参照,去掉或改为 visible
- 吸顶元素自身是
position: fixed或在 transform 容器里,需要调整 DOM 结构
NoticeBar 文本很短却也在滚动?
组件默认「超宽才滚动」,若短文本也滚,通常是容器宽度异常(如父级 flex 未约束)。显式设置 :scrollable="false" 可强制不滚。
多页签下吸顶位置不对?
每个 van-tab 是独立滚动容器,Sticky 放在 tabs 外层只对第一个页签生效;需要每个页签内各自包一层 van-sticky,或把 offset-top 配合页签高度计算。
总结
Sticky 与 NoticeBar 都是「零样式成本」的体验型组件:Sticky 用 offset-top 对齐固定导航、用 container 限定吸顶范围;NoticeBar 记住 scrollable / wrapable / mode 三个开关。组合进列表页后,长内容的浏览效率会明显提升。
让重要信息留在屏幕上,让次要信息自己动起来。