封装html ui 控件,聊聊前端 UI 组件:组件设计

本文首发于欧雷流。由于我会时不时对文章进行补充、修正和润色,为了保证所看到的是最新版本,请阅读原文。

在本系列文章《聊聊前端 UI 组件:组件体系》中初步说明了 UI 组件的架构设计,本文将在此基础上进一步展开说说那篇文章中一笔带过的部分,并阐述在设计一个 UI 组件时应该注意的点有哪些。

目录结构

在《聊聊前端 UI 组件:组件体系》中列出的目录结构的基础上做了些许调整——component

├── demo # 示例相关文件

│ └── ...

├── test # 测试相关文件

│ └── ...

├── style # 样式相关文件

│ ├── _functions.scss # Sass 函数(可选)

│ ├── _properties.scss # CSS 自定义属性(必需),风格组件的一部分,供外部运行时自定义主题风格

│ ├── _variables.scss # Sass 变量(必需),风格组件的一部分,供外部编辑时/编译时自定义主题风格

│ ├── _mixins.scss # Sass 混入(可选)

│ └── _rules.scss # CSS 规则(必需),视觉组件,具有约束结构的作用

├── typing # 类型相关文件

│ ├── custom-properties.ts # CSS 自定义属性配置项(必需),用于运行时生成 CSS 自定义属性

│ ├── aliases.ts # 类型别名(可选)

│ ├── interfaces.ts # 结构组件接口(必需)

│ └── index.ts # 类型统一导出

├── HeadlessComponent.ts # 无头组件,UI 组件与结构无关的逻辑

├── Component.vue # 结构组件,受生成 HTML 的 JS 库/框架的源码、平台限定的视图结构描述语言影响

├── index.ts # 模块统一导出

├── changelog.md # 组件变更记录

├── readme.md # 组件说明文档

├── metadata.yml

└── package.json

命名约定

HTML & CSS class

在基于组件开发(Component-based Development),即大家所说的「组件化」,在 web 前端领域普及之前,流行过一种神奇的 class 命名方式,可以说是一种方法论了——原子类(atomic classes)。

估计一入行就是 React、Vue 横行的前端,压根儿就没听过更没见过「原子类」是个什么东西——

.w-100 { width: 100px; }

.w-150 { width: 150px; }

.h-100 { height: 100px; }

.h-150 { height: 150px; }

.m-10 { margin: 10px; }

.m-20 { margin: 20px; }

.mt-10 { margin-top: 10px; }

.ml-15 { margin-left: 15px; }

.bgc-red { background-color: red; }

.bgc-greed { background-color: green; }

