ctk 组件创建 ui

by Gabriel Colombo

加布里埃尔·科伦坡(Gabriel Colombo)

创建可重复使用的UI组件的提示和技巧 (Tips & tricks for creating reusable UI components)

In this article I want to share some tips and tricks I use while building our core frontend library using Ember.js. Having no contact with it before, it has been a great learning opportunity. I hope you guys enjoy it! Please note, the code used to exemplify the ideas in the article contains just enough information to get the point across. It also uses some Ember.js terminology, but the concepts are meant to be framework-agnostic.

在本文中,我想分享一些在使用Ember.js构建核心前端库时使用的提示和技巧。 以前没有接触过,这是一个很好的学习机会。 希望大家喜欢! 请注意,用于例示本文中思想的代码仅包含足够的信息以阐明要点。 它还使用一些Ember.js术语,但是这些概念与框架无关。

目标 (The objectives)

To put it simply, the requirements for building the library are the following:

简而言之,构建库的要求如下:

  1. It must be productive.它必须富有成效。
  2. It must be maintainable.它必须是可维护的。
  3. It must be consistent.它必须是一致的。

方法 (The approaches)

最小化业务逻辑 (Minimize business logic)

One of most frequent problems I encounter on projects are components that contain way too much logic in them. Thus, performing tasks that are, theoretically, out of their scope.

我在项目上遇到的最常见问题之一是组件中包含太多逻辑的组件。 因此,执行理论上超出其范围的任务。

Before implementing any functionality, it is good to outline some of the duties the component is responsible for.

在实现任何功能之前,最好概述一下组件负责的一些职责。

Imagine we’re building a button component.

想象一下我们正在构建一个按钮组件。

I would like to be able to:

我希望能够:

  • Inform which type of button it is — Primary or regular告知按钮是哪种类型-主按钮或常规按钮
  • Inform the content displayed inside the button (Icon and text)通知按钮内显示的内容(图标和文本)
  • Disable or enable the button禁用或启用按钮
  • Perform some action upon click点击后执行一些操作

Having this little outline, pull apart the different parts involved in the process of building this component. Try to identify where things could be placed.

有了这个小轮廓,将构建此组件的过程中涉及的不同部分拆开。 尝试确定可以放置物品的位置。

1 — The type and content are component-specific, so they can be placed into the component file.

1-类型和内容是特定于组件的,因此可以将它们放置在组件文件中。

Since the type is — to some extent — required, let’s add a verification in case no value was provided.

由于在某种程度上需要类型,所以我们在没有提供值的情况下添加一个验证。

const type = get(this, 'type');
const types = {  primary: 'btn--primary',  regular: 'btn--regular',}
return (type) ? types[type] : types.regular;

I like mapping the properties into an object because it allows things to scale without much effort — in case we need a danger button or anything like it.

我喜欢将属性映射到对象中,因为它可以使事情轻松缩放,以防万一我们需要一个危险按钮或类似的按钮。

2 — The disabled state can be found on different components like an input. In order to avoid repetition, this behavior can be moved into a module or any shared structure — folks call it a mixin.

2-禁用状态可以在不同组件(例如输入)上找到。 为了避免重复,可以将此行为移至模块或任何共享结构中,人们称其为mixin

3 — The click action can be found in different components. So it can also be moved to another file and should contain no logic inside it — simply calling the callback provided by the developer.

3-单击动作可以在不同的组件中找到。 因此,它也可以移动到另一个文件中,并且其中不应包含任何逻辑-只需调用开发人员提供的回调即可。

This way we can have an idea what cases our component needs to address while helping to outline a base architecture that supports expansion.

这样,我们可以了解我们的组件需要处理哪些情况,同时帮助概述支持扩展的基本体系结构。

单独的可重用UI状态 (Separate reusable UI state)

Certain UI interactions are common among different components, like:

某些UI交互在不同组件之间是常见的,例如:

  • Enable/disable — eg. buttons, inputs

    启用/禁用- 例如。 按钮,输入

  • Expand / Shrink — eg. collapse, drop-down lists

    展开/缩小- 例如。 折叠,下拉列表

  • Show / hide — Pretty much everything

    显示/隐藏- 几乎所有内容

