Appearance
样式
自定义导航栏
在 page.json 中修改需要展示的页面的设置 navigationStyle
json
{
"path": "pages/index/index",
"style": {
"navigationStyle": "custom",
"navigationBarTextStyle": "white",
"navigationBarTitleText": "首页"
}
},自适应机型顶部
底部不用管,tabBar已经自适应了
vue
<script setup lang="ts">
const top = ref()
onMounted(() => {
// 获取屏幕边界到安全区域距离
const { safeAreaInsets } = uni.getSystemInfoSync()
top.value = safeAreaInsets?.top
})
</script>
<template>
<view class="navbar" :style="{ paddingTop: safeAreaInsets!.top + 10 + 'px' }">
</view>
</template>然后在 index 页面引入该组件
滚动视图
scroll-view
vue
<template>
<!-- 自定义导航栏 -->
<CustomNavbar />
<scroll-view class="scrollView" scroll-y>
<!-- 轮播图 -->
<XtxSwiper :list="bannerList" />
<!-- 分类 -->
<CategoryPanel :list="categoryList" />
<!-- 热门 -->
<HotPanel :list="hotList" />
<!-- 猜你喜欢 -->
<XtxGuess />
</scroll-view>
</template>
<style lang="scss">
page {
background-color: #f7f7f7;
height: 100%;
display: flex;
flex-direction: column;
}
.scrollView {
flex: 1;
}
</style>滚动触底
@scrolltolower
html
<template>
<!-- 自定义导航栏 -->
<CustomNavbar />
<!-- 滚动容器 -->
<scroll-view @scrolltolower="onScrolltolower" class="scrollView" scroll-y> // [!code ++]
<!-- 轮播图 -->
<XtxSwiper :list="bannerList" />
<!-- 分类 -->
<CategoryPanel :list="categoryList" />
<!-- 热门 -->
<HotPanel :list="hotList" />
<!-- 猜你喜欢 -->
<XtxGuess ref="guessRef" />
</scroll-view>
</template>调用子组件中的获取分页的方法
js
// 触底触发
const onScrolltolower = () => {
console.log("触底触发");
guessRef.value?.getMore(pageParams);
pageParams.page++;
};停止滚动
根据接口返回的最大页数进行判断
ts
/**
* 当前页码和每页条数
*/
const pageParams: Required<PageRequest> = {
page: 1,
pageSize: 10,
};
// 获取猜你喜欢接口数据
const guessList = ref<GuessItem[]>([]);
// 分页结束标志
const finish = ref(false);
async function getHomeGoodsGuessLike() {
if (finish.value) {
return;
}
const res = await getHomeGoodsGuessLikeAPI(pageParams);
const list = res.result.items;
guessList.value.push(...list);
if (pageParams.page < res.result.pages) {
pageParams.page++;
} else {
finish.value = true;
}
}通过状态来显示最底层的文字
html
<view class="loading-text">{{ finish ? "已经到底啦~" : "正在加载..." }}</view>回到顶部
scroll-top
html
<scroll-view :scroll-top="scrollTop" class="secondary" scroll-y />ts
// 顶部
const scrollTop = ref(0)
// 左侧tab切换方法
function leftTabClick(index: number) {
activeIndex.value = index
// 必须让scrollTop的值在0和-1之间切换才能让他回到顶部
scrollTop.value = scrollTop.value === 0 ? -1 : 0
}开启下拉刷新
refresher-enabled
html
<!-- 滚动容器 -->
<scroll-view
refresher-enabled
@refresherrefresh="onRefresherrefresh"
@scrolltolower="onScrolltolower"
class="scrollView"
scroll-y
>
<!-- 轮播图 -->
<XtxSwiper :list="bannerList" />
<!-- 分类 -->
<CategoryPanel :list="categoryList" />
<!-- 热门 -->
<HotPanel :list="hotList" />
<!-- 猜你喜欢 -->
<XtxGuess ref="guessRef" />
</scroll-view>ts
// 自定义下拉刷新被触发
const onRefresherrefresh = () => {
console.log("下拉刷新了");
};- refresherTriggered 设置当前下拉刷新状态
html
<scroll-view
refresher-enabled
@refresherrefresh="onRefresherrefresh"
:refresherTriggered="isTriggered"
@scrolltolower="onScrolltolower"
class="scrollView"
scroll-y
>
<!-- 轮播图 -->
<XtxSwiper :list="bannerList" />
<!-- 分类 -->
<CategoryPanel :list="categoryList" />
<!-- 热门 -->
<HotPanel :list="hotList" />
<!-- 猜你喜欢 -->
<XtxGuess ref="guessRef" />
</scroll-view>ts
// 当前下拉状态
const isTriggered = ref(false);
// 自定义下拉刷新被触发
const onRefresherrefresh = async () => {
// 开始动画
isTriggered.value = true;
console.log("下拉刷新了");
// 等所有接口都返回结果后,再继续执行
await Promise.all([getHomeBanner(), getHomeCategory(), getHomeHot()]);
// 关闭动画
isTriggered.value = false;
};TIP
必须给 refresherTriggered 的值设置 true 和 false 的变化,如果只写 false 的话,会一直卡在刷新动画上
骨架屏
通过微信开发者工具生成骨架屏的 .wxml 和 .wxss 这两个文件 将其转成 .vue 组件
在主页面中,通过条件语句来渲染不同的内容,使用 Promise.all 方法来控制 v-if 绑定的状态的变化
html
<!-- 骨架屏 -->
<PageSkeleton v-if="isLoading" />
<template v-else>
<!-- 轮播图 -->
<XtxSwiper :list="bannerList" />
<!-- 分类 -->
<CategoryPanel :list="categoryList" />
<!-- 热门 -->
<HotPanel :list="hotList" />
<!-- 猜你喜欢 -->
<XtxGuess ref="guessRef" />
</template>TIP
如果生成的轮播图组件,没有高度的话,在组件的身上增加高度即可,swiper 组件默认高度280rpx
大图预览
使用 uni.previewImage
ts
function onTapImg(url: string) {
// 大图预览
uni.previewImage({
current: url,
urls: goods.value!.mainPictures,
})
}动态设置当前页面的标题
适用于组件复用的时候,根据组件内参数不同修改标题
ts
uni.setNavigationBarTitle({ title: '新的标题' })滑动删除
使用 uni-ui 中的 uni-swipe-action
html
<uni-swipe-action class="address-list">
<!-- 收货地址项 -->
<uni-swipe-action-item v-for="item in addressList" :key="item.id" class="item">
<view class="item-content">
内容
</view>
<!-- 右侧插槽 -->
<template #right>
<button class="delete-button" @click="deleteAddress(item.id)">
删除
</button>
</template>
</uni-swipe-action-item>
</uni-swipe-action>滚动驱动的动画
ts
// 获取页面栈
const pages = getCurrentPages()
// 获取当前页面实例
// const pageInstance = pages[pages.length - 1]
const pageInstance = pages.at(-1) as any
// 页面渲染完毕,绑定动画效果
onReady(() => {
console.log('页面渲染完毕', pageInstance)
pageInstance.animate('.navbar', [
{ backgroundColor: 'transparent' },
{ backgroundColor: '#f8f8f8' },
],
1000,
{
scrollSource: '#scroller',
timeRange: 1000,
startScrollOffset: 0,
endScrollOffset: 50,
})
// 动画效果,导航栏标题
pageInstance.animate('.navbar .title', [{ color: 'transparent' }, { color: '#000' }], 1000, {
scrollSource: '#scroller',
timeRange: 1000,
startScrollOffset: 0,
endScrollOffset: 50,
})
// 动画效果,导航栏返回按钮
pageInstance.animate('.navbar .back', [{ color: '#fff' }, { color: '#000' }], 1000, {
scrollSource: '#scroller',
timeRange: 1000,
startScrollOffset: 0,
endScrollOffset: 50,
})
})