.c-fff { color: #fff; }

.c-000 { color: #000; }

.f-l { float: left; }

.f-r { float: right; }

Atomic classes

看到了吧,这种方法论强调的就是尽可能将 CSS 的每个属性和值的组合拆成 class,命名方式也基本是「属性名 + 属性值」的形式,并且属性名和属性值是否进行「简写」以及中间有没有 -、_ 等分隔符就看编写的人的素养和心情了。

原子类的「优点」是,它把 class 拆分到足够细,很好很「原子」;原子化带来的特点就是可组合性很强,这样任何页面都可以通过原子类的有机组合去实现,只有想不到,没有做不到!哪天设计师说要把按钮距离左边的 15 像素改为 10 像素——没问题!把 的 .ml-15 换成 .ml-10 就好!小菜一碟!

为什么上面说的「优点」是加了引号的?我就想知道,原子类除了写的时候字符数可能会稍微少些,跟写内联样式(inline style)有什么区别?有更语义化吗?可读性有变更好吗?人脑负担有降低吗?中、大型项目维护起来更方便吗?

随着基于组件开发在 web 前端领域的普及,原子类的身影逐渐消失;但最近因为某个 CSS 框架人气走高的原因,原子类再度死灰复燃……

那么,原子类或者说样式原子化是错的吗?不是,都是时臣的错!啊,不!都是 utility-first 思想的错!

class 应该是语义化的,尤其是在基于组件开发时,让在视图结构中一眼看到 class 后,就知道它是个什么东西,而不是它长什么样。

另外,基于组件开发的特点之一就是封装,对外屏蔽内部细节;而 utility-first 思想恰恰是暴露细节,这与基于组件开发的理念「三观不合」。

在基于组件开发的体系下,class 理应是 component-first,即应用 CSS 组件(CSS component),那些 utility class 作为辅助存在。也就是说,当 CSS 组件自带样式与实际需求有些许不符时,利用 utility class 进行「微调」,而不是在外部重写 CSS 组件的样式——这也是一种组合方式。

比如,按钮 CSS 组件本身是不会在水平方向撑满容器的,但设计师想让它占满一行——

.Button {

display: inline-block;

text-align: center;

}

.u-block {

display: block !important;

}

CSS component

CSS 组件在本系列文章所阐述的 UI 组件体系中,叫做「视觉组件」,class 的命名遵循 BEM 的变体——SUIT CSS 命名约定。

SUIT CSS 是 Normalize.css 的作者 Nicolas Gallagher 于 2013 年左右时创立,虽然现在已经处于基本不维护的状态了,但它基于组件开发的思想仍发挥着余热。

SUIT CSS 命名约定我从 2014 年用到现在,并且会继续用下去。本系列文章 CSS 相关的示例代码中 class 的命名皆遵循此命名约定。在基于组件开发的体系下,强烈建议 class 命名遵循 SUIT CSS 命名约定——/* 组件 */

.ComponentName {}

/* 组件修饰符 */

.ComponentName--modifierName {}

/* 组件后代 */

.ComponentName-descendentName {}

/* 组件状态 */

.ComponentName.is-stateOfComponent {}

/* 辅助工具 */

.u-utilityName {}

组件基类 .ComponentName 及其后代 .ComponentName-descendentName 很好理解,它们天然具有层级关系,共同描述了一个 UI 组件的结构——

文章标题

章节标题

章节段落

一些其他信息

文章标题

章节标题

章节段落

而组件修饰符 .ComponentName--modifierName 和组件状态 .ComponentName.is-stateOfComponent 有时就不能很好地区分何时该用哪个了。就拿按钮 CSS 组件来说,它的颜色、是否可用与尺寸,哪个该用修饰符?哪个算是状态?

我给出一个比较简单的判断标准:如果是 UI 组件的特性,即不会因为什么条件而改变的,用修饰符;倘若会因某个条件满足与否而变化,那就是状态——

新增

批量删除

应该注意的是,组件修饰符和组件状态都是直接加在 UI 组件的根节点上的,也就是要跟在组件基类的后面,不能用于组件后代上。假如一个组件后代需要程序化地改变它本身的样式,要用辅助工具类而不是状态类。当一个组件后代的结构、功能等变得复杂时,要将其封装成一个新的组件。

Sass 变量与 CSS 自定义属性

在本系列文章所阐述的 UI 组件体系中,Sass 变量和 CSS 自定义属性合称为「风格组件」,它们负责主题风格的定制,是与设计体系(Design System)的结合点。其中,Sass 变量是在编辑时/编译时,CSS 自定义属性则是在运行时。

在这里,Sass 变量与 CSS 自定义属性的命名方式比较类似,它们大概都是 -[-descendent-name|-modifier-name][-state]-(variable-name|property-name) 的形式。

由于我在基于本系列文章所阐述的思想做一套叫做「Petals」的半成品 UI 组件,因此之后的示例代码中涉及到的 部分基本都会用 petals。

Sass 变量是以 $__petals 或 $petals 开头,与组件名之间用 -- 连接,前者是内部使用(私有)的,上层开发者无需关心,后者是供外部在编辑时/编译时定制用;CSS 自定义属性则用 --petals 开头,以 - 与组件名相连——/* 实际形式:--(variable-name|property-name) */

$__petals--button-font-size: --petals-button-font-size;

$__petals--button-line-height: --petals-button-line-height;

/* 实际形式:----(variable-name|property-name) */

$petals--button-primary-focus-color: var($__petals--primary-active-color, $petals--primary-active-color) !default;

$petals--button-primary-focus-bg: var($__petals--primary-active-bg, $petals--primary-active-bg) !default;

上文所说的 CSS 组件,即视觉组件,它是将样式进行封装,对外屏蔽细节;而风格组件相反,通过将视觉组件所用到的 CSS 属性值动态化的方式达到样式可定制化的目的,这就变得像 utility-first 的原子类一样暴露了样式细节。

但与 utility-first 的 CSS 框架不同的是,风格组件只给进行主题风格定制的人带来了心智负担,对其他的上层开发者并无影响。

业务无关

本系列文章主要讨论的对象是业务无关的 UI 组件,在单说「UI 组件」或「组件」时也是指这个;而业务相关的 UI 组件,在本系列文章所阐述的 UI 组件体系中叫做「部件」。根据 UI 组件的通用性,可分为「通用组件」和「专用组件」。「通用组件」是能够满足大部分常规场景的 UI 组件,它们的集合通常会作为「组件库」整体打包发布为一个软件包;「专用组件」是为了解决某些特殊场景需求而存在的,像数据网格、各种编辑器等,这类一般都是单独发包。

上面提到的「通用组件」和「专用组件」都是业务无关的 UI 组件。

UI 组件是什么?可以认为它是一个返回视图结构的函数,而 UI 组件的属性(prop)和事件(event)就是这个「函数」的参数。属性是 UI 组件的外部与其内部进行主动通信的数据,事件则是进行被动通信的回调函数。

一个封装得好的函数,它的参数应尽可能少,要想明白每个参数的语义,且必须确实有其存在的意义——UI 组件的属性和事件的设计也该如此。

在设计 UI 组件的属性时,先思考下要加的这个属性是不是属于这个 UI 组件本身的特性?若不是,那要加的属性的值所对应的 UI 组件的特性是什么?如果这两个问题都没有得到答案,那么这个属性可以不用加了。

UI 组件的属性只应与其本身的特性有关,与业务意义无关——自身特性是自然特性,业务意义是附加特性。

比如,一个按钮组件通常会有「主要」、「次要」和「危险」这几种多少与业务沾边的语义,那么组件的属性该如何设计来满足这种需求呢?

Ant Design 和 Element 的做法是将其作为 type 属性的值或独立成一个属性——Ant Design 中的主要按钮

Ant Design 中的次要(默认)按钮

Ant Design 中的危险按钮

Element 中的主要按钮

Element 中的次要(默认)按钮

Element 中的危险按钮

按照上面说的 UI 组件属性设计原则来看,「主要」、「次要」和「危险」作用到按钮组件上的表现主要是颜色发生了变化,所以应该去用表示按钮的自然特性「颜色」的 color 属性来满足同样的需求——主要按钮

次要(默认)按钮

危险按钮

红色按钮

黄色按钮

蓝色按钮

若 UI 组件的某组特性是二元对立的,如「禁用」与「启用」,则选择默认不生效的那个作为属性,且属性值是布尔型,默认值为 false。

还是拿按钮组件来举例:如果默认是「禁用」,那就设计一个代表「启用」的 enabled 属性,其默认值是 false,只要组件在被使用时传入了 enabled,就变成了「启用」状态;反之亦然。

另外,UI 组件的属性值尽可能是简单数据类型,也就是数字、字符串等。

业务相关

业务相关的 UI 组件,即上文所说的「部件」,因其关注点与业务无关的 UI 组件不同,所以在设计时所遵守的原则和考虑的事情也不尽相同,甚至会大相径庭。一般来说,会用到上下文与依赖注入等技术。

由于业务相关的 UI 组件不是本系列文章主要讨论的对象,在此就不展开说了。

总结

前几天在朋友圈立了个 flag——

140e7b59a05ef90fa8b680d6826bb311.png

本文就是该 flag 的「引子」。

欢迎关注微信公众号【Coding as Hobby】(微信中搜「coding-as-hobby」)以及时阅读最新的技术文章~ ;-)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/555122.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

live555推流rtsp_Hi3518 RTSP推流

1、openssl编译下载地址:http://distfiles.macports.org/openssl/解压后进入源码根路径执行./config no-asm no-async --prefix/home/chenyc/project/hi3518e/Hi3518E_SDK_V1.0.3.0/armlib/openssl --cross-compile-prefixarm-hisiv300-linux-#打开生成的makefile 删除-m64 在…

怎么两边同时取ln_男生“两边铲光”发型out了?试试这4款吧,剪完清爽又帅气...

发型对于男生来说是特别重要的!女生可以通过化妆来让自己变得更完美,而男生想要改变自己的形象,是不敢轻易化妆的,只有通过改变自己的发型,才能更好地展现自己的魅力。现下男生最流行的发型,莫过于“两边铲…

ionic 修改组件默认样式_开源Magpie:组件库详解

开源项目专题系列(八)1.开源项目名称:magpie_fly2.github地址:https://github.com/wuba/magpie_fly3.简介:magpie_fly 是58集体出品组件库,统一管理日常开发中的基础组件及高阶组件,并提供了相对友好的方式介绍组件的具…

口袋之旅html5超强账号,口袋之旅特攻排行榜 强大的绝对能力

历史上是在金银版分了精灵的特攻物攻,在宝石版分了技能的特攻物攻,让很多精灵和技能得以重生。口袋之旅采用的是第二世代的精灵加第三世代的技能分类,于是特攻手也成为了一个需要挑选的部分,本文继续为你缩小挑选范围。特攻种族值…

使用ftl生成word

背景:根据word模板下载word。word里面需要填充数据,格式是固定的。首先在word中给数据起个变量名称 需要更换的数据改成${变量名!},必须是英文的,加感叹号是为了防止null,如果数据是null,文档下载下来后会直…

什么叫做项目孵化_蓝莓孵化营12进5争夺战,项目人绽放自我不留遗憾

国内首档互联网职业竞技励志节目《蓝莓孵化营》,今晚22点在浙江卫视播出第十一期。本期节目中,第三事业群的12组项目人将为最终的5张终极考核入场券展开争夺。这一次,他们比拼的是以“2020”为主题的短视频,每一组项目人都拼尽了自…

七台河计算机网络工程专业,网络工程本科专业介绍

网络工程本科专业介绍网络工程专业是教育部第二类特色专业,比较热门,竞争力较大,考生报考此专业的时候要慎重。网络工程本科就业前景本专业的就业前景不错,学生可从事各级各类企事业单位的企业办公自动化处理、计算机安装与维护、…

Java实体类不要使用基本类型_为何封装javabean时,成员变量一律都不用基本类型

Java实体类不要使用基本类型 记录一下,在项目中因为基本类型,所产生的bug 包装类:8种基本类型的包装类 应用场景:数据库建立实体映射多用包装类 这两句话是重点:就是建立实体类禁止使用基本数据量类型!…

一开机就提示脱机工作_「华为手机维修自学教程」华为手机的开机触发电路 华为维修技巧...

谈谈华为的开机触发电路华为这段时间的新闻不少,大家应该都有说了解。华为的强大意味着华为手机的维修市场越来越大。从事维修的朋友们你们准备好了吗?今天给大家说一说,华为手机的开机触发电路。修苹果手机的朋友大家都知道,电源…

html怎么保存曲奇,自制曲奇饼能保存多久 这些存放方法你懂吗

来源:站酷作者:Wandzilak虽然市场上的饼干种类很多,而且吃起来也感觉十分香,但是这些食品一般添加了比较多的防腐剂膨松剂,多吃度身体健康不是很好。因此很多人都喜欢自己在家里制作饼干,其中曲奇饼干就是很多人都喜欢制作的饼干之…

SpringBoot 整合mybatis-plus 高级功能及用法详解

springboot 整合mybatis-plus 高级功能及用法详解 学习并使用mybatis-plus的一些高级功能的用法例如&#xff1a; AR模式、 乐观锁 、逻辑删除 、自动填充、数据保护等功能 为了方便演示&#xff0c;咱们还是新建一个全新的项目 引入mp依赖 <dependency><groupId>…

8除以2表示什么意思_八字中劫财,比肩分别表示什么意思

◆◆比劫与其他十神的生克关系◆◆食伤&#xff1a;比劫生食伤财星&#xff1a;比劫克财星官星&#xff1a;官星克比劫印星&#xff1a;印星生比劫◆◆比劫帮身◆◆八字术语&#xff0c;比肩劫财均可助日干之力&#xff0c;如甲见甲(比)、乙(劫)、寅(禄)、卯(刃)之类&#xff0…

江苏省计算机一级考试基础知识,江苏省计算机一级考试大纲及复习指南

江苏省计算机一级考试大纲及复习指南江苏省计算机等级考试大纲(一级)计算机信息技术考试要求(试用)及使用说明1&#xff0e;掌握计算机信息处理与应用的基础知识。2&#xff0e;能比较熟练地使用六个常用的软件(IE、Outlook Express,Word,Excel,PowerPoint,和FrontPage)3掌握Ac…

MyBatis-plus 自动填充MetaObjectHandler不生效问题

背景 在项目中经常遇到一些数据需要自动填充&#xff0c;填充方法都是同一种规则&#xff0c;例如创建时间等。 1 自动填充方法配置 1.1 实体类添加注解 1.2 在handler包下实现元对象处理器接口 import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import o…

html拖拽模态框,可拖拽的谷歌样式纯javascript模态窗口插件

draggable-google-modal是一款可拖拽的谷歌样式纯javascript模态窗口插件。该模态窗口插件使用纯js编写&#xff0c;模态窗口可以任意进行拖动&#xff0c;并且模态窗口可以全屏放大&#xff0c;或左右对齐占据半边屏幕。使用方法使用该模态窗口插件需要引入draggabilly.pkgd.j…

centos7修改网卡顺序_CentOS7网卡名称的修改

生产环境中&#xff0c;托管于机房的服务器经常会进行割接操作&#xff0c;为了能让网卡更容易让运维人员和机房识别&#xff0c;避免因为弄错网线或找错网卡导致业务中断&#xff0c;在服务器上架前就应该对所有网卡按照 eth0、eth1 的方式来命名&#xff0c;并按照网卡的物理…

new Gson().toJson日期转特定格式日期实体

Google的Gson功能非常强大&#xff01; 格式化日期我们只需要这样创建就好了 Student stu new Student();stu.setName("张三");stu.setBirthDay(new Date());如果张三的生日是日期型的话&#xff0c;直接实体转json的话&#xff0c; new Gson().toJson(stu);日期…

计算机考试internet应用好考吗,2015年职称计算机考试XP好考还是internet应用好考...

WindowsXP和Internet的相似考点Windows XP模块和Internet模块是两个常考模块&#xff0c;2010年7月以来&#xff0c;国家职考题库发生了较大的变动&#xff0c;之前我们已经从题目上总结出了两个的模块的类似点&#xff0c;现在从大纲上总结两个模块的相似考点。一&#xff1a;…

博途变量类型_PLC数据类型(UDT)

UDT类型是一种由多个不同数据类型元素组成的数据结构&#xff0c;元素可以是基本数据类型&#xff0c;也可以是STRUCT、数组等复杂数据类型以及其它UDT等。UDT类型嵌套UDT类型的深度限制为 8 级。UDT类型可以在DB、OB/FC/FB接口区处使用。从TIA 博途 V13SP1 开始&#xff0c;S7…

Mybatis-Plus条件参数查询手册

【引言】 使用mybatis-plus框架的基础上&#xff0c;直接使用其中的条件参数进行查询还是很方便的。但每次使用到像大于、不等于这样一些不常用条件时&#xff0c;都需要现查&#xff0c;所以记录在这篇博客里&#xff0c;当作一个自己的查询手册。 【手册】 查询方式说明se…