Build complex layouts(构建复杂布局)¶
Designing the look and feel of your application is an exciting prospect, and Slate gives you the flexibility to customize and override many aspects of widget appearance. Many projects, however, go off track when achieving a pixel-perfect match to a design mockup becomes more important than clean, efficient implementation of workflow features.
Another way to think of this is that every style override is a tradeoff against the simplicity and maintainability of your application. Be cautious and thoughtful in choosing your layout and styling and take the time to periodically refactor and clean up your application before moving on to another round of new feature development.
Building Complex Layouts¶
Use Container widgets to lay out your application. Strike a balance between enough containers to logically organize your application and nesting containers unnecessarily. Keep in mind that as you build your application, every widget will eventually add several layers to the Document Model (DOM) ↗ and that the complexity of the DOM has a direct relationship with the browser resource usage, page load, and general responsiveness of your application - that is, how “heavy” your application is. When in doubt, use fewer widgets and try to avoid nesting containers more than 3 or 4 levels deep.
In almost all cases you should avoid using CSS to affect the layout of your application - stay away from position and either use the static widget positioning or a flex container for relative positioning. There are some exceptions here in specific cases, but for the general layout of an application, you'll avoid unnecessary complexity and improve legibility of your app by sticking to the built-in positioning tools.
Aligning widgets¶
An often overlooked feature of Slate is the ability to align widgets to each other. Hold the CTRL (CMD on Mac) key and click to select one or more widgets. With multiple widgets selected, the right panel will no longer show the widget configuration, but instead present several options to align or distribute the widgets.
Further, if you would like your layout to happen “automatically”, you can use the Flex Container to lay out the child widgets. See the section below on Responsive Layouts for much more on working with Flex containers.
Showing and Hiding Widgets¶
Dynamic layouts often include showing or hiding content based on the state of the application. There are a number of ways to achieve this. Three patterns below share a few options and discuss the relative strengths and drawbacks.
Simple: Hiding with a Class¶
In the simplest case, you can hide a widget by templating the Additional Classes property in the widget display configuration to hidden. The common pattern would be to determine using a function (or your state variable) if a widget should display, and then template the output of that function into the widget. While this is simple, it does not scale well to multiple widgets and you will see a brief flicker for widgets that are “hidden” on page load, since they will remain visible until the dependency graph resolves and the class is applied.
Improvement: Hiding with a Tabbed Container¶
Better instead, especially with multiple widgets, is to use a Tabbed container where one tab is blank and the other contains the widgets to display. The pattern here is to apply a bit of CSS to hide the container border and background (i.e. make the container “invisible” relative to the background):
// This will remove the border and background from any container with 'minimal' as
// an 'Additional Class'
.minimal sl-app-container {
border: none;
background: none;
}
Then template the selectedTabIndex property to toggle between hidden and visible. With this pattern there will be no flicker on page load and the widgets will hide instantly.
Complex: Hide from Root Element¶
If you need a widget to not only “hide”, but to be removed from the DOM completely, you can accomplish this by templating an additional class on the parent container to hide the widget by the root element selector. This pattern is most common in a responsive layout where you need to hide a widget and cause the other child widgets on the same level to reposition themselves.
The root element of every slate widget has an ID selector formatted like: widget-[widgetName]. So let's say we have a widget called w_myHTMLWidget that is a child of the w_sidebar container. To hide the widget completely, you define a class in the global styles:
.hide-myHTMLWidget {
#widget-myHTMLWidget {
display: none;
}
}
Then in w_sidebar you can conditionally add this class and the entire widget will hide. See the Working With Styles section below for more patterns and examples for using conditional CSS classes.
“Multi-Page” Applications¶
The most common pattern for segmenting an application is to use a Tabbed Container. Each container tab can be treated as a separate page, however it's important to remember that these “pages” are simply a UI function - it won't affect the resolution of the dependency graph for instance, so even if a chart is on a different tab, the query to populate that chart will still run with the resolution of the dependency graph.
If you are building a multi-page application using a tabbed container, make sure to check the Lazy rendering enabled option - this moves the rendering of the widgets on a tab to when the tab opens rather than when the page loads. This is especially useful for very large applications where the majority of widgets are “hidden” on another tab at any given point and can substantially improve page load times.
You should use Tabbed containers even if you don't want to allow the user to select a given tab manually - if, for instance, you're building a workflow app and need to control when the user is moved to the next tab. In this case, you can uncheck the Show tab titles option and then use a Handlebars statement to template which tab (zero indexed) should be displayed at any given point. A common pattern is to track this tab as part of your application state (see Building Stateful Applications above) so that you can simply update the value of the current tab in your state variable and the tab will change in your application.
Responsive Layouts¶
Search for the Working with Flex Containers tutorial in your Foundry instance.
中文翻译¶
构建复杂布局¶
设计应用程序的外观和风格是一件令人兴奋的事情,Slate 为您提供了灵活的自定义和覆盖功能,可以调整许多小部件的显示效果。然而,许多项目在追求像素级完美匹配设计稿时,往往会偏离轨道,忽视了工作流功能的简洁高效实现。
另一种理解方式是,每一次样式覆盖都是在应用程序的简洁性和可维护性之间进行权衡。在选择布局和样式时,请谨慎且深思熟虑,并在进入下一轮新功能开发之前,花时间定期重构和清理您的应用程序。
构建复杂布局¶
使用容器小部件(Container widgets)来布局您的应用程序。在合理组织应用程序所需的容器数量与避免不必要的容器嵌套之间找到平衡。请记住,在构建应用程序时,每个小部件最终都会向文档模型(DOM) ↗添加若干层级,而 DOM 的复杂度与浏览器资源使用、页面加载以及应用程序的整体响应速度(即应用程序的“重量”)直接相关。如有疑问,请尽量使用更少的小部件,并避免容器嵌套超过 3 到 4 层。
在绝大多数情况下,您应避免使用 CSS 来影响应用程序的布局——远离 position 属性,而是使用静态小部件定位或弹性容器(Flex container)进行相对定位。在某些特定场景下存在例外,但对于应用程序的通用布局,坚持使用内置定位工具可以避免不必要的复杂性,并提高应用程序的可读性。
对齐小部件¶
Slate 一个常被忽视的功能是能够将小部件相互对齐。按住 CTRL 键(Mac 上为 CMD 键)并点击选择一个或多个小部件。当选中多个小部件时,右侧面板将不再显示小部件配置,而是提供多个对齐或分布小部件的选项。
此外,如果您希望布局“自动”完成,可以使用弹性容器(Flex Container)来排列子小部件。有关使用弹性容器的更多内容,请参见下方的响应式布局部分。
显示和隐藏小部件¶
动态布局通常涉及根据应用程序状态显示或隐藏内容。有多种方法可以实现这一点。以下三种模式分享了一些选项,并讨论了各自的优缺点。
简单方法:通过类隐藏¶
在最简单的情况下,您可以通过将小部件显示配置中的附加类(Additional Classes)属性模板化为 hidden 来隐藏小部件。常见模式是使用函数(或状态变量)判断小部件是否应显示,然后将该函数的输出模板化到小部件中。虽然这种方法简单,但不适用于多个小部件,并且在页面加载时,您会看到“隐藏”的小部件短暂闪烁,因为它们在依赖关系图解析并应用类之前仍保持可见。
改进方法:通过标签页容器隐藏¶
更好的方法(尤其是涉及多个小部件时)是使用标签页容器(Tabbed container),其中一个标签页为空白,另一个包含要显示的小部件。此模式的思路是应用一些 CSS 来隐藏容器的边框和背景(即让容器相对于背景“不可见”):
// 这将移除任何包含 'minimal' 作为 '附加类' 的容器的边框和背景
.minimal sl-app-container {
border: none;
background: none;
}
然后将 selectedTabIndex 属性模板化,以在隐藏和可见之间切换。使用此模式,页面加载时不会出现闪烁,小部件会立即隐藏。
复杂方法:从根元素隐藏¶
如果您需要小部件不仅“隐藏”,还要完全从 DOM 中移除,可以通过在父容器上模板化一个附加类,使用根元素选择器来隐藏小部件。此模式在响应式布局中最常见,当您需要隐藏一个小部件并导致同一层级上的其他子小部件重新定位时使用。
每个 Slate 小部件的根元素都有一个格式为 widget-[widgetName] 的 ID 选择器。假设我们有一个名为 w_myHTMLWidget 的小部件,它是 w_sidebar 容器的子元素。要完全隐藏该小部件,您可以在全局样式中定义一个类:
.hide-myHTMLWidget {
#widget-myHTMLWidget {
display: none;
}
}
然后在 w_sidebar 中,您可以有条件地添加此类,整个小部件将被隐藏。有关使用条件 CSS 类的更多模式和示例,请参见下方的样式处理部分。
“多页面”应用程序¶
分割应用程序最常见的模式是使用标签页容器(Tabbed Container)。每个容器标签页都可以视为一个独立的页面,但重要的是要记住,这些“页面”仅仅是 UI 功能——例如,它不会影响依赖关系图的解析,因此即使图表位于不同的标签页上,填充该图表的查询仍会随着依赖关系图的解析而运行。
如果您使用标签页容器构建多页面应用程序,请确保勾选启用延迟渲染(Lazy rendering enabled)选项——这会将标签页上小部件的渲染从页面加载时推迟到标签页打开时。这对于非常大的应用程序尤其有用,因为在任何给定时间,大多数小部件都“隐藏”在另一个标签页上,这可以显著改善页面加载时间。
即使您不希望允许用户手动选择某个标签页,也应使用标签页容器——例如,如果您正在构建一个工作流应用程序,并需要控制用户何时切换到下一个标签页。在这种情况下,您可以取消勾选显示标签页标题(Show tab titles)选项,然后使用 Handlebars 语句模板化应显示哪个标签页(从零开始索引)。常见模式是将此标签页作为应用程序状态的一部分进行跟踪(参见上方的构建有状态应用程序),这样您只需更新状态变量中当前标签页的值,应用程序中的标签页就会随之改变。
响应式布局¶
请在您的 Foundry 实例中搜索使用弹性容器(Working with Flex Containers)教程。