首页

如何设计一个超长长长长长的复杂表单?

涛涛

导语

你平时填写过的最复杂的表单是什么?调查问卷还是文档信息录入?如果一个表单字段内容巨多,结构多变,填写耗时耗力,那你将如何设计你的表单,使之体验更佳?

面临的问题

1. 业务复杂,功能较多;

不知道大家是否看过法律合同之类的文件,多则好几箩筐,少也有厚厚一叠,类似的文档如果进行线上结构化,势必要同样要花费巨大的人力去填写表单,完成基础信息的录入工作,同时,由于录入的时间不确定,流程不明确等问题,也制约着表单的填写。

2. 流程较长,操作繁琐;

多个不同表单之间的互有关联又相互区别,填写的时候需要来回查看以确认信息,查阅和填写相互并行,操作繁琐。

3. 字段较多,关联项较多;

几乎每一个字段都有对应的关联项,每个单选字段的不同项决定不同的内容,同时,由于字段数量,层级划分不明确,会使填写的人失去定位,产生迷惑。

解决的方案

1. 内容分组,分步填写;

根据业务内容分级,合理运用颜色、间距、字体大小、卡片层级等进行信息分级

如何设计一个超长长长长长的复杂表单?

2. 实时保存,避免数据丢失,提供草稿功能,避免任务中断;

如何设计一个超长长长长长的复杂表单?

3. 字段分组,示意结构,联动项隐喻;

如何设计一个超长长长长长的复杂表单?

4. 信息自动带入,节省时间;

一般表单是与某项功能挂钩的,信息会在多个入口录入,因此在填写长表单的时候,如果能从系统中自动获取到数据,就可以自动为其填充,可根据业务场景,判断是否让其修改和更新。

如何设计一个超长长长长长的复杂表单?

5. 提供二次编辑功能,防止信息输入有误;

一般的长表单在涉及非审批流的时候,可以让其无限二次编辑,如果是处于审批流,则需要根据业务场景限制其编辑次数或者限定其编辑规则(草稿可编辑,一旦提交则不可编辑)。

6. 提供多人协作编辑功能;

如果一个长表单,需要多个不同的业务域的人来填写,那么需要协同编辑,并实时显示编辑的人员信息,同时,为了避免信息丢失和编辑错乱,在同一个表单下,同一时间应该限制只允许一个人进行编辑,等其提交完后,可允许其他人进行编辑。

如何设计一个超长长长长长的复杂表单?

7. 实时检验;

前端实时校验字段输入规则,后端统一校验信息交换规则。

比如对于数字输入框的校验、电话号码的校验、身份证号的校验,应该在前端实时完成,在鼠标离开焦点区域或定位到下一个字段的时候,提示其填写有误,这样做的目的是减少后续修改的次数,在长表单下,统一提示其填写错误会是一场灾难。

如何设计一个超长长长长长的复杂表单?

在点击保存并填写下一步或点击提交信息的时候,就需要跟后端交换数据,验证录入的信息,如果不匹配,则提示错误,并从上至下定位至相应的错误字段。

8. 做好填写引导功能;

要通过多种方式,引导表单的填写,

在开始填写之前,简要说明该表单的业务目标,大概需要花费的时间等;

如何设计一个超长长长长长的复杂表单?

开始填写后,关于每个字段的特殊说明,都需要标注出来,重要的要显示在页面上,不重要的就收起在注释符号中;

如何设计一个超长长长长长的复杂表单?

填写的过程中,切记不要到最后才告诉用户哪里出错了,重要的信息一定要提示到位,否则一旦出错,前功尽弃;

如何设计一个超长长长长长的复杂表单?

填写完成后,引导其下一步的操作,或者返回至列表。

如何设计一个超长长长长长的复杂表单?

9. 详情页也需要注意信息分级

表单填写完毕后的产出物就是详情页,详情页是需要浏览的,因此在设计详情页的时候,应该本着让用户浏览方便的原则去设计,需要注意以下几个点:

结构清晰。是指不要将内容一股脑的全堆在页面上,要做好信息的分类,同时,注意规划页面的层级。

设置快捷导航。如果一个表单是长且复杂的,那么其对应的详情页也会变得复杂和冗长,因此在页面的右侧或者顶部设置合理的快捷导航是很有必要的。

如何设计一个超长长长长长的复杂表单?

最后:小细节,大体验

1. 提供快速返回顶部的按钮;

快速返回顶部按钮的使用要注意场景,如果你的页面比较长,且没有分组浏览的导航,那就需要设置快速返回顶部的按钮,但是在存在分组浏览导航和顶部悬浮标签的情况下,不建议使用快速返回顶部的按钮,因为在填写表单的时候,使用快速置顶的场景比较少。

2. 提供分组模块收起展开功能;

当一个模块混杂着各种信息的时候,单纯的模块分组已经无法处理它的复杂度了,因此需要收起高频且信息量大的模块,可以合理的减少页面的复杂度。

如何设计一个超长长长长长的复杂表单?

3. 步骤提供信息填写完成度提示;

步骤条可以单纯的作为步骤指示器使用,也可以作为一个表单完成度的提示区域。

如何设计一个超长长长长长的复杂表单?

4. 重要说明性文字尽量显示而非收起;

在填写大量字段的表单时,阅读表单内容和填写表单同样耗时耗力,如果我们将所有的提示信息隐藏在提示符中,一般情况下,用户不会去查看,但是如果去挨个查看提示信息,则会多花费一个步骤去点击或者悬停来查看提示信息,浪费了大量的时间,因此如果涉及到重要的提示信息,请直接展示在字段的后面,不要隐藏起来。

如何设计一个超长长长长长的复杂表单?

5. 产品内组件应该规范统一;

在后台产品上,关于组件的规范统一,想必是人尽皆知的设计原则,无论是各类平台型设计组件,还是各个公司自造的设计组件,保持统一和规范对产品设计有着重要的作用,在这里不赘述组件应该怎样规范统一,因为无论是Ant Design还是其他设计语言,都有详尽的关于组件的定义方法,我在这里讲述一个产品设计更高层面或者更深层面的原因:

组件的规范统一并不仅仅是为了省时省力,而是为了使用户在使用的过程中达到认知上的统一和行为上的统一,在进行高频次的操作后,界面的流程或者组件样式已大致在用户脑海中形成固定印象,因此在操作相同类的流程时,用户会有更多的掌控感,试想一下,如果你在操作人事相关的流程后,去填写绩效部分的内容时,发现一个迥异的界面或者弹窗,你肯定觉得这是不是哪里出错了,甚至会怀疑这是否是同一个系统,目前大多数公司的管理系统经过多次缝缝补补,内部的跳转逻辑已经异常感人,界面风格也大放异彩,但是使用起来却无从下手,深感迷茫。

因此大到界面样式,小到间距大小,产品设计的规范和统一应该是最基础又不可缺少的原则。

6. 庞大的信息录入,表单内部要分步填写,外部可拆分成不同的表单分别填写;

对付复杂的表单,你需要解决的主要问题并不是填写方式或者页面设计,而是信息分级和结构拆分,解决了这个问题,基本上就解决了业务问题,其余部分就跟我们常用的表单一致。

将复杂度降低并不意味着减少页面的信息,而是通过设计师合理的信息划分,降低视觉上的复杂度和流程上的复杂度,这样才会达到当前场景下的「最佳解决方案」。

如何设计一个超长长长长长的复杂表单?

如何设计一个超长长长长长的复杂表单?

结语

随着互联网信息化的深入发展,复杂是避免不了的,我知道大家都推崇简洁的设计,但那只是对视觉和样式的定义,而非对信息的定义,我们所处的世界是复杂的,行业更是复杂的,信息的复杂度与日俱增,想要处理复杂的信息,就需要从复杂中寻求规律,这规律与业务息息相关,


文章来源:优设    作者:

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

如何让你的「按钮设计」上档次?

涛涛

按钮在界面设计中,属于最基础的元素部分组成,按钮设计的精致,整个页面的品质也会上升不少的档次。今天给大家分享这篇文章,主要讲解在设计按钮时我们应该考虑哪些因素,包括视觉上,有哪些万能的方法及公式,能够正确的制定按钮的设计标准,来提升整个设计的系统性。

如何让你的「按钮设计」上档次?送你这份万能公式!

按钮有哪些作用?

在设计按钮之前,需要先理解按钮起到的代表含义。什么地方该加按钮,什么地方不加按钮,在系统化设计思路中需要非常有讲究。通常按钮在页面,主要起到以下三点作用:

1. 某一类型的功能操作

这种比较常见,如一些控件形态的按钮,比如加减、折叠、展开,下拉等。这类按钮会起到一些功能形态的作用,常用于交互场景。所以在这类按钮设计中,应当弱化按钮形式,重点强调功能,突出主体信息。

如何让你的「按钮设计」上档次?送你这份万能公式!

2. 下一步的明确指引

当页面内容信息过多后,用户容易失去信息焦点,从而忘记下一步操作。信息种类越多,用户权衡的时间就会越久,用户选择罢手及跳出的几率也会越大。所以这个时候,在合适的地方增添按钮,能够很好的引导用户进行下一步操作,提升整体操作的成功率。其次从体验层面,也一定程度能起到页面动线的引导作用,比如下方的一组卡片,在增添了按钮后行动点很明确,非常有点击欲望~

如何让你的「按钮设计」上档次?送你这份万能公式!

3. 固定习惯,明确心理预期

当用户知悉某个按钮能指向某个操作,或者获取某类信息后,长期以往用户就会形成使用这个按钮的习惯,这样对提升复访及固定心智是非常有效果。

所以如果你认为你负责的产品或者是内容,能持续为用户带来价值,那么在页面的关键节点,不如将按钮设计的更醒目。这样用户下次再看到这个按钮时,固定习惯会引导他持续的点击。

如何让你的「按钮设计」上档次?送你这份万能公式!

按钮有哪些类型?

这里我不以按钮的长相来区分按钮的类型,如汉堡按钮或者别的什么的,意义不大。我主要还是想通过以按钮的功能区分,来划分类型,这样大家理解起来更为清晰。

1. 功能性质按钮

这类按钮见到的最多,我们常用的APP里,大量都充斥了这类按钮,这类按钮会起到重点的功能交互,帮助用户得到TA想要的信息。其次样式上面,其实圆形的点击欲,会更强一些,看起来也更利于点击。而方型的按钮,则显得更为正式、严谨。

如何让你的「按钮设计」上档次?送你这份万能公式!

公式:如果是圆形按钮,圆角的半径=高度的50%比较合适,而如果是方按钮,边角的小圆角半径控制在15%以下比较合适,我个人喜好用10%。

如何让你的「按钮设计」上档次?送你这份万能公式!

2. 聚焦大按钮

这类按钮通常见于一些核心页面的强指引,比如登录、注册、提交表单、或者是保存,等对页面全局进行操作的一些按钮。需要注意的是,这类按钮只适合对页面全局进行操作,而且页面中大按钮的数量不宜超过2个,信息尽量需要保持聚焦。

如何让你的「按钮设计」上档次?送你这份万能公式!

公式:基于@2x,这类大按钮的高度≥72px是比较合适的,通常的尺寸有 80px、88px、96px,大家可以根据产品面向的人群来定高度,如果页面面向的人群较为广泛,我建议采用 88px 或者是 96px 的这种大号版本,毕竟操作起来更为方便。

