-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
模态框的最佳实践 #4
Comments
这周讨论的话题是「模态框的最佳实践」,在我看来,模态框的最佳实践就是:能不用就不用。 原生的 仔细回想一下,你在浏览网页的时候有没有遇到过各种流氓弹窗?像早些年间这些广告都是用 不仅是国内的网站,在访问许多国外的网站时都会弹出一个请求你 subscribe 他们 maillist 的弹窗。这不最近就有人在吐槽 —— No, I Don’t Want to Subscribe to Your Newsletter。 突然想到一个有意思的,当年 IE 还是主流浏览器的时候, 回到这周的话题,我们没有模态对话框真的不能活吗? 我想起了 Facebook 里这个惊艳的设计,它看起来像模态框,但是完全没有上下文切换的成本,不会让你觉得进入了一个新的页面,需要适应过程: 同理,很多原本需要 总的来说,如果真的需要使用模态对话框,请遵循本文提出的最佳实践;如果不是真的需要,请不要使用模态对话框。 |
本文从视觉角度分析了模态框,我从代码的角度分析一下。 如果下定决心使用 对有状态模态框来说,很多库会支持 这种无状态模态框的方式,在模态框需要显示复杂逻辑的场景中,会自然将初始化逻辑写在父级,当模态框出现在循环列表中,往往会引发首屏触发 2-30 次模态框初始化运算,而这些运算最佳状态是模态框显示时执行一次,由于模态框同一时间只会出现一个,最次也是首屏初始化一次,但下面看似没问题的代码往往会引发性能危机: const TdElement = data.map(item => {
return (
<Td>
<Button>详情</Button>
<Modal show={item.show}>{/* balabala.. */}</Modal>
</Td>
)
}) 上面代码初始化执行了 N 个模态框初始化代码,在模态框复杂的时候,我们还会封装一层: class CustomModal {
init() {
// balabala..
}
render() {
return <Modal/>
}
} 引用了这种自定义模态框更是加剧了初始化时计算消耗,为了避免这个问题,尽量将模态框与按钮再封装一个组件,模态框内数据的初始化行为在其状态变更为 class CustomModal {
init() {
// do nothing
}
componentWillReceiveProps(nextProps) {
if (nextProps.show) {
// balabala..
}
}
render() {
return <Modal/>
}
} |
对于 table 操作列中触发的模态框(虽然已经习惯称之为 Dialog), 我们应该有两种写法,一种是 @ascoders 所说的: 每一个单元格对应一个模态框: const TdElement = data.map(item => {
return (
<Td>
<Button>详情</Button>
<Modal show={item.show}>{/* balabala.. */}</Modal>
</Td>
)
}) 第二种是: 所有行都对应一个模态框,通过父级中一个状态变量来控制展示的内容: class Table extends Component {
static state = {
activeItem: null,
};
render() {
const { activeItem } = this.state;
return (
<div>
<AbcModel show={!!activeItem} data={activeItem} />
</div>
);
}
} 第二种方案减少了节点数,但是可能会带来的问题是,每次模态框被展示的时候,触发是会是模态框的 更新 (componentDidUpdate) 而不是 新增。当然结合table 中操作的特点,我们可以这样优化: {activeItem ? <AbcModel show={true{} data={activeItem} /> : null} 这样每次触发模态框的时候,都会创建新的模态框。 |
对于问题作者提到的模态框的第四种使用情况:
我们也是经常会用到,例如用于展示一些明细数据,对于这种情况,模态框一般不会很小,我看过两种替代方案:
对于用户而言,这三种方案哪种更加打扰用户呢? 另外作者的文中如果有数据证明方案的优劣感觉会更加有说服力。 |
手机打字,没有md的效果,见谅。 |
@monkingxue 多个 modal 并不是一起显示,而是满足条件后触发显示,很多代码都是这么写的。 |
@arcthur |
模态框的滥用是导致其臭名昭著的根本原因。在用户不知情或不需要的情况下,通过模态框的方式来引起用户的注意。这样不仅打断了用户的交互操作,而且会让用户养成看到模态框就下意识关闭的习惯。 但我依旧坚持,在遵守最佳实践的前提下,模态框是可以给用户带来轻量级体验的。首先,它的出现与消失不需要刷新页面,与页面切换相比,成本要小很多,例如,用户在淘宝上看中了一款商品,想登陆购买,此时弹出登陆模态框的体验就要远远好于跳转到登陆页面,因为用户在模态框中登陆后,就可以直接购买了。其次,模态框的内容对于当前页面来说是一种衍生或补充,可以让用户更为专注去阅读或者填写一些内容。 |
说点自己的看法。我是比较同意 淡苍 的观点。 模态框的不合理使用导致一大部分用户对它比较嫌弃,其根源是开发者的不合理滥用,却要模态框背锅,这就好比刀被拿去杀人,最后大家都在说刀的错。 其实在合适的场景下使用模态框是能够起到提升体验的作用。 它的些许优点: 更好的使用它 & 某些不适用的场景: 关于模态框,我个人感觉它的视觉交互设计&合理使用远比它的开发要重要的多,所以我这里就不讨论模态框开发的问题了。 |
现在有非常多的设计倾向于用动画完成流畅的过渡,让 Modal 变得不再突兀。FB 的算一个,还有 dribble 上诸多例子。https://dribbble.com/shots/3206370-Coverage-Modal-Motion-Study 本文有一些重点强调,第一一定要有退出的方式,设定退出键。第二是 Error 提示不能用弹框,我认为这个强调来源于很难将上下文带到 Modal 中,而且我们一般这类提示都会做一些统一的组件。因此在界面该位置作提示是最好的做法。第三是 ARIA 的支持,做为前端一定要注重无障碍网页。 不要忘记前端的初心一直是保障用户体验。 |
@monkingxue 回复你的为什么一个table中需要渲染多个modal呢,这里并不是说多个同时显示,是点击 ID 后显示对应的详情。 多modal的适用场景还有(可能是 bad design)
前面 @twobin 的总结已经比较完善,对于面向大众用户的产品,由于用户的关注点和黏性比较低,应该尽可能少的使用 Modal。我补充一个细分的场景。在一些围绕数据来做复杂处理的应用中,如 ERP、CRM,用户通常关注点都在一个表单和围绕表单做的一系列操作,页面来回切换或复杂的看似酷炫的动画可能都会影响效率。用户需要的是直截了当的完成操作,这时候 Modal 就显出了它的优势,但也要注意不能滥用。 |
@camsong 烂用 -> 滥用 |
从用户体验上来说,模态框有这些类似组件: 另外,结合 ReactDOM.render(content, document.createElement('div')); 这种方式的问题是 ReactDOM.unstable_renderSubtreeIntoContainer(content, document.createElement('div')); |
在这篇文章中我看到了一个细节,关于模态框的退出方式。在文章里,提到了四种退出方式:
回想一下那些年自己写的模态框,能做到这四种都俱备的又有多少呢?尤其是后面两个也真是容易忽略的重灾区。但是,走出理想,不可忽视的是现实中,模态框作为一种强干扰的组件,往往使用他的场景,都是不希望用户能太轻松就把它关掉了。这和之前提到的最佳实践就是一个矛盾。 如果只是一般的消息提醒,大可用信息条、小红点,甚至跑马灯这些方式,至少是不阻塞用户操作的。在文末引用的10 Guidelines to Consider when using Overlays一文中,第8条强调了模态框不到万不得以不应该使用。但是真到万不得已的时候,你觉得是使用恶心的交互突出内容吸引用户,还是用更好的体验留住用户?这个真不好回答?对于产品而言,前者如洪水猛兽,后者则是细水长流,是各有利弊的。 作为开发和交互,说服产品的设计规划,尊重用户的使用体验是我们的义务。但是我依旧认为,不应该为了追求极致的用户体验放弃产品本身需要重点突出的内容——也就是说,有些时候,该恶心的地方还是得恶心。(对此观点,虚心接受各方批判。) 随后的一句话,让我对这一情形进一步深思:
Accessibility,用苹果的翻译是“辅助功能”,是对不同终端用户的体验完善。上面这句话就是在说,每一个模态框,都要有通过键盘关闭的功能,通常使用ESC键。似乎我们程序员多少总会把我们自我的惯性思维带进实现的产品,尤其是当我们敲着外置的键盘,用着Mac的时候。下面的这些是我遇到过的:
这样的点还有很多,平时自己做的那些东西,还真不敢称最佳实践。 |
有种交互场景使用Modal我还是挺喜欢的。 |
本期精读的文章是:https://uxplanet.org/best-practices-for-modals-overlays-dialog-windows-c00c66cddd8c
这是一篇 UX 相关的文章,讲了很多细节问题,可以一起来看看
The text was updated successfully, but these errors were encountered: