首页

交互深耕-B端设计师要懂的信息架构

鹤鹤

信息架构这篇是本人在现阶段觉得较难学习与阐述的知识点,网上关于信息架构的知识内容也是参差不齐。在学习与探究的过程中查阅了很多资料,反复修改多次,尽量用直白的语言结合实例来阐述信息架构。目录如下:

大家可以根据上述目录来进行选择性阅读,当然全文阅读也是极好的~





1.1 前言

这篇文章的起源,来源于最近看到的话题“B端设计师会被组件库取代吗?”。从表面上看,在组件库越来越完善的时代,很多页面设计依靠组件库就能够快速搭建。


那么在这种情况下,B端设计师存在的意义和价值到底体现在哪里呢?其实B端设计的重点并不在页面的视觉上,视觉只是作为设计师最终输出成果的一小部分。个人认为B端设计师工作重心体现在做「正确的设计」,比如以下几个方面:

1.这个设计能否完成对应的商业目标和产品目标;

2.我们的信息呈现是否合理以及能否解决当前需求;

3.用户能否在页面上快速找到想要的信息;

而想要弄清楚并解决上述这些问题,在众多的话题阐述之下,我发现其论述本质上都逃离不了「信息架构」这个概念。因此我认为设计师都需要对这个概念有充分的认知,这能够帮助我们做出正确且出色的设计。


1.2信息架构概念

关于信息架构的概念,在百科上面的定义大部分都比较晦涩难懂,比如维基百科和百度百科的解释:

相信大部分人都很难明白其中描述的意思。在这里换种思路,将信息架构拆分为信息与架构去理解。

信息指的是内容的载体,常见的文字、图像等都是信息;架构的含义则形容对应的组织和结构。那么信息架构就是将信息通过一定的形式组织起来,然后呈现出来。其本质就是研究信息的表达与传递。

通俗点讲,信息架构就是让用户可以更容易的理解我们的产品,让用户在使用我们的产品时可以更顺利、更自然。因此信息架构没有一个具体的呈现形式,它更多的是体现在产品设计的各方面。具体主要表现为组织系统、标签系统、导航系统和搜索系统。





为什么需要信息架构?我们都知道B端产品设计的核心是「降本提效」,在设计这一侧的可以将其理解为降低认知成本,提升使用效率。

降低认知成本需要我们更好的表达信息,让用户能看明白我们的产品能够做什么,如何用;提升使用效率需要提升信息的传递效率,让用户能够很容易的找到需要的功能;


而信息架构从本质上来讲也正是研究信息的表达和传递。因此我们需要通过它来帮助我们更好的完成B端产品设计。如果没有信息架构来作底层支撑,那么我们在页面上看到的可能就只有功能的堆叠,让产品陷入难以上手或者不知道怎么用的尴尬境地。

一个强大信息架构是产品质量的保证,是作为设计支撑点的骨架,它会减少可用性问题,提升整体导航行,创造对用户友好的体验。比如举一个工具层面的例子:

PS的工具栏堆叠在界面各个部分,而Figma的工具栏则集中在右侧且只出现当前需要的功能。很明显Figma在信息架构中的信息组织部分做得更为友好,PS则会显得逊色一些。这也是我们在学习PS的时候会显得比较吃力的原因之一。


可以说良好的信息架构是高效用户体验的基础。视觉元素,功能,交互和导航都是在信息架构的基础上构建的。因此想要做出体验好且合理的页面设计,我们就需要参与到信息架构这个过程中来,和产品一起完成对应架构的梳理。而不是只完成从原型到页面这个部分。


如果想要搭建一个好的建筑,我们需要知道其建造的目的,是按照什么样的结构搭建,内部有哪些系统,以及最后呈现的模样。


那么信息架构也同理,我们首先需要知道信息是为了什么目标服务,然后我们通过怎样的结构来组织这些信息,以及过程中会用到的信息元素,最后如何呈现它们。这都是我们在搭建信息架构中需要进行的必要步骤。如果某些环节没有做好或者没有了解透彻,那么在输出信息架构时往往会出现方向或者策略上的问题。接下来我们看看这些步骤是如何具体呈现的。


3.1 信息获取:先理解业务,再谈架构

B端行业对于业务理解的要求是比较高的,只有在理解业务的基础上,将业务需求转化为对应的设计目标,我们才能够输出合理的信息架构方案。

个人认为理解业务的基础,就是能够用一句话讲清楚当前设计的产品。这句话可以描述为:谁在什么地方想要完成什么目标。比如「用户想要不出门就能够吃到东西」,这就是外卖软件提供的产品服务。


虽然看上去这句话很简单,但其中包括了三个要素:用户、场景和目标。因此我们在分析和梳理业务的过程中首先要弄清楚的就是这三个要素。


3.1.1用户:分清购买者与使用者

用户永远是排在第一位的,也是我们首先需要弄清楚的。在B端设计中,本质上可以分为两类角色:客户和用户。比如我们常用的钉钉或企业微信,购买客户是企业,实际用户是员工。

对于企业:「我想要有一款软件可以更好的管理员工」

对于员工:「我想要这款软件能够更好地提高工作效率」

客户决定了我们产品的购买(部分情况下也兼顾使用),而用户则决定了后续产品的复购率。因此在业务理解中,我们需要弄清楚当前产品所处的服务阶段,比如初期为了打开市场肯定更倾向于客户,而中后期为了提高产品的使用体验又会偏向于用户。


因此我们首先需要弄清楚的就是当前产品是为哪些「目标用户」服务,这也就决定了我们在设计信息架构时对应的不同侧重点。


3.1.2场景:需求源于场景

场景是指需求产生的某种条件,这个条件包括但不限于环境、时间、地点、空间等,只有上述条件满足,这个需求才能成立。这里可以把场景理解为产生该问题的原因

比如当用户提出「她需要一件衣服」,那么我们就需要弄清楚用户为什么需要添加衣服,是她感冒了自身觉得冷还是因为外界环境冷。这两种场景涉及到的解决方案是完全不一样的。


在平日的工作中我们可以通过以下两种方式来更好的了解业务场景:

1.通过业务方文档进行业务背景的初步理解。业务文档中一般都会包括需求背景,我们可以通过文档进行初步了解。

2.通过业务沟通进一步加深业务背景的理解。由于很多B端业务离设计师本身的生活比较远。因此对于需求背景中不理解或者比较模糊的部分,我们可以通过与业务方或产品多次沟通来挖掘最底层的背景。

毕竟需求背景是理解业务的重要步骤,我们只有知道需求产生的原因,才能够针对性的给出解决方案。


3.1.3目标:业务目标和设计目标

目标决定了我们的产品最终的方向。我们首先接触到的一般都是业务目标,而我们要做的就是将业务目标转化为我们此次的设计目标。


A.业务目标

业务目标就是此次业务想要解决的实际问题,它通常是一个宏观上的描述。比如打车软件的业务目标简单概括来讲就是让用户能够更快速地打到车,减少等待焦虑。我们一般通过文档或者沟通来了解该目标。


B.设计目标

设计目标是我们基于业务目标而给出的设计策略,是一种更具体的实现方式。比如我们要让用户快速的打到车,那么这个时候我们的设计目标就是通过将用户位置和司机位置进行快速匹配,并通过超时补贴红包的方案来降低用户焦虑。从而实现业务目标。而这一过程涉及到的信息点就有:司机位置、乘客位置、等车时间、补贴金额等元素,并需要思考它们之间的关系和呈现方式。


可以发现从业务目标转化到设计目标这个过程,实际上就是在确定功能和信息点的过程。这样才能让我们更好地设计信息架构。


3.2信息架构核心:信息组织

从前文可以看出我们会在整体设计过程中出现很多的信息元素。如果不经过对应的组织和处理,直接堆叠在一起,那么信息含义会比较乱且难以调用。比如下方:

而右侧图片信息的组织过程可以理解为通过将零散的数据信息进行分类再以某种结构化的形式将它们重新组合排布的过程,直白一点就是先分类,再结构化呈现。我用一张图来表明这个过程:

那么这个过程中「信息组织」和「结构呈现」到底应该怎么做,也就是接下来要讲的组织方式和结构类型。


3.2.1组织方式:模糊分类和精确分类

组织方式可以分为精确分类和模糊分类。精确分类就是我们会利用物体本身物理属性来进行分类,比如位置、字母表、时间、类别、层级等方式进行组织。一些工具类应用例如滴答清单内容信息都是按照时间来进行组织的:

而模糊分类则是按照更为主观的逻辑对信息进行分类, 如主题、任务、用户、隐喻等来进行归类,比如我们常用的APP商城是按照不同的主题类别来进行区分的。