如何让你的「按钮设计」上档次?送你这份万能公式!

3. 吸底按钮

这类按钮的优先级,在整个页面属于最高,页面的所有信息,都将聚焦在这个按钮中。由于按钮是吸底的,所以会一直浮在页面上,不受页面篇幅影响控制。

如何让你的「按钮设计」上档次?送你这份万能公式!

需要注意的是,吸底按钮一定是页面最重要的功能,或者是整个页面的下一步指引,比如淘宝的立即购买,或者是饿了么、美团的立即下单,又或者是常见的充值界面。

如何让你的「按钮设计」上档次?送你这份万能公式!

公式:基于@2x,吸底的高度≥80px是比较合适,常见的尺寸有88px、100px、112px ,按钮的大小可以根据内容来定,建议高度保持在72px以上比较合适。这里需要注意的是,吸底的按钮,需要产出两套设计稿,一套为常规稿,一套为iPhoneX的适配稿。iPhoneX底部控件的区域高度为68px,所以iPhoneX设计稿的吸底高度=常规设计稿吸底高度+68px

如何让你的「按钮设计」上档次?送你这份万能公式!

按钮有哪些状态?

另外在设计按钮的时候,也别忘了补充按钮的多个状态的设计稿。常见的状态,有以下四种:

1. Normal-正常态

这个为按钮的正常显示态,就是正常页面中的显示效果。

如何让你的「按钮设计」上档次?送你这份万能公式!

2. Hover-悬浮态

这个为按钮的悬浮态,一般只会出现在使用鼠标的时候。当鼠标指针停留在按钮时,按钮发出的特殊反馈,则为悬浮态。这类形式在移动端交互中无作用,所以移动界面设计中不需要考虑这个状态。

如何让你的「按钮设计」上档次?送你这份万能公式!

公式:正常情况 Hover 态增加 10% 黑色就可以,原理如下

如何让你的「按钮设计」上档次?送你这份万能公式!

3. Pressed-点击态

这个为按钮的按压态,就是按钮在被点击或者是按压后的效果。

如何让你的「按钮设计」上档次?送你这份万能公式!

公式:在APP设计中,点击后的效果我们设一个标准值让开发实现就好了。常用的值有按钮减少20%的透明度,或者增添20%的暗度,这两个都可以。通常我建议在亮色上的按钮,使用暗度叠加(增添20%的黑色),在暗色上的按钮,则使用透明度减少(透明度改为80%),实现效果原理参考 Hover 态那张配图

4. Disable-禁用态

当信息未填充完整,或者是某类条件未到,按钮会出现不可点击的状态,处于禁用形式,这个时候,按钮就会呈现禁用态。这个禁用态无论是web还是app,很多场景都会用到,所以建议设定一套标准的设计规范,避免重复定义这个效果。

如何让你的「按钮设计」上档次?送你这份万能公式!

公式:禁用态尺寸及大小不变,仅使用色值做区分。建议使用灰色或者是不透明色,常用的禁用色有#CCC或者#999,需要尽可能把样式做弱,避免用户做无效的点击。

按钮的风格及尺寸

在目前移动互联网设计中,虽然按钮的种类很多,但风格变的逐渐统一,更多都是色值及细节上的差异。从大的风格来看,按钮还是分为这这几种类型:扁平化、轻拟物、重拟物及游戏按钮。

1. 扁平化按钮

这类按钮我们设计用的最多,信息简洁,操作方便,形式追随功能。这里也给大家分享一下我在设计扁平化按钮的一些经验,比如高度宽度,以及阴影的色值。

公式:按钮高度,这个通常是文字字号的2.4倍然后取4的倍数整数,比如字号是24,那么按钮的高度=57.6,离4倍数最近的是56,所以高度=56,圆角=10%的高度,取整后是6px。

如何让你的「按钮设计」上档次?送你这份万能公式!

另外如果觉得不合适,也可以单位往8递增或者是递减即可,例如 56、64、72、80、88 px

按钮宽度:如果不是那种全局按钮,通常按钮的宽度=最多容纳字数的宽度+按钮高度,就好啦。还是以上面那个例子为例,按钮高度=56,文字宽度=96,那么按钮的宽度=56+96=152

如何让你的「按钮设计」上档次?送你这份万能公式!

2. 轻拟物按钮

这类按钮近几年变的非常流行,甚至QQ、淘宝,都开始大面积使用,因为这类按钮在保持信息简洁的同时,仍然有较强的点击欲,视觉上面也能够增添页面的品质感。

如何让你的「按钮设计」上档次?送你这份万能公式!

公式:渐变方向,建议采用水平渐变,重色在右侧,轻色在左侧更为合适。阴影色值我之前就写过,不知道大家还记得么,阴影颜色=按钮颜色的 Alpha50%,x=0,y=按钮高度的20%,模糊值=按钮高度的50%,扩展=按钮高度的 -15%,高级又简单,完美!

如果觉得这个弥散阴影太大的同学,也可以自己手动简单调整下,不碍事。(这个公式仅适用于Sketch,用PS的同学,也可以按照这个逻辑自行研究一下)

如何让你的「按钮设计」上档次?送你这份万能公式!

另外说一句,实际上这个阴影公式并没有什么很多的依据,大多数都是我个人原创总结出来的,简单好用。比如下面的这些按钮的样式,用了公式后的效果大家可以自行感受~

如何让你的「按钮设计」上档次?送你这份万能公式!

 

3. 重拟物及游戏按钮

在一些营销页面中,按钮的样式通常需要做的比较游戏化。游戏化的按钮,大部分会采取游戏场景中的元素,再采用拟物的手法,来进行打造。

通常游戏化的按钮,需要重点几个部分组成,学过素描的同学应该会知道,立体的物体,通常会有几大特征,分别为高光,亮部,暗部,投影及反光。那么如果我们需要绘制一个在营销或者游戏场景中使用的按钮,只需要保证这个按钮有高光,亮部,暗部,投影及反光的这些特征,然后饱满一点就,立马就可以出效果啦。

如何让你的「按钮设计」上档次?送你这份万能公式!

当然,我举的这几个例子都是最基础版本,如果你想做的更丰富一些,那也是没问题的,这个可以case by case 来定。

这个没有太多的公式可以总结,更多的是看设计师的基础美术水平啦~~

如何让你的「按钮设计」上档次?送你这份万能公式!

新拟态按钮

在写这篇文章的时候,突然刷到了一套新拟态的控件设计风格,有种眼前一亮的感觉。虽然这套设计视觉上很有层次很好看,不过感觉短时间之内,比较难大面积推广,因为开发实现起来还是会比较耗费成本。

如何让你的「按钮设计」上档次?送你这份万能公式!

我把源文件保存下来了,对这个感兴趣或者好奇这种效果如何实现的同学,可以下载源文件研究~~ sketch、psd、Figma 格式都有。

文章来源:优设    作者:UX小学

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

Vue.js教程-目录

前端达人

简介

  • 本目录作为Vue教程的首页,所以会持续更新。
  • 如果某篇章节中有错误的地方,希望大家能够指出来,我会更正,私信和评论里说都可以,不懂的地方也可以说,如果我也不会那就请教一下大佬们吧,毕竟我对前端的东西也不是特别了解,多多包涵!嘿嘿。

章节列表

章节名称 地址
Vue.js教程-安装和HelloWorld https://coderhqf.blog.csdn.net/article/details/107574556
Vue.js教程-Vue项目的目录结构和.vue文件的构成 https://coderhqf.blog.csdn.net/article/details/107621070
Vue.js教程-Vue基本指令 https://coderhqf.blog.csdn.net/article/details/107677588
Vue.js教程-组件化开发 https://coderhqf.blog.csdn.net/article/details/107783664

Vue简介

  • Vue官网
  • Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。
  • Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
  • Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。

Vue特点

  • 易用:在有HTML CSS JavaScript的基础上,快速上手。
  • 灵活:简单小巧的核心,渐进式技术栈,足以应付任何规模的应用。
  • 性能:20kb min+gzip 运行大小、超快虚拟 DOM 、最省心的优化。

Vue中数据观测的实现

  • Vue.js利用了ES5的Object.defineProperty方法,直接将原生数据对象的属性改造为getter和setter,在这两个函数内部实现依赖的收集和触发,而且完美支持嵌套的对象结构。对于数组,则通过包裹数组的可变方法(比如push)来监听数组的变化。这使得操作Vue.js的数据和操作原生对象几乎没有差别[注:在添加/删除属性,或是修改数组特定位置元素时,需要调用特定的函数,如obj.$add(key, value)才能触发更新。这是受ES5的语言特性所限。],数据操作的逻辑更为清晰流畅,和第三方数据同步方案的整合也更为方便。

Vue项目打包

  • 在构建大型应用时,推荐使用Webpack+vue-loader这个组合以使针对组件的开发更。
  • 在后面的章节中会细说怎么打包并部署到服务器上,也会讲怎么白嫖阿里云(学生版),好像有大佬写过这个文章,大家搜一下也行,最重要的还是开发。

Vue的组件化开发

  • Vue最主要的是组件化开发,因为是单页面,也就是在一个页面中渲染出多个页面的效果,这个特点能够让非常多的组件在不同的项目中重复使用。
  • Vue中的组件基于Web components进行了上层功能的实现,例如数据绑定、动画系统等。

Vue与后端的数据交互:axios

  • 传统的一般都用Ajax,但如果请求有先后关系的话就容易产生回调地狱,套娃套的吧。
  • Vue2之后就推荐使用axios了,等写到前后端交互的时候再讲这个就行。

相关说明

  • Vue参考了AngularJS、KnockoutJS、Ractive.js、Rivets.js,可以是把他们的缺点都优化成了自己的优点,参考过程中不但去其糟粕,还加入了自己的特性,但目前也只有国内用Vue的比较多,毕竟社区小,资源少,但以后应该会是潮流,因为开发快好上手。
  • 其实Vue相对来说是非常好上手的,因为它只专注于视图层。如果只是要用的话,其实对原理也不用太纠结,但既然要全栈,何不贯彻到底,我也是在学习中,如果想正规学习的话,我比较推荐coderwhy-王红君老师的课,他讲的挺好的,有些原理讲的也是很清楚的,渠道嘛,B站大学、腾讯课堂啥的都有,还有他的微博,大家可以去网上找。
  • 再强调一遍,如果发现不对的地方请联系我,因为不想误人子弟,毕竟这是自己的总结,也不想以后自己还用着错误的东西,嘿嘿嘿。。。
  • Vue作为现在国内最潮流的前端框架,也逐渐成为后端开发人员需要学的新知识了,我看现在很多后端岗位的面试里都会提到这个前端框架,所以大家学一下是不亏的。
  • 在CSDN杂志中有一篇文章:Vue.js:轻量的前端组件化方案,如果大家有兴趣就看看吧。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_45062103/article/details/107763788

手机appUI界面设计赏析(五)

前端达人

与传统PC桌面不同,手机屏幕的尺寸更加小巧操作,方式也已触控为主,APP界面设计不但要保证APP功能的完整性和合理性,又要保证APP的功能性和实用性,在保证其拥有流畅的操作感受的同时,满足人们的审美需求。

接下来为大家介绍几款手机appui界面设计

点击查看原图


   --手机appUI设计--

点击查看原图

 --手机appUI设计--

点击查看原图

 --手机appUI设计--

微信图片_20200805221704.png

 --手机appUI设计--

微信图片_20200805221707.jpg

 --手机appUI设计--

