Skip to content

样式

自定义导航栏

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,
  })
})