惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Y
Y Combinator Blog
有赞技术团队
有赞技术团队
J
Java Code Geeks
H
Hackread – Cybersecurity News, Data Breaches, AI and More
美团技术团队
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Hugging Face - Blog
Hugging Face - Blog
人人都是产品经理
人人都是产品经理
酷 壳 – CoolShell
酷 壳 – CoolShell
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
C
Check Point Blog
博客园 - 【当耐特】
The GitHub Blog
The GitHub Blog
Recent Announcements
Recent Announcements
The Cloudflare Blog
Microsoft Azure Blog
Microsoft Azure Blog
腾讯CDC
Vercel News
Vercel News
IT之家
IT之家
MyScale Blog
MyScale Blog
博客园_首页
Martin Fowler
Martin Fowler
WordPress大学
WordPress大学
罗磊的独立博客

蚊子的前端博客

微说 | 有的人觉得只要不考XX,一定能考好!-蚊子的前端博客 微说 | 春天来了-蚊子的前端博客 明天和意外不知道哪个先来-蚊子的前端博客 微说 | 既然错过了路口,就及时止损,重新规划路线上路-蚊子的前端博客 微说 | 2025年的出生人口数是792万-蚊子的前端博客 微说 | 工作年终总结,让写对接的接口的数量?-蚊子的前端博客 微说 | 温家宝:没有政治体制改革的成功 经济体制改革不可能进行到底-蚊子的前端博客 微说 | 违法犯罪了该不该被禁言?-蚊子的前端博客 微说 | 不明白为什么在推荐去俄罗斯旅游-蚊子的前端博客 微说 | 易中天论骗子-蚊子的前端博客 微说 | 一场大风吹散了秋天-蚊子的前端博客 微说 | 既要、又要、还要、更要!-蚊子的前端博客 又是一年的国庆雨季-蚊子的前端博客 微说 | 预估下2025年的出生人口数据-蚊子的前端博客 微说 | 可惜了我那些小时候的书本-蚊子的前端博客 微说 | 牛马有的是,驴不够了!-蚊子的前端博客 微说 | 能否有一条非户口也能高考的路-蚊子的前端博客 微说 | 小聊中医-蚊子的前端博客 微说 | 将要制作的一款新产品-蚊子的前端博客 微说 | 做人要有信-蚊子的前端博客 微说 | 好一个正义联盟-蚊子的前端博客 微说 | 都是见过吃过的主儿-蚊子的前端博客 微说 | 追求8小时工作制有错吗?-蚊子的前端博客 微说 | 如果尖锐的批评完全消失-蚊子的前端博客 微说 | 很好!-蚊子的前端博客 微说 | 封禁用户可以,但要告知具体原因-蚊子的前端博客 微说 | 面朝大海,春暖花开-蚊子的前端博客 微说 | 程序员的悲哀是什么?-蚊子的前端博客 微说 | 2025年出生人口的预测-蚊子的前端博客 前端在 LiveKit 中如何获取所有的参与者-蚊子的前端博客
前端如何提升用户的交互体验-蚊子的前端博客
author · 2024-03-28 · via 蚊子的前端博客

前端是离用户最近的岗位,优异的前端设计,能大大提高用户的使用体验。之前我们曾经在文章【学完这 4 个小技巧,让你的移动端交互体验更加优秀】聊过一些交互体验上的一些小技巧,本篇文章是在准备内部分享时,重新整理了下,部分内容也与之前的稍微有点重复。

1. 即时反馈 #

用户在看到页面时,或者在页面上做出了什么动作,都应当予以即时的反馈,告诉用户他的操作是有效的,系统已收到他的操作,内部正在处理中。

1.1 点击按钮 #

比如用户点击按钮发起了网络请求,一定要在按钮上(或者页面上)加上 loading 效果,一方面是告知用户系统正在处理,再一个是避免用户的多次重复。若前端没有任何的提示,用户可能以为刚才的点击无效,会多次点击。有同学用防抖的方式来解决,也可以,但使用的场景不太对,最好是用 loading。

还有删除列表数据,或者将该数据流转到其他的状态,有时间的话,可以做个动效,比如该数据所在区域的高度变成 0,或者左滑删除等。

1.2 搜索 #

在 select 等标签搜索或者其他自动搜索时,虽然我们用了防抖策略,避免短时间内发生多次网络请求。但因为网络状态,依然可能会存在这样的情况。这里我们还要添加上时序控制,否则前面的搜索结果可能会把最新的搜索结果覆盖掉。

const App = () => {
  const requestIdRef = useRef(0);
  const [loading, setLoading] = useState(false);

  const request = async () => {
    setLoading(true);
    requestIdRef.current++;
    const requestId = requestIdRef.current;

    const result = await fetch("https://api.xxx.com");

    if (requestId < requestIdRef.current) {
      // 这是之前的请求,直接舍弃掉
      return;
    }
    setLoading(false);

    console.log(result);
  };
};

2. 数据的展示 #

有的页面一进来就需要展示数据,有些同学可能做的操作有:

  1. 有 loading 状态,但遇到 loading 就返回 null(此时页面处于白屏中);

loading时直接返回null

  1. 没有 loading 状态,默认展示「暂无数据」的提示;
const App = () => {
  const [list, setList] = useState([]);

  return (
    <div>
      {list.length ? (
        <div>
          {list.map((item) => (
            <div></div>
          ))}
        </div>
      ) : (
        <div className="nothing"></div>
      )}
    </div>
  );
};

这两种情况对用户来说都不太友好,毕竟网络请求的时长谁也保证不了。一旦请求时长过长,第 1 种方式可能会认为页面崩了;第 2 种方式用户可能以为数据丢了(实际上没丢,正在来的路上)。

若在接口返回数据之前,不方便展示页面(如跟主题相关的),可以添加整屏的 loading,或者用骨架屏来当做 loading。

若存在「有数据」和「暂无数据」的两种展示,可以在外层嵌套一个 。

还有 antd 中的 <Select / 组件,搜索时,其实是有 loading 效果的,但他的 loading 在搜索框的最右边,而且还非常小,特别不明显。我们在下拉面板中添加下 loading 效果:

const App = () => {
  const [inputValue, setInputValue] = useState(""); // 输入框中的文案
  const [loading, setLoading] = useState(false);
  const [options, setOptions] = useState < SelectProps["options"] > [];

  return (
    <Select
      dropdownRender={(menu) => {
        if (loading) {
          return <Spin />;
        }
        if (inputValue && !options.length) {
          // 有输入的文本,但没有下拉项,说明没检索到结果
          return <p>关键词{inputValue},未找到搜索结果</p>;
        }
        return menu;
      }}
      onSearch={debounce(handleSearch, 700)}
    />
  );
};

可以有个约定:凡是有网络请求的,一定要有 loading。

3. 页面布局 #

考虑到大部分都是右利手,我们最好是把常用操作(如确认、提交等),或产品希望进行的操作(再想想),放在右侧。

4. 页面兜底 #

一般是在报错时才会白屏,因此我们可能需要做一些预防性编程。如:

  1. 读取多层级数据时,某个字段数据可能为空,这里需要用到可选链;
  2. 有数据时接口返回的是数组,没数据时接口返回的是 null;当使用 length 或者 map 时,最好先用 Array.isArray() 判断下是否是数组,或者用可选链;

5. 总结 #

当然还有很多需要注意的地方,这里仅是小结一下。我们应当多多从用户角度和产品角度来考虑,每一步的操作是否合理和顺畅。