但在很多时候,产品倾向于将两种组织方式结合起来形成复合型组织方式,从而能够使我们的整体组织形式更符合用户的使用习惯。比如蓝湖的信息组织,其中既包含了模糊分类(按使用类型等分类),也包含了精确分类(按上传文件时间等)。

其实在大部分B端产品中,大都按照模糊分类来进行处理,比如按照任务、流程等方式。而精确分类更多用于在页面内的局部信息模块,比如创建时间和文件大小等。


归根结底,我们分类方式的选择需要结合我们前面提到的用户、场景和目标,这样才能让我们的分类更具说服力。


3.2.2组织结构:选择合适的结构类型

当信息按照分类维度组织后,我们接下来就是把整体信息进行结构化,这样才可以将信息整体连接起来并呈现出来。一般分为以下四种组织方式:


A.层级结构(最重要的结构)

这是信息架构中最为常见的结构,也是比较符合用户认知的结构。有时也称为「树状结构」。以子父节点的形式一层一层延展。

层级结构的优势就在于可以承载复杂的多层级内容,通过层级递进的方式将复杂的多层级拆解得更简洁。


但我们需要把控好内容的广度和深度,广度指的是在层级结构中每一层的数目,最好控制在7个以内。如果广度太宽意味着每个页面会给用户展示太多的信息,增加寻找内容的负担。深度为纵向结构,建议一般3层,最多不超过5层。过深的层级会让用户点击很多次,且不容易被用户发现。比如飞书的基本信息架构也是主要以层级结构来进行的。


B.矩阵结构(多维度结构)

矩阵结构是各个节点都相互连接的一种信息架构方式,通俗来讲就是用户既可以通过多个维度去触达同一信息,也可以从单个维度连接多种信息。

这种结构其实就更类似于我们在做相关功能时:比如当你进入电影全屏时想要退出时,既可以通过点击按钮退出,还可以通过键盘的Esc返回到,通过多点触达同一操作。


又比如我们的联系人功能,我们既可以通过输入数字拨打电话,也可以查找联系人进行拨打,还可以查询电话记录进行回拨。

矩阵结构最重要的意义在于给用户提供多种路径,使用户能够在不同路径中寻找各自想要的东西。


C.自然结构(随机性)

自然结构不遵循任何一致的模式,节点都是被逐一连接起来的。

自然结构一般都具有随机性和不确定性。这种更倾向于泛娱乐化的C端应用。比如我们常见视频网站的在推荐流都是应用的自然结构。比如打开B站等视频平台,你很难猜到刚进入看到的是什么。

但一般自然结构不会单独存在,比如B站在自然结构中也绑定了层级结构来进行层级上的划分。


D.线性结构(单一性)

线性结构是非常单一的一个结构,整体是一层一层向下递进。比较强调先后顺序的一种结构。


这种结构通常用于我们常见的软件安装程序等,也可以用于部分功能结构,比如网站的视频发布,一般都是经过上传-编辑-发布这三个步骤来依次进行。

大家可以发现在进行信息架构时,我们在很多情况下可能会运用多种组织结构方式,我们需要根据对应的用户决策场景来考虑让最适合的几种方式相结合。但最终目的都是为了让用户能够更快速的获取信息。


3.2.3注意事项:关注用户心智模型

在信息的组织过程中,我们需要注意用户的心智模型。比如当我们看到红点就知道有新信息通知,看到下拉箭头就知道可以展开。这是互联网产品在无形中给用户建立的底层习惯认知。用户目前对于普遍产品的一些基础布局、功能名称和交互逻辑都形成了一定的习惯,这都属于用户的心智模型的内容。


因此我们在组织信息时尽可能不要去打破用户常见的心智模型,否则必然会导致用户的不习惯。我们常见的「扫一扫」功能,微信、支付宝和QQ会隐藏在「+」号里面。而微博和抖音却分别放置在了「我的」和「搜索」里面。

这样会导致用户难以发现该功能。因为用户接触新的信息时,会以最初接触的局部信息为依据展开并形成初步认知,用户认知中的信息组织逻辑和实际信息的吻合度越高, 他在进一步查看或寻找信息的过程中体验会更顺畅, 反之, 若一开始形成的认知与实际信息的差异过大, 在后期的信息搜寻过程中则容易遇到困难。而这个吻合程度其实就是用户心智模型。


虽然建议在一定程度上遵循用户心智,但并不是说绝对遵循。对于用户不熟知的场景或者某些专业术语,我们需要通过灵活有效的提示(比如标记注释等)来引导用户就可以了。比如我们刚才提出的抖音扫一扫,它的应用场景其实是用于抖音官网后台登录,且在后台登录时已经给出了对应提示,那么这样的设计也是合理的。


3.3信息架构支撑:标签、导航和搜索

当经过上面的信息组织,其实我们已经能够归纳出一个大体的信息架构框架。但在信息组织之外,我们还需要关注以下三点:标签、导航和搜索。这对于信息架构的完整性也有非常重要的意义。


3.3.1 标签系统:让信息识别更通用

标签系统,通俗来讲就是要我们对当前整个系统信息节点的命名,从而让信息的呈现更容易识别。拿个最简单的例子来进行说明:

可以看到左侧和右侧关于卫生间的信息标示,可能左边你能一眼区分,右边可能就需要反应半天才能猜出到底代表什么含义了。


这其实就是关于我们的信息命名是否能够被大多数用户所接受的场景,也就是我们标签作用所起的作用。标签可以分为图片和文字标签,都需要考虑用户对该信息命名的认知程度,也就是前面提到的心智模型。那么如何能够更好的去定义标签名称呢,这里需要注意2个方面:


A.优先选用被行业广泛接受的词或图标

在进行标签定义的时候,尽量选择已经被用户所熟知的词语,比如「工作台」「通讯录」等已经被运用得非常熟练,对于类似功能就直接以该形式命名,比如我们的设计软件中,很多图标和功能名称都是通用的:

这样做能够很大程度减少用户的学习成本。因此在B端设计中我们也需要注意到我们所在的行业,哪些名词已经达成了共识,就无需再造新名词。


B.不确定的词语可以参考竞品或调研来决策

当某类功能或场景的标签难以确定时,我们就可以尝试去找一下竞品是否有类似功能,或者找该行业的领头羊(比如聊天工具的巨头微信),那么在进行标签定义的时候,可以参考它的命名体系。因为它已经替我们教育了一部分用户,会间接降低学习成本。


如果某些标签在上述过程中还是无法确定,那么我们结合自己经验或者与咨询业务相关人员来进行讨论,在必要时候可以在标签旁边添加注释来进一步说明。


3.3.2 导航系统:让用户不迷路

导航系统其实应该是大家比较熟知的一个系统了。就像使用导航系统来规划行程一样,导航系统都会存在于每个网站中。比如我们常见的侧边导航、顶部导航等。

因为网上关于导航系统已经有很多资料的讲解了,在这里阐述下四类导航的含义:

1.全局导航:位于页面最上层的导航,用户几乎在页面的每个地方都可以看见,是最高层级的导航系统;

2.局部导航:位于最高导航的下级子类导航,子类导航并不是必须的导航,根据场景进行取舍;

3.情景式导航:通过点击文字链接进行跳转的导航,比如在个人资料里面植入其它网站的链接地址;

4.辅助导航:这里包括网站地图,网站索引,网站指南等辅助类型的导航。


辅助导航的网站指南包括新手引导和演示教程等。现阶段更巧妙的功能引导,是当用户在进行某些功能的操作时及时进行提示,这样不仅达到了为用户引导的效果,还减少了一连串的新手引导对于用户的打扰。比如figma在进行组件更新后,只有当你调用组件功能时,才会及时进行提醒。


3.3.3 搜索系统:让用户轻松找信息

搜索,是我们平日最常用的查找信息的功能,它能够帮助我们快速进行信息的检索。虽然搜索功能非常重要,但并不是每个系统每个页面都需要搜索。我们决策是否添加搜索时需要考虑下列三点:

1:内容复杂度:当前页面承载的内容复杂度如果较少,对于简单内容页面往往不需要搜索;

2:内容性质:当前页面的性质是偏向于用户浏览还是查找,根据用户行为来决定是否需要搜索;

3.搜索场景:如果搜索场景很简单,考虑是否只用筛选或分类就能够解决问题;反之如果搜索内容很复杂,我们还可以搜索结合筛选来更好的查找信息;


上述3点决定了我们是否需要考虑搜索功能。而关于搜索的其他细节点,比如搜索规则和搜索结果等,在这里不做进一步的阐述。在这篇文章中更重要的是弄清楚我们何时需要搜索功能。


3.4信息架构表达:视觉化你的架构