These properties are often used just to control visual state — hopefully.

这些属性通常仅用于控制视觉状态(希望如此)。

Maintain a consistent nomenclature throughout different components. All actions related to a visual state can be moved to a mixin.

在不同组件之间保持一致的命名法。 与视觉状态有关的所有动作都可以移至混合。

/* UIStateMixin */
disable() {  set(this, ‘disabled’, true);
return this;},
enable() {  set(this, 'disabled', false');
return this;},

Each method is only responsible for toggling a particular variable and returns the current context for chaining, like:

每个方法仅负责切换特定变量,并返回用于链接的当前上下文,例如:

button  .disable()  .showLoadingIndicator();

This approach can be extended. It can accept different contexts and control external variables instead of using internal ones. For example:

这种方法可以扩展。 它可以接受不同的上下文并控制外部变量,而不是使用内部变量。 例如:

_getCurrentDisabledAttr() {  return (isPresent(get(this, 'disabled')))    ? 'disabled'            /*  External parameter  */    : 'isDisabled';         /*  Internal variable   */},
enable(context) {  set(context || this, this._getCurrentDisabledAttr(), false);
return this;}

抽象基础功能 (Abstracting base functionalities)

Every component contains certain routines. These routines must be performed regardless of the component’s purpose . For example, verifying a callback before triggering it.

每个组件都包含某些例程。 无论组件的用途如何,都必须执行这些例程。 例如,在触发回调之前先对其进行验证。

These default methods can be also moved to their own mixins, like so:

这些默认方法也可以移至其自己的mixins,如下所示:

/* BaseComponentMixin */
_isCallbackValid(callbackName) {  const callback = get(this, callbackName);    return !!(isPresent(callback) && typeof callback === 'function');},
_handleCallback(callback, params) {  if (!this._isCallbackValid(callback)) {    throw new Error(/* message */);  }
this.sendAction(callback, params);},

And then included in the components.

然后包含在组件中。

/* Component */
onClick(params) {  this._handleCallback('onClick', params);}

This keeps your base architecture consistent. It also allows expansion and even integration with third-party software. But please, don’t be a philosophizing abstracter.

这使您的基本架构保持一致。 它还允许扩展甚至与第三方软件集成。 但是请不要成为一个哲学化的抽象者

组成组件 (Composing components)

Avoid rewriting functionality as much as you can. Specialization can be achieved. It can be done through composition and grouping. As well as tweaking smaller components together in order to create new components.

尽可能避免重写功能。 可以实现专业化。 可以通过组合和分组来完成。 以及将较小的组件调整在一起以创建新组件。

For example:

例如:

Base components: Button, dropdown, input.
Dropdown button => button + dropdownAutocomplete => input + dropdownSelect => input (readonly) + dropdown

This way, each component has its own duties. Each handles its own state and parameters while the wrapper component handles its specific logic.

这样,每个组件都有自己的职责。 每个组件都处理自己的状态和参数,而包装器组件则处理其特定的逻辑。

Separation of concerns at its finest.

最好的关注点分离。

分散关注点 (Splitting concerns)

When composing more complex components, there is the possibility of splitting concerns. You can split concerns between different parts of a component

组成更复杂的组件时,可能会分散关注点。 您可以在组件的不同部分之间分配关注点

Let’s say we’re building a select component.

假设我们正在构建一个选择组件。

{{form-select binding=productId items=items}}
items = [  { description: 'Product #1', value: 1 },  { description: 'Product #2', value: 2 }]

Internally, we have a simple input component and a drop-down.

在内部,我们有一个简单的输入组件和一个下拉菜单。

{{form-input binding=_description}}
{{ui-dropdown items=items onSelect=(action 'selectItem')}}

Our main task is to present the description to the user, but it has no meaning to our application — the value does.

我们的主要任务是向用户提供描述,但对我们的应用程序没有意义-价值确实存在。

When selecting an option, you split the object, sending the description down to our input through an internal variable while pushing the value up to the controller, updating the bound variable.

选择一个选项时,您将拆分对象,将描述通过内部变量发送到我们的输入,同时将值上推到控制器,更新绑定变量。

This concept can be applied to components where the bound value must be transformed, like a number, autocomplete or select field. Datepickers can also implement this behavior. They can unmask the date before updating the bound variable while presenting the masked value to the user.

此概念可以应用于必须转换绑定值的组件,例如数字,自动完成或选择字段。 日期选择器也可以实现此行为。 他们可以在更新绑定变量之前取消屏蔽日期,同时向用户显示已屏蔽的值。

The risks get higher as the transformations increase in complexity. By excessive logic or having to support events — so think it through before implementing this approach.

随着转换复杂性的增加,风险也越来越高。 由于逻辑过多或必须支持事件,因此在实施此方法之前请仔细考虑。

预设与新组件 (Presets vs New Components)

Sometimes it is necessary to optimize components and services in order to facilitate development. These are delivered in the form of presets or new components.

有时有必要优化组件和服务以促进开发。 这些以预设或新组件的形式提供。

Presets are parameters. When informed, they set predefined values on the component, simplifying its declaration. However, new components are usually more specialized versions of base components.

预设是参数。 收到通知后,他们在组件上设置了预定义的值,从而简化了其声明。 但是,新组件通常是基础组件的更专业版本。

The hard part is to know when to implement presets or create new components. I use the following guidelines when making this decision:

困难的部分是要知道何时实施预设或创建新组件。 做出此决定时,我使用以下准则:

When to create presets

何时创建预设

1 — Repetitive usage patterns

1-重复使用模式

There are times when a particular component is reused in various places with the same parameters. In these cases, I like to favor presets over new components, especially when the base component has an excessive number of parameters.

有时,某个特定的组件会在不同的地方以相同的参数重复使用。 在这些情况下,相对于新组件,我更喜欢预设,尤其是当基础组件的参数过多时。

/* Regular implementation */
{{form-autocomplete    binding=productId    url="products"            /*   URL to be fetched         */    labelAttr="description"   /*   Attribute used as label   */    valueAttr="id"            /*   Attribute used as value   */    apiAttr="product"         /*   Param sent on request     */}}
/* Presets */
{{form-autocomplete    preset="product"    binding=productId}}

The values from the preset are only set if the parameter has not been informed, keeping its flexibility.

仅在未通知参数的情况下才设置预设值,以保持其灵活性。

/* Naive implementation of the presets module */
const presets = {  product: {    url: ‘products’,    labelAttr: ‘description’,    valueAttr: ‘id’,    apiAttr: ‘product’,  }, }
const attrs = presets[get(this, ‘preset’)];
Object.keys(attrs).forEach((prop) => {  if (!get(this, prop)) {    set(this, prop, attrs[prop]);  }});

This approach reduces the knowledge required to customize your component. Concurrently, it is facilitating maintenance by allowing you to update default values in a single place.

这种方法减少了自定义组件所需的知识。 同时,它允许您在一个地方更新默认值,从而简化了维护工作。

2 — Base component is too complex

2-基本组件太复杂

When the base component you’d use to create a more specific component accepts too many parameters. Thus, creating it would generate some problems. For example:

当您用于创建更具体组件的基本组件接受太多参数时。 因此,创建它会产生一些问题。 例如:

  • You’d have to inject most — if not all — the parameters from the new component to the base component. As more and more components derive from it, any updates on the base component would reflect a huge amount of changes. Thus, leading to higher bug incidence.您必须将大多数(如果不是全部)参数从新组件注入到基础组件。 随着越来越多的组件派生自该组件,基本组件上的任何更新都将反映出大量更改。 因此,导致更高的错误发生率。
  • As more components are created, the harder it gets to document and memorize the different nuances. This is especially true for new developers.随着创建的组件越多,记录和记住不同细微差别的难度就越大。 对于新开发人员而言尤其如此。

When to create new components

何时创建新组件

1 — Extending functionality

1-扩展功能

It is viable to create a new component when extending functionality from a simpler component. It helps you prevent leaking component-specific logic to another component. This is particularly useful while implementing extra behavior.

从更简单的组件扩展功能时,可以创建一个新组件。 它有助于防止特定于组件的逻辑泄漏到另一个组件。 这在执行额外行为时特别有用。

/* Declaration */
{{ui-button-dropdown items=items}}
/* Under the hood */
{{#ui-button onClick=(action 'toggleDropdown')}}  {{label}} <i class="fa fa-chevron-down"></i>  {{/ui-button}}
{{#if isExpanded}}  {{ui-dropdown items=items}}{{/if}}

The example above utilizes the button component. This extends its layout to support a fixed icon while including a drop-down component and its visibility state.

上面的示例利用了按钮组件。 这扩展了其布局以支持固定图标,同时包括一个下拉组件及其可见性状态。

2 — Decorating parameters

2 —装饰参数

There is another possible reason for creating new components. This is when it is necessary to control parameter availability or decorate default values.

创建新组件还有另一个可能的原因。 这是在有必要控制参数可用性或修饰默认值时。

/* Declaration */
{{form-datepicker onFocus=(action 'doSomething')}}
/* Under the hood */
{{form-input onFocus=(action '_onFocus')}}
_onFocus() {  $(this.element)    .find('input')    .select();                 /* Select field value on focus */
this._handleCallback('onFocus'); /* Triggers param callback */}

In this example, it was provided to the component a function meant to be called when the field is focused.

在此示例中,向组件提供了一个功能,该功能旨在在聚焦字段时调用。

Internally, instead of passing the callback straight to the base component, it passes an internal function. This performs a particular task (selecting the field value) and then calls the callback provided.

在内部,它传递内部函数,而不是直接将回调传递给基本组件。 这将执行特定任务(选择字段值),然后调用提供的回调。

It is not redirecting all the parameters accepted by the base input component. This helps to control the scope of certain functionalities. It also avoids unnecessary validations.

它不会重定向基本输入组件接受的所有参数。 这有助于控制某些功能的范围。 它还避免了不必要的验证。

In my case, the onBlur event was replaced by another event — onChange. This triggers when the user either fills the field or selects a date on the calendar.

就我而言,onBlur事件被另一个事件onChange代替。 当用户填写字段或在日历上选择日期时,将触发此操作。

结论 (Conclusion)

When building your components, consider your side as well as whoever is using that component in their daily life. This way, everyone wins.

在构建组件时,请考虑您的身边以及在日常生活中使用该组件的任何人。 这样,每个人都赢了。

The best result comes from everyone in the group doing what is best for himself and the group — John Nash

最好的结果来自团队中的每个人都为自己和团队做出了最大的贡献— John Nash

Also, don’t be ashamed to ask for feedback. You’ll always find something that can be worked on.

另外,不要以羞于寻求反馈。 您将始终找到可以解决的问题。

To sharpen your software engineering skills even more, I recommend following Eric Elliott’s series “Composing Software”. It’s awesome!

为了进一步提高您的软件工程技能,我建议遵循Eric Elliott的系列“ 撰写软件”。 这很棒!

Well, I hope you enjoyed the article. Please take these concepts, turn into your own ideas and share it with us!

好吧,希望您喜欢这篇文章。 请采纳这些概念,转变成您自己的想法,并与我们分享!

Also, feel free to reach out to me on twitter @gcolombo_! I’d love to hear your opinion and even work together.

另外,请随时通过Twitter @gcolombo_与我联系 ! 我很想听听您的意见,甚至共同努力。

Thanks!

谢谢!

翻译自: https://www.freecodecamp.org/news/tips-tricks-for-creating-reusable-ui-components-2b1452147bda/

ctk 组件创建 ui

ctk 组件创建 ui_创建可重复使用的UI组件的提示和技巧相关推荐

  1. 创建, 发布自己的 Vue UI 组件库

    创建, 发布自己的 Vue UI 组件库 前言 在使用 Vue 进行日常开发时, 我们经常会用到一些开源的 UI 库, 如: Element-UI_, _Vuetify 等. 只需一行命令, 即可方便 ...

  2. 组件cdn引入_高性能 React UI组件库SHINEOUT

    今天给大家推荐一款超不错的React.js桌面端UI组件库Shineout. shineout 基于react.js构建的轻量级UI组件库.包含表单元素.数据表.通知提示.布局选项.导航等多种组件. ...

  3. Vue UI 组件库(移动端常用 UI 组件库,PC 端常用 UI 组件库,Element UI基本使用,Element UI按需引入)

    文章目录 Vue UI 组件库 7.1 移动端常用 UI 组件库 7.2 PC 端常用 UI 组件库 7.3 Element UI基本使用 7.4 Element UI按需引入 Vue UI 组件库 ...

  4. Unity自定义UI组件(十一) 雷达图、属性图

    前言 借用梦想世界宠物属性图 想必大家都在游戏中见过属性图用于展示多种属性的数值,可以较为直观的对比某种属性的缺陷或者是哪种属性有优势.在三维可视化领域也会遇到类似的属性对比,用属性图来展示最为合适. ...

  5. Vue2基础、组件化编程、脚手架、Vuex、Vue路由、UI组件库

    尚硅谷张天禹老师讲课 学习视频 1.Vue简介 Vue2中文官网 1.1 Vue 介绍 一套用于构建用户界面的渐进式JavaScript框架 构建用户界面:把数据通过某种办法变成用户界面 渐进式:可以 ...

  6. 优秀的Vue UI组件库

    Vue 是一个轻巧.高性能.可组件化的MVVM库,API简洁明了,上手快.从Vue推出以来,得到众多Web开发者的认可.在公司的Web前端项目开发中,多个项目采用基于Vue的UI组件框架开发,并投入正 ...

  7. VUE常用UI组件插件及框架-vue前端UI框架收集

    UI组件及框架 element - 饿了么出品的Vue2的web UI工具套件 mint-ui - Vue 2的移动UI元素 iview - 基于 Vuejs 的开源 UI 组件库 Keen-UI - ...

  8. 使用html编写SVG圆图形,CSS vs. SVG:任意图形UI组件

    在这个系列教程的前两篇文章中,我们比较了CSS和SVG创建图形文本.复选框和单选按钮的技术与效果.在这篇文章中将介绍CSS和SVG对比技术中的另一个技术--创建图形UI组件的技术. 具体地说,我们将要 ...

  9. Unity自定义UI组件(七)渐变工具、渐变色图片、渐变遮罩

    欢迎阅读Unity自定义UI组件(七)渐变工具.渐变色图片.渐变遮罩 前言 在Unity中UGUI只为我们提供了最为基础的Image和RawImage两种可展示图片的组件,但是这两种组件要展示一些特殊 ...

最新文章

  1. Linux软件安装小结
  2. VTK:PolyData之ExtractCellsUsingPoints
  3. 使用摄像头录像后,需要删除系统缓存数据!
  4. Windows 中的环境变量 Path 与 XXXX_HOME 的区别
  5. 微软 MVP 福利大赏
  6. 原生语言开发web版万岳网校源码 v2.2.0
  7. 【白皮书分享】2021国有企业数字化转型指数与方法路径白皮书.pdf(附下载链接)...
  8. pytorch按照索引取batch中的数
  9. 【比赛】智源-知乎联合发布大规模用户邀请回答数据集,同步开启10万元竞赛...
  10. python遗传算法解决分配问题
  11. js检查ie低版本浏览器,并跳转更新页面
  12. 上海车展6大热门车型自动驾驶配置梳理
  13. 数据库——设计实体联系图
  14. C# 插入或删除word分页符
  15. 新手上路千万记住学会用灯
  16. 实例图解:摄影构图大实话
  17. eclipse背景怎么改颜色
  18. Ubuntu18.04配置搭建基于Gazebo的虚拟仿真平台(Px4):无人机(UAV)、无人车等模拟实验平台
  19. 一个嵌入式牛人学习经历
  20. 如何使用eclipse开发单片机程序

热门文章

  1. 自定义异常 java
  2. 04 能够使用String类常用方法操纵字符串 0214
  3. 草稿 复选框绑定数据 1204
  4. 前端开发 认识css 体验变色的效果 0228
  5. 数据结构与算法-时间复杂度
  6. django-数据的插入-利用pymysql
  7. Laravel初探——安装
  8. RPC的负载均衡策略
  9. dubbo 相关面试题 有用
  10. Sql server 数据转到 Mysql 数据库