blender视图缩放_如何使用主视图类型缩放Elm视图

柯捷
2023-12-01

blender视图缩放

A concept to help Elm Views scale as applications grow larger and more complicated.

当应用程序变得更大和更复杂时,可帮助Elm Views扩展的概念。

In Elm, there are a lot of great ways to scale the Model, and update, but there is more controversy around scaling the view. A lot of the debate is around Reusable Views versus Components. Components are not recommended, but a lot of people are still advocating for them.  This article presents an idea that hopefully strengthens the argument for Resuable Views.

在Elm中,有很多很棒的方法可以缩放Model和进行update ,但是围绕缩放view存在更多争议。 关于可重用视图与组件的争论很多。 不建议使用组件,但是许多人仍在倡导使用它们。 本文提出了一个想法,希望能加强对可恢复观点的争论。

In almost all cases, the scaling problem comes down to enforcing consistency, which usually means allowing child views to make some adjustments to the master view, while at the same time not allowing child views to make a mess.

在几乎所有情况下,缩放问题都归结为强制执行一致性,这通常意味着允许子视图对主视图进行一些调整,而同时不允许子视图造成混乱。

I will be using Richard Feldman's excellent Real World app (specifically written to demonstrate scaling in Elm) as an example, as it is contains a lot of current best practice techniques, it is well known (2000+ stars and 300+ forks) and Richard is a well known Elm expert.

我将以Richard Feldman出色的“ 真实世界”应用程序 (专门为演示Elm中的缩放比例而编写)作为示例,因为它包含许多当前的最佳实践技术,众所周知(2000多颗星星和300多颗叉子)和Richard是一位著名的榆木专家。

I will be suggesting some improvements to this code, so I want make a clear at this point that I mean no disrespect by this (I would bet large sums of money that he did it in about one tenth of the time it would have taken me!). You could also argue that the problems are small and not worth fixing. Ultimately, this decision is yours, but by the end of the article I hope to persuade you that there are problems, and that they are fixable if you think it is worthwhile.

我将建议对此代码进行一些改进,因此我想在此说明一下,我的意思是不要无视此事(我敢打赌,他花了大笔钱才花了我将近十分之一的时间) !)。 您还可以争辩说问题很小,不值得解决。 最终,这是您的决定,但是到本文结尾,我希望说服您存在问题,并且如果您认为值得的话,这些问题是可以解决的。

具有条件的主视图功能 (Master view functions with conditionals)

One option is to define a master view function. This function takes care of shared concerns, like the header bar and overall layout. Then it calls child view functions depending on the current view and / or has parameters to control child specific behaviour.

一种选择是定义主视图功能。 此功能可解决共享问题,例如标题栏和整体布局。 然后,它根据当前视图调用子视图函数,并且/或者具有控制子特定行为的参数。

This works, but can quickly lead to:

这行得通,但可以很快导致:

  • An explosion of parameters, potentially forcing your child views to return a lot of things they don't care about.

    参数的爆炸式增长,可能会迫使您的孩子视图返回很多他们不在乎的东西。
  • A mixing of responsibilities between master and child views.

    主视图和子视图之间的职责混合。
  • Extra code and duplication.

    额外的代码和重复。

In the Real World App, a parameter of type Page is passed to the master view so that it can render a navbar link as active. There is a large case statement that uses this parameter to work out what which link is active, and it would be a lot easier for the child just to specify this.

在Real World App中,将Page类型的参数传递到主视图,以便它可以将导航栏链接呈现为活动状态。 有一个大写的语句使用此参数来确定哪个链接处于活动状态,对于孩子来说,仅指定此链接会容易得多。

The line below shows the master view passing Page.Home, which has to match up with Home.view home. This is easy to get wrong, there is no help from the compiler or type system, and really it is the responsibility of the child view the specify this.

下面显示了传递Page.Home的主视图,该视图必须与Home.view home匹配。 这很容易出错,没有来自编译器或类型系统的帮助,这实际上是指定此子视图的职责。

viewPage Page.Home GotHomeMsg (Home.view home)

viewPage Page.Home GotHomeMsg (Home.view home)