我们通过上述方法已经知道如何梳理信息架构了,那么我们应该如何呈现它呢。这部分其实也是很多资料中比较模糊的点。

在学习的过程中,发现部分资料认为信息架构就是单纯的指思维导图,但实际上信息架构并不能单纯只用思维导图就能够完全表示。

因为信息架构包含了很多部分的内容。只能说思维导图可以是信息架构的一种表现形式,其可以帮助我们在思考阶段梳理整体产品的信息构成。


这里抛出一个很有意思的观点,那就是「功能结构图」和「信息架构图」到底什么关系,这里用两张图示例:

可以看到,功能结构图更多体现的形式是功能阐述,一般形式为名词+动词,比如头像设置;而信息架构图重点呈现的应该都为信息元素,一般为名词,比如头像图片。

但在大多数时候我们看到的产品架构图,其实更偏向于功能结构图和信息架构图的结合。因为在很多时候阐述信息构成时需要依赖功能进行辅助说明。


因此这篇文章讲述的信息架构更偏向于基于产品的整体架构。其实信息架构对于呈现形式并没有特别的限制,只要能够帮助你清晰表达产品整体结构就行。《信息架构:超越web设计》第4版中其实也并没有对表现形式这一块进行严苛的定义,其用「显示信息元素间的关系——站点地图」的说法概括了信息架构的呈现形式,其表达如下:

可以看到其表达形式包括思维导图和流程图等形式:思维导图的优势是能够总览全局信息,查看信息的深度和广度,而流程图的优势则更能够表达整体的逻辑关系。


因此信息架构的呈现需要根据你的产品场景选择合适的视觉框架表达。不必让形式限制了我们的发挥,而是应该形式追随于我们的架构表达。其只是一个信息梳理结构的说明结果(类似于中间态),我们需要借助它来更好的阐述思路与沟通想法。


3.5信息架构之后:让信息具像化

在输出信息架构之后,其实这里想聊一聊页面的呈现。因为当梳理好大的框架后,剩余的页面细节其实都需要通过原型图来进行体现。这个过程是从框架到页面的阶段,其实对于设计师来说也是很重要的部分。在这里根据自己的理解列出了以下几方面的注意点:

A.页面能够让用户看懂

这其实就是涉及到我们的信息组织和标签系统。如果当我们的某个页面不能让用户第一时间获取到该页面表达的信息,反思一下是在哪个方面做得不好。是标签系统含义模糊呢,还是信息的组织分类方式不对。从页面呈现倒推信息架构。

综合来说就是设计时的排列要考虑用户的心智模型(比如网页的常规排版和通用名词定义等),对于某些难以理解的地方给予用户帮助和解释。虽然B端产品想要完全避免学习成本是不可能的,但我们可以尽量减少其学习成本。


B.考虑用户的视觉动线

当我们在进行信息排列时,这时需要思考的就是用户的视觉动线,也就是我们常说的视觉浏览「F模型」和「Z模型」。对于不同的信息流来说,采用不同的动线模型能够让用户更好地查找信息。

F模型和Z模型的使用区分其实就是在使用场景上,对于内容页面来说F模型会更为合适(比如文章或者搜索结果),适合文本类的内容。但对于非文本的页面,则更适合用Z模型,Z型模式的设计跟踪了人眼扫描页面时的路线——从左到右,从上到下,能够更好引导用户的视线。


C.掌控好适度的信息层级

B端由于在视觉的发挥空间不多,那么相对来说保持良好的信息层级能够让整体的体验变得更为良好。

不管是原型图还是视觉,整体的视觉层级要体现得更为清晰。按理说最好的视觉层级控制在三级左右。如果发现视觉层级过多,需要考虑是不是因为信息架构设计时纵向层级过深,通过调整架构的形式来更好的呈现信息。以及对同页面的信息进行重要程度分级。


当我们做完或者听别人阐述对应的信息架构时,该如何评判呢,到底怎样的信息架构才算优秀呢。个人认为可以从3方面去进行判断:

业务层:

1.设计目标合理:能平衡商业目标和用户的目标,保证客户和用户都有较为良好的体验;

2.核心任务目标:能够让用户顺利完成产品的核心任务,需要通过用户测试来进行验证

结构层:

1.平衡广度和深度:在进行功能使用时不会隐藏的太深而找不到,是否有冗余步骤

2.保证拓展性:当前信息架构在面对未来新增或者删减信息时能够稳定拓展

体验层:

1.保证易读性:用户不经过介绍,通过页面信息呈现能够看懂该产品是用来做什么的

2.保证易查找性:用户在需要某个功能时能否快捷的找到,是否有多种查找方法(比如搜索或筛选)


合理的信息架构需要具备以上条件,我们需要在做设计呈现时也尽量保证以上条件。但在很多情况下其实并不能完全满足,这个时候我们需要根据业务目标的重要性来选择某些点进行满足。


梳理一下整体文章的架构,其实是按照「是什么-为什么-怎么做」的形式来进行拆分的:

这篇文章想要表达的观点,不是让设计师独立去梳理整体信息架构,而是让设计师拥有信息架构意识,了解其是如何进行并产生的。这样你在看到整体架构时,有足够的理论支撑去判断它的好坏,并通过自己的理论认知去理解和改进不好的地方。


当我们对信息架构有足够的认知时,我们在设计页面时才能有合理的思考方向,做出「正确的设计」,避免成为无情的作图机器。信息架构作为产品交互视觉最底层的支撑,只有骨架搭好,对于用户的使用体验才能够有本质上的提升。

蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码ben_lanlan,报下信息,会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

文章来源:站酷  作者:进击的M

分享此文一切功德,皆悉回向给文章原作者及众读者.

免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

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

从用户体验的角度了解按钮

鹤鹤

按钮的点击率低,用户在放置按钮的页面上花费了大量时间,这可能是由于按钮不直观和混乱。

我们将从用户体验的角度详细解释直观且易于用户理解的按钮,例如内容中按钮的排列、按钮的形状以及基于内容的配色方案。

什么是用户友好按钮?

您拥有的按钮越多,做出决定所需的时间就越长。用户使用每个按钮以确定需要哪个按钮来实现目标。对按钮的不确定性会导致对按钮不做任何操作。

为防止出现这种情况,请直观地确定每个操作的优先级。用户一旦知道哪些按钮对其任务很重要,就可以立即采取行动。

1. 按视觉扫描模式排列按钮

应用程序中最常见的错误就是按与用户自然扫描模式不同的顺序排列按钮。优先级最高的按钮放在最前面,以便用户首先注意到它。然而,通过视觉加权,用户会以任何顺序注意到按钮。

按钮的顺序不是为了提高可见度,而是为了提高效率。首先放置高优先级按钮会使扫描方向从上到下颠倒,从而破坏视线的自然流动。

它不是强制用户重新扫描按钮,而是允许用户在单向扫描中执行高优先级操作。这允许用户在做出决定之前依次扫描按钮所需的所有信息。

将最高优先级的动作放在底部使其成为视觉阻力最小的路径,并且可以快速轻松地点击。此外,底部位置是手指最容易触及的位置,进一步提高了效率。

2. 使用形状区分按钮和文本

应用程序中的另一个常见错误是使用文本来表示按钮。设计师使用文本按钮来表明它们的优先级低于其他操作。但是,这对于操作按钮来说是不合适的选择。文本看起来不像按钮。通过使用文本按钮,用户可以忽略操作而只看到主要操作。

文本按钮也会使得用户对内容是按钮还是信息而引起混淆。这种不确定性会导致这些按钮被跳过。

文本按钮不仅令人困惑,而且还是难以点击的小目标。将文本标签放置在按钮形状内可以更轻松地调用操作并点击它。

按钮形状是抑制优先级低于文本按钮的操作的好方法。使用户更容易识别以他们喜欢的方式实现目标的所有选项。

3. 为渐进式动作添加颜色

高优先级操作是最容易看到的。此操作与用户的目标直接相关。如果您不确定其余的操作,请考虑哪些操作将用户推向目标,哪些操作正在远离目标。

在上面的例子中,“结帐”是优先的,这是用户达到目标的一个动作。但是,尚不清楚“查看购物车”或“继续购物”操作是否具有中等优先级。

“查看购物车”操作允许用户查看他们添加到购物车中的产品,这会促进结帐。“继续购物”操作将用户从结账返回到产品页面。

通过查看每个操作,很明显“查看购物车”具有中等优先级,而“继续购物”具有低优先级。

按钮颜色从文本颜色中脱颖而出并吸引用户的注意力,因此它是显示渐进式动作的有效方式。如果按钮颜色与文字颜色相同,则信号不是很强。为渐进式动作添加不同的颜色意味着用户应该采取的动作。

如果您为每个渐进式动作使用相同的颜色,则用户无法确定哪个具有更高的优先级。此外,为每种颜色使用不同的颜色只会使用户感到困惑,并且不会理解不同的颜色。并且,您还会在每个按钮上感受到相同的视觉重量。

设计的诀窍是使用相同的色调,但改变中等优先级动作的饱和度和亮度,使其看起来比高优先级动作更亮。现在按钮权重不冲突,很明显哪个突出。

对比以增强对比度。主要按钮使用深色背景上的浅色文字,次要按钮使用浅色背景上的深色文字。这为高优先级操作提供了更亮的文本标签和最佳对比度。

4. 改变标签上文字的粗细

到目前为止,应用这些技术足以区分优先级,但您还可以做更多的事情。按钮越直观,用户就越不需要考虑它。

对每个标签上的文本使用相同的粗体可以赋予该文本相同的强调量。因此,建议根据优先级分别强调每个标签的文本。更改文本的粗细,使高优先级按钮最厚重,低优先级按钮相对单薄。这样,当用户阅读文本标签时,文本的权重表示优先级。

在上面的例子中,“结账”标签比其他标签更厚更亮。“查看购物车”标签为半粗体,“继续购物”标签为中等。因此,文本标签反映了每个动作的视觉权重。“查看购物车”标签上指示“3件商品”的文字没有加粗,因为它是补充信息,并不代表所执行的操作。

5. 为高优先级操作提供图标

最后一种技术是让色盲用户可以访问您的按钮。色盲用户无法通过颜色区分重量差异。因此,我们需要的东西是不是颜色作为一个视觉线索。

为高优先级操作添加图标将进一步强调它以使其脱颖而出。用户浏览时,用户通常关注视觉元素而不是文本。该图标将使所有用户更加关注高优先级操作。

用户仍然可以通过移除颜色和标签来识别结账按钮。

总结

如果用户在操作屏幕上花费大量时间,或者点击率较低,可能就是按钮设计的不直观。在这种情况下,可以使用这些技术来增强按钮显示并有利于突显优先级。

蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码ben_lanlan,报下信息,会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

文章来源:站酷  作者:对啊设计君

分享此文一切功德,皆悉回向给文章原作者及众读者.

免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

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


Vue的防抖和节流(接口频繁调用如何处理)

前端达人

首先描述一下我所使用的业务场景:系统有一个批量审批的功能,每个审批的流程需要根据提交的用户实时的反馈回去进去用户页面的刷新,如果一个用户同时有多个流程被审批通过,前端会向服务端频繁的多次调用同一个接口,造成服务器压力过大和页面卡顿,非常影响用户体验。
目标:需要短时间内向服务端频繁调用接口时只去调用最后一次的接口。(防抖)

防抖和节流的区别:主要体现在执行次数上的区别,比如我们写一个200ms的延迟时间,节流就是每200ms执行一次,而抖动是只有在最后一次事件的200ms内调用一次回调函数。
防抖和节流都可以用于 mousemove、scroll、resize、input、click等事件,他们的区别在于防抖只会在连续的事件周期结束时执行一次,而节流会在事件周期内按间隔时间有规律的执行多次。

防抖 debounce

当事件被频繁触发时,在一定的时间内再去执行回调函数,如果在等待期间再次被触发,则重新计时,直至整个等待期间没有新的事件被触发,执行回调函数。

举个例子:一个点击事件,为了防止用户重复发起请求,如果用户在三秒内多次发生点击事件,点击事件将只执行一次,第一次和第二次点击的间隔只要在三秒钟内就会重置这个等待时间,第二次和第三次之间的最大等待时间也是三秒,如果第二次点击事件发生后的三秒内没有新的点击事件产生,第二次点击后的三秒就会调用回调函数。

可以直接引用loadsh的debounce方法来实现函数防抖,也可以自己写一个防抖函数(利用定时器)

  1. 引用loadsh

这里先给一个中文文档的地址:https://www.lodashjs.com/docs/lodash.debounce
在vue3.x中也推荐了这种方式:https://v3.vuejs.org/guide/data-methods.html#methods
有多种引用方式,这里我直接采用npm的方式

npm i --save lodash 
  • 1

使用loadsh的debounce方法

<el-button id="myBtn" type="goon" icon="el-icon-search" @click="test">点击事件</el-button> 
  • 1
let _ = require('lodash'); _.debounce(fun,ms,options) fun: 回调函数
ms:等待时间,毫秒
options:选项对象 
  • 1
  • 2
  • 3
  • 4
  • 5

注意:这里点击事件要写成test: 的形式,test()这样是不生效的

import debounce from 'lodash/debounce' methods:{ test:debounce(()=>{ console.log("防抖函数执行",) },3000) } //或者下面这种写法 document.getElementById("myBtn").addEventListener('click', debounce(function (event) { console.log("防抖函数执行",) }, 3000)) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  1. 自定义防抖函数
<el-button type="goon" icon="el-icon-search" @click="test">点击事件</el-button> 
  • 1