微信图片_20200805221712.jpg

 --手机appUI设计--

微信图片_20200805221759.png

 --手机appUI设计--

微信图片_20200805221803.jpg

 --手机appUI设计--

微信图片_20200805221808.png

 --手机appUI设计--

微信图片_20200805221813.jpg

 --手机appUI设计--

微信图片_20200805221823.jpg

 --手机appUI设计--

(以上图片均来源于网络)



  蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服



  更多精彩文章:

       手机appUI界面设计赏析(一)

       手机appUI界面设计赏析(二)

       手机appUI界面设计赏析(三)

       手机appUI界面设计赏析(四)




这样设计光影轻拟物,想不脱颖而出都难!

涛涛

还记得2019年4月上映的复仇者联盟4么,漫威电影宇宙的第三阶段结束了,电影很精彩,但最令人震撼的是先导版的电影海报!就是那个「五彩斑斓」的黑~

这样设计光影轻拟物,想不脱颖而出都难!

从设计上看,海报的设计师是把光运用到极限了,通过逆光和环境塑造出了酷+神秘的视觉感受。光是一切视觉表现的基础,是构图和传递调性的关键,也是视觉表现重要的组成部分。所以今天就和大家聊聊啥样的光是一个牛X的光以及如何塑造一个合格的光影?

光影的基本原理

常见形式1-聚光

这样设计光影轻拟物,想不脱颖而出都难!

这样设计光影轻拟物,想不脱颖而出都难!

△ 图片来源:小米米家台灯1S

聚光是最常见光,也是在设计中用到最多的光,通常在塑造一个物体的时候就会用的到。

这样设计光影轻拟物,想不脱颖而出都难!

因为聚光的原因,场景更像个舞台,凸显「主角」的存在。具体的原理可以根据下图去理解。

这样设计光影轻拟物,想不脱颖而出都难!

常见形式2-自然光

这样设计光影轻拟物,想不脱颖而出都难!

自然光其实就是阳光,理论上讲其实光源是太阳也是聚光,但由于光源太过于庞大,无法真正的聚焦,所以就把这种光当成一种泛光源就好。在产品设计中也会经常看到类似的光源出现,比如行为召唤按钮:

这样设计光影轻拟物,想不脱颖而出都难!

因为不需要强有力的表现和氛围的营造,所以通常产品设计中更需要自然光来作为核心光源,通过泛光源去统一控制产品的光影体系就好(发布的 Mac OS – big Sur 的整体光源同样是自然光,下文会讲到)。

常见形式3-逆光

这样设计光影轻拟物,想不脱颖而出都难!

坦诚的讲逆光也是聚光的一种,只不过由于角度特殊,呈现的视觉效果也非常不一样,所以就单独把逆光拿出来说一说。当画面需要逆光来营造氛围的时候,只需要在固有色上加上黑色蒙板和边缘的高光就可以大概塑造出一个处于逆光的物体了。

这样设计光影轻拟物,想不脱颖而出都难!

小米是典型的逆光氛围营造高手,但万变不离其宗,依旧可以从海报里看到相同的方法。

这样设计光影轻拟物,想不脱颖而出都难!

△ 图片来源:小米传播物料

光影的塑造(光影层级)

通常现实中的光源并非那么理想,光线的复杂超出肉眼所见。所以我们在绘制的过程需要注意到,可以适当的抽象。举个例子,自然光是普照的,所以我们抽象为四个小光源平均分布,依次打到物体上:

这样设计光影轻拟物,想不脱颖而出都难!

在他们叠加的部分可以清晰的看到,1是最重的,2其次,3再次。按照这个办法就可以获得光影的层级关系,在绘制轻拟态的图标或者运营活动中更加细腻。

这样设计光影轻拟物,想不脱颖而出都难!

体积塑造+色彩对光影的影响(反光/对比光)

这样设计光影轻拟物,想不脱颖而出都难!

△ 图片来源:09UI设计工作室-陌陌直播礼物设计

所有的光影其实都是帮助主体塑造体积感,一个合格的立体图形必须具备:高光/过度色/明暗交界线和反光这四个基本属性。

这样设计光影轻拟物,想不脱颖而出都难!

然后需要一点超现实主义的手法,把太阳光过滤下,从「赤橙黄绿青蓝紫」的色调里提取跟主体和谐的颜色(通常是补色),营造出介于真实与玄幻之间的美妙效果hiahia~

这样设计光影轻拟物,想不脱颖而出都难!

然后再在投影上加一点点色彩倾向,一个完美的黑八就出现啦~按照这种方法,你可以试着去尝试更多的物体/场景。(下图是笔者作品「插着红旗的地球」hiahia)

这样设计光影轻拟物,想不脱颖而出都难!

光影/材质与产品设计中的层级关系

这样设计光影轻拟物,想不脱颖而出都难!

影响主体的除了光影之外就是材质了,近年来的三大巨头apple/Microsoft/Google的设计都在材质上下足了功夫,苹果的毛玻璃,微软的亚克力和谷歌的「纸」。

从趋势上看,材质的引入对产品中拉开层级关系上有巨大意义,以往的设计仅仅是通过光影和焦距来拉开关系,这两个维度在少量的叠加界面中还能有效果,但到了复杂的多窗口互压互叠里就不是那么奏效了,所以铁子们要善于运用材质区分产品显示的优先级。

这样设计光影轻拟物,想不脱颖而出都难!

图标与插图的光影使用技巧

这样设计光影轻拟物,想不脱颖而出都难!

△ 图片来源:Eric Hoffman – Big Sur Mac Icons

这样设计光影轻拟物,想不脱颖而出都难!

△ 图片来源:JIAJIE – WeSing Live gift

图标好坏除了造型之外最重要的就是质感了,通常图标也就是4种形式(如下图),类似苹果的系统图标和抖音直播间礼物的图标都是最后一种形式。

这样设计光影轻拟物,想不脱颖而出都难!

但如果仅仅是这样就太水了,既然都说了是干货预警,那就要拿出哥们看家的本领~此图是大家关注公号后就会收到的推图,主体就是一个POI的图标加上微信的对话框和代表干货的小星星营造出的氛围。

这样设计光影轻拟物,想不脱颖而出都难!

刨析下这个图,三个发光体和底下的投影,通过上文的讲解依次绘制完成~

这样设计光影轻拟物,想不脱颖而出都难!

之后就到了amazing的时刻了,打开photoshop找到「滤镜-模糊画廊-场景模糊」设置几个key-point,调试模糊值和透明度/亮度,最终完成对光影的塑造。

这样设计光影轻拟物,想不脱颖而出都难!

借助环境塑造光影

空气中的灰尘相信大家都不陌生,这种情况多数是一束光影从窗户里射入后,在光的折射下把平时看不到的灰尘统统照了个遍。

这样设计光影轻拟物,想不脱颖而出都难!

如果你是mac用户一定熟知keynote里的动画效果「轰然坠落」,这个效果是在模拟物体振动后弹开周围灰尘,非常震撼。在PPT的设计中你也可以同样借助光和雾来营造你想要的效果,下图是我在做工作总结的时候为了凸显Q4工作采用的办法。

这样设计光影轻拟物,想不脱颖而出都难!

小结一下

光影轻拟物在产品设计中的应用面还是很广的,比如:图标、数据可视化、插图等等。而在大量扁平设计时代适量使用会显得很出彩,当然再好的教程也比不上大家多动手试试练练,所以铁汁们行动起来咯~

文章来源:优设    作者:Nana的设计锦囊

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

JavaScript中的for循环

seo达人

JavaScript 语言中的 for 循环用于多次执行代码块,它是 JavaScript 中最常用的一个循环工具,还可用于数组的遍历循环等。


我们为什么要使用 for 循环呢?打个比方,例如我们想要控制台输出1到1000之间的所有数字,如果单写输出语句,要写1000句代码,但是如果使用 for 循环,几句代码就能实现。总之,使用 for 循环能够让我们写代码更方便快捷(当然啦,否则要它干嘛)。


for 循环语法

语法如下所示:


for(变量初始化; 条件表达式; 变量更新) {

   // 条件表达式为true时执行的语句块

}

变量初始化,表示代码块开始前执行。

条件表达式,定义运行循环代码块的条件。

变量更新,在循环代码块每次被执行之后再执行。

示例:

例如我们在一个HTML文件中,编写如下代码,实现计算1到100的总和:


<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<title>JS_侠课岛(9xkd.com)</title>

</head>

<body>

<script>

 var result = 0;

 for(var i = 1; i <= 100; i++) {

   result = result + i;

 }

 alert(result);

</script>

</body>  

</html>

在浏览器中打开这个文件,会弹出一个弹出层,弹出层中显示的是1到100的总和:



上述代码中,我们声明了一个变量 result 并给它赋值为 0,表示初始的总和为 0 。


然后在 for 循环中三个语句:


变量初始化 i = 1,表示从 1 开始计算。

条件表达式 i <= 100,表示只要 i 小于等于 100 循环就会一直执行,当 i 大于 100 循环会停止。

变量更新 i++,之前我们学运算符的时候学过,这是递增运算符 ++,表示为其操作数增加 1。

此时我们可以一点点来看这个 for 循环:


第一次循环: result = 0 + 1   // 此时result值为0,  i的值为1

第二次循环: result = 1 + 2   // 此时result值为0+1,i的值为2

第三次循环: result = 3 + 3   // 此时result值为1+2,i的值为3

第四次循环: result = 6 + 4   // 此时result值为3+3,i的值为4

第五次循环: result = 10 + 5  // 此时result值为6+4,i的值为5

...

我们只需要搞清楚 for 循环中的执行原理,不需要手动来计算求和,只要写好代码,执行代码后计算机会很快会告诉我们1到 100 的总和。


再补充一下,上述代码中result = result + i,我们也可以写成 result += i,这是我们之前学过的加赋值运算符,还记得吗?


示例:

再来看一个例子,例如我们可以使用 for 循环来实现数组遍历,首先定义一个数组 lst:


var lst = ["a", "b", "c", "d", "e"];

在写 for 循环时,首先就是要搞清楚小括号里面的三个语句,因为我们可以通过数组中元素的下标索引来获取元素的值,而数组的索引又是从 0 开始,所以变量初始化可以设置为i = 0。第二个条件表达式,因为数组中最后一个索引为 lst.length - 1,所以只要小于等于 lst.length - 1,循环就会一直执行。而i <= lst.length - 1 就相当于 i<lst.length。第三个变量更新,当循环每循环一次,索引值就加一,所以为 i++。


所以循环可以像下面这样写:


for(i = 0; i<lst.length; i++){

   console.log(lst[i]);  // 输出数组中的元素值,从索引为0的值开始输出,每次加1,一直到lst.length-1

}

输出:


a

b

c

d

e

其实遍历数组还有一种更好的方法,就是使用 for...in 循环语句来遍历数组。


for...in 循环

for...in 循环主要用于遍历数组或对象属性,对数组或对象的属性进行循环操作。for...in 循环中的代码每执行一次,就会对数组的元素或者对象的属性进行一次操作。


语法如下:


for (变量 in 对象) {

   // 代码块

}

for 循环括号内的变量是用来指定变量,指定的可以是数组对象或者是对象属性。


示例:

使用 for...in 循环遍历我们定义好的 lst 数组:


var lst = ["a", "b", "c", "d", "e"];

for(var l in lst){

   console.log(lst[l]);

}

输出:


a

b

c

d

e

除了数组,for...in 循环还可以遍历对象,例如我们遍历 侠侠 的个人基本信息:


var object = {

   姓名:'侠侠',

   年龄:'22',

   性别:'男',

   出生日期:'1997-08-05',

   职业:'程序员',

   特长:'跳舞'

}


for(var i in object) {

   console.log(i + ":" + object[i]);

}

输出:


姓名: 侠侠

年龄: 22

性别: 男

出生日期: 1997-08-05

职业:程序员

特长:跳舞

动手小练习

请自定义一个长度为7的数组,然后通过 for 循环将数组中的元素遍历出来。

求和:1~100的奇数和。

求和:1~100的偶数和。

使用对象定义一个人的个人信息(包括姓名、性别、年龄、出生日期、兴趣爱好、职业、特长等),然后使用 for...in 循环将这些信息遍历输出。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

封装element-ui表格

seo达人

表格需求

一般管理系统对表格会有以下需求


可以分页(需要有分页条)

可以多选(表格带复选框)

顶部需要加一些操作按钮(新增,删除等等)

表格每行行尾有操作按钮

表格行可以编辑

如下图为一个示例表格




如果我们直接使用element-ui提供的组件的话,那么开发一个这样的表格就需要使用到以下内容


需要使用表格的插槽功能,开发每一行的按钮

需要通过样式调整顶部按钮,表格,分页条的布局样式

需要监听分页的事件然后去刷新表格数据

顶部按钮或操作按钮如果需要获取表格数据,需要调用表格提供的api

对于有行编辑的需求,还需要通过插槽去渲染行编辑的内容,同时要控制行编辑的开关

不仅仅开发表格比较麻烦,而且还要考虑团队协作,如果每个人实现表格的方式存在差别,那么可能后期的维护成本也会变得很高。那怎么办呢?


项目安装

安装插件

在使用element-ui的项目中,可以通过以下命令进行安装


npm install vue-elementui-table -S

在项目中使用

在main.js中添加以下代码


import ZjTable from 'vue-element-table'


Vue.use(ZjTable)

然后即可像下文中的使用方式进行使用


表格配置

为了满足团队快速开发的需要,小编对上面提出来的需求进行了封装,然后使用的时候,开发人员只需要配置一些JSON便可以完成以上功能的开发。


基础配置

一个基础的表格包含了数据和列信息,那么如何用封装的表格去配置呢?


<template>

 <zj-table

   :columns="columns"

   :data="data"

   :pagination="false"

 />

</template>

<script>

export default {

 data() {

   return {

     // 表格的列信息, 数组每一项代表一个字段,可以使用element 列属性的所有属性,以下仅为示例

     columns: Object.freeze([

       {

         // 表头显示的文字

         label: '姓名',

         // 对应数据里面的字段

         prop: 'name'

       },

       {

         label: '性别',

         prop: 'sex',

         // 格式化表格,与element-ui 的表格属性相同

         formatter(row, column, cellValue) {

           return cellValue === 1 ? '男' : '女'

         }

       },

       {

         label: '年龄',

         prop: 'age'

       }

     ]),

     data: [

       {

         name: '子君',

         sex: 1,

         age: 18

       }

     ]

   }

 }

}

</script>

通过上面的配置,就可以完成一个基础表格的开发,完整代码见 https://github.com/snowzijun/vue-element-table/blob/master/example/views/demo/base.vue,效果如下图所示




表格默认会显示复选框,也可以通过配置selectable属性来关闭掉


添加分页

简单的表格用封装之后的或未封装的开发工作量区别并不大,我们继续为表格添加上分页


<template>

   <!--

   current-page.sync 表示页码, 添加上 .sync 在页码发生变化时自动同步页码

   page-size.sync 每页条数

   total  总条数

   height="auto" 配置height:auto, 表格高度会根据内容自动调整,如果不指定,表格将保持充满父容器,同时表头会固定,不跟随滚动条滚动

   @page-change 无论pageSize currentPage 哪一个变化,都会触发这个事件

 -->

 <zj-table

   v-loading="loading"

   :columns="columns"

   :data="data"

   :current-page.sync="currentPage"

   :page-size.sync="pageSize"

   :total="total"

   height="auto"

   @page-change="$_handlePageChange"

 />

</template>

<script>

export default {

 data() {

   return {

     columns: Object.freeze([

       // 列字段与上例一样,此处省略

     ]),

     data: [],

     // 当前页码

     currentPage: 1,

     // 每页条数

     pageSize: 10,

     // 总条数

     total: 0,

     // 是否显示loading

     loading: false

   }

 },

 created() {

   this.loadData()

 },

 methods: {

   // 加载表格数据

   loadData() {

     this.loading = true

     setTimeout(() => {

       // 假设总条数是40条

       this.total = 40

       const { currentPage, pageSize } = this

       // 模拟数据请求获取数据

       this.data = new Array(pageSize).fill({}).map((item, index) => {

         return {

           name: `子君${currentPage + (index + 1) * 10}`,

           sex: Math.random() > 0.5 ? 1 : 0,

           age: Math.floor(Math.random() * 100)

         }

       })

       this.loading = false

     }, 1000)

   },

   $_handlePageChange() {

     // 因为上面设置属性指定了.sync,所以这两个属性会自动变化

     console.log(this.pageSize, this.currentPage)

     // 分页发生变化,重新请求数据

     this.loadData()

   }

 }

}

</script>

完整代码请参考 https://github.com/snowzijun/vue-element-table/blob/master/example/views/demo/pagination.vue


通过封装,表格将自带分页功能,通过上面代码,实现效果如下所示,是不是变得简单了一些。接下来我们继续给表格添加按钮




添加顶部按钮

表格上面可能会有新增,删除等等按钮,怎么办呢,接下来我们继续通过配置去添加按钮


<template>

 <zj-table

   :buttons="buttons"

 />

</template>

<script>

export default {

 data() {

   return {

     buttons: Object.freeze([

       {

         // id 必须有而且是在当前按钮数组里面是唯一的

         id: 'add',

         text: '新增',

         type: 'primary',

         icon: 'el-icon-circle-plus',

         click: this.$_handleAdd

       },

       {

         id: 'delete',

         text: '删除',

         // rows 是表格选中的行,如果没有选中行,则禁用删除按钮, disabled可以是一个boolean值或者函数

         disabled: rows => !rows.length,

         click: this.$_handleRemove

       },

       {

         id: 'auth',

         text: '这个按钮根据权限显示',

         // 可以通过返回 true/false来控制按钮是否显示

         before: (/** rows */) => {

           return true

         }

       },

       // 可以配置下拉按钮哦

       {

         id: 'dropdown',

         text: '下拉按钮',

         children: [

           {

             id: 'moveUp',

             text: '上移',

             icon: 'el-icon-arrow-up',

             click: () => {

               console.log('上移')

             }

           },

           {

             id: 'moveDown',

             text: '下移',

             icon: 'el-icon-arrow-down',

             disabled: rows => !rows.length,

             click: () => {

               console.log('下移')

             }

           }

         ]

       }

     ])

   }

 },

 created() {},

 methods: {

   // 新增

   $_handleAdd() {

     this.$alert('点击了新增按钮')

   },

   // 顶部按钮会自动将表格所选的行传出来

   $_handleRemove(rows) {

     const ids = rows.map(({ id }) => id)

     this.$alert(`要删除的行id为${ids.join(',')}`)

   },

   // 关注作者公众号

   $_handleFollowAuthor() {}

 }

}

</script>

表格顶部可以添加普通的按钮,也可以添加下拉按钮,同时还可以通过before来配置按钮是否显示,disabled来配置按钮是否禁用,上面完整代码见 https://github.com/snowzijun/vue-element-table/blob/master/example/views/demo/button.vue


通过上面的代码就可以配置出下面的表格,是不是很简单呢?




表格顶部可以有按钮,行尾也是可以添加按钮的,一起来看看


行操作按钮

一般我们会将一些单行操作的按钮放在行尾,比如编辑,下载等按钮,那如何给行尾配置按钮呢?


<template>

 <zj-table

   :columns="columns"

 />

</template>

<script>

export default {

 data() {

   return {

     columns: Object.freeze([

       {

         // 可以指定列的宽度,与element-ui原生用法一致

         width: 220,

         label: '姓名',

         prop: 'name'

       },

       // 行编辑按钮,在表格末尾出现,自动锁定右侧

       {

         width: 180,

         label: '操作',

         // 通过 actions 指定行尾按钮

         actions: [

           {

             id: 'follow',

             text: '关注作者',

             click: this.$_handleFollowAuthor

           },

           {

             id: 'edit',

             text: '编辑',

             // 可以通过before控制按钮是否显示,比如下面年龄四十岁的才会显示编辑按钮

             before(row) {

               return row.age < 40

             },

             click: this.$_handleEdit

           },

           {

             id: 'delete',

             text: '删除',

             icon: 'el-icon-delete',

             disabled(row) {

               return row.sex === 0

             },

             // 为了拿到this,这里需要用箭头函数

             click: () => {

               this.$alert('女生被禁止删除了')

             }

           }

         ]

       }

     ])

   }

 },

 methods: {

   // 关注作者公众号

   $_handleFollowAuthor() {

           console.log('微信搜索【前端有的玩】,这是对小编最大的支持')

   },

   /**

    * row 这一行的数据

    */

   $_handleEdit(row, column) {

     this.$alert(`点击了姓名为【${row.name}】的行上的按钮`)

   }

 }

}

</script>

行操作按钮会被冻结到表格最右侧,不会跟随滚动条滚动而滚动,上面完整代码见, https://github.com/snowzijun/vue-element-table/blob/master/example/views/demo/button.vue


通过上面的代码就可以完成以下效果




最后再来一起看看行编辑


行编辑

比如上例,我希望点击行尾的编辑按钮的时候,可以直接在行上面编辑用户的姓名与性别,如何配置呢?


<template>

 <zj-table

   ref="table"

   :columns="columns"

   :data="data"

 />

</template>

<script>

export default {

 data() {

   return {

     columns: Object.freeze([

       {

         label: '姓名',

         prop: 'name',

         editable: true,

         field: {

           componentType: 'input',

           rules: [

             {

               required: true,

               message: '请输入姓名'

             }

           ]

         }

       },

       {

         label: '性别',

         prop: 'sex',

         // 格式化表格,与element-ui 的表格属性相同

         formatter(row, column, cellValue) {

           return cellValue === '1' ? '男' : '女'

         },

         editable: true,

         field: {

           componentType: 'select',

           options: [

             {

               label: '男',

               value: '1'

             },

             {

               label: '女',

               value: '0'

             }

           ]

         }

       },

       {

         label: '年龄',

         prop: 'age',

         editable: true,

         field: {

           componentType: 'number'

         }

       },

       {

         label: '操作',

         actions: [

           {

             id: 'edit',

             text: '编辑',

             // 如果当前行启用了编辑,则不显示编辑按钮

             before: row => {

               return !this.editIds.includes(row.id)

             },

             click: this.$_handleEdit

           },

           {

             id: 'save',

             text: '保存',

             // 如果当前行启用了编辑,则显示保存按钮

             before: row => {

               return this.editIds.includes(row.id)

             },

             click: this.$_handleSave

           }

         ]

       }

     ]),

     data: [

       {

         // 行编辑必须指定rowKey字段,默认是id,如果修改为其他字段,需要给表格指定row-key="字段名"

         id: '0',

         name: '子君',

         sex: '1',

         age: 18

       },

       {

         // 行编辑必须指定rowKey字段,默认是id,如果修改为其他字段,需要给表格指定row-key="字段名"

         id: '1',

         name: '子君1',

         sex: '0',

         age: 18

       }

     ],

     editIds: []

   }

 },

 methods: {

   $_handleEdit(row) {

     // 通过调用 startEditRow 可以开启行编辑

     this.$refs.table.startEditRow(row.id)

     // 记录开启了行编辑的id

     this.editIds.push(row.id)

   },

   $_handleSave(row) {

     // 点击保存的时候,通过endEditRow 结束行编辑

     this.$refs.table.endEditRow(row.id, (valid, result, oldRow) => {

       // 如果有表单验证,则valid会返回是否验证成功

       if (valid) {

         console.log('修改之后的数据', result)

         console.log('原始数据', oldRow)

         const index = this.editIds.findIndex(item => item === row.id)

         this.editIds.splice(index, 1)

       } else {

         // 如果校验失败,则返回校验的第一个输入框的异常信息

         console.log(result)

         this.$message.error(result.message)

       }

     })

   }

 }

}

</script>

不需要使用插槽就可以完成行编辑,是不是很开心。上述完整代码见 https://github.com/snowzijun/vue-element-table/blob/master/example/views/demo/row-edit.vue


效果如下图所示:




其他功能

除了上面的功能之外,表格还可以配置其他许多功能,比如


可以指定字段为链接列,需要给列配置link属性

可以通过插槽自定义顶部按钮,行操作按钮,行字段等

可以在按钮区域右侧通过插槽配置其他内容

其他等等

表格开发说明

通过上面的代码示例,我们已经知道了封装之后的表格可以完成哪些事情,接下来一起来看看表格是如何实现的。完整代码见 https://github.com/snowzijun/vue-element-table/tree/master/src/components/zj-table


表格布局

整个表格是通过JSX来封装的,因为JSX使用起来更加灵活。对于我们封装的表格,我们从竖向可以分为三部分,分别是顶部按钮区,中间表格区,底部分页区,如何去实现三个区域的布局呢,核心代码如下


render(h) {

   // 按钮区域

   const toolbar = this.$_renderToolbar(h)

   // 表格区域

   const table = this.$_renderTable(h)

   // 分页区域

   const page = this.$_renderPage(h)


   return (

     <div class="zj-table" style={{ height: this.tableContainerHeight }}>

       {toolbar}

       {table}

       {page}

     </div>

   )

 }

通过三个render函数分别渲染对应区域,然后将三个区域组合在一起。


渲染表格列

通过前文的讲解,我们可以将表格的列分为以下几种


常规列

行编辑列

操作按钮列

插槽列

链接列(文档后续完善)

嵌套列(文档后续完善)

   $_renderColumns(h, columns) {

     // 整体是否排序

     let sortable = this.sortable ? 'custom' : false

     return columns

       .filter(column => {

         const { hidden } = column

         if (hidden !== undefined) {

           if (typeof hidden === 'function') {

             return hidden({

               columns,

               column

             })

           }

           return hidden

         }

         return true

       })

       .map(column => {

         const {

           useSlot = false,

           // 如果存在操作按钮,则actions为非空数组

           actions = [],

           // 是否可编辑列, 对于可编辑列需要动态启用编辑

           editable = false,

           // 是否有嵌套列

           nests,

           // 是否可点击

           link = false

         } = column

         let newSortable = sortable

         if (column.sortable !== undefined) {

           newSortable = column.sortable ? 'custom' : false

         }

         column = {

           ...column,

           sortable: newSortable

         }

         if (nests && nests.length) {

           // 使用嵌套列

           return this.$_renderNestColumn(h, column)

         } else if (editable) {

           // 使用编辑列

           return this.$_renderEditColumn(h, column)

         } else if (useSlot) {

           // 使用插槽列

           return this.$_renderSlotColumn(h, column)

         } else if (actions && actions.length > 0) {

           // 使用操作列

           column.sortable = false

           return this.$_renderActionColumn(h, column)

         } else if (link) {

           // 使用链接列

           return this.$_renderLinkColumn(h, column)

         } else {

           // 使用默认列

           return this.$_renderDefaultColumn(h, column)

         }

       })

   },

行编辑列

当前表格行编辑支持input,select,datepicker,TimeSelect,InputNumber等组件,具体渲染代码如下所示


// 编辑单元格

   $_renderEditCell(h, field) {

     const components = {

       input: Input,

       select: ZjSelect,

       date: DatePicker,

       time: TimeSelect,

       number: InputNumber

     }

     const componentType = field.componentType

     const component = components[componentType]

     if (component) {

       return this.$_renderField(h, field, component)

     } else if (componentType === 'custom') {

       // 如果自定义,可以通过component指定组件

       return this.$_renderField(h, field, field.component)

     }

     return this.$_renderField(h, field, Input)

   },

   $_renderField(h, field, Component) {

     // 编辑行的id字段

     const { rowId, events = {}, nativeEvents = {} } = field


     const getEvents = events => {

       const newEvents = {}

       Object.keys(events).forEach(key => {

         const event = events[key]

         newEvents[key] = (...rest) => {

           const args = [

             ...rest,

             {

               rowId,

               row: this.editRowsData[rowId],

               value: this.editRowsData[rowId][field.prop]

             }

           ]

           return event(...args)

         }

       })

       return newEvents

     }

     // 事件改写

     const newEvents = getEvents(events)

     const newNativeEvents = getEvents(nativeEvents)

     return (

       <Component

         size="small"

         on={newEvents}

         nativeOn={newNativeEvents}

         v-model={this.editRowsData[rowId][field.prop]}

         {...{

           attrs: field,

           props: field

         }}

       />

     )

   }

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务


UI 配色方法

涛涛

配色,设计师的世纪难题。从平面到屏幕,CMYK 到 RGB,墨点到像素,色彩越来越丰富,形式越来越复杂。UI 的发展从拟物的繁琐细节中挣脱出来,却在色彩的展现中放飞了自我。

零售业有个有趣的研究成果 —— 「七秒钟定律」:人们在挑选商品和服务时 ,只需要 7 秒钟就可以确定是否感兴趣,而在这短暂的 7 秒钟内,色彩的作用占到了 67%。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

要在小小的手机屏幕中加入这么多颜色,并保持其中的联系和逻辑,着实不易。如果你还对配色一无所知,完全不知道配色应该怎么入手,那么你需要了解一下,我几年经验总结的配色思路。

拾色器中的黄金三分法

无论我们用 PS、AI,还是 Sketch、XD、Figma,和色彩打交道最多的地方就是拾色器窗口,我们来看看这些案例:

10年经验的资深设计师,总结了这份 UI 配色终极奥义

虽然是不同的应用,但是这个拾色器的用法大同小异,但是,很多新人并没有搞懂拾色器的正确应用逻辑。

很多人知道,UI 的色彩使用 RGB 模式,但是拾色器主要的选色原理遵循的是 HSB 模式的逻辑,也就是色相(H)、饱和度(S)、明度(B)。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

HSB 是色彩科学中对所有颜色属性的理论划分,是种概念上的定义,可以用来解释任何色彩,也就是说可以和 RGB 和 CMYK 相互转化,且 HSB 的选色逻辑更清晰、简洁、干练。

因为一个正确的选色过程,是先确定出色相,然后再在这个色相维度下选出明度和饱和度,所以我们首先要关注色相选择条。

细心的同学应该已经发现了,它们的首尾都是红色,那是因为色相的序列是一个首尾相接的环形模式,所以它实际上就是色环的柱状展示图,应用起来和色环没有实际区别。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

接下来就要说到重点,饱和度和明度选择区,我自己使用的习惯,是将这个选择区通过黄金三分法的方式切割成等比的 9 个区域,然后明确它们在 UI 中的对应情绪和应用场景。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

在过去的大量分析中,互联网产品的主色和重要辅助色都会往右上角聚集,一些次要、不可点的色彩聚集在中上方,而文字背景色则聚集在左侧,无人区则是我们重点避开的对象。

下面我们分析几个案例,看看它们在这个选择区中的色彩分布情况:

10年经验的资深设计师,总结了这份 UI 配色终极奥义

10年经验的资深设计师,总结了这份 UI 配色终极奥义

10年经验的资深设计师,总结了这份 UI 配色终极奥义

大家也可以自己拿一些主流的应用做截图,然后把它们的 UI 元素色彩排列到拾色面板中,就会得到基本一致的结果。牢记这9个区域的场景划分,可以帮助我们非常、安全地完成 UI 配色。

UI配色中的色彩选择

在众多的 UI 设计规范中,色彩部分的介绍,都必然包含三种类型,分别是:

  • 主色:应用的核心色彩,品牌色
  • 辅色:丰富页面视觉和传达效果的次要颜色
  • 中性:没有色相的文字、背景用色

1. 主色的选择

主色是一个应用的最核心的色彩,品牌的象征色,比如想到饿了么的蓝色、微信的绿色、京东的红色、淘宝的橙色。

确定主色,并没有大家想象的那么复杂,它的要点在于——你想让用户感受到哪种情绪,然后通过情绪关联一个大致的色彩范围,再进行微调。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

在今天的互联网产品中,主色的应用选择范围在拾色器区域的右上角,前面已经有解释了。这和平面设计中的用色有非常大的不同。

移动端产品要在一个方寸大的空间中争夺用户的注意力,引起用户的兴趣,那么低饱和清淡的色调是无法实现这个目标的,所以今天主色饱和度越来越,比如我们之前整理的一篇总结:

为什么支付宝要换 Logo 颜色?分析下目前 Logo 的主色趋势

再加上屏幕的 RGB 显示特性,高对比度,高动态范围的特质能给用户提供更好的观感。所以选择主色最安全的做法,就是在确定色相类型后,在右上方区域选出合适的色值。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

2. 辅助色的选择

辅助色是丰富应用中的次要色彩,它会包含一到若干个和主色不同的色彩,除了品牌传达外,具有更强的实用性。

前面我们提到过色环,这里就要派上用场了。我们知道色环是个色彩序列首尾相连的环形模型,它蕴含一个最朴素的原则,即两个颜色在这个环形中角度越大,那么视觉差异性越大,对比越强,比如下图的展示:

10年经验的资深设计师,总结了这份 UI 配色终极奥义

这些配色的模式是不能闭着眼随便挑的,它们仅仅作为一个色彩对比度的判断标准。而真正辅助色的选择,是根据实际场景的功能决定的。

比如通知、提醒、取消用大红色,确认、同意用绿色或者蓝色,收藏、打分、评价用橙黄色。都是已经在用户心智中建立了标准的用色类型,跟着常规方法来做,是没有其它思路的情况下最简单、最安全的辅助色选择方式。

没有标准元素用色的情况下,再考虑应用色环的 「角度原则」,越需要被突出的颜色,可以在色环中离主色越远,越不需要被突出的则越近。

比如下方携程的案例,主色在蓝色的情况下,支付、保险金标签这些需要被重点突出的色彩,使用了主色的互补色, 让我们一眼就能看见并产生强烈的操作欲望。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

3. 中性色的选择

中性色,是页面中文字、背景用到的颜色,它们承担起最基本的层次表现、便于阅读的重任。多数新手觉得中性色无关紧要,实际情况恰恰相反。

主色辅助色决定了界面视觉是否出彩,而中性色的应用直接决定了页面能不能正常使用。如果看过比较多的原型案例,就应该明白,即使只有黑白灰的状态下,我们理解这些页面和进行使用也不会有丝毫的障碍。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

中性色的配置,就是制定一个由深到浅的灰度阶梯,应用在对应权重的元素上,色彩轻重的主要判断依据是 HSB 中的 B(明度) 值。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

中性色虽然指的是无个性,但并不是只能用纯灰色,常见的一种做法,就是为中性色添加适量的蓝色饱和度,提升观看体验(满足RGB的某种特性)。

这种做法,颜色越浅的时候饱和度应用色值就越低,将这个规律在拾色器中进行表现,那么我们就可以得到一个 L 型曲线,我称它为 「中性曲线」。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

掌握对于主色、辅助色、中性色的选择方法,那么对于UI配色的奥义来说,你已经掌握了一半,接下来就要了解更具体的实践思路了。

配色方式的四象限

配色并不是只有色彩的色值本身,大家一直在研究各种色彩心理学和理论,却很少关心它们如何应用,如何配置。

所以,我根据主色和辅助色应用总结了一个配色的四象限表格,再分别看看它们对应的案例:

10年经验的资深设计师,总结了这份 UI 配色终极奥义

1. 主色占比大,色彩丰富度高

主色会作为顶部标题栏或其它重要模块中的背景色,进行大面积应用,加深用户对品牌的认知和辨识度。而产品中又包含了大量功能和服务,需要用丰富的色彩来进行暗示,吸引用户关注。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

10年经验的资深设计师,总结了这份 UI 配色终极奥义

2. 主色占比大,色彩丰富度低

这类配色中,主色的应用占比也大,出现频率高,鲜有其它颜色出现。比较适用于图片内容丰富的题材中,或者是相对正式、品牌感强的应用。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

10年经验的资深设计师,总结了这份 UI 配色终极奥义

3. 主色占比小,色彩丰富度高

这是多数主流应用的趋势,降低主色占比,留出更多的空间给内容模块的展示上,突出自身带有的服务和功能。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

10年经验的资深设计师,总结了这份 UI 配色终极奥义

4. 主色占比小,色彩丰富度低

通常,会应用这种方式是因为产品的服务是相对单一,但也需要用户投入注意力的应用,设计师就会尽力避免给予用户过多的干扰。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

10年经验的资深设计师,总结了这份 UI 配色终极奥义

每次在进行配色的时候,我们都需要对自己要应用哪种配色应用方式做出规划,然后再动手执行。有了这个目标,后面在整个项目的设计中的配色步骤就是水到渠成的事情了。

配色流程演示

在实践前,我们要简单讲讲一个应用或者界面的标准配色的流程了,流程顺序如下:

10年经验的资深设计师,总结了这份 UI 配色终极奥义

具体应该怎么使用这套流程,我们用一个图虫APP改版的案例来做演示,首先从四象限中的第一个主色占比高、色彩丰富度高的类型做起。

1. 配色流程演示

原型是 UI 设计的基本艺能了,在开始具体设计、配色前,搭建页面的框架原型是一个必备的条件,下面,是我们已经准备好的原型案例。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

然后,我们确定以橙色作为应用主色,并在拾色器中进行确认。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

有了主色,就可以对页面进行色彩填充和图片填充了。既然我们主色是占比大的,那么首先可以用到的就是顶部标题栏的背景色了,以及底部 Tabbar 中的选中色,大按钮色等。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

接着,我们开始整理中性色的使用,选择新的颜色来填充文字和背景,清晰的表现模块层级,文字信息的权重。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

最后,就是添加辅助色和其它色彩的元素了,这个步骤建议都是放在最后一步操作。因为色彩越丰富,越难控制,容易让整个画面显得杂乱无序,所以先完成基础搭建,可以更好的帮助我们判断彩色的使用是否合理。

下面,我们使用彩色的金刚区图标,然后将用户关注、认证用户、标签等元素使用其它色彩,来丰富页面的色彩内容。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

2. 其他配色类型应用

根据第一个方案,我们可以再用这个原型来实现其余的三个方案的配色。

比如下面的主色占比大,但是色彩丰富度低的。因为已经不太适用其它辅助色,所以主色填充上我们不再填充顶部导航栏的背景,而是将更多元素应用主色,减少辅助色数量。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

然后是主色占比小,色彩丰富度高的方案,进一步降低主色应用的比例,然后在金刚区、标签等处使用较为丰富的配色。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

最后,就是主色占比小,色彩丰富性也低的方案,那么使用中性色的元素就开始增多,只保留最核心的一些元素使用主色,和极少的辅助色。

10年经验的资深设计师,总结了这份 UI 配色终极奥义

根据四种不同的配色方案,我们就可以得到四种不同的配色结果和风格,在每次设计开始实施前,我们都可以根据这种做法来做尝试,并选出自己满意的方案。

要再次强调,UI 配色是极其强调形式的应用科学,最后做的往往会和一开始想的效果有极大出入,所以需要我们有几个备选方案,可以随时进行调整,并选出合理的那个。

总结

以上是我们关于配色有关知识点的分享,希望可以帮助大家提升对 UI 配色的认识。

文章来源:优设    作者:超人的电话亭

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

让你的 commit 更有价值

seo达人

提交规范

AngularJS 在开发者文档中关于 git commit 的指导说明,提到严格的 git commit 格式规范可以在浏览项目历史的过程中看到更易读的信息,并且能用 git commit 的信息直接生成 AngularJS 的 change log 。


commit messages 格式规范

commit messages 由 header 、body 、footer 组成。


header 又包含 type 、scope 、subject 。header 是必需的,不过其中的 scope 是可选的。


body 和 footer 可以省略。


<type>(<scope>): <subject>

// 空行

<BLANK LINE>

<body>

// 空行

<BLANK LINE>

<footer>

注:为了能在 github 以及各种 git 工具中看得更清晰,commit messages 的每一行都不要超过 100 个字符。

Header

Type

类型必须是以下几种之一:


feat: 新功能

fix: bug 修复

docs: 仅修改文档

style: 修改格式(空格,格式化,省略分号等),对代码运行没有影响

refactor: 重构(既不是修 bug ,也不是加功能)

build: 构建流程、外部依赖变更,比如升级 npm 包、修改 webpack 配置等

perf: 性能优化

test: 测试相关

chore: 对构建过程或辅助工具和库(如文档生成)的更改

ci: ci 相关的更改

除此之外,还有一个特殊的类型 revert ,如果当前提交是为了撤销之前的某次提交,应该用 revert 开头,后面加上被撤销的提交的 header,在 body 中应该注明: This reverts commit <hash>. ,hash 指的就是将要被撤销的 commit SHA 。


// 例如


revert: feat(user): add user type


This reverts commit ca16a365467e17915f0273392f4a13331b17617d.

Scope

scope 可以指定提交更改的影响范围,这个视项目而定,当修改影响超过单个的 scope 时,可以指定为 * 。


Sbuject

subject 是指更改的简洁描述,长度约定在 50 个字符以内,通常遵循以下几个规范:


用动词开头,第一人称现在时表述,例如:change 代替 changed 或 changes

第一个字母小写

结尾不加句号(.)

Body

body 部分是对本地 commit 的详细描述,可以分成多行。


跟 subject 类似,用动词开头,第一人称现在时表述,例如:change 代替 changed 或 changes。


body 应该说明修改的原因和更改前后的行为对比。


Footer

footer 基本用在这两种情况:


不兼容的改动( Breaking Changes ),通常用 BREAKING CHANGE: 开头,后面跟一个空格或两个换行符。剩余的部分就是用来说明这个变动的信息和迁移方法等。

关闭 Issue, github 关闭 Issue 的例子

// BREAKING CHANGE: 的例子

BREAKING CHANGE: isolate scope bindings definition has changed and

   the inject option for the directive controller injection was removed.


   To migrate the code follow the example below:


   Before:


   scope: {

     myAttr: 'attribute',

     myBind: 'bind',

     myExpression: 'expression',

     myEval: 'evaluate',

     myAccessor: 'accessor'

   }


   After:


   scope: {

     myAttr: '@',

     myBind: '@',

     myExpression: '&',

     // myEval - usually not useful, but in cases where the expression is assignable, you can use '='

     myAccessor: '=' // in directive's template change myAccessor() to myAccessor

   }


   The removed `inject` wasn't generaly useful for directives so there should be no code using it.




// Closes Issue 例子

Closes #2314, #3421

完整的例子

例一: feat

feat($browser): onUrlChange event (popstate/hashchange/polling)


Added new event to $browser:

- forward popstate event if available

- forward hashchange event if popstate not available

- do polling when neither popstate nor hashchange available


Breaks $browser.onHashChange, which was removed (use onUrlChange instead)

例二: fix

fix($compile): couple of unit tests for IE9


Older IEs serialize html uppercased, but IE9 does not...

Would be better to expect case insensitive, unfortunately jasmine does

not allow to user regexps for throw expectations.


Closes #392

Breaks foo.bar api, foo.baz should be used instead

例三: style

style($location): add couple of missing semi colons

查看更多例子

规范 commit message 的好处

首行就是简洁实用的关键信息,方便在 git history 中快速浏览

具有详实的 body 和 footer ,可以清晰的看出某次提交的目的和影响

可以通过 type 过滤出想要查找的信息,也可以通过关键字快速查找相关提交

可以直接从 commit 生成 change log

// 列举几个常用的 log 参数


// 输出 log 的首行

git log --pretty=oneline


// 只输出首行的 commit 信息。不包含 hash 和 合并信息等

git log --pretty=format:%s


// 查找有关“更新菜单配置项”的提交

git log --grep="更新菜单配置项"


// 打印出 chenfangxu 的提交

git log --author=chenfangxu


// 红色的短 hash,黄色的 ref , 绿色的相对时间

git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr)%Creset'

用工具实现规范提交

上面介绍了规范提交的格式,如果让各位同学在 git commit 的时候严格按照上面的规范来写,首先心智是有负担的,得记住不同的类型到底是用来定义什么的,subject 怎么写,body 怎么写,footer 要不要写。其次,对人的规范大部分都是反人性的,所以很可能在过不了多久,就会有同学渐渐的不按照规范来写。靠意志力来控制自己严格按照规范来写是需要额外耗费一些精力的,把精力耗费在这种事情上面实在有些浪费。


用工具实现规范提交的方案,一种是在提交的时候就提示必填字段,另一种是在提交后校验字段是否符合规范。这两种在实际项目中都是很有必要的。


Commitizen

Zen-like commit messages for internet citizens. 嗯~~一种禅意

Commitizen 是一个帮助撰写规范 commit message 的工具。他有一个命令行工具 cz-cli,接下来会把使用 Commitizen 分成几个阶段来介绍。


体验 git cz

// 全局安装 Commitizen

npm install -g commitizen

你的仓库可能还不是对 Commitizen 友好的,此时运行 git cz 的效果跟 git commit 一样,也就是没有效果。 不过,可以执行 npx git-cz 来体验。


如果想直接运行 git cz 实现语义化的提交,可以根据 streamich/git-cz 文档中说的全局安装 git cz。


// 全局安装 git cz

npm install -g git-cz

除此之外还有一种更推荐的方式,就是让你的仓库对 Commitizen 友好。


Commitizen 友好

全局安装 Commitizen 后,用 cz-conventional-changelog 适配器来初始化你的项目


// 初始化 cz-conventional-changelog 适配器

commitizen init cz-conventional-changelog --save-dev --save-exact

上面的初始化做了三件事:


安装 cz-conventional-changelog 依赖

把依赖保存到 package.json 的 dependencies 或 devDependencies 中

在根目录的 package.json 中 添加如下所示的 config.commitizen

"config": {

   "commitizen": {

     "path": "./node_modules/cz-conventional-changelog"

   }

 }

或者,在项目根目录下新建一个 .czrc 文件,内容设置为


{

 "path": "cz-conventional-changelog"

}

现在运行 git cz 效果如下:




cz-customizable 自定义中文配置

通过上面的截图可以看到,提交的配置选项都是英文的,如果想改成中文的,可以使用 cz-customizable 适配器。


运行下面的命令,注意之前已经初始化过一次了,这次再初始化,需要加 --force 覆盖


npm install cz-customizable --save-dev


commitizen init cz-customizable --save-dev --save-exact --force

现在 package.json 中 config.commitizen 字段为:


"config": {

   "commitizen": {

     "path": "./node_modules/cz-customizable"

   }

 }

cz-customizable 文档中说明了查找配置文件的方式有三种,我们按照第一种,在项目根目录创建一个 .cz-config.js 的文件。按照给出的示例 cz-config-EXAMPLE.js 编写我们的 config。 commit-type 可以参考 conventional-commit-types 。


可以点击查看我配置好的文件 qiqihaobenben/commitizen-git/.cz-config.js ,里面中详细的注释。


commitlint 校验提交

Commitizen 文档中开始就介绍到,Commitizen 可以在触发 git commit 钩子之前就能给出提示,但是也明确表示提交时对 commit messages 的校验也是很有用的。毕竟即使用了 Commitzen,也是能绕过去,所以提交最后的校验很重要。


commitlint 可以检查 commit messages 是否符合常规提交格式,需要一份校验配置,推荐 @commitlint/config-conventional 。


npm i --save-dev @commitlint/config-conventional @commitlint/cli

在项目根目录创建 commitlint.config.js 文件并设置校验规则:


module.exports = {

 extends: ["@commitlint/config-conventional"],

 // rules 里面可以设置一些自定义的校验规则

 rules: {},

};

在项目中安装 husky ,并在项目根目录新建 husky.config.js 文件,加入以下设置:


// 安装 husky

npm install --save-dev husky



// husky.config.js 中加入以下代码

module.exports = {

 "hooks": {

   "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"

 }

}

注意:因为 @commitlint/config-conventional 校验规则遵循 Angular 的规范, 所以我们在用 cz-customizable 自定义中文配置时, 是按照给出的符合 Angular 规范的示例 cz-config-EXAMPLE.js 编写.cz-config.js 的。但是如果你自定义的 Commitizen 配置不符合 Angular 规范,可以使用 commitlint-config-cz 设置校验规则。(推荐还是按照 Angular 规范进行 cz-customizable 自定义配置)

// 安装 commitlint-config-cz

npm install commitlint-config-cz --save-dev



// commitlint.config.js 改为

module.exports = {

 extends: [

   'cz'

 ]

};

git commit 触发 git cz

在提交的时候,我们都习惯了 git commit ,虽然换成 git cz 不难,但是如果让开发者在 git commit 时无感知的触发 git cz 肯定是更好的,

而且也能避免不熟悉项目的人直接 git commit 提交一些不符合规范的信息。


我们可以在 husky.config.js 中设置:


"hooks": {

 "prepare-commit-msg": "exec < /dev/tty && git cz --hook || true",

}

注意: 在 window 系统,可能需要在 git base 中才能生效。

生成 CHANGELOG

standard-version

是一个使用 semver 和 conventional-commits 支持生成 CHANGELOG 进行版本控制的实用程序。

standard-version 不只是能生成 CHANGELOG , 还能根据 commit 的 type 来进行版本控制。


// 安装 standard-verison

npm i --save-dev standard-version


// 在 package.json 中的 scripts 加入 standard-version

{

 "scripts": {

   "release": "standard-version"

 }

}

示例项目

可以查看 commitizen-git ,里面归纳了快速配置 Commitizen 友好仓库的步骤。

差不多三五分钟就能搞定。


可以看一下配置完后,执行 git commit 的效果。




扩展

更复杂的自定义提示

cz-customizable 中自定义配置项通常情况是够用的,

commitlint 中校验的规则基本上也是够用的,但是会有比较硬核的开发者会觉得还是不够,还要更多。比如一些 prompt 更加自定义,

提交时询问的 question 添加更多的逻辑,比如可以把一些重要的字段校验提前到 Commitizen 中,或者添加更多自定义的校验。


如果真想这么干,那就去 fork 一份 cz-conventional-changelog 或者 cz-customizable 来改,

或者直接自己写一个 adapter。


Commitizen 友好徽章

如果把仓库配置成了对 Commitizen 友好的话,可以在 README.md 中加上这个小徽章

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

一文读懂 Web 安全

seo达人

Web 安全是互联网中不可或缺的一个领域,这个领域中诞生了大量的黑帽子与白帽子,他们都是安全领域的王者,在平时里,他们利用各种巧妙的技术互相博弈,时不时就会掀起一场 Web 安全浪潮,真可谓神仙打架,各显神通。


本文从一个吃瓜群众的角度,聊一聊 Web 安全的一些有趣故事。


安全世界观

安全攻防案例

总结与思考

安全世界观

在互联网发展之初,IE 浏览器垄断的时期,大家上网的目的都很单纯,主要通过浏览器分享信息,获取新闻。但随着互联网的不断发展发展,一个网页能做的事情越来越多,除了看新闻,我们还可以看视频、玩游戏、购物、聊天等,这些功能都大大丰富了我们的生活。


随着网页功能的逐渐增多,就开始出现了一些黑帽子,他们试图通过一些技术手段来牟取利益。在我小的时候,印象最深的就是木马病毒,它可以监控你的键盘,将你在键盘上敲打的内容发送到黑客的机器上,黑客通过分析这些内容,很容易就能得到你的游戏账号和密码。


在这之后,就诞生出了一些杀毒软件,致力于解决网络上的各种病毒,随着不断地发展,杀毒软件已经成为一台电脑必不可少的软件。


为什么会出现这样的安全问题?

安全归根到底是信任的问题,如果所有人都按照正常的流程去上网,不去谋取私利,也就没有安全问题可谈了。


安全的根本在于信任,但要让所有人互相信任谈何容易。在当前阶段,我们可以做到:持续做好安全防护,让漏洞越来越少,非法攻击越来越困难,这样就能逐渐减少黑帽子的数量,让病毒制造者越来越少。


如何做好安全

要做好安全,首先得理解安全问题的属性,前人通过无数实践,最后将安全的属性总结为安全三要素,分别为:机密性、完整性、可用性。


机密性


保护数据内容不被泄露。

通常使用加密的方法。

完整性


保护数据内容是完整的、没有被篡改。

通常使用数字签名的方法。

可用性


数据随时都能够使用。

通常是在防御 DOS。

有了安全 3 要素之后,我们就可以对安全问题进行评估了。


资产等级划分


找出最重要的数据。

找出最重要数据的宿主空间,如:在数据库里,那么数据库就得重点防御。

找出数据库的宿主空间,如:在一台服务器上,那么这台服务器就得做次等防御。

找出服务器的宿主空间,如:在 OSI 网络层级上,那么在网络层面就得做一般防御。

威胁分析


找出威胁(可能造成危害的来源)。

找出风险(可能出现的损失叫做风险)。

风险分析


采取多标准决策分析,即:风险 = 威胁等级 * 威胁可行性。

计算所有的威胁,将最终的风险进行排序,优先解决风险大的问题。

确认解决方案


找出不安全的实现方式,并确定解决方案。

解决方案不要改变商业需求的初衷。

解决方案需对用户透明,不要改变用户的习惯。

做好安全评估之后,我们就有了一份安全解决方案,后续的安全工作只需按照这个方案去做,就没有任何问题。


安全的原则

有了安全解决方案之后,我们还可以制定一些安全原则,遵守原则做事,可以让我们事半功倍。


黑名单、白名单原则


白名单方案指的是给安全的资源授权。

黑名单方案指的是禁用不安全的资源。

我们应该优先使用白名单方案,因为黑名单通常统计不完所有的不安全资源。

如:XSS 攻击的方式非常多,可以通过 script、css、image 标签等,尽管你将这些标签都加入黑名单,也不能保证其他的标签都没有 XSS 的攻击隐患。

最小权限原则


只授予必要的权限,不要过度授权,减少出错机会。

如:普通权限的 Linux 用户只能操作 ~ 文件夹下的目录,如果有人想删库跑路,在执行 rm -rf / 时,就会提示无权限。

纵深防御原则


这条原则类似 木桶理论,安全水平往往取决于最短的那块板。

即:不要留下短板,黑帽子们往往可以利用短板为突破口,挖掘更大的漏洞。

数据与代码分离原则


当用户数据被当成代码执行时,混淆了数据和代码的边界,从而导致安全问题。

如:XSS 就是利用这一点去攻击的。

不可预测性原则


这条原则是为了提高攻击门槛,有效防止基于篡改、伪造的攻击。

如:数据库中使用 uuid 代替 number 型的自增主键,可以避免 id 被攻击者猜到,从而进行批量操作。

token 也是利用不可预测性,攻击者无法构造 token 也就无法进行攻击。

有了这些安全原则,我们就可以开干了,接下来介绍几个常见的攻防案例。


安全攻防案例

安全攻防的案例非常多,这里主要介绍几个出镜率比较高的安全问题。


客户端攻击

XSS 攻击

CSRF 攻击

点击劫持

XSS 攻击

XSS 攻击的本质是将用户数据当成了 HTML 代码一部分来执行,从而混淆原本的语义,产生新的语义。




如图所示,我们注册了一个 <script>alert(document.cookie)</script> 的用户名,所有能看到此用户名字的页面,都会弹出当前浏览器的 Cookie,如果代码的逻辑是将 Cookie 发送到攻击者的网站,攻击者就能冒充当前用户进行登录了。


XSS 攻击方式有很多,所有和用户交互的地方,都有可能存在 XSS 攻击。


例如:


所有 input 框。

window.location。

window.name。

document.referrer。

document.cookie。

localstorage。

...

由于页面中与用户交互的地方非常多,肯定还有一些 XSS 的攻击方式没有被发现,而一旦被黑帽子发现,就可能造成严重的影响,所以我们务必引起重视。


XSS 攻击影响

被 XSS 攻击成功后,攻击者就可以获取大量的用户信息,例如:


识别用户 UA。

识别用户浏览器扩展。

识别用户浏览过的网站。


通过 CSS 的 Visited 属性。

获取用户真实的 IP。


通过 WebRTC 等。

盗取 Cookie


伪造用户登录,窃取用户资料。

XSS 钓鱼。


向页面注入一个登录弹窗,让用户认为是网站内的登录弹窗(其实是钓鱼网站的),一旦用户登录,账号密码就泄露给了钓鱼网站。

XSS 攻击防御

目前来说,XSS 已经得到了互联网行业的重视,许多开发框架都内置了安全的 HTML 渲染方法。


我们也可以自定义进行一些安全配置。


配置 HTTP 中的 http-only 头,让前端 JS 不能操作 Cookie。

输入检查,在用户提交数据时,使用 XssFilter 过滤掉不安全的数据。

输出检查,在页面渲染的时候,过滤掉危险的数据。

CSRF 攻击

CSRF(Cross-site request forgery)跨站请求伪造,是一种利用用户身份,执行一些用户非本意的操作。




如图所示:


用户先登录了服务器 B,然后去访问服务器 C。

服务器 C 通过恶意脚本,冒充 A 去调用服务器 B 上的某个功能,

对于服务器 B 来说,还以为这是 A 发起的请求,就当作正常请求处理了。

试想一下,如果 C 冒充 A 进行了一次转账,必定会造成大量的经济损失。


CSRF 防御方式

防御 CSRF 主要有以下几种方式:


验证码


每一次请求都要求用户验证,以确保请求真实可靠。

即:利用恶意脚本不能识别复杂的验证码的特点,保证每次请求都是合法的。

Referer 检查


检查发起请求的服务器,是否为目标服务器。

即:HTTP 请求中的 Referer 头传递了当前请求的域名,如果此域名是非法服务器的域名,则需要禁止访问。

Token


利用不可预测性原则,每一请求必须带上一段随机码,这段随机码由正常用户保存,黑帽子不知道随机码,也就无法冒充用户进行请求了。

点击劫持

点击劫持是一种视觉欺骗的攻击手段。攻击者将需要攻击的网站通过 iframe 嵌套的方式嵌入自己的网页中,并将 iframe 设置为透明,在页面中透出一个按钮诱导用户点击。


就像一张图片上面铺了一层透明的纸一样,你看到的是攻击者的页面,但是其实这个页面只是在底部,而你真正点击的是被攻击者透明化的另一个网页。




如果所示,当你点击了页面上的按钮之后,本以为会...... ,而真正执行的操作是关注了某人的博客。


点击劫持防御

由于点击劫持主要通过 iframe,所以在防御时,主要基于 iframe 去做。


方案一:frame busting


正常网站使用 JS 脚本判断是否被恶意网站嵌入,如:博客网站监测到被一个 iframe 打开,自动跳转到正常的页面即可。

if (self !== top) {  // 跳回原页面  top.location = self.location;}

方案二:使用 HTTP 中的 x-frame-options 头,控制 iframe 的加载,它有 3 个值可选:


DENY,表示页面不允许通过 iframe 的方式展示。

SAMEORIGIN,表示页面可以在相同域名下通过 iframe 的方式展示。

ALLOW-FROM,表示页面可以在指定来源的 iframe 中展示。

配置 iframe 的 sandbox 属性


sandbox = "allow-same-origin" 则只能加载与主站同域的资源。

服务器端攻击

服务器端的攻击的方式也非常多,这里列举几个常见的。


SQL 注入攻击

文件上传漏洞

登录认证攻击

应用层拒绝服务攻击

webServer 配置安全

SQL 注入攻击

SQL 注入和 XSS 一样,都是违背了数据和代码分离原则导致的攻击方式。


如图所示,我们利用 SQL 注入,就能在不需要密码的情况下,直接登录管理员的账号。




攻击的前提是:后端只用了简单的拼接 SQL 的方式去查询数据。


# 拼接出来的 sql 如下:select * from user where username = 'admin' or 1=1 and password = 'xxx'# 无论密码输入什么,这条 sql 语句都能查询到管理员的信息

除此之外,SQL 注入还有以下几种方式:


使用 SQL 探测,猜数据库表名,列名。


通过 MySQL 内置的 benchmark 探测数据库字段。

如:一段伪代码 select database as current if current[0]==='a',benchmark(10000,'猜对了') 如果表明猜对了,就延迟 10 s 并返回成功。

使用存储过程执行系统命令


通过内置的方法或存储过程执行 shell 脚本。

如:xp_cmdshell、sys_eval、sys_exec 等。

字符串截断


如:MySQL 在处理超长的字符串时,会显示警告,但会执行成功。

注册一个 admin + 50 个空格的用户,会触发截断,最终新增一个 admin 用户,这样就能拥有管理员权限了。

SQL 注入防御

防止 SQL 注入的最好的办法就是,不要手动拼接 SQL 语句。


最佳方案,使用预编译语句绑定变量


通常是指框架提供的拼接 SQL 变量的方法。

这样的语义不会发生改变,变量始终被当成变量。

严格限制数据类型,如果注入了其他类型的数据,直接报错,不允许执行。

使用安全的存储过程和系统函数。

CRLF 注入

在注入攻击中,换行符注入也是非常常见的一种攻击方式。


如果在 HTTP 请求头中注入 2 个换行符,会导致换行符后面的所有内容都被解析成请求实体部分。

攻击者通常在 Set-Cookie 时,注入换行符,控制请求传递的内容。

文件上传漏洞

上传文件是网页开发中的一个常见功能,如果不加处理,很容易就会造成攻击。




如图所示,攻击者上传了一个木马文件,并且通过返回的 URL 进行访问,就能控制服务器。


通常我们会控制上传文件的后缀名,但也不能完全解决问题,攻击者还可以通过以下方式进行攻击:


伪造正常文件


将木马文件伪装成正常的后缀名进行上传。

如果要避免这个问题,我们可以继续判断上传文件的文件头前 10 个字节。

Apache 解析方式是从后往前解析,直到找到一个认识的后缀名为止


如:上传一个 abc.php.rar.rar.rar 能绕过后缀名检查,但在执行时,被当成一个 php 文件进行执行。

IIS 会截断分号进行解析


如:abc.asp;xx.png 能绕过后缀名检查,但在执行时,被当成一个 asp 文件进行执行。

HTTP PUT 方法允许将文件上传到指定位置


通过 HTTP MOVE 方法,还能修改上传的文件名。

通过二者配合,就能先上传一个正常的后缀名,然后改为一个恶意的后缀名。

PHP CGI 路径问题


执行 http://abc.com/test.png/xxx.php 时,会把 test.png 当做 php 文件去解析。

如果用户正好是把一段恶意的 php 脚本当做一张图片进行上传,就会触发这个攻击。

文件上传漏洞防御

防御文件上传漏洞,可以从以下几点考虑:


将文件上传的目录设置为不可执行。

判断文件类型


检查 MIME Type,配置白名单。

检查后缀名,配置白名单。

使用随机数改写文件名和文件路径


上传文件后,随机修改文件名,让攻击者无法执行攻击。

单独设置文件服务器的域名


单独做一个文件服务器,并使用单独的域名,利用同源策略,规避客户端攻击。

通常做法是将静态资源存放在 CDN 上。

登录认证攻击

登录认证攻击可以理解为一种破解登录的方法。攻击者通常采用以下几种方式进行破解:


彩虹表


攻击者通过搜集大量明文和 MD5 的对应关系,用于破解 MD5 密文找出原文。

对于彩虹表中的 MD5 密码,我们可以加盐,进行二次加密,避免被破解。

Session Fixation 攻击


利用应用系统在服务器的 SessionID 固定不变机制,借助他人用相同的 SessionID 获取认证和授权。

攻击者登录失败后,后端返回了 SessionID,攻击者将 SessionID 交给正常用户去登录,登录成功后,攻击者就能使用这个 SessionID 冒充正常用户登录了。

如果浏览器每一次登录都刷新 SessionID 可以避免这个问题。

Session 保持攻击


有些时候,后端出于用户体验考虑,只要这个用户还活着,就不会让这个用户的 Session 失效。

攻击者可以通过不停发起请求,可以让这个 Session 一直活下去。

登录认证防御方式

多因素认证


密码作为第一道防御,但在密码验证成功后,我们还可以继续验证:动态口令,数字证书,短信验证码等,以保证用户安全。

由于短信和网页完全是 2 套独立的系统,攻击者很难获取到短信验证码,也就无法进行攻击。

除此之外,前端登录认证还有多种方式,如果你对此感兴趣,可以参考我之前写的 前端登录,这一篇就够了。


应用层拒绝服务攻击

应用层拒绝服务攻击,又叫 DDOS 攻击,它指的是利用大量的请求造成资源过载,导致服务器不可用。




通常有以下几种 DDOS 攻击方式:


SYN Flood 洪水攻击


利用 HTTP 3 次握手机制,消耗服务器连接资源。

如:攻击者发起大量的 HTTP 请求,但并不完成 3 次握手,而是只握手 2 次,这时服务器端会继续等待直至超时。这时的服务器会一直忙于处理大量的垃圾请求,而无暇顾及正常请求。

Slowloris 攻击


以非常低的速度发送 HTTP 请求头,消耗服务器连接资源。

如:攻击者发送大量 HTTP 请求,但每个请求头都发的很慢,每隔 10s 发送一个字符,服务器为了等待数据,不得始终保持连接,这样一来,服务器连接数很快就被占光了。

HTTP POST DOS


发送 HTTP 时,指定一个非常大的 Content-Length 然后以很长的间隔发送,消耗服务器连接资源。

CC 攻击


针对一些非常消耗资源的页面,不断发起请求。

如:页面中的某些页面,需要后端做大量的运算,或者需要做非常耗时的数据库查询。在大量的请求下,服务器的 CPU、内存等资源可能就被占光了。

Server Limit DOS


通过 XSS 注入一段超长的 Cookie,导致超出 Web 服务器所能承受的 Request Header 长度,服务器端就会拒绝此服务。

ReDOS


针对一些缺陷的正则表达式,发起大量请求,耗光系统资源。

应用层拒绝服务攻击防御

对于应用层拒绝服务攻击,目前也没有特别完美的解决方案,不过我们还是可以进行一些优化。


应用代码做好性能优化


合理使用 Redis、Memcache 等缓存方案,减少 CPU 资源使用率。

网络架构上做好优化


后端搭建负载均衡。

静态资源使用 CDN 进行管理。

限制请求频率


服务器计算所有 IP 地址的请求频率,筛选出异常的 IP 进行禁用。

可以使用 LRU 算法,缓存前 1000 条请求的 IP,如果有 IP 请求频率过高,就进行禁用。

其实,处理 DDOS 核心思路就是禁用不可信任的用户,确保资源都是被正常的用户所使用。


WebServer 配置安全

我们在部署 web 应用的时候,经常会用到 Nginx、Apache、IIS、Tomcat、Jboss 等 Web 服务器,这些服务器本身也存在一些安全隐患,如果配置不当,很容易收到攻击。


在配置 Web 服务器时,可以参考以下几点:


以用户权限运行 Web 服务器


遵守最小权限原则,以最小权限身份运行 Web 服务器,限制被入侵后的权限。

删除可视化后台


运行 Tomcat、Jboss 等 Web 服务器时,默认会开启一个可视化的运营后台,运行在 8080 端口,并且第一次访问是没有认证的。

攻击者可以利用可视化后台,远程加载一段 war 包或者上传木马文件,进行控制。

及时更新版本


主流的 Web 服务器,每隔一段时间就会修复一些漏洞,所以记得及时更新版本。

总结与思考

本文介绍了 Web 安全的基本概念,以及大量的攻防技巧,其实这只是 Web 安全中的冰山一角,如果你对此感兴趣,不妨在安全领域继续深耕学习,一定能看到更广阔一片天。


对于一个开发者来说,我们应该在写代码时就将安全考虑其中,形成自己的一套安全开发体系,做到心中有安全,时时考虑安全,就能无形之中化解不法分子的攻击。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档