There is some duplication when creating the NavBarLink Html, and the linkTo function will accept any Html, although only very particular Html is valid.

创建NavBarLink Html时会有一些重复,并且linkTo函数将接受任何Html,尽管只有非常特殊的Html有效。

约定与信任 (Convention and trust)

Another possibility is for child views to be responsible for keeping shared elements consistent, by convention and trust.

子视图的另一种可能性是根据约定和信任负责使共享元素保持一致。

Arguably this also happens in the Real World App. The Home, Article and Profile views all have the concept of a banner. The banner is different in each view, but presumably is meant to be a consistent and recognisable visual element (essentially, it's the title / header for the view). The views don't share any code for these banners, and as a result of this they are not the same size or colour. You could theoretically try and enforce a convention using tests, but it would be difficult, and probably not worthwhile.

可以说,这在真实世界应用程序中也会发生。 “ 主页” ,“ 文章”和“ 个人资料”视图均具有横幅的概念。 横幅在每个视图中都是不同的,但大概是一个一致且可识别的视觉元素(实际上,它是视图的标题/标题)。 视图不共享这些横幅的任何代码,因此,它们的大小或颜色都不相同。 从理论上讲,您可以尝试使用测试来强制执行约定,但是这很困难,而且可能不值得。

辅助功能 (Helper functions)

Another possibility is for child views to be responsible for keeping shared elements consistent, but by using some helper functions. This is definitely a step forward, and is probably the most common solution I see in the wild. The functions can go in the same file and be next to each other. This makes it easier to see that they are related and are representing the same visual element, and easier to make them consistent.

子视图的另一种可能性是负责使共享元素保持一致,但是要使用一些辅助函数。 这绝对是向前的一步,可能是我在野外看到的最常见的解决方案。 这些功能可以放在同一文件中,并且可以彼此相邻。 这使得更容易看到它们是相关的并且代表相同的视觉元素,并且更容易使它们保持一致。

However, there are still some drawbacks. The main one is that the child views have to know to use the helper functions, and there is nothing enforcing this. This isn't a huge deal when you only have one shared element and one function to call, but as applications get bigger, you end up with a combinatorial explosion of differences in the shared visual elements. Most people tame this by providing a number of small, focused functions for the various differences. Then the child view has to know about all these functions, and how to compose them, and there no help from the compiler.

但是,仍然存在一些缺点。 主要的一点是子视图必须知道如何使用帮助器功能,并且没有什么强制执行此功能。 当您只有一个共享元素和一个函数要调用时,这并不是什么大问题,但是随着应用程序变得越来越大,您最终将共享视觉元素之间的差异组合起来爆炸。 大多数人通过为各种差异提供一些小的,集中的功能来驯服这一点。 然后,子视图必须了解所有这些功能以及如何编写它们,并且编译器没有任何帮助。

Again, this arguably occurs in the Real World App: for example in this part of the Profile.view function, which needs to know how to use the viewTabs, Feed.viewArticles and Feed.viewPagination helper functions, and what Html they need to be contained in.

同样,这可以说是发生在Real World App中:例如,在Profile.view函数的这一部分中 ,它需要知道如何使用viewTabsFeed.viewArticlesFeed.viewPagination帮助器函数,以及它们需要使用的viewTabs Feed.viewArticles包含在。

使用主视图类型缩放 (Scaling with Master View Types)

In order to overcome these problems, I propose using a Type to define your site structure (I rather pompously call this a "Master View Type"). Child views then return this type, and the master view takes it as a parameter and returns the html.

为了克服这些问题,我建议使用一种Type来定义您的站点结构(我相当称呼它为“主视图类型”)。 然后,子视图返回此类型,而主视图则将其作为参数并返回html。

For the Real World App examples we have been looking at, the Master View Type is below (Viewer is the person viewing the page in the Real World App). You could arguably have more general banner types here, such as AvatarBanner, or even IconBanner (instead of ViewerBanner) depending on your domain.

对于我们一直在查看的Real World App示例,下面是Master View Type( Viewer是在Real World App中查看页面的人)。 可以说,根据您的域的不同,这里可能有更通用的横幅类型,例如AvatarBanner或什至IconBanner(而不是ViewerBanner)。

type alias Page =
    {   activeNavBarLink: NavBarLink
		, banner: Banner
        , body: Html Msg
    }
	
type Banner =
    TextBanner TextBannerProperties
    | ViewerBanner Viewer
    | ArticleBanner Viewer ArticlePreview

type NavBarLink =
    NavBarLink NavBarLinkProperties

To demonstrate this, I have create a repository with just the Header and Banner parts of the Real World App and then created a new repository after refactoring to use a  Master Page Type, NavBarLink Type and Banner Type. You can peruse the code to get a feel for how it works.

为了演示这一点,我创建了一个仅包含Real World AppHeader和Banner部分的存储库,然后在重构后使用Master Page TypeNavBarLink TypeBanner Type创建了一个新的存储库。 您可以细读代码以了解其工作原理。

To my mind, using a Master Page Type has the following benefits:

我认为,使用母版页类型具有以下好处:

  • Writing the master view code is easier

    编写主视图代码更容易
  • Writing the child view code is easier

    编写子视图代码更容易
  • Communication and understanding are improved, as UI concepts now have names

    交流和理解得到改善,因为UI概念现在有了名称
  • Theming / redesigning a site is a lot easier

    主题化/重新设计网站要容易得多
  • Elm packages can provide UI templates

    Elm包可以提供UI模板

The master view can precisely define what it will accept / support via the types, with union types and opaque types. Non supported combinations can be made unrepresentable or uncreatable.

主视图可以通过联合类型不透明类型通过类型精确定义它将接受/支持的内容。 不受支持的组合可能无法显示或无法创建。

In my example repository the NavBarLink type is opaque, so it is only possible to create supported NavBarLinks (home, article and viewer). In a similar way Banner is a union type, which means that only supported variants can be represented.

在我的示例存储库中, NavBarLink类型是opaque ,因此只能创建受支持的NavBarLinks( homearticleviewer )。 以类似的方式Banner是联合类型 ,这意味着只能表示受支持的变体。

It would be possible for a programmer to simply change these files, but a proficient programmer would recognise the patterns and follow them. If this isn't enough and you are feeling paranoid, then you can require stricter code review on such files, potentially taking advantage of CODEOWNERS functionality on GitHub and GitLab. In the extreme you can  provide the modules via an elm package, and restrict push access to the underlying repository.

程序员可以简单地更改这些文件,但是精通的程序员会识别并遵循这些模式。 如果这还不够,您会感到偏执,那么您可能需要对此类文件进行更严格的代码审查,从而有可能利用GitHub和GitLab上的CODEOWNERS功能。 在极端情况下,您可以通过elm包提供模块,并限制对基础存储库的推送访问。

Child views don't have to do anything more than create an instance of the types. The helper functions all return types, so it's easy to see which functions can be used in a particular context, and is impossible to use functions in the wrong context. For example, if a function returns a HeaderBarLink, it is impossible to mistakenly use this function to create a link in the FooterBar, or elsewhere on the page. Child views can also leave some of the complexity to the master view. For example, the child view can define a list of options to choose from, and the master view can render this using buttons, a drop down list or an autocomplete list, depending on the number of options.

子视图除了创建类型的实例外,无需执行其他任何操作。 辅助函数将所有返回类型用作函数,因此很容易看出可以在特定上下文中使用哪些函数,并且不可能在错误的上下文中使用函数。 例如,如果一个函数返回HeaderBarLink ,则不可能错误地使用此函数在FooterBar或页面的其他位置创建链接。 子视图也可以将某些复杂性留给主视图。 例如,子视图可以定义一个选项列表,主视图可以根据选项的数量使用按钮,下拉列表或自动完成列表来呈现。

The master page type also provides names for UI concepts, which can then be discussed. For example, a designer could say "Let's move the NavBarLinks to the left hand side", and everybody would know what they meant. A product owner could say "Let's create a new page with an IconBanner, and we'll use the current weather api for the icon" and again, everybody would know what they mean. You can look at this excellent thoughtworks article for more details of this.

母版页类型还提供UI概念的名称,然后可以对其进行讨论。 例如,设计师可以说“让NavBarLinks移到左侧”,每个人都会知道它们的意思。 产品负责人可能会说:“让我们用IconBanner创建一个新页面,然后我们将使用当前的天气api作为图标”,同样,每个人都会知道它们的含义。 您可以查看这篇出色的Thoughtworks文章,以获取更多详细信息。

Since the responsibility for turning the Master View Type in to html is all in the same place, it is easy to make drastic changes to the look and feel of a website, and to do theming. These changes and themes can alter the Css and the Html, which is something that the normal theming techniques just can't do. Pragmatically, your Master View Type will often have a body: Html Msg property (to allow child views complete flexibility on the child specific parts of the page) so there would still be some sprawling code to fix up, but it will definitely be a lot easier.

由于将“主视图类型”转换为html的责任都在同一个地方,因此很容易对网站的外观和风格进行重大更改并进行主题化。 这些更改和主题可能会更改Css 和Html ,这是常规主题技术无法做到的。 实用上,您的“主视图类型”通常会有一个body: Html Msg属性(允许子视图在页面的子特定部分上具有完全的灵活性),因此仍然会有一些庞大的代码需要修复,但是肯定会有很多更轻松。

Finally, it opens up possibility of providing ready made themes and site layouts as packages. This would allow you to just do the following to get a working app, complete with layout and styling:

最后,它提供了将现成的主题和站点布局作为软件包提供的可能性。 这将使您只需执行以下操作即可获得可运行的应用程序,包括布局和样式:

  • create-elm-app

    create-elm-app

  • elm install elm-bootstrap-starter-template

    elm install elm-bootstrap-starter-template

  • Write some code to create the Master Page Type

    编写一些代码来创建母版页类型
  • elm-app start

    elm-app start

Companies could create packages like these to ensure a consistent look and feel across their applications. Open source designs and layouts could emerge and become commonplace, similar to the way that Bootstrap has revolutionised html and css design. Developers with limited design skills (like me) could concentrate on the the bits they are best at (the logic), but still produce produce elegant websites using these packages.

公司可以创建这样的软件包,以确保整个应用程序的外观一致。 开源设计和布局可能会出现并变得司空见惯,类似于Bootstrap彻底改变了html和css设计的方式。 设计技能有限的开发人员(如我)可以专注于他们最擅长的部分(逻辑上),但仍可以使用这些软件包来生成美观的网站。

To demonstrate this I have created a bootstrap starter master view package. It mimics the layout and design of the bootstrap starter template. I have then used this package in a demo elm application. You can browse the demo application to see how it looks, and view the source to see how it works.

为了演示这一点,我创建了一个bootstrap starter主视图包 。 它模仿了引导程序入门模板的布局和设计。 然后,我在演示elm应用程序中使用了此软件包。 您可以浏览演示应用程序以查看其外观,并查看源代码以查看其工作方式。

All these advantages come at a small to negative cost. There is a little more code for the new types, but some duplication is removed. You can view the source of the Real World App repositories from before and after refactoring to use a Master Page Type for the full details.

所有这些优点付出的代价很小或为负。 新类型还有更多代码,但是删除了一些重复项。 您可以在重构 前后查看“真实世界”应用程序存储库的源, 以使用母版页类型获取完整的详细信息。

结论 (Conclusions)

Master View Types bring a lot of benefits (view code is easier to write and maintain, UI concepts are named and UI packages are possible) for little or no cost. They should improve the code of any Elm application that has issues around enforcing consistency (while allowing flexibility) in their view code, which in my experience is most medium and large applications.

主视图类型带来了很多好处(视图代码更易于编写和维护,命名UI概念并且可以使用UI包),而几乎没有成本。 他们应该改进任何Elm应用程序的代码,这些应用程序在其视图代码中存在围绕加强一致性(同时允许灵活性)的问题,据我的经验,这是大多数中型和大型应用程序。

翻译自: https://www.freecodecamp.org/news/scaling-elm-views-with-master-view-types/

blender视图缩放

 类似资料: