介绍
实时告知当前处于屏幕中的锚点,或者滚动到指定锚点位置。
引入
js
import ScrollSpy from 'sard-uniapp/components/scroll-spy/scroll-spy.vue'
import ScrollSpyAnchor from 'sard-uniapp/components/scroll-spy-anchor/scroll-spy-anchor.vue'代码演示
基础使用
ScrollSpy 组件内部使用 scroll-view 作为滚动容器,需要设置固定的高度。 ScrollSpyAnchor 是用作定位的锚点,需要设置 name 属性,且其值必须唯一。
使用 v-model:current 绑定当前的锚点。
vue
<template>
<view>当前 anchor: {{ current }}</view>
<sar-button root-style="margin: 10rpx 0" @click="current = 2">
设置当前 anchor 为: 2
</sar-button>
<sar-scroll-spy
v-model:current="current"
root-style="height: 400rpx; border: 1px solid var(--sar-border-color)"
>
<template v-for="item in list" :key="item.name">
<sar-scroll-spy-anchor :name="item.name" />
<view class="title">{{ item.title }}</view>
<view class="content">{{ item.content }}</view>
</template>
</sar-scroll-spy>
</template>
<script setup lang="ts">
import { ref } from 'vue'
let id = 0
const list = ref(
Array(4)
.fill(0)
.map(() => {
id++
return {
title: 'title' + id,
content: 'content' + id,
name: id,
}
}),
)
const current = ref(1)
</script>
<style lang="scss" scoped>
.title {
position: sticky;
top: 0;
padding: 10rpx;
background-color: var(--sar-emphasis-bg);
}
.content {
display: flex;
justify-content: center;
align-items: center;
height: 400rpx;
background-color: var(--sar-tertiary-bg);
margin: 20rpx;
}
</style>vue
<template>
<view>当前 anchor: {{ current }}</view>
<sar-button root-style="margin: 10rpx 0" @click="current = 2">
设置当前 anchor 为: 2
</sar-button>
<sar-scroll-spy
v-model:current="current"
root-style="height: 400rpx; border: 1px solid var(--sar-border-color)"
>
<template v-for="item in list" :key="item.name">
<sar-scroll-spy-anchor :name="item.name" />
<view class="title">{{ item.title }}</view>
<view class="content">{{ item.content }}</view>
</template>
</sar-scroll-spy>
</template>
<script setup lang="js">
import { ref } from "vue";
let id = 0;
const list = ref(
Array(4).fill(0).map(() => {
id++;
return {
title: "title" + id,
content: "content" + id,
name: id
};
})
);
const current = ref(1);
</script>
<style lang="scss" scoped>
.title {
position: sticky;
top: 0;
padding: 10rpx;
background-color: var(--sar-emphasis-bg);
}
.content {
display: flex;
justify-content: center;
align-items: center;
height: 400rpx;
background-color: var(--sar-tertiary-bg);
margin: 20rpx;
}
</style>动态更新
如果锚点的位置有变动,或者新增/删除了锚点,需要调用 update 方法重新计算锚点位置。
vue
<template>
<view>当前 anchor: {{ current }}</view>
<sar-button root-style="margin: 10rpx 0" @click="current = 2">
设置当前 anchor 为: 2
</sar-button>
<sar-scroll-spy
ref="scrollSpyRef"
v-model:current="current"
root-style="height: 400rpx; border: 1px solid var(--sar-border-color)"
@scrolltolower="onScrolltolower"
>
<template v-for="item in list" :key="item.name">
<sar-scroll-spy-anchor :name="item.name" />
<view class="title">{{ item.title }}</view>
<view style="padding: 20rpx">
<view class="content">{{ item.content }}</view>
</view>
</template>
<sar-load-more :status="loadMoreStatus" @load-more="onLoadMore" />
</sar-scroll-spy>
</template>
<script setup lang="ts">
import { type ScrollSpyExpose, sleep, type LoadMoreStatus } from 'sard-uniapp'
import { nextTick, ref } from 'vue'
let id = 0
const list = ref(
Array(4)
.fill(0)
.map(() => {
id++
return {
title: 'title' + id,
content: 'content' + id,
name: id,
}
}),
)
const current = ref(1)
const scrollSpyRef = ref<ScrollSpyExpose>()
const loadMoreStatus = ref<LoadMoreStatus>('incomplete')
const loadData = async () => {
loadMoreStatus.value = 'loading'
await sleep(300)
list.value = [
...list.value,
...Array(2)
.fill(0)
.map(() => {
id++
return {
title: 'title' + id,
content: 'content' + id,
name: id,
}
}),
]
loadMoreStatus.value = list.value.length > 10 ? 'complete' : 'incomplete'
await nextTick()
await sleep(50)
scrollSpyRef.value?.update()
}
const onLoadMore = async () => {
await loadData()
}
const onScrolltolower = () => {
if (loadMoreStatus.value === 'incomplete') {
loadData()
}
}
</script>
<style lang="scss" scoped>
.title {
position: sticky;
top: 0;
padding: 10rpx;
background-color: var(--sar-emphasis-bg);
}
.content {
display: flex;
justify-content: center;
align-items: center;
height: 400rpx;
background-color: var(--sar-tertiary-bg);
}
</style>vue
<template>
<view>当前 anchor: {{ current }}</view>
<sar-button root-style="margin: 10rpx 0" @click="current = 2">
设置当前 anchor 为: 2
</sar-button>
<sar-scroll-spy
ref="scrollSpyRef"
v-model:current="current"
root-style="height: 400rpx; border: 1px solid var(--sar-border-color)"
@scrolltolower="onScrolltolower"
>
<template v-for="item in list" :key="item.name">
<sar-scroll-spy-anchor :name="item.name" />
<view class="title">{{ item.title }}</view>
<view style="padding: 20rpx">
<view class="content">{{ item.content }}</view>
</view>
</template>
<sar-load-more :status="loadMoreStatus" @load-more="onLoadMore" />
</sar-scroll-spy>
</template>
<script setup lang="js">
import { sleep } from "sard-uniapp";
import { nextTick, ref } from "vue";
let id = 0;
const list = ref(
Array(4).fill(0).map(() => {
id++;
return {
title: "title" + id,
content: "content" + id,
name: id
};
})
);
const current = ref(1);
const scrollSpyRef = ref();
const loadMoreStatus = ref("incomplete");
const loadData = async () => {
loadMoreStatus.value = "loading";
await sleep(300);
list.value = [
...list.value,
...Array(2).fill(0).map(() => {
id++;
return {
title: "title" + id,
content: "content" + id,
name: id
};
})
];
loadMoreStatus.value = list.value.length > 10 ? "complete" : "incomplete";
await nextTick();
await sleep(50);
scrollSpyRef.value?.update();
};
const onLoadMore = async () => {
await loadData();
};
const onScrolltolower = () => {
if (loadMoreStatus.value === "incomplete") {
loadData();
}
};
</script>
<style lang="scss" scoped>
.title {
position: sticky;
top: 0;
padding: 10rpx;
background-color: var(--sar-emphasis-bg);
}
.content {
display: flex;
justify-content: center;
align-items: center;
height: 400rpx;
background-color: var(--sar-tertiary-bg);
}
</style>API
ScrollSpyProps
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| root-class | 组件根元素类名 | string | - |
| root-style | 组件根元素样式 | StyleValue | - |
| current | 当前绑定锚点名称 | string | number | - |
| offset | 锚点距离顶部的偏移量 | number | 0 |
| upper-threshold | 距顶部/左边多远时(单位 px),触发 scrolltoupper 事件 | number | string | 50 |
| lower-threshold | 距底部/右边多远时(单位 px),触发 scrolltolower 事件 | number | string | 50 |
| disabled 1.24.7+ | 是否禁用,禁用时无法滚动 | boolean | false |
ScrollSpySlots
| 插槽 | 描述 | 属性 |
|---|---|---|
| default | 自定义默认内容 | - |
ScrollSpyEmits
| 事件 | 描述 | 类型 |
|---|---|---|
| update:current | 当前锚点改变时触发 | (name: number | string) => void |
| change | 当前锚点改变时触发 | (name: number | string) => void |
| scrolltoupper | 滚动到顶部时触发 | () => void |
| scrolltolower | 滚动到底部时触发 | () => void |
| scroll | 滚动时触发 | (event: any) => void |
ScrollSpyExpose
| 属性 | 描述 | 类型 |
|---|---|---|
| update | 更新锚点位置 | () => void |