uni-ui组件库实战踩坑与性能优化经验分享

瑞琴~ 移动 阅读 852
赞 10 收藏
二维码
手机扫码查看
反馈

先看效果,再看代码

最近在搞一个 uni-app 的小程序项目,UI 组件库直接选了 uni-ui。不是因为多高大上,而是它和 uni-app 官方深度绑定,打包体积小、兼容性好,尤其在微信小程序里跑得稳。我一开始是想用 uView,但发现有些组件在 H5 和小程序表现不一致,折腾半天不如直接用官方的。

uni-ui组件库实战踩坑与性能优化经验分享

今天不讲怎么安装(npm install 一敲就完事),直接上干货:怎么用 uni-ui 做一个带下拉刷新 + 上拉加载的列表页,还带个搜索框和空状态提示。这几乎是每个 App 都有的场景。

<template>
  <view class="page">
    <uni-search-bar @confirm="handleSearch" v-model="searchKeyword" />
    
    <view class="list-container" v-if="list.length > 0">
      <uni-list>
        <uni-list-item 
          v-for="(item, index) in list" 
          :key="index"
          :title="item.name"
          :note="item.desc"
          clickable
          @click="goDetail(item.id)"
        />
      </uni-list>
    </view>
    
    <view class="empty-tips" v-else>
      <text>暂无数据</text>
    </view>
    
    <!-- 加载更多提示 -->
    <uni-load-more 
      :status="loadStatus" 
      @clickLoadMore="loadMore"
    />
  </view>
</template>

别看这段代码简单,里面有几个坑我踩过不止一次。

踩坑提醒:这三点一定注意

第一,uni-search-bar 的 v-model 必须是字符串类型。 我之前把 searchKeyword 初始化成 null,结果输入框根本没法输入,控制台也不报错,查了半天才发现 uni-ui 内部对非字符串值做了拦截。现在我一律初始化为 ''

data() {
  return {
    searchKeyword: '',
    list: [],
    page: 1,
    loadStatus: 'more' // more / loading / noMore
  }
}

第二,uni-list-item 的 clickable 属性不是可选项,是必须加的。 不加的话,在 iOS 小程序里点击没反馈,用户以为卡了。加上之后才有 hover 效果和点击波纹(虽然波纹只在 H5 有,但至少小程序会有轻微变色)。

第三,uni-load-more 的 status 控制逻辑要自己写清楚。 它不会自动判断是否还有下一页,你得在接口返回后手动改状态。比如:

async loadMore() {
  if (this.loadStatus === 'loading' || this.loadStatus === 'noMore') return;
  
  this.loadStatus = 'loading';
  try {
    const res = await fetch(https://jztheme.com/api/list?page=${this.page + 1});
    const data = await res.json();
    
    if (data.list && data.list.length > 0) {
      this.list = [...this.list, ...data.list];
      this.page += 1;
      this.loadStatus = 'more';
    } else {
      this.loadStatus = 'noMore';
    }
  } catch (err) {
    this.loadStatus = 'more'; // 失败后允许重试
    uni.showToast({ title: '加载失败', icon: 'none' });
  }
}

这里注意:catch 里我把状态改回 'more',这样用户还能点“点击加载”重试。如果直接设成 'noMore',用户就没法再试了——这种细节体验很重要。

这个场景最好用:自定义空状态

uni-ui 没有提供空状态组件,但实际项目中几乎每个列表都要处理。我的做法是:用 v-if 判断 list.length === 0,然后放个自定义的空提示区域。

<view class="empty-tips" v-if="list.length === 0 && !loading">
  <image src="/static/empty.png" mode="widthFix" class="empty-img" />
  <text class="empty-text">什么都没找到</text>
  <button class="reload-btn" @click="reload">重新加载</button>
</view>

这里有个小技巧:**一定要加 !loading 条件**。否则首次进入页面时,list 是空数组,会立刻显示空状态,而此时数据其实正在加载中,体验很割裂。所以我一般还会加个 loading 状态控制:

async fetchData() {
  this.loading = true;
  try {
    const res = await fetch(https://jztheme.com/api/list?page=1);
    this.list = (await res.json()).list || [];
  } finally {
    this.loading = false;
  }
}

高级技巧:动态切换主题色

uni-ui 的组件样式是通过 CSS 变量控制的,比如 --uni-color-primary。如果你想在运行时切换主题(比如夜间模式),可以直接修改根节点的 CSS 变量。

// 切换深色主题
switchTheme(dark) {
  const root = uni.getSystemInfoSync().platform === 'ios' 
    ? document.documentElement 
    : document.body;
  
  if (dark) {
    root.style.setProperty('--uni-bg-color', '#121212');
    root.style.setProperty('--uni-text-color', '#ffffff');
    root.style.setProperty('--uni-color-primary', '#BB86FC');
  } else {
    root.style.setProperty('--uni-bg-color', '#ffffff');
    root.style.setProperty('--uni-text-color', '#333333');
    root.style.setProperty('--uni-color-primary', '#007AFF');
  }
}

不过要注意:**这个方法在小程序里无效**。因为小程序没有 DOM 操作权限。如果你要做小程序的主题切换,得靠条件 class 或者动态 style 绑定。比如:

<view :class="{'dark-theme': isDark}" class="page">
  <uni-list-item 
    :style="{ backgroundColor: isDark ? '#1e1e1e' : '#fff' }"
    ...
  />
</view>

虽然麻烦点,但兼容性好。我现在的项目就是 H5 用 CSS 变量,小程序用 class 切换,一套逻辑两套实现。

别被文档骗了:有些组件其实不推荐用

uni-ui 文档里列了一堆组件,但有些真的别碰。比如 uni-data-picker,在微信小程序里层级问题严重,经常被原生 input 盖住;还有 uni-swipe-action,滑动逻辑和 iOS 手势冲突,导致页面无法正常滚动。

我的建议是:**核心交互用原生组件 + uni-ui 基础组件组合**。比如侧滑删除,我宁愿自己用 touchstart/touchmove 手写,也不用 uni-swipe-action。虽然多写 20 行代码,但稳定得多。

另外,uni-icons 图标库很全,但注意:**图标名称大小写敏感**。比如 icon-home 可以,icon-Home 就不显示。我曾经因为这个调试了半小时,最后发现是文档示例写错了(他们 GitHub 上有人提过 issue,但还没改)。

结尾碎碎念

uni-ui 不是银弹,但它在“够用+稳定”之间找到了平衡点。尤其适合赶工期、多端发布、不想折腾兼容性的项目。我用它做了三个上线项目,除了偶尔的小坑,整体体验比第三方 UI 库省心多了。

以上是我踩坑后的总结,希望对你有帮助。这个技术的拓展用法还有很多(比如结合 Vuex 做全局状态管理、自定义 uni-ui 主题包等),后续会继续分享这类博客。有更优的实现方式欢迎评论区交流,毕竟前端这行,谁还没被 UI 库坑过几次呢?

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论