data:{ timer:null }, methods:{ //在最后一次点击三秒后才会触发一次点击事件 test(){ clearTimeout(this.timer) //自定义个定时器三秒后执行,一旦有新的事件发生会将这个定时器清除重新创建一个,只有三秒内不出现事件这个定时器才不会被销毁重构 this.timer = setTimeout(()=>{ console.log("防抖执行,这里就是你需要执行的操作") },3000) } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

节流 throttle

在规定的时间内只触发一次回调函数,在规定时间内多次触发函数,只会执行一次

举个例子:一个点击事件,你设定了节流的延迟时间为一秒钟,那么在你一直点击的情况下,每隔一秒会触发一次这个事件,直到你的点击停止,这个不会累积,比如一秒钟内点击了五次,然后不再点击时,事件也只会触发一次而不会累积到触发五次,这种累积的可以采用定时器实现。

节流一般多用于监听输入框和滚动条,同样的在我们的loadsh中也有写好的节流的函数throttle,使用方法和上面防抖类似,这里就不详细写了,主要写一下 自定义的节流函数。

throttle(fun, ms,options) fun:需要节流的回调函数
ms:等待时间
options:额外配置项 
  • 1
  • 2
  • 3
  • 4

自定义节流函数:
原理就是用时间戳判断是否到了回调的执行时间,记录上次执行的时间戳,然后每次触发 事件执行回调,回调里边判断当前时间戳距离上一次执行时间戳的间隔是否已经到达规定的时间,如果是就执行,并且会更新上次执行的时间戳。
下面是我写的一个简单的例子,可以根据自己需求进行修改

data:{ //这里我直接页面创建时定义了一个初始的变量,保存上一次函数执行的时间 lastTime:new Date() }, methods:{ //fun 代表要执行的函数,需要被节流的函数 throttle(fun){ //函数执行时的时间 let now = new Date() console.log("now",now) console.log("lastTime",this.lastTime) //两次调用的时间差 if (now - this.lastTime > 1000){ fun() //调用成功,上一次调用时间值修改 this.lastTime = now } }, test(){ this.throttle(function (){ //1000ms内无论点击多少下,只会调用一次 console.log("节流函数调用,时间1000ms") }) }, } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

image.png

如果项目多次用到可以将以上的方法封装成一个工具类。

参考文章:https://www.jb51.net/article/161713.htm














蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

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

ES6——数组扩展 ... Array.from() Array.of() flat() reduce()

前端达人

1.扩展运算符…

ES6——扩展运算符…

2.Array.from()

将两类对象转为真正的数组:类数组(querrySelectAll)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)

类数组

1.赋给length属性的对象

 //将类数组转化为真正的数组 let k={ 0:'a', 1:'b', length:2 //没有length属性就不行 } console.log(Array.from(k)); //['a', 'b'] 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2.字符串也有length属性,它也是类数组

 let str='hello'; console.log(Array.from(str)); // ['h', 'e', 'l', 'l', 'o'] 
  • 1
  • 2

3.参数如果是真正的数组 则返回一个全新数组

 let s1=[1,2,3]; let s2=Array.from(s1); console.log(s2==s1); //false 
  • 1
  • 2
  • 3

3.Array.of()

一组值,转换为数组

Array.of(3, 11, 8) // [3,11,8] Array.of(3) // [3] Array.of(3).length // 1 
  • 1
  • 2
  • 3

这个方法的主要目的,是弥补数组构造函数Array()的不足。因为参数个数的不同,会导致Array()的行为有差异。

只有当参数个数不少于 2 个时,Array()才会返回由参数组成的新数组

Array() // [] Array(3) // [, , ,] Array(3, 11, 8) // [3, 11, 8] 
  • 1
  • 2
  • 3

4.find() 和 findIndex()

find方法,用于找出第一个符合条件的数组成员

 var result1=[1,2,3,4].find(function (item) { return item%2==0; }) console.log(result1); //2 
  • 1
  • 2
  • 3
  • 4

findIndex方法,返回第一个符合条件的数组成员的位置。
如果所有成员都不符合条件,则返回-1

 var result1=[1,2,3,4].findIndex(function (item) { return item%2==0; }) console.log(result1); //1 
  • 1
  • 2
  • 3
  • 4

5.fill() 填充数组

使用给定值,填充一个数组

console.log(new Array(5).fill('a')); //['a', 'a', 'a', 'a', 'a'] 
  • 1

fill方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置。

['a', 'b', 'c'].fill(7, 1, 2) // ['a', 7, 'c'] 
  • 1

6.数组实例的 entries(),keys() 和 values()

Set,Map,Object中都有这些方法

entries(),keys()和values()——用于遍历数组。
它们都返回一个遍历器对象,可以用for…of循环进行遍历
唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。

 let yes=[1,2,3,4]; console.log(yes.keys()); //Array Iterator {} console.log(yes.values()); //Array Iterator {} console.log(yes.entries()); //Array Iterator {} 
  • 1
  • 2
  • 3
  • 4
 let yes=[1,2,3,4]; for(let key of yes.keys()){ console.log(key); //0 1 2 3 } for(let key of yes.values()){ console.log(key); //1 2 3 4 } for(let [key,value] of yes.entries()){ console.log(key,value); //0 1 //1 2 //2 3 //3 4 } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

7.includes()

console.log([1, 2, 3].includes(1)); //true console.log([1, 2, 3].includes(1,1)); //false 从1号索引开始找 
  • 1
  • 2

8.flat()

将嵌套的数组“拉平”,变成一维的数组。
该方法返回一个新数组,对原数据没有影响

//默认只能拉平一层 console.log([1, 2, [3, 4]].flat()); //[1, 2, 3, 4] //如果拉平多层 设置层数 console.log([1, 2, [3, [4, 5]]].flat(2)); // [1, 2, 3, 4, 5] //如果层数太多 设置Infinity console.log([1, 2, [3, 4, [5, 6, [7, 8]]]].flat(Infinity)); //[1, 2, 3, 4, 5, 6, 7, 8] 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

9.reduce()

reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。对空数组是不会执行回调函数的。

1.计算数组总和

var num = [1,2,3,4,5]; var res = num.reduce(function(total,num){ return total+num; //return total + Math.round(num);//对数组元素四舍五入并计算总和 },0); console.log(res); //15 //num.reduce((total,num) => total += num, 0); //没有初始值initialValue(即上面例子中的0),当数组为0时会抛出异常提示reduce函数没有初始值,所以为兼容性一般加上initialValue 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2.合并二维数组

var red = [[0, 1], [2, 3], [4, 5]].reduce(function(a, b) { return a.concat(b); }, []); console.log(red); //[0, 1, 2, 3, 4, 5] 
  • 1
  • 2
  • 3
  • 4

3.统计一个数组中有多少个不重复的单词
reduce()函数










蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

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

Vue的设计理念

前端达人

目录

Mvvm模型

Vue中的Mvvm实现原理

自己实现双向数据绑定的示例

Vue与模板引Thymeleaf擎对比

显示变量值(Vue)

 显示变量值(Thymeleaf)

替换Html(Vue)

替换Html(Thymeleaf)

绑定属性(Vue)

绑定属性(Thymeleaf)

隐藏显示区块(Vue)

隐藏显示区块(Thymeleaf)

遍历列表数据-带索引(Vue)

 遍历列表数据-带索引(Thymeleaf)

引入其他文件内容(vue)

引入其他文件内容(Thymeleaf)

Vue的页面定义基石-Options API

Vue中的代理运用

nginx反向代理

vue代理(正向代理)

Vue特性能力-filter


Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合

Mvvm模型

MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式,其核心是提供对View 和 ViewModel 的双向数据绑定,这使得ViewModel 的状态改变可以自动传递给 View,即所谓的数据双向绑定。
Vue.js 是一个提供了 MVVM 风格的双向数据绑定的 Javascript 库,专注于View 层。它的核心是 MVVM 中的 VM,也就是 ViewModel。 ViewModel负责连接 View 和 Model,保证视图和数据的一致性,这种轻量级的架构让前端开发更加高效、便捷。

Vue中的Mvvm实现原理

Vue.js的实现方式,对数据(Model)进行劫持,当数据变动时,数据会出发劫持时绑定的方法,对视图进行更新。

这里有两个方向: 

1、数据流向视图:数据变动时,能自动更新Dom节点的内容。此功能是通过数据劫持实现的,对数据(Model)进行劫持,当数据变动时,会调用劫持时绑定的方法,对视图进行更新。

2、视图流向数据:如输入框input内容发生变动时,input对应的数据也会发生变动。此功能是通过监听Dom事件实现的。当用户在输入框中输入文字(即inputkeyup事件发生时),vue会监听到这个事件,找到对应的数据模型变量,修改变量值。

vue中双向数据绑定的示例


  1. <div id="app-6">
  2. <p>{{ message }}</p>
  3. <input v-model="message">
  4. </div>

  1. var app6 = new Vue({
  2. el: '#app-6',
  3. data: {
  4. message: 'Hello Vue!'
  5. }
  6. })

自己实现双向数据绑定的示例


  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>双向绑定demoo</title>
  5. <meta charset="UTF-8">
  6. </head>
  7. <body>
  8. <div id="app">
  9. <input type="text" id="txt">
  10. <p id="show-txt"></p>
  11. </div>
  12. </body>
  13. <script>
  14. var model={}
  15. Object.defineProperty(model,'txt',{
  16. _txt: "",
  17. get:function(){
  18. return _txt
  19. },
  20. set:function(newValue){
  21. _txt = newValue
  22. document.getElementById('txt').value = newValue
  23. document.getElementById('show-txt').innerHTML = newValue
  24. }
  25. })
  26. document.addEventListener('keyup',function(e){
  27. model.txt = e.target.value
  28. })
  29. </script>
  30. </html>

这里要讲到一个关键函数

Object.defineProperty 

Object.defineProperty 需要三个参数(object , propName , descriptor)

1 object 对象 => 给谁加
2 propName 属性名 => 要加的属性的名字 【类型:String】
3 descriptor 属性描述 => 加的这个属性有什么样的特性【类型:Object】

descriptor 属性描述

get一个给属性提供getter的方法,如果没有getter则为undefined。该方法返回值被用作属性值。默认为undefined
set一个给属性提供setter的方法,如果没有setter则为undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认值为undefined

Vue与模板引Thymeleaf擎对比

显示变量值(Vue)


  1. <div id="app">
  2. {{ message }}
  3. </div>

 显示变量值(Thymeleaf)


  1. <div id="app" th:text="${message}">
  2. </div>

替换Html(Vue)


  1. <div id="app" v-html="content">
  2. </div>

替换Html(Thymeleaf)


  1. <div id="app" th:html="${content}">
  2. </div>

绑定属性(Vue)

<img :src="imgUrl" :id="newId"/>

绑定属性(Thymeleaf)

<img th:attr="id=${newId},src=${imgUrl}"/>

隐藏显示区块(Vue)


  1. <div id="app" v-if="show">
  2. 这是一个区块
  3. </div>

隐藏显示区块(Thymeleaf)


  1. <div id="app" th:if="${show}">
  2. 这是一个区块
  3. </div>

遍历列表数据-带索引(Vue)


  1. <ul id="app">
  2. <li v-for="(item, index) in dataList">
  3. {{ index }} - {{ item.message }}
  4. </li>
  5. </ul>

 遍历列表数据-带索引(Thymeleaf)


  1. <ul id="app">
  2. <li th:each="item, stat: ${dataList}">
  3. {{ stat.index }} - {{ item.message }}
  4. </li>
  5. </ul>

引入其他文件内容(vue)

在vue中,可复用的单元块被称为组件,定义组件


  1. <template>
  2. <button v-on:click="count++">You clicked me {{ count }} times.</button>
  3. </template>
  4. <script>
  5. export default {
  6. name: "button-counter"
  7. data(){
  8. count: 0
  9. }
  10. }
  11. </script>

 引入组件


  1. <div id="components-demo">
  2. <button-counter></button-counter>
  3. </div>

引入其他文件内容(Thymeleaf)

被导入模块index.html:


  1. <div th:fragment="head">
  2. 这是网页头
  3. </div>

在其它页面导入index.html中的head模块:

<div th:include="index::head"></div>

由此可见在Html层面上来讲,vue和后台的模板引擎,整个设计方向是一样。都是使用特定属性标签,来描述如何把数据映射到视图上。

Vue的页面定义基石-Options API

Options API,即大家常说的选项API,即以vue为后缀的文件,通过定义methodscomputedwatchdata等属性与方法,共同处理页面逻辑

可以看到Options代码编写方式,如果是组件状态,则写在data属性上,如果是方法,则写在methods属性上...

这种形式的页面定义类似一个配置文件,定义了页面的数据模型和行为

Vue中的代理运用

代理服务器:所谓代理服务器就是位于发起请求的客户端与原始服务器端之间的一台跳板服务器,是以正向代理可以隐藏客户端,反向代理可以隐藏原始服务器。

代理分为正向代理和反向代理,下面就以我们实际使用中的示例讲解下这两种代理方式的区别。

nginx反向代理

这样对于浏览器而言,浏览器只需要访问代理服务器,就可以达到同时访问两个网站的目的

 

我们看下实际场景下的nginx的配置 


  1. server {
  2. listen 4503;
  3. server_name vue.izkml.com;
  4. access_log "pipe:rollback logs/gov-manage-new-vue/access_log interval=1d baknum=7 maxsize=2G" main;
  5. # 接口代理
  6. location /api {
  7. #去除 /api前缀
  8. rewrite ^.+api/?(.*)$ /$1 break;
  9. # 转发到 117.71.53.199:50020端口上
  10. proxy_pass http://117.71.53.199:50020;
  11. proxy_buffering off;
  12. }
  13. # 页面文件代理
  14. location / {
  15. # 直接去本地文件读取文件路径
  16. root html/gov-task-supervison;
  17. index index.html index.htm;
  18. if (!-e $request_filename) {
  19. rewrite ^/(.*) /index.html last;
  20. break;
  21. }
  22. }
  23. }

其中可以看到,主要分为接口代理和页面代理两部分
1. 如果是/api前缀的请求,则去除/api前缀,转发到后台网关端口上
2. 其他情况下,请求的为页面内容,在html/gov-task-supervison文件夹中读取文件内容

vue代理(正向代理)

 


  1. devServer: { // 支持webPack-dev-server的所有选项
  2. port: 8888, // 端口号
  3. host: '0.0.0.0',
  4. https: false,
  5. open: true, //配置自动启动浏览器
  6. proxy: {
  7. '/api': {
  8. // 转发地址
  9. target: 'http://117.71.53.199:50020', //测试环境
  10. changeOrigin: true,
  11. ws: true,
  12. // 去除/api前缀
  13. pathRewrite: {
  14. '^/api': ''
  15. }
  16. }
  17. }
  18. }

这里主要看的是proxy字段,其中定义了规则

1. 如果是/api前缀的请求,则去除/api前缀,转发到后台网关端口上
2. 其他情况下,请求的为页面内容,直接读取本地项目路径下面的页面内容 **(隐式包含)**

Vue特性能力-filter

Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化

应用场景: 前端常量翻译


  1. <el-tag v-if="scope.row.status" class="round" size="small" >
  2. {{scope.row.status | CodeMaster('TASK_STATUS')}}
  3. </el-tag>

  1. Vue.filter('CodeMaster', function (value, type) {
  2. return Vue.prototype.$codeMaster.getCodeValue(type, value);
  3. })

在上面的代码中,我们在模板html中,添加了filter的调用,并传入了一个参数。
在vue进行html生成的过程中,会调用相应的filter,根据自定义的规则,完成文本格式化操作。




蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

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

JavaScript防抖与节流,深入浅出,一本正经讲透彻

前端达人

目录

一、函数防抖(debounce)

1. 什么是防抖?

二.、函数节流

2.1 定时器实现

2.2 时间戳实现

2.3 时间戳+定时器

最后 


一、函数防抖(debounce)

1. 什么是防抖?

函数防抖在频繁触发某一个事件时,一段时间内不再触发该事件后才会去调用对应的回调函数,在设定间隔时间内如果下一次事件被触发, 那么就重新开始定时器,直到事件触发结束。

规定时间内没有继续触发事件的前提下,再去调用事件处理函数;

具体如下面的例子所示:


  1. /*定义防抖函数
  2. * func:传入一个函数,事件不再持续触发时会调用该函数
  3. * delay:定义持续多久后执行传入的回调函数
  4. * */
  5. function debounce(func,delay) {
  6. let timer = null // 用于保存定时器
  7. return function (...args) {
  8. // 如果定时器存在,清除定时器,随后重新设置timer
  9. if(timer !== null) clearTimeout(timer)
  10. timer = setTimeout(func, delay) // 超过delay为接收到事件会调用这里的func 必要的额时候可以修改func的this指向 由于timer对外部存在引用,因此不会被销毁
  11. }
  12. }
  13. /*事件处理函数*/
  14. function testDeBounce(){
  15. console.log('你看我执行了几次??')
  16. }
  17. // 接收debounce返回的函数
  18. const temp = debounce(testDeBounce(),1000)
  19. /*绑定事件,测试防抖函数*/
  20. window.addEventListener('scroll',()=>{
  21. temp()
  22. }); // 这样写最少调用一次事件处理函数,最多也不会多余下面的写法执行的次数
  23. window.addEventListener('scroll', testDeBounce); // 如果这样写的话,每当页面滚动就会调用事件处理函数
  • 总结一下思路

    1.定义一个节流函数

    2.函数内部使用一个变量保存定时器

    3.返回一个函数,函数内部定义:如果定时器已经存在就清除定时器,重新设置定时器

    4.定义一个变量来接收debounce返回的函数

    5.在事件的回调函数中直接调用上一步的变量接收的方法


二.、函数节流

函数节流在事件持续触发的前提下,保证一定时间段内只调用一次事件处理函数,就是函数节流;

函数节流实现的方式定时器、时间戳、定时器+时间戳;

2.1 定时器实现

思路

1.定义节流函数throttle

2.定义timer保存定时器

3.返回一个函数。函数内部定义:如果定时器不存在,设置定时器,间隔某一时间后将timer设置为null,如果在这之前事件再次触发,则定时器中的回调无效

<button>这是一个孤独的按钮</button> 

  1. /*
  2. * 定义定时器节流函数
  3. * func:传入事件处理函数
  4. * delay:在delay指定的时间内定时器回调无效
  5. * */
  6. function throttle(func,delay) {
  7. let timer = null
  8. const context = this
  9. return function(...args){
  10. // 如果定时器不存在
  11. if(!timer){
  12. timer = setTimeout(()=>{
  13. func.apply(context,args) // 考虑返回的函数调用的环境,因此这里不直接使用this
  14. timer = null // delay之后清除定时器
  15. },delay)
  16. }
  17. }
  18. }
  19. function test() {
  20. console.log('啊啊啊!')
  21. }
  22. const temp = throttle(test,1000)
  23. document.querySelector('button').addEventListener('click',()=>{
  24. temp()
  25. })

2.2 时间戳实现


  1. var throttle = function(func, delay) {
  2. var prev = Date.now();
  3. return function() {
  4. var context = this;
  5. var args = arguments;
  6. var now = Date.now();
  7. if (now - prev >= delay) {
  8. func.apply(context, args);
  9. prev = Date.now();
  10. }
  11. }
  12. }
  13. function handle() {
  14. console.log(Math.random());
  15. }
  16. window.addEventListener('scroll', throttle(handle, 1000));

2.3 时间戳+定时器


  1. // 节流throttle代码(时间戳+定时器):
  2. var throttle = function(func, delay) {
  3. var timer = null;
  4. var startTime = Date.now();
  5. return function() {
  6. var curTime = Date.now();
  7. var remaining = delay - (curTime - startTime);
  8. var context = this;
  9. var args = arguments;
  10. clearTimeout(timer);
  11. if (remaining <= 0) {
  12. func.apply(context, args);
  13. startTime = Date.now();
  14. } else {
  15. timer = setTimeout(func, remaining);
  16. }
  17. }
  18. }
  19. function handle() {
  20. console.log(Math.random());
  21. }
  22. window.addEventListener('scroll', throttle(handle, 1000));

最后 

想跟博主交朋友的可以查找,公_号❤:前端老实人,跟博主一起探讨学习哦❤


蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

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

重新设计东南亚头部在线超市的真实案例

lanlanwork


I. 发现

客户访谈

由于这位甲方的合作态度良好,所以设计师有机会与 SESA 的创始人和产品经理进行了 2-3 次会议。

借此了解了业务目标、用户需求和技术限制等关键问题:

图片

主要问题:

  • 低转化率:杂乱的界面使用户很难浏览商品。
  • 手机端体验不友好:几乎 90% 的用户是通过手机访问网站,但手机版的设计不够理想。
  • 手机端糟糕的界面和体验:目前他们使用的是现有的网站模板,根据目标用户的反馈,缺乏优化而且加载速度很慢。

客户需求

  • 一键式购物
  • 轻松的界面和体验
  • 无缝的商品搜索
  • 折扣和优惠更容易被看到
  • 使用网站时能感觉熟悉而简便

成功指标

  • 增加客单价
  • 增强人们的对品牌的认知感
  • 增加用户和订单数量
  • 无缝的体验
  • 让健康的生活方式更加受欢迎、评价、容易取得,更加有趣而美好
  • 提供并教育用户健康的生活方式,并转化为愉快美好的生活

 

目标人群

根据产品团队提供的数据,整理出了目标人群的特征:

图片

 

II. 构思

人物角色

根据以上信息,整理出了两个完全不同的人物角色:

图片图片

 

故事版

没有区分人物角色的故事版:

图片

目标用户的故事版:

图片

 

体验地图

思考分析用户旅程的五个阶段(探索网站、比较商品、确认下单、完成购买和接收配送)和用户感知的三个方面(行为、思考和感知),制作了体验地图:

图片

将当中的关键信息挑选出来:

图片

 

竞品分析

设计师找到了三家主要竞品,先大概了解他们的特色和优势:

图片图片图片

然后从 Google Play 的评论中寻找竞品的问题,这样就可以思考如何战胜他们:

图片图片

P.S. 评论分析是一种简单有效的竞品分析利器(也可以用来分析自己的产品),具体方法我之前有分享过:别总想着数据分析/用户调研,先把评论分析做了吧!

 

III. 设计

信息导航

先把大致的用户流程确定下来,这样对整个产品就有了一个整体构思:

图片

 

线框图

然后用手画出线框图,定下页面的整体布局:

图片

 

低保真

将线框图手稿用绘图软件细化,制作成低保真方案,用来向客户展示和做用户测试:

图片

图片

 

IV. 完成

可用性测试

找用户做测试时,用的是低保真可交互原型。

根据测试发现的问题,设计师直接将优化方案运用到了高保真方案上,所以下面整理的问题都用高保真方案来配图展示:

  • 1. 自动定位:测试之前用户必须手动搜索位置。
  • 2. 属性选择:由于客户想要一键式购物,所以当用户点击熟悉(通常是重量)右侧的箭头时,可以反转卡片进行详细选择。

图片

  • 3. 促销展示:原本设计了三个促销区,但是测试中发现用户面对大量的信息无法充分理解,所以移除了一部分,只保留了头图和分类优惠。

  • 4. 商品导航:为了避免用户迷路,将商品分类导航放在了所有页面顶部,并且悬停时展示子分类和相关文章。

 

高保真

图片

 

响应式

这个网站需要具备很高的响应式能力,不论在 PC 端还是手机端,都能轻松使用。

但由于 PC 端和手机端的尺寸相差太大了,所以不得不使用断点(Breakpoint)来判断用户当前处在哪个端,并展示相应的界面。

这个断点的概念在栅格系统很常用到,指的是当界面尺寸缩小或增大到某个(或几个)零界点时,间距大小或其它界面元素发生突变。

图片

上图来源:三种最主流的响应式栅格

 

这个方案的对于移动端的特殊处理包括:

  • 确保商品分类的位置,方便用户记忆
  • 使用汉堡菜单
  • 提供模仿原生 APP 的吸底导航

图片

 

Before&After

最后对比一下优化前后的方案:

图片

图片
图片
图片

图片

 

原文地址:体验进阶(公众号)

作者:设计师ZoeYZ

转载请注明:学UI网》重新设计东南亚头部在线超市的真实案例

蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

截屏2021-05-13 上午11.41.03.png

分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

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




UI&UE实用方法论 | 一直被错用的米勒法则(7±2)

lanlanwork


因为「米勒法则」研究的是人类大脑的短期记忆量,而导航菜单、金刚区这些场景,是侧重用户识别,而不是侧重用户记忆。试想你作为用户的时候,你会去记导航菜单的名称吗,哪怕是短暂地记下来(就像我们记短信中的验证码,然后到另一个应用中输入的场景一样,短暂地记住)?我想大部分的人在这些场景中,应该都是所见所得、过眼云烟的吧。

并且“导航菜单的设计旨在用户识别而不是用户记忆”这个观点,在UX研究咨询公司 Nielsen Norman Group(NN/g 尼尔森诺曼集团)的“web可用性”一文中也有指出。

所以以上导航菜单、金刚区的案例,产品可能确实也是有在控制菜单项目的数量,但更多应该是出于对「希克定律」的考量,而不是「米勒法则」(我之前也有在《交互四策略实现希克定律》一文中说过:用户的决策能力会跟随选项数量的增长而降低,给用户非常多的选择,约等于没给用户选择)。

这些案例完全是强行反推,给套了个「米勒法则」的结论…实属不妥…那我就来谈谈,我对「米勒法则」的理解以及它在产品设计中的用途。

 

01、「米勒定律」在研究什么

米勒在1956年《心理学评论》刊中的《神奇的数字7±2:我们处理信息能力的一些限制(The Magical Number Seven, Plus or Minus Two: Some Limits on Our Capacity for Processing Information)》一文中,首次提出「米勒定律」。但该文只算是一篇阐述学术观点的文章,不算严格意义上的论文。

米勒在文中引用了实验者记忆变化音调的实验,发现人们在短时间内可以很好地记忆并复述5~6位的信息,随着收到的信息位数增多,记忆出错的概率也在不断增加。但因为实验者存在个体差异,最终的信息记忆量基本都能在该基础上再浮动2~3位。所以得出了“人的大脑在短期记忆中最多可以记住大约7±2个信息团”的结论。

但因为该实验与文章不属于正式的科研研究和论文,所以后来的科研学者又对“人类短期记忆上限”进行了更多的实验研究,最后形成了很多种学说。有坚持7±2的守旧派;有认为最佳短期记忆信息团为4±1的创新派;也有认为“人类的最佳短期记忆不应该被束缚于一个固定数值区间”的不站队派(确实 NN/g 尼尔森诺曼集团也说过,用户的短期记忆能力存在较大的个体差异,前25%的人群比尾部25%的人群会好大约2.4倍)。

但不论怎么说,这些实验都明确表明了:人的短期记忆存在上限,只是对具体能记住的信息团数量存在分歧。

基于这个结论,我们在设计产品时,该如何加以运用呢?

 

02、在人机交互中的运用

NN/g 尼尔森诺曼集团基于「米勒法则」,提出了以下几则设计指南参考:

  • · 响应时间必须足够快,以便用户在等待下一页加载时不会忘记他们正在做什么;(体验侧)
  • · 更改访问链接的颜色,以便用户不会忘记他们已经单击过哪里;(UI+交互侧)
  • · 不要让用户去记优惠券代码,而是该将优惠信息置入短信或邮件中的链接,通过链接自动将优惠券转移到用户的购物车中。这样可以让计算机承担记住晦涩代码的负担;(交互侧)
  • · 在用户可能需要帮助的场景显示“用户帮助”功能,这样他们就不必前往单独的帮助功能区去记步骤,然后再回来解决手头的问题。(交互侧)

你会发现,实际上专业团队对「米勒法则」的理解,基本都在于如何解决“人的短期记忆上限”问题,并没有去纠结,到底是7±2,还是4±1…

并且我在 NN/g 团队每一条设计指南的后面都标注了该条指南作用的侧重向,发现大多都体现在交互侧。因为「米勒法则」研究的是人的短期记忆极限,在视觉表现层其实很少会运用到。视觉更多强调的是“从识别到操作”,这并不是「米勒法则」的研究内容。

举一些切实的例子吧,基于「米勒法则」而诞生的产品交互中,我们最常接触到的就是移动设备自动获取短信验证码,方便用户一键填充;通过图像识别用户的银行卡号,减轻用户记忆负担。

这一类有关用户短时记忆的场景,为减轻用户记忆负担而诞生的交互形式,才是真正的基于「米勒法则」。

现在你明白了吗?因为「米勒法则」中提到了短时记忆极限量为7±2个信息团,让许多人都去关注数字了,而忽略了「米勒法则」到底在研究什么。然而这个数值,迄今为止,在科研领域依然还存在着分歧。

 

03、关于「米勒定律」的拓展与延伸

3.1 拆解与再组合  

米勒在他发表的文章中也提到了:虽然短时记忆存在上限,但是人们的大脑也总是在努力寻找其他方式拓宽这个极限,例如拆解与再组合。

在前面米勒让实验者记忆变化音调的实验中,就有人通过自主拆解、再组合信息形成信息团的形式,来增加自己最终记住的单位信息数。

基于此,前面图像识别用户的银行卡号的示例,如果因为技术受限而无法实现,我们也可以通过拆解卡号为“4位一个信息团”的方式,来方便用户记忆、输入与校验。这样在体验方面也是一种弥补。

 

3.2 让用户放弃记忆  

要将用户的记忆负担减轻到极限,那就干脆让用户放弃记忆。

例如苹果基于自己的云管理与密钥技术,在识别到用户在创建密码时,会自动填充强密码,强密码复杂混乱到很难被人脑记忆。

一方面加强了密码的安全性;另一方面,搭载其他技术手段来减轻用户的记忆负担,不再纠结于用户究竟能记住多少个、多少位的密码,直接将用户需要记忆的内容减轻至0,这也许才是真正基于「米勒定律」而创造出来的产品设计吧。

 

04、写在最后

其实这篇文章我认为更多是写给交互和体验设计师看的,如果你着手的功能有涉及到用户记忆的场景,不防可以参考一下这些减轻用户记忆负担的案例,还有NN/g的设计指南。

但好像现在「米勒定律」被很多UI设计师用成套路了…然而你发现了吗,文中「米勒定律」的案例,与视觉、与“7±2”很少存在关联。

如果文章开头导航菜单、金刚区的例子,你硬要说是参考了神奇数字7±2,我认为勉强也算行吧(嗯…勉强算)。

因为虽然我认为其设计理论更多是建立于「希克定律」之上的,但「希克定律」告诉我们要减少展示给用户的选项数量,却并没有给出一个建议值。如果你希望在某些场合给你的设计一些立足点(大家懂的),你如果说结合了「希克定律」与神奇数字7±2,我认为比直接说基于「米勒定律」要更内行一些。

 

原文地址:UCD耍家(公众号)

作者:Howiet

转载请注明:学UI网》UI&UE实用方法论 | 一直被错用的米勒法则(7±2)

蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

截屏2021-05-13 上午11.41.03.png

分享此文一切功德,皆悉回向给文章原作者及众读者.
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

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



v-for的键值key

前端达人

我们现在在使用v-for的时候、都必须会加上一个必要的key值,并且很多人会使用index来作为key,其实这样是不太妥当的一种做法。那么v-for中的键值key到底有什么作用呢。请看:

官方给出的解答

当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。这个类似 Vue 1.x 的 track-by="$index"。

这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。

为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key attribute:


  1. <div v-for="item in items" v-bind:key="item.id">
  2. <!-- 内容 -->
  3. </div>

建议尽可能在使用 v-for 时提供 key attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。

举例


  1. <div v-for="(item,index) in list" :key="index"> {{item.name}}</div>
  2. list: [
  3. {
  4. id: 1,
  5. name: "name1",
  6. },
  7. {
  8. id: 2,
  9. name: "name2",
  10. },
  11. {
  12. id: 3,
  13. name: "name3",
  14. }
  15. ]

这个场景如何我们不佳key vue 回直接报错,所以大部分人都会使用index作为key的值

如果我们在添加一个数据


  1. list: [
  2. {
  3. id: 1,
  4. name: "name1",
  5. },
  6. {
  7. id: 2,
  8. name: "name2",
  9. },
  10. {
  11. id: 3,
  12. name: "name3",
  13. },
  14. {
  15. id: 4,
  16. name: "last",
  17. },
  18. ]

此时前面3条数据直接服用之前的,新渲染最后一条数据,此时index作为key没有任何问题

如何我们在中间添加一条


  1. list: [
  2. {
  3. id: 1,
  4. name: "name1",
  5. },
  6. {
  7. id: 2,
  8. name: "name2",
  9. }, {
  10. id: 4,
  11. name: "last",
  12. },
  13. {
  14. id: 3,
  15. name: "name3",
  16. }
  17. ]

此时我们更新渲染的数据 通过index 定义key 进行数据对比一下

之前的数据:

中间插入之后的数据 :

由此可以发现除了第一条数据可以复用以为其余的3条数据都是需要重新渲染,因为key的值发生了变化。

这个时候就可以体现出一个效率的问题,只插入一条数据,却要从新渲染3条数据

所以我们需要可以想办法让数组中不会变化的数据的key值也不变,所以不能通过index来设置key值,应该设置一个唯一的id来标识数据的唯一性;我们修改之后再来对比一下渲染的效率:

之前的数据:

<div v-for="(item,index) in list" :key="item.id"> {{item.name}}</div>

中间插入之后的数据:

 对此对比发现,只有一条数据发生改变,因为其他数据的id 都没有变、所以对应的key也没有发生改变。我们只需要渲染这一条新的数据就可以。 所以一般推荐使用id作为key值配合v-for使用

总结:

Vue很大的一个特点就是双向数据绑定,数据一旦改变,那么页面就渲染新的数据呈现在页面上。但是对于用v-for渲染的列表数据来说,数据量可能一般很庞大,而且我们经常还要对这个数据进行一些增删改操作,而key的出现就是尽可能的回避这个问题,提高效率,如果我们给列表增加了一条数据,页面只渲染了这数据。




蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

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

JS数组去重的几种方法

前端达人

数组去重

1 双层for循环(类似冒泡排序的双层循环写法)

var arr = [2,3,4,2,34,21,1,12,3,4,1] for(var i =0;i<arr.length;i++){ //第一层:每次循环拿到arr中一个元素 for(var j=i+1;j<arr.length;j++){ //第二层:每次拿到的元素再和每次拿到的元素后边的元素依次进行比对(因为第一个要从第二个开始比,第二个要从第三个比以此类推,所以这里的j应比i大1为j=i+1) if(arr[i] === arr[j]){ //如果相同就删除后边的元素 arr.splice(j,1) } } } //arr:[1, 2, 3, 4, 12, 21, 34] 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2 循环和indexof、循环和includes

创建新数组,循环旧数组,看每次循环的元素是否存在于新数组中没有就把当前元素添加到新数组中

//indexof var arr = [2,3,4,2,34,21,1,12,3,4,1] var arr2 = [] arr.forEach((e)=>{ if(arr2.indexOf(e)==-1){ arr2.push(e) } }) console.log(arr2) //arr2:[1, 2, 3, 4, 12, 21, 34] 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
//includes var arr = [2,3,4,2,34,21,1,12,3,4,1] var arr2 = [] arr.forEach((e)=>{ if(!arr2.includes(e)){ arr2.push(e) } }) console.log(arr2) //arr2:[1, 2, 3, 4, 12, 21, 34] 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3 利用对象属性不能重复去重

var arr = [2,3,4,2,34,21,1,12,3,4,1] var obj = {}; arr.forEach((e,i)=>{ obj[arr[i]] = "abc"; }); var arr2=Object.keys(obj) console.log(arr2) //arr2:["1", "2", "3", "4", "12", "21", "34"] var arr3 = arr2.map(e => ~~e ) //arr3:[1, 2, 3, 4, 12, 21, 34] //注意这种方法不仅给数组重新排列而且还改变了数组中元素的类型 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

~是js里的按位取反操作符,~~就是执行两次按位取反,其实就是保持原值,但是注意虽然是原值,但是对布尔型变量执行这个操作,会转化成相应的数值型变量,也就是 ~~true === 1,~~false === 0。

4 ES6 Set

ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

var arr = [2,3,4,2,34,21,1,12,3,4,1] var arr1 = [...new Set(arr)] console.log(arr1) //arr1:[1, 2, 3, 4, 12, 21, 34] 
  • 1
  • 2
  • 3
  • 4

5 ES6 Array. prototype.filter()

注:indexOf在数组中找元素的时候,碰到符合条件的第一个就会把它的下标返回

var arr = [2,3,4,2,34,21,1,12,3,4,1] var arr2 = arr.filter((e,i)=>{ //看每次循环的元素在数组中出现的第一个下标位置(indexOf返回的位置),和每次循环的元素的下标(filter循环每次的i)是否一致,一致就说明他就是第一个符合条件,不会被过滤掉。 return arr.indexOf(e)==i; }) console.log(arr2) //arr2:[1, 2, 3, 4, 12, 21, 34] 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

6 ES6 Array. prototype.reduce()

var arr = [2,3,4,2,34,21,1,12,3,4,1] var arr2 = arr.reduce((pre,e)=>{ //这里当然也可以用indexOf来判断是否存在 pre.includes(e)?pre:pre.push(e); return pre },[]) console.log(arr2) //arr2:[1, 2, 3, 4, 12, 21, 34]

蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn 免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

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

日历

链接

个人资料

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

存档