首页

设计思维 - 激活空间

ui设计分享达人

42个设计思维中的一个知识点~


设计思维 - 激活空间





1.激活空间 - 概念


激活空间的意义在于元素与空间的搭配,能让页面产生灵动性和活力;另外激活空间还有一个影响比较难理解;
当主元素占用版面的主导位置,其他空间过大就会造成观众视线的停顿与停滞;
这样就会导致主体与次客体不会产生一定的关联性;
这时就需要“激活空间”来使两个元素有一定的联结;

undefined



2.空间的概念


在我们理解“激活空间”的概念之前,先来理解一下“空间”的概念。因为平面是一个二维的空间,是二维零曲率广延的一种面,因此我们在定义空间时不需要考虑三维的“第个三维度(一个方向的向量)”带来的影响,我们只要定义空间中的最小单位与空间的相对关系,和定义空间的边际就可以了。如下图所示,平面二维空间中x轴与y轴无限大,那空间也会随之变大。而三维空间中z轴的不断扩大,空间就会随之变大。


只有在有边际的空间中置入一个要素,即使这个要素是最小要素,空间也能被界定。例如一个正方块(一个要素),被放置到一个参照的方框中,这时小的空间就会被界定。如下图所示,二维平面和三维中坐标轴的范围就是界定后的空间,而坐标轴中具体的一个单位就相当于平面中的单一要素。当把要素放入一个有边际的空间中,这个空间就会被界定。


到这里我们只需要了解当我们定义空间中最小的单位,空间也就被界定下来了,理解这个概念就行了。这里的空间中最小的单位指的就是“元素”,而元素被设置好后空间就被界定了下来,这里元素的位置影响着空间,元素激活了部分空间,即激活空间。这了不理解也没有关系,我用简单的图来进行绘制,大家就能理解激活空间的概念了。



3.激活空间 - 理解部分


当我们在一个空间中置入一个元素(一个圆),这时我们就会发现这个元素占了一整个空间。这里如果不好理解就用生活中的例子举例,例如大家都站在自己家的卧室里,并且站在中心点也就是正中间,那这时候给人的感觉就是你占用的一整个卧室的感觉,也就是说整个卧室的空间就被你(视觉元素等于一个圆)所占据了。


接下来大家仔细看啊,如果当我移动一个元素(一个圆)的位置,大家感觉一下平面会有什么样的变化。是不是感觉上面有元素,但下面的空间有些空啊。这是因为只元素只激活了上面的空间,而下面就成了空白的空间。

undefined


接下来我再把平面中的这个元素,向左移动一些位置,大家注意看会有什么样的变化。是不是会发现,左面这一小块的空间被激活了,而右面和下面的一大块是空白的空间。


这时当我再分裂出一个相同的元素,并把这个元素向右移动,这时我们观察后会发现,上面一整块的空间都被激活了,而下面的一整块还是空白空间。并且两个元素之间产生了一定的关联性,它们看上去更像一个整体了。

undefined


接下来我再分裂出一个元素,并且把它的位置移动到最下方,这时我们观察就会发现下面的空间被这个元素激活了,但是中级的部分还是处于空白的,也就是空白空间。如下图这个状态呢,我其实可以延伸出另一个设计思维,那就是“把留白当做一种视觉元素”,但今天就不讲这么多了。这时我们再观察,三个元素所占的位置,是不是刚好能填满一个版面啊,那也就是说他们三个整合到一起,又占据了整个平面。



4.激活空间 - 实际案例1


如果讲到这理论讲的就差不多了,像细节部分大家通过类似的想法脑补一下就行了,接下来我们讲一下激活空间的设计思维如何应用到我们的实际设计当中。我们先来看一个设计作品,如下图所示,大家通过自己的思考,想一下这个作品哪里有问题?


这个作品的问题在于,蓝色标出的部分的视觉重量明显要比红色部分大,而且红色部分之间空白空间占的面积太大了,这样两个红色元素之间就缺少了一定的关联性,整体也会显得十分不协调,那要如何解决这个问题呢?


当我们把红色区域之间的空白空间,用其他元素把它激活,把这里的空间激活,那上下之间就能产生一定的关联。并且用一个有颜色的元素,这里的左右的视觉重量也达到了一定的平衡。



5.激活空间 - 实际案例2


再讲一个案例,咱们看一下第二个案例,我们直接看作品看看它都有啥问题?直接这么一瞅是不是标题的位置不太合适,似乎位置太高了,而下面的冰山看上去很不舒服,不知道哪里有问题,有没有这种感觉?


这个作品的问题在于冰山这块的视觉重量偏左,而且冰山的物理重量并不重,再加上企鹅在上面就会造成物理重量上的不平衡,从自然角度来看也不是很和谐;另外标题与冰山之间的留白太大了,这样就造成了视觉停滞,没有元素可看了,也没有办法引导视线了,也会造成观众对作品整体的影响与理解上的差异。


我们要怎么解决这个问题呢,冰山的物理重量不平衡,我们给右侧画一个企鹅,让它把右面的区域的空间激活,那整体的物理重量相对就平衡了;另外标题与下面元素的距离,可以通过设置新元素-太阳的方式,来使上下之间具有关联性。



6.激活空间 - 实际案例3


再讲一个案例,咱们看一下第三个案例。我们直接看作品看看它都有啥问题?看这个作品总感觉太碎片化了,整体性差没有统一感,而且也不规整并很混沌,元素之间的关联性也不强,有没有这种感觉?


这个作品最主要的原因就是留白产生的负形会对作品产生缺乏整体性的影响。因为这些空间看上去是开放的,没有约束的,零散的且没有统一感的,这时我们需要通过增加元素,利用激活空间的方法来布置它们,这样这些元素就具有了统一性,整体性也就会更强。

这样的整体感就强了一些有没有~

转自:站酷-罗耀_UI

耍好控件 | 拿什么拯救你?我的导航栏

ui设计分享达人

讲一个老东家的故事。


一次产品迭代会上,老板在台上讲到打算重构C端产品框架,想重整标签栏的标签设定。可在讲到这一部分的时候卡壳了,迟迟说不出“标签栏”这个控件名,气氛有那么一丁点尴尬。这时在座的一名产品经理慷慨解囊地说道:底部导航栏!会议得以继续。


嗯,不全错,这么说也算能理解。控件在界面底部,能引导用户切换页面。但如果标签栏把导航栏的名字占了...那原本的导航栏应该叫什么呢?顶部标题栏?那导航栏里的内容控件又应该叫什么?左上角或者右上角的按钮?


接地气的名称让我们一听就懂,直到有一天你打算跳槽,你拿着自己的作品到下家面试,设计总监几个术语啪啪把你问的不知所云。这些“死控件”、“死栏目”在页面上不可或缺,在设计每一个页面时你以为你对它们早已了如指掌,偏偏在关键时刻,它们却六亲不认了。(说多了都是泪,我曾经面试也吃过专业名词的亏,以后有机会再娓娓道来。)


“我又不走形式主义,为什么一定要说专用名词装x呢?接地气的名称不是挺好吗,沟通。”——很简单的道理,如果名词和概念都混淆不清,有没有花功夫在UI设计领域进行深度专研也就一目了然了,还何以谈论如何将它们运用自如呢?——“你连迪丽热妈和古力娜扎都没分清,你敢说你知道什么是真皮沙发?”


于是我的经历,让我产生了一个想法。是时候做一些知识内容沉淀与分享了,不能让更多的人走我踩过的坑。第一期我们便来讲一讲导航栏。


-


01.导航栏究竟在哪里


导航栏 Navigation Bar,也简称为Navbar。一定会有不少刚入门的UI新人,在诸多的Bar控件中,难以区分它所指代的区域。


在iOS上,导航栏是指显示在应用程序顶部,位于状态栏下方的容器区域,层级应高于当前页面内容。


在安卓上,Google公司在Material Design中也赋予了它同样的定义,但是却给了它另一个名称,顶部应用栏( Top App Bar)。


iOS与安卓的规范与命名区别


请务必要记住:导航栏是用于构架当前屏幕的内容,阐述当前屏幕的状态,并且起到连接父子级页面层次结构的作用。——所以回到开头的小故事,为什么标签栏不能叫做底部导航,因为标签栏是构架了多个屏幕之间平级页面的内容切换。和“导航”的定义没有半毛钱关系。


_


02.规范里告诉我们该怎么做 vs 实际项目我们该怎么做


一个基本的导航栏容器一般承载的信息可能会有:标题导航按钮内容控件按钮其他控件(比如搜索栏、分页标签或分页控件等);千万别忘了还有分割线


2.1 导航栏标题


时间倒退回2017年以前,这时候的移动端规范下的导航栏还是循规蹈矩的,样式单一。但随着iPhone X等一系列全面屏手机相继问世后,移动设备在屏幕高度上有了进一步的扩展,界面设计在一屏内的发挥空间也随之增加。iOS11发布后,大标题导航栏设计风格兴起,随后被引入平台规范。


于是现在iOS与Material Design在导航栏上也都定义了两种导航栏标题规范:常规标题大标题


常规标题是指在高度为88px(iOS@2x下)的导航容器中,居中放置一个当前页面的标题。标题字号一般为34px-38px(34px为iOS标准规范,但实际项目中可以在尽量在不小于34px标准的情况下根据设计需求确定)。


常规导航不同标题字号的案例及视觉效果


大标题是将导航栏栏高增加到192px(iOS@2x),保留高度为88px的导航容器来承载内容控件按钮,将标题下坠居左。iOS的标准规范定义大标题的字号为68px。但由于英文有大小写区分,在视觉上有一定的层次表现,而中文因为缺少一定的层次结构,并且相同字号的中文视觉大小大于英文,所以大多数时候我们在进行大标题设计时,会适当缩小,一般为56px-64px居多。


大标题不同标题字号的案例及视觉效果


大标题导航栏的优点毋庸置疑,页面留白更多,呼吸感更强,大气现代、逼格更高,因为页面标题巨大,能够帮助用户快速确认当前所处位置;采用统一的大标题,让页面布局风格快速统一。但缺点也显而易见,因为增加了导航栏的高度,导致屏幕利用率降低一些通过广告变现或更加注重一屏内内容呈现的应用便中和了常规导航与大标题导航的优缺点,进行了风格改进。


改进的大标题案例


那我们如何在常规标题和大标题之间抉择呢,这可不单单是设计风格的问题,还受产品定位与功能的影响。苹果的设计师在Apple Music中实验并验证了一条结论——在内容非常丰富、层级结构较深的产品当中,大标题能够帮用户快速确认自己的位置。


所以我理解的适合使用大标题风格的产品一定是:突出内容呈现而不是功能繁琐的;产品定位更偏向于现代或文艺艺术的;需要快速统一界面风格的。而层级结构需不需要很深,这并不一定,我反而觉得功能越单一、产品体量级越轻的应用,越适合大标题。


所以如此看来,国内使用大标题成功的案例就为数不多了,这可能与中文字体还有国内app产品功能都比较繁琐的原因有关,真正做到了使用大标题快速帮助用户确认自己位置,并且结合了产品特性与风格的,我认为人人都是产品经理的移动端在这方面做的非常棒。


 2.2 导航按钮及内容控件按钮


iOS规定导航按钮位置仅能用于放置返回按钮,可以添加一个层级的面包屑,帮助用户有效地明确当前页面层级;Material Design中,则不仅可以放置返回按钮,还另有作用,菜单图标-用于打开导航抽屉 或者 关闭图标-关闭工具栏。


iOS与安卓的导航按钮区域区别


这一点与iOS的定义有着天壤之别,iOS非常明确地赋予了工具栏的定义,并且将导航栏和工具栏(Toolbars)彻底地分离开,典型案例就是Safari。


iOS明确地将导航栏与工具栏分离开


在内容控件上iOS与Material Design也大相径庭,Material Design不去限制你的内容控件多少,因为它提供了溢出菜单,并可以根据屏宽的变化,自适应释出和收纳溢出菜单中的控件。



而iOS则规定我们,要给内容控件按钮足够多的空间,必要的时候,隐藏导航栏标题也未尝不可。



那么真实的项目中,我们经常为了快速落地,会存在一稿适配双平台的情况。这时候我们应该遵从哪一个平台的规范呢?答案是:许多大厂的做法已经向我们验证,规范不分家。


在iOS诸多的应用中溢出菜单早已普及,尽管这是Material Design提出的设计理念。



Material Design的溢出菜单也被运用在iOS端


虽然国内遵从Material Design进行Android应用设计的情况相对较少,但它提供的设计理念与方案却并不局限在安卓平台。


 2.3 分割线


分割线只是一种体现形式,我想要表达的是,别忘记区分导航栏与内容界面的视觉层级关系。Matetial Design提醒我们,顶部应用栏可以与内容位于同一高度,但滚动时,请增加导航栏的视觉高度,让内容在其后方滚动。而iOS则默认采用了背景模糊的方式区分了导航栏与内容区域的层级关系。


区分导航栏与内容区域的层级关系


缺少视觉分割会让用户分不清导航栏与内容界面,它们看起来会更像一个平级。对用户视觉区分内容主次其实是极不友好的。


 2.4 其他控件


关于其他控件,iOS只在规范中提及到了分页控件。苹果设计师考虑到部分场景在当前页面中还存在信息层级结构划分,此时建议可以在导航栏中使用分段控件。


但国内的应用程序早已将导航栏容器的作用发挥到,基于导航栏层级始终高于内容区域的特性,我们通常可以将分段控件、分页标签、搜索栏等等用户可能随时使用的工具放在导航栏中。


导航栏通常会承载的其他控件


-


03.总结


导航栏是几乎每一个界面都必定存在的控件,正因为无法轻易删减,逃不掉就必须用好它,不然很容易沦为页面的减分项。


设计好导航栏不仅仅是视觉上的工作,表现的方式、承载的按钮与组件、滚屏时的组合操作还能给用户带来极大的体验增益。

转自:站酷-UCD耍家 

好图片,设计过稿率提升50%

ui设计分享达人

如今我们的生活,到处都是大幅图像广告,纷扰喧闹的各类短视频与直播。这是一个快节奏时代,我们更倾向阅读图像。为什么我们偏爱图像视觉超过文字?从人类进化角度来看,原始时代的祖先通过五感感知着这个世界,其中通过视觉来感知判断生活,其他四感辅助之。即使后面我们发明了文字,但发展至今,对图像的本能吸引力依旧强烈。因为在我们认知的潜意识里图像相较于文字更能让我们快速轻松理解并记忆。


图像如此重要,设计作品中当然也必不可少。因为图片,它能一定程度上决定画面基调;引导视觉流程;调剂平衡多段文字信息的枯燥性,让阅读变得轻松容易。 


在UI设计中,我们经常需要把设计输出物拿给产品经理或者其他有设计决断力的人看,UI设计中图片使用的好与坏,能很大程度上影响着决策者的感知,以及你的设计过稿率。


如下左图:商品视角、调性、细节,都没有右图来的统一、有质感。单看这两张图,会让用户有这样的心理感知:左图感觉像山寨盗版商城;右图则会认为是严肃官方认证商城。所以,在同样页面布局下,不同的图片使用与处理,能让UI页面的品质有较大的感知差异。 

图片的使用如此重要。那么,我们在正式做UI设计前,首先需要弄清楚图片在页面的占比情况以及后续图片的支撑来源问题。



1.了解图片占比与来源


在构思UI页面阶段,首先需要了解以下两个问题:1.图片区域占比问题;2.图片来源问题。当页面图片占比多,且让用户自定义,那么需要预估到APP上线后设计可控率会降低。换句话说,实际上线效果会不尽人意。如下图:由于淘宝和网易严选平台属性不同,在图片品控上就有着不同的视觉感受。当然,不是说淘宝做的不好,而是当一个平台集纳不同的店铺,不同调性的产品类型,即使有图片规范,也难如统一品类、调性的产品来的统一。 

弄清图片内容的可控性问题后,开始进入设计环节,那么我们该如何选择图片?



2.怎样选择以及运用图片


1.是否符合产品气质?

在不同的场合有恰当合适的场景搭配,是十分基础且重要的事情。在UI设计中,任何一个部分的设计以及元素运用都需要为产品服务。图片也不例外。如果你是厨房类APP,头图选用小清新感的图片,就显得不够合适,带有环境食材元素的图片才更让用户有共鸣。 


2.是否能清晰表达产品核心内容?

图片是否主体明确?能一眼正确无误的传达核心内容?会不会因为其他元素元素抢了主体视觉,找不到视觉重点? 


3.是否美观、有品质、让人想拥有?

图片是否能表达美好生活以及美好品质的向往?光影关系是否自然?图片是否高清有细节? 

当明白图片如何选择后,还想和你分享一些冷门且重要的图片过稿小技巧。记下来,将大大提升你的设计过稿率。



3.过稿高手图片使用小技巧


1.图片风格统一风格调性

漂亮图片有很多,如果我们都以漂亮为基准,找出来的图片也会形色各异。由于用户的实际使用场景是:浏览一个完整APP,统一风格调性比美更重要。如果商品角度不一样;饱和度高低不同;抽象与具象等,都会形成产品不统一,用户视觉不适应等问题。 

2.图片使用符合场景,让决策者可以看到最后的显示效果

有时我们为了赶时间,直接用图片填充插件,让图片区域自动填充。但我还是想要给到你这样一个建议:一个专业且成熟的设计师,即使是设计初稿,也不能随便拿张图,凑合一下。任何时候的汇报,都需要有着处女座对于事物的完美要求,过自己这关。因为任何时候你的表达与表现,都形成了你在别人心目中专不专业的看法,从而影响着后续的设计话语权问题。如下图都是商城陈列页面,右侧的图片给出上线的实际效果,更贴合产品,方便设计决策者给出建议方向,或做出决策。 


总结


我们都是视觉动物,不管你是否愿意承认:我们常常通过视觉表象,才决定是否愿意去更深入的了解某个东西。

设计就是在做产品视觉表象的表达,我们需要尽可能使用贴切的,漂亮的图片。让UI视觉看起来更加美观,让用户愿意停留,认可以及信赖平台。 

转自:站酷-丘丘的设计笔记 

浅谈如何做产品的优化设计

ui设计分享达人

我把整体分为了三个部分

1.空洞的设计方法(因为大多数的人对设计的方法论都处在一个看了、学了、但是用不上的阶段,主要是讲在我分享的内容中可能会用到的一些设计理论和方法)

2.很一般的设计流程(这个优化设计的流程其实千千万,最重要的还是和真实的项目相结合,每一个点都值得拿出来写一个长篇大论,有机会具体来说说)

3.不成熟的实际应用(设计流程大多复杂而冗长,对于处在初创期或者发展期的产品来说,可能并没有那么长的时间线来实践,这一点也是我想和设计同行一起探讨的问题)

“奥卡姆剃刀原理”是设计师们耳熟能详的一个理论,即“如无必要,勿增实体”,在UI\UX设计中,我的理解是,如果能够在用户的行为路径上和交互方式做出优化,就不要增加新的功能。

这个理论会贯穿在整个产品设计流程中。

用户体验五要素,是我们在学生时代就会听到的一个理论,但其实对于五要素真的对应着什么,意味着什么,可能并没有一个确切的概念。

我说说我的理解:
这五个要素,从战略层到表现层,是一个从抽象到具象的过程,是一个易用产品背后必不可少的东西。

战略层:用户需求、产品目标——就是说在使用完这个产品之后,能不能很好的满足了用户的需求,达没达成做这个产品的目的。

范围层:在产品定位明确的情况下,我们要有什么样的功能和内容——具体需求

结构层:各页面、功能的联系,用户通过一个什么样的路径、什么样的层级关系完成一个流程

架构层:按钮、控件、图片、文本区域的布局,用户对页面的整体感知

表现层:长什么样,颜色啊、风格啊等等)


所谓KANO模型,它和接下来要说的消极选择、NUF评估筛选都可以理解成为一个需求筛选的方法,他们都能够帮助设计师在众多需求当中,找到最合适和最合理的那个。

KANO模型中,我们可以把需求或者说创意点分成5个属性

1.魅力/惊喜属性
用户意想不到,如果没有这个功能用户可能感知不到,但是做了这个功能,用户会非常惊喜和满意。(我们有没有这样的功能?首页tab bar动效)

2.期望/期待属性
做了这个功能,用户满意度会提升,否则反之,会降低

3.必备/必要属性
一个产品的有效性功能,最基本的功能。如果做了用户满意度不会提升,觉得理所当然,但是如果没有,满意度会大幅下降。

4.无差异因素
做和不做对用户的影响并不大,用户也不太在意。

5.反相/错误因素
你不做还好,一旦做了用户反而会反感,降低满意度。

对于一个产品,最重要的即是必要属性和期望属性。



消极选择其实是我们在生活当中也用得到的筛选方法,简单来说就是:当我们想到的两个idea都能用来解决一个问题,那么我们要选这两个当中实现成本低的那个或者说“性价比”最高的那个。


NUF评估筛选相比前两种方法,就显得稍微繁复一点,用起来可能并不如前两种方法更容易。
它其实是,在新颖、使用、可行三个维度,对我们要筛选的点进行打分,再根据分值进行筛选。
用起来其实比较消耗时间。



我把这一部分分成了4个步骤,分别是:桌面研究,用户研究、概念提炼、设计方案



产品深度使用,提问并分析(比如素养课页面,有多少卡片类型,有多少内容分类?哪些课程点击率比较高,为什么?等等)-同类产品分析-用户体验诊断,舒适体验和不是体验-确定设计方向,产品定位、改版(优化)目的、用户群体、价值点)(确定大致设计方向,提出假设,如:经过我们上述的研究和分析,发现丰富、高质量的内容和清晰的布局,能够让用户有浏览和互动欲望,从而达到转化目的



我们一般通过定量问卷和定性访谈来从用户那里获得想要的信息点以得出用户画像和验证我们前期的假设



在做访谈之前,要明确的就是我们要得到什么,或者说我们要访谈用户的哪些方面
即:用户习惯的研究、用户行为模式的研究、用户行为动机的研究



在设置问题时,要明确每个问题的背后我们关注的点在哪里,不可能在不相干问题中浪费时间。



通过前面的两个阶段,我们已经可以得到很多东西了:完整清晰的用户画像、同理心地图、As is 旅程图。我们通过这些东西,找到我们可以优化、可以提升用户体验的地方,即机会点,然后利用我们之前提到的筛选方法,进行创意决策。


(同理心地图)

(As is 旅程图 来自:池喜太厚)

通过前面完整的研究和决策,在此阶段,得出交互设计方案、UI设计方案等等



这一部分是我想和大家探讨的,前面所说的设计流程,多数时候在实际工作当中应用起来并不容易,这也是很多设计师对设计方法嗤之以鼻的原因,觉得设计方法都是玄学,胡说胡有理,这里我也说说我的一些思考。

在我们日常的工作当中要把上述的所有流程都走到,所有设计方法都应用,显然是不现实的。而且,在产品的不同阶段,优化和迭代的驱动力是不同的。在初创和成长阶段,一般为问题驱动,在成熟期,一般为价值驱动。

也就是说,平时的工作可能是一个,发现问题到解决问题的过程,我们需要把成熟的方法和流程进行拆分,进行小部分流程的应用,这样也能够让我们得出一个合理的设计方案。

转自:站酷-鹿爷不是咸鱼

交互设计:如何做到惊喜?

ui设计分享达人

保持好奇,巧妙融合,追求卓越,自然而然


上一篇,探讨了如何做到品质。这一篇,探讨下如何做到惊喜。

一家之言,未必全面,甚至未必正确。欢迎交流探讨。


01
交互设计的惊喜,是什么?

之前的文章,有简单定义过交互设计的“惊喜”,即为:超出用户预期,并让用户开心。

具体而言有两类,分别是:小惊喜、大惊喜。

1 小惊喜

所谓小惊喜,是指一些颇具趣味性或人文属性的交互设计小细节。


先说趣味性。常见的有两类,第一类是比较好玩的动效,第二类是一些小功能。第二类有时也会包含第一类。

动效这块,大家比较熟悉的,有 iPhone 上删除应用前图标的抖动,仿佛是吓的发抖,也可能是在摇头求饶;还有移动端登录 B 站、输入密码时,动画人物的捂眼捂脸动作。

(B 站登录页面)

小功能这块,也可以分成两类。一类是隐藏的小功能,一类是有趣的小功能


很多隐藏功能,头几次用的时候,多少会有一些惊喜之感。

比如在订阅号消息列表页,某个公众号你已经几个月没看过,对它失去了兴趣和信任。这时,尝试长按这个公众号的头像或名称,会呼出一个包含“删除消息”和“取关”功能的弹窗。

(订阅号消息列表)

还有些隐藏功能,既能让用户觉得惊喜和方便,又能引发用户思考。这种思考,可能会让用户感叹设计之妙,也可能也会给用户一种猜对谜语的欣喜之感。

比如用墨刀的时候,尝试按数字键 1,会呼出“内置组件”这个使用频率非常高的功能,会让人觉得墨刀很聪明。

如果再仔细看一下,会发现,“内置组件”的缩略图标,和其他 4 个诸如“我的组件”、“图标”等功能的缩略图标,并成一列。这 5 个缩略图标的排列顺序(上到下),和它们快捷键("、"键和数字键1、2、3、4)的排列顺序(左到右),是完全一致的。不得不说,这是一个简单又巧妙的设计。


再比如朋友圈里,某个不熟的好友每天都发集赞的小广告,搞的我们不胜其烦。长按其头像,会呼出设置权限(屏蔽等)的功能。

有意思的是,长按好友名字,则不会呼出这个功能。要知道点击头像或名字是都能进入好友主页的;另外刚才那个例子,长按公众号头像或名字,也都能呼出取关的弹窗。

个人的理解,生活中,我们用力长按一个人,通常是表达强烈不满,比如打架时。比起长按名字,长按头像更像是长按真人,所以也更能表达我们的不满。


说完隐藏的小功能,再说下有趣的小功能。比如微信聊天里的扔骰子、石头剪刀布,微信给朋友发生日快乐后漫天飘落的蛋糕,拍照软件里的贴纸,等等。

最后说下带有人文属性的交互设计小细节。常见的有如下类型:帮助弱势、关照情绪、表达情感、保护隐私。


帮助弱势这块,比如 iPhone 的辅助功能,里面有针对视力障碍的放大镜功能、有针对不识字群体的旁白功能。

关照情绪这块,很重要的一点,就是避免引起用户的负面情绪。比如微信的删好友是单方面删除,被删时我们很难察觉到,而且微信也不会通知我们。个人觉得,微信之所以不通知我们,其中一点,就是不给我们添堵。类似的还有,微信消息没有“已读”功能,这就大大减轻了接收者的回复压力。

表达情感这块,比较为人所知的例子,5 月 20 号这天,微信红包的限额,从 200 元升到了 520 元。还有一个例子,在微信聊天里发一个“ohh”,长按并点翻译,结果也是一个惊喜。

保护隐私这块,比如借助 iPhone 的“引导式访问”功能,可以让小朋友只能访问你的某个视频应用来看动画片。再比如别人用你电脑的时候,如果你不想让对方看到你的微信,就可以通过手机微信来锁定或退出电脑版微信。

2 大惊喜

所谓大惊喜,是指那些系统性大创新,并且能够引领潮流、代表未来的交互设计。通常而言,这些大惊喜,最开始给用户的感觉,就是酷。

iPhone 就是典型例子之一 。

2007 年的初代 iPhone,带来了当时的大屏幕:3.5 寸屏幕,以及纯触摸屏,和极为灵敏的触控体验。

2011 年,Siri 同 iPhone 4S 一起问世,为我们带来了语音交互。如今,在 100 元就能买到品牌类智能音响的情况下,依靠语音交互的智能音响也在慢慢走入寻常百姓家。

也许后乔布斯时代的 iPhone 创新不如以前,但不可否认的是,时至今日,iPhone 依然在引领潮流,在给我们大惊喜。比如这几年流行的手机无线充电和以 AirPods 为代表的极简的无线耳机。

以上是比较广为人知的交互设计,还有一些不太为人所知的设计。比如在家里网购一条床单,但是不知道床的尺寸,家里又没有尺子。这时,打开 iPhone 里的测距仪这款 App,就可以量出床的尺寸,会不会觉得有点酷。

(测距仪 App)

微信在引领潮流方面也有一些建树,比如极大的普及了二维码和扫一扫。小程序作为一种体验接近原生 App、同时又不用下载的产品,也正在引领新一轮的潮流。

还有一个比较酷的功能,就是以图搜图。笔者最早用过百度和谷歌的相关功能,主要是在电脑上搜索相似的图片,使用频率极低。

假设一个场景,比如在路上看到一个陌生人的外套很好看,但又不好意思上前问,就可以拿起手机,利用淘宝的拍立淘功能,拍张照就能马上看到相同或相似的商品。

如果淘宝上没有搜到类似商品,还可以用微信的扫一扫识物。和拍立淘相比,区别之处有两点。第一,不用拍,直接能识别,不过通常得等 1-3 秒;第二,识物结果里面,除了商品,可能还会有百科词条和资讯。


02
交互设计:如何做到惊喜?

个人觉得,有 4 个要点:既要有好奇心,又要有卓越心;既要天马行空,又要保持自然。

听起来可能有点乱,且听笔者一一道来。


1 保持好奇心

笔者观察身边读小学的小孩,发现,当大人聊天时,特别是谈正事时,小孩特别喜欢坐在旁边听,而且听的很认真。小孩有时也会说两句,或是问问题,或是发表自己的看法。

看得出来,小孩对成年人的世界,怀有极大的好奇心。实际上,不止于成年人的世界,小孩对周遭世界都有比较强烈的好奇心。

整体而言,成年人对周遭世界的好奇心,远不如小孩。我们互联网从业者也不例外。

好奇心和交互设计,有什么关系?

交互设计,某种程度上,也是一种创作。好的创作,一定来自生活。这就需要我们去观察生活。

观察生活,非常重要的一点,就是好奇心,对周遭人、事、物要有足够的好奇心。

比如上文提到的例子,在 iPhone 上删除应用前,应用图标会抖。这种抖是一种趣味隐喻,既可以理解成吓的发抖,也可以理解成摇头求生。如果对生活没有足够的好奇心,是很难留意到这种生活细节,并把它们作为一种隐喻运用到交互设计中的。

以上是关于好奇心,还有一种特质,也是在小孩身上表现突出,同时也和本文主题有关,那就是:童趣。

还是上文的例子,在 B 站 App 上输入登录密码时,动画人物会捂眼睛。这个设计,可能不会打动所有用户,但至少一部分用户会觉得比较有趣。如果我们内心没有一点童趣,可能也会觉得,这个设计,没啥意思。

玩是人的天性。对于比较好玩的交互设计,大部分人是比较容易产生共鸣的。实际上,据笔者观察,我们大部分从业者是有童趣的。我们比较缺的,是好奇心。

那么,怎样判断自己是否拥有足够的好奇心,其标志是什么?

个人观点,有两个标志。第一,是对与个人利益无关的生活小事的关注,远多于对个人利益本身的关注。第二,观察和思考,远多于评价和自大;追本和溯源,远多于偏见和傲慢。

为什么会提到个人利益?

因为,通常而言,个人利益,尤其是短期利益(比如少花时间设计和修改原型),往往会和用户体验存在一个此消彼长的关系。

如果过于关注个人利益,不仅很难照顾到用户体验,甚至会伤害用户体验。至于给用户带来惊喜,就更无从谈起了。

回到现实当中。在时代洪流面前,好奇心的两个标志,显得很难,该如何实现?

关键在于找到背后的源动力。这个源动力,在笔者看来,有两点,分别是:求知若渴、淡泊宁静。


求知若渴,可以源源不断的驱动我们去观察、去思考万事万物的规律和联系。

淡泊宁静,正如诸葛亮在《诫子书》中所说,“非淡泊无以明志,非宁静无以致远”。人的心力和精力终归是有限的,如果我们沉迷名利、物欲、享乐,就难有兴趣和精力去琢磨万事万物了。

所以,只要找回自己童年的那种求知若渴,同时修身养性到淡泊宁静,这份好奇心,就会回来。

2 巧妙融合

某种程度上,很多带给我们惊喜的交互设计,都是一种巧妙融合。

笔者把这种巧妙融合,初步分成了三类,分别是:简单融合、直接融合、委婉融合


简单融合,最常见的就是隐藏功能。把一个较为简单的操作动作,比如长按、双击、下拉、左滑等,和一个合适的功能,融合在一起。用电脑时我们常说的快捷键,也属于这一类。

通常而言,操作对应什么功能,讲究的是合适,并无固定章法束缚。比如在微信朋友圈,发表文字的功能可以靠长按(相机图标)唤起,设置权限的功能也可以靠长按(好友头像)唤起。所以,简单融合这块,可供我们发挥的空间很大。

另外,简单融合最常见的形式——隐藏功能,既实现了界面的简洁,又带来了一定惊喜。

简单融合,既简单,又实用。建议大家充分开发这一块。

直接融合,是指将生活中的趣味性,直接搬到软件中,搬到交互设计中。比如微信聊天中的扔骰子、石头剪刀布,以及漂流瓶、抽奖等。

这一类融合,有点像商场里的电玩城,虽然我们不会经常去玩,但确实比较好玩。

委婉融合,是指用明喻或隐喻的手法,将生活中微不足道的一些细节,移植到交互设计中。

这种移植,有时是直白的。比如 Mac 上打开应用时,其图标会在 dock 栏里有规律的弹跳,这会让我们联想到皮球的弹跳。

这种移植,有时是隐晦的。比如 iPhone 上删除应用前,其图标会抖。这种抖,是害怕还是求饶,任凭我们想象。

这种移植,有时是无声的。比如在朋友圈,要想呼出隐藏的设置权限功能,只能长按头像,长按名字则不行。这个设计,不乏想象空间。如果不尝试长按名字,则不会发现这个细节。

委婉融合,有时会带一些趣味性。更为重要的是,它能够引发我们的思考和想象,所以是一种很出彩的融合。这种融合,也会赋予交互设计,一种禅的味道。

整体而言,笔者非常推荐委婉融合。

3 追求卓越

如果目标是小惊喜,则保持好奇心、并做到巧妙融合,基本足矣。

如果目标是大惊喜,则需要雄心壮志,需要舍我其谁,需要追求卓越。

日常工作中,可能会有这样的对话。“这个动效/功能,实现不了”。

大惊喜里的几个例子,比如初代 iPhone 的触控体验,iPhone 里的测距仪,微信的扫一扫识物。这种设计,意味着要修一条最好的长城,背后往往有很多技术难题要攻克,有很多脏活累活要做。

如果团队文化就是做出最优秀的交互设计,那么,“实现不了”这句话,估计就听不到了。取而代之的,可能是:“还在研究中”,“下个大版本能上”。

4 自然而然

提到惊喜,还有一款值得研究和学习的产品,那就是锤子手机的 Smartisan OS。

个人观点,在小惊喜方面,Smartisan OS 颇有建树。在大惊喜方面,Smartisan OS 也进行了一些值得学习的探索。

先说小惊喜,比如华丽而细腻的桌面翻页动画,比如四指横划桌面可以切换桌面背景。还有一些贴心的小功能,比如静音可以设置时间,比如方便的长截屏。

(静音可设置时间)

(长截屏)

再说大惊喜。2016 年 10 月发布的一步和大爆炸,是比较大比较系统的功能,在当时也很新。锤子公司也一直有宣传这两个功能。所以相对而言,这两个功能是 Smartisan OS 的大惊喜。

笔者的备用机是锤子手机,身边也有朋友在用锤子手机。以一步为例,这个功能,笔者体验过很多次。但平常很少用,身边朋友的情况也类似。

(一步)

根据使用情况和主观感受,个人觉得,一步这个大惊喜,还存在进步空间,主要有两个方面。

第一,宏观层面。一步作为新生事物,好比一颗新种子。种子破土而出时,是一颗嫩芽,而不是一棵大树。新生的一步功能繁多,犹如一棵破土而出的大树,一方面有违自然规律,另一面因为功能繁多,很多用户无法一下子看懂,看不懂可能就不想用了。

第二,微观层面。一步这棵新大树,结了很多不同的果子,比如拖拽图片到其他应用、切换后台应用、展示最近图片/文件等。这些果子,是用户真正需要的吗?这个是要存疑的。

比如拖拽图片到朋友圈就能发朋友圈这个设计。通常而言,我们发到朋友圈的图片都是精挑细选的,会占用一定量的时间,比如旅游或聚会结束后发的照片。一步解决的是效率问题。发朋友圈的时候,少点几下这种效率问题,优先级是比较靠后的,我们没那么在乎。

还有拖拽图片/文件这个交互动作,大家通常在电脑上用的比较多,在手机上是没有这个习惯的,实际上应用场景也少。在手机上,大家一般只习惯拖拽应用图标。

还有切换后台应用这块,大家第一个想到的,一定是系统自带的,已经用惯了。而且唤起速度比一步快,点击面积也比一步大。

总的来说,微观层面上,比较缺让大家能马上想到一步的功能点。

最后,总结一下。对于领先时代、引领潮流的交互设计,需要做到自然。

具体而言,就是,大惊喜是一种系统性的大功能,好比一棵大树。这棵大树,最好有一个从种子到果子的生长过程,这样最自然,生命力也会最旺盛。

因为,从破土而出的嫩芽阶段,就可以通过用户反馈和数据来检验,这种嫩芽,是不是真的对用户有价值。如果价值不大或没有价值,还可以再调整。如果长成大树结满果子,再去调整,就很难了。


结语

交互设计小细节,如果有一定的趣味性或人文属性,则是小惊喜。

系统性工程的交互设计,如果最初感觉很酷,而且能引领潮流、代表未来,则是大惊喜。

始终保持孩童身上那种非功利的好奇心,用心观察并思考生活中的小事;

将生活小事和交互设计巧妙融合起来;

以上两点,可以帮我们做出小惊喜类的交互设计。

追求卓越,独立思考,做最酷最好的交互设计;

酷是结果也好,是目标也好,都不是最重要的。最重要的是,避免刻意和心切。酝酿大惊喜,犹如培养一个新生的孩子,需要投入极大耐心和精力,需要让孩子自然成长。没有家长会教半岁的孩子唱歌、把 3 岁的孩子送到高中念书。

再加上以上两点,可以帮我们做出大惊喜类的交互设计。

最后,用爱因斯坦的一句话来共勉。

想象力比知识更重要。
转自:站酷-SnowDesign 

汽车行业的UX启发-车载HMI的经验法则

ui设计分享达人




在网上找UX汽车相关的材料和文章是相当困难的。(学习君说:表示相当赞同:( )尽管有关移动和台式设备UX的信息太多,但要获得关于HMI(人机交互)原理的见识似乎要困难得多。为什么?


我的回答是,与为手持设备和计算机进行设计相比,这可能是一门利基学科,再加上汽车屏幕出现的时间不长。当然,车辆上的用户体验不仅仅是屏幕,只有旋钮和物理按钮时已经是用户体验了,但是在这种知识上也没有太多分享。



没有标准


但是,主要原因可能是缺乏标准化。如果您现在看一下市场,您会发现有太多不同的方法和解决方案(满足相同的需求),很难提出一套共享的规则。屏幕可以是横向或纵向屏幕,可以是直角或倾斜角度,可以是一个或2个或3个或更多,超宽或更大的正方形,仪表板上的高度或膝盖以下的高度,等等。与这种混乱相比,我们在手机上拥有的屏幕尺寸数量似乎是在开玩笑。



严格测试


另一个原因是所有车载系统都需要非常全面的测试。用户在可能致命的情况下与这些对象进行交互。因此,测试必须绝对优先。搞砸移动应用程序上的按钮的位置或大小可能会带来麻烦,但在汽车操作系统上这样做(我不是说“信息娱乐”,因为在这一点上,它是一个简化的术语)会造成生命损失。上面提到的缺乏标准化使得很难将先前测试的结果用于其他系统并在其他系统上重用。


但尽管如此,仍然存在一个人为因素组件,它使我们可以定义一组经验法则(或启发法)。这并不意味着他们可以跳过测试,但这是对所有对这个不断发展的行业感到好奇的UX设计人员(包括UI人员)的一些通用原则。



1.首选暗模式


各种研究表明,黑暗的UI在汽车环境中是最安全的选择。深色界面可减少干扰和眩光,但是,存在一个组件,从暗模式切换为亮模式可能有助于提高可读性,这就是导航图。在几乎所有导航系统中,地图都会自动从暗切换为亮,反之亦然。



Android Auto 



2.短文本,无段落


文字应略读,因此所有的号召性用语,菜单和所有文字通常都应保持最少。除非是在不运动的情况下阅读的文本,否则任何文本都不应排在两行或更多行上。



3.最小字体


眼睛到中央显示器的平均距离约为60厘米/ 24英寸。该数字只是根据市场上最常见的配置进行的平均测量,但是同样,由于没有适当的标准,因此该距离可能会有很大差异。


假定此措施为有效基准,则在运动情况下字体的最小尺寸为5.3 / 6毫米(不同的研究表明最佳做法略有不同)。考虑到1mm为6.299 dp(@ 160dpi),则文本应为34/38像素高,用于应该在行驶时读取的文本。



4.减少号召性用语


应该只有一个主要动作,而第二个动作则尽可能少。同样,我们希望用户快速浏览并一眼就能找到所需的内容。


(美国)美国国家公路交通安全管理局(NHTSA)指南指出,驾驶员应该能够在1.5秒的一系列扫视中完成一项任务,并且花在离开道路上的累积时间不超过12秒。



Apple CarPlay — phone call: 1 primary CTA 




5.导航,媒体和通话是主要功能


自从诞生以来,车载操作系统已超越了信息娱乐功能。通过镜像智能手机甚至系统内部的镜像,我们可以访问多种功能,例如消息传递,日历和提醒,流视频等等。但是,用户在使用这些系统时要寻找的主要功能是3:


  • 音乐/播客/有声读物

  • 导航

  • 拨打/接听电话


这三个主要功能在驾驶时应该比其他功能更醒目且易于使用。



6.文字上方的图标,但必须明显


图标优于文本标签,但图标的含义必须绝对清楚,不能解释误解。图标标签的字体大小可以小于第3点指示的最小字体大小。




Porsche Panamera UI 




7.高对比度


驾驶情况下的理想对比度至少应为7:1,因此绝大多数系统都将白色(或浅灰色)变成黑色(或深灰色)。

对于行驶中未使用/读取的组件,最小值应为4.5:1。



8.首选手势


旋钮和物理按钮的性能仍然优于GUI组件,这是由于其具有肌肉内存映射功能,触摸屏上的可视元素要求驾驶员每次查看屏幕。但是,数字接口的灵活性毋庸置疑,世界正在朝这个方向发展。尽管大多数(如果不是全部)现代触摸屏都支持各种类型的交互,例如您的常规平板电脑,但由于易于执行,因此它们是首选的:


  • 单点

  • 向左/向右/向上/向下滑动

  • 滚动(带有捕捉)


应避免使用其他更复杂的手势,例如触摸和按住,双击,捏合,多点触摸手势,或者在非运动情况下使用。

关于滚动的注意事项:在列表或卡片上自由滚动不是理想的选择。垂直和水平滚动动作均应具有捕捉效果,以始终将滚动项锁定在同一位置



Scroll with snapping on the left, free on the right 



非接触手势是许多OEM尝试的新事物。目前,这项技术似乎还远远不够完美,但是除此之外,在这种情况下使用的手势通常并没有真正令人难忘和自然。



9.语音不一定是所有互动的解决方案


虽然语音控制似乎是理想的选择,但根据研究,在某些情况下,精神工作量可能会超出预期。在VUI并不是真正的“对话式”的较早系统上,情况更是如此,诸如Google Assistant或Siri之类的现代助手对信息较长的字符串的理解程度更高,从而减少了用语表达命令的精力。


但是,我们应该考虑不能选择说话的情况,例如,当婴儿在后座上睡觉或某人有言语障碍时,并提供一种安全,可视/触觉的方式来执行所有动作。



10.考虑屏幕的可达性和可读性


与移动设备甚至与带有台式计算机和椅子的办公室设置不同,在汽车中,座椅相对于屏幕呈固定角度,屏幕也固定在适当的位置。因此,必须考虑屏幕的可达性及其可读性。考虑到左侧的驾驶员,屏幕右侧的元素将导致可读性和可访问性降低(当然,在方向盘位于右侧的汽车中会发生相反的情况)。





11.使用明确的能力


避免使用重影按钮,辅助功能应非常清晰可见。主要行动和次要行动均应清晰可辨



Tesla Model 3 UI 



12.安全性和可用性在美观性之前


当然,这也不意味着丑陋(不幸的是,那里有一些丑陋的车载体验)。但是,在为车载屏幕设计时,您必须考虑告别微妙的色调,细腻的对比度,笔触细腻的图标,浅色字体,细小的文字……


极简主义受到欢迎,但它是由更少的可见组件组成的极简主义




正如本文开头所述,这些原则只是经验法则,不能以任何方式跳过严格的测试。但是,如果您是第一次使用智能手机和计算机的UX来接触汽车的HMI,那么这可能是您开始着手涉足这一复杂学科的起点。


转自:站酷-NickM 

利用键盘控制小方块的移动

前端达人

原理

  1. 利用键盘控制移动,则需要了解onkeydown函数,表示某个按键被按下,可以以此绑定一个事件响应函数,当键盘被按下时候,触发此事件,进行移动
  2. keyCode 对于keypress 事件,该属性声明了被敲击的键生成的 Unicode 字符码。对于 keydown 和 keyup 事件,它指定了被敲击的键的虚拟键盘码。虚拟键盘码可能和使用的键盘的布局相关。 因此我们可以根据keycode返回的字符码来判断用户所按下的键,下面就是一个用于测试上下左右按键的js代码,经过我的测试之后,返回37 38 39 40;

    window.onload = function(){
                var box = document.getElementById("box");
                document.onkeydown = function(event){
                    event = event || window.event;
                    console.log(event.keyCode);
                }           
            };
    3



    3.方块的移动实际上就是坐标的改变,因此需要offsetLeft 和offsetTop 来获得当前方块的坐标,然后将坐标进行一定的更改,就可以实现移动的效果了,下面给出代码

    window.onload = function() {
                document.onkeydown = function(event) {
                    event = event || window.event;
                    //设置移动速度
                    var speed = 10;
                    //当ctrl和方向按键同时按下时,提升移动速度
                    if(event.ctrlKey) {
                        speed = 50;
                    }
                    //获取div
                    var box01 = document.getElementById("box01");
                    switch(event.keyCode) {
                        /*keyCode返回按下按键的编码
                         * 37 向左
                         * 38向上
                         * 39向右
                         * 40向下
                         */
                        case 37:
                            box01.style.left = box01.offsetLeft - speed + "px";
                            break;
                        case 39:
                            box01.style.left = box01.offsetLeft + speed + "px";
                            break;
                        case 38:
                            box01.style.top = box01.offsetTop - speed + "px";
                            break;
                        case 40:
                            box01.style.top = box01.offsetTop + speed + "px";
                            break;
    
                    }
                };
    
            };
    



    这样就可以简单实现方块的移动,但是此时我们会发现一个问题,当我们进行移动的时候,按住按键不松手,理论上方块应该直接平滑的进行移动,但实际上并非如此,第一下它会有一个小的停顿,这实际上是浏览器防止误触所设置的,因此我们需要对此进行优化
    解决方案

    这里我采用了定时器的做法来解决这个问题,因为控制移动的因素有两个,一个是控制方向,一个是控制速度,控制方向没有问题,因此我们需要改变速度
    setInterval(function(){},time);这是一个定时器,我们只需要在time时间内调用一次函数,就可以解决停顿的问题了
    下面附上修改后的完整代码


    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            #box01 {
                width: 100px;
                height: 100px;
                background-color: #008000;
                position: absolute;
            }
        </style>
        <script type="text/javascript">
            window.onload = function() {
    
                //获取div
                var box01 = document.getElementById("box01");
                //设置移动速度
                var speed = 10;
                //设置移动的方向
                var dir = 0;
    
                setInterval(function() {
                    switch(dir) {
                        /*keyCode返回按下按键的编码
                         * 37 向左
                         * 38向上
                         * 39向右
                         * 40向下
                         */
                        case 37:
                            box01.style.left = box01.offsetLeft - speed + "px";
                            break;
                        case 39:
                            box01.style.left = box01.offsetLeft + speed + "px";
                            break;
                        case 38:
                            box01.style.top = box01.offsetTop - speed + "px";
                            break;
                        case 40:
                            box01.style.top = box01.offsetTop + speed + "px";
                            break;
    
                    }
    
                }, 50)
    
                document.onkeydown = function(event) {
                    event = event || window.event;
    
                    //当ctrl和方向按键同时按下时,提升移动速度
                    if(event.ctrlKey) {
                        speed = 50;
                    } else {
                        speed = 10;
                    }
                    //使dir等于keycode的值
                    dir = event.keyCode;
    
                    //当鼠标松开时,停止移动         ---如果不写这一个会造成无法停止移动的效果
                    document.onkeyup = function() {
                        dir = 0;
                    };
    
                };
    
            };
        </script>
    </head>
    
    <body>
        <div id="box01"></div>
    </body>
    

</html>

————————————————

版权声明:本文为CSDN博主「loving-cat」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/weixin_42878211/article/details/104558443



Vuex的一些用法

前端达人

vuex的基础

1,状态管理(共享)

缓存数据==>内存, 只要刷新页面,数据就丢了

订单,详情等,,,不适用vuex缓存数据



用于



非父子通信的问题

缓存后端数据,提高用户体验

注意:

vuex只能有一个store,

为了防止多人修改,我们切割成子store, 再合并成唯一一个大的store对象

模块写法

import Vue from 'vue'
import Vuex from 'vuex'
import cinema from './module/cinemaModule'
import tabbar from './module/tabbarshowModule'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {

  }, // "全局"状态
  mutations:{

  },//唯一修改状态的地方
  //异步处理
  actions:{
  },
  // 对上面的“全局状态”进行数据处理, 类似于vue中的计算属性
  getters:{
  },

  modules:{
    cinema,
    tabbar
  }
})
export default store

2,子模块的写法

const module = {
  namespaced:true, //命名空间
  state :{
    cinemaList:[]
  },
  actions:{
    store.commit("setCinemaList",res.data.data.cinemas) //支持传参
  },
  mutations:{
    setCinemaList(state,data){
      console.log("setCinemaList",data)
      state.cinemaList = data
    }
  },
  getters:{
    topDataList(state){
      //state形参s, vuex自动调用时候,传来值
      return state.cinemaList.slice(0,5)
    }
  }
}

export default module

3,为了防止页面刷新丢失数据,所以还得找到其他插件来帮忙

import createPersistedState from "vuex-persistedstate"; //在index.js页面加入这个插件

// 加入下面的代码
const store = new Vuex.Store({
  plugins: [createPersistedState({
    reducer(val){
      return {
        user: val.user
      }
    }
  })]


————————————————
版权声明:本文为CSDN博主「m0_46436313」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_46436313/article/details/104572076

javascript设计模式九:中介者模式

前端达人

中介者对象践行了最少知识原则,指一个对象尽可能少的了解别的对象,从而尽量减少对象间耦合程度。这样各个对象只需关注自身实现逻辑,对象间的交互关系交由中介者对象来实现和维护。



需求背景:



手机购买页面,在购买流程中,可以选择手机的颜色及输入购买数量,同时页面有两个展示区域,分别向用户展示刚选择好的颜色和数量。还有一个按钮动态显示下一步的操作,我们需要查询该颜色手机对应的库存,如果库存数量少于这次购买的数量,按钮将被禁用并显示库存不足,反之按钮可以点击并显示放入购物车。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>中介者模式 购买商品</title>
</head>
<body>
    选择颜色: 
    <select id="colorSelect">
        <option value="">请选择</option>
        <option value="red">红色</option>
        <option value="blue">蓝色</option>
    </select>

    输入购买数量:
    <input type="text" id="numberInput">

    您选择了颜色:<div id="colorInfo"></div><br>
    您输入了数量:<div id="numberInfo"></div><br>

    <button id="nextBtn" disabled>请选择手机颜色和购买数量</button>

</body>
<script>

// 最初级的写法
var colorSelect = document.getElementById('colorSelect'),
    numberInput = document.getElementById('numberInput'),
    colorInfo = document.getElementById('colorInfo'),
    numberInfo = document.getElementById('numberInfo'),
    nextBtn = document.getElementById('nextBtn');

var goods = {
    'red': 3,
    'blue': 6
}

colorSelect.onchange = function(){
    var color = this.value,
        number = numberInput.value,
        stock = goods[color]

    colorInfo.innerHTML = color;

    if(!color){
        nextBtn.disabled = true;
        nextBtn.innerHTML = '请选择手机颜色';
        return;
    }

    if( ( (number-0) | 0 ) !== number-0 ){      //用户输入的购买数量是否为正整数
        nextBtn.disabled = true;
        nextBtn.innerHTML = '请输入正确的购买数量';
        return;
    }

    if(number > stock){     //当前选择数量大于库存量
        nextBtn.disabled = true;
        nextBtn.innerHTML = '库存不足';
        return;
    }

    nextBtn.disabled = false;
    nextBtn.innerHTML = '放入购物车';
}

numberInput.oninput = function(){
    var color = colorSelect.value,
        number = this.value,
        stock = goods[color]

    colorInfo.innerHTML = color;

    if(!color){
        nextBtn.disabled = true;
        nextBtn.innerHTML = '请选择手机颜色';
        return;
    }

    if( ( (number-0) | 0 ) !== number-0 ){      //用户输入的购买数量是否为正整数
        nextBtn.disabled = true;
        nextBtn.innerHTML = '请输入正确的购买数量';
        return;
    }

    if(number > stock){     //当前选择数量大于库存量
        nextBtn.disabled = true;
        nextBtn.innerHTML = '库存不足';
        return;
    }

    nextBtn.disabled = false;
    nextBtn.innerHTML = '放入购物车';
}

</script>
</html>

在上个示例中,对象间联系高度耦合,只是两个输入框还好,但如果有多个的话,相互联系就非常复杂了,此时就要考虑用到中介者模式。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>中介者模式 购买商品</title>
</head>
<body>
    选择颜色: 
    <select id="colorSelect">
        <option value="">请选择</option>
        <option value="red">红色</option>
        <option value="blue">蓝色</option>
    </select>

    选择内存: 
    <select id="memorySelect">
        <option value="">请选择</option>
        <option value="32G">32G</option>
        <option value="16G">16G</option>
    </select>

    输入购买数量:
    <input type="text" id="numberInput">

    您选择了颜色:<div id="colorInfo"></div><br>
    您选择了内存:<div id="memoryInfo"></div><br>
    您输入了数量:<div id="numberInfo"></div><br>

    <button id="nextBtn" disabled>请选择手机颜色、内存和购买数量</button>
</body>
<script>
    var goods = {
        'red|32G': 3,
        'red|16G': 0,
        'blue|32G': 1,
        'blue|16G': 6
    }

    //引入中介者
    var mediator = (function(){
        var colorSelect = document.getElementById('colorSelect'),
            memorySelect = document.getElementById('memorySelect'),
            numberInput = document.getElementById('numberInput'),
            colorInfo = document.getElementById('colorInfo'),
            memoryInfo = document.getElementById('memoryInfo'),
            numberInfo = document.getElementById('numberInfo'),
            nextBtn = document.getElementById('nextBtn');

        return {
            changed: function(obj){
                var color = colorSelect.value,
                    memory = memorySelect.value,
                    number = numberInput.value,
                    stock = goods[color + '|' + memory];

                if(obj == colorSelect){      //如果改变的是选择颜色下拉框
                    colorInfo.innerHTML = color;
                }else if(obj == memorySelect){
                    memoryInfo.innerHTML = memory;
                }else if(obj == numberInput){
                    numberInfo.innerHTML = number;
                }

                if(!color){
                    nextBtn.disabled = true;
                    nextBtn.innerHTML = '请选择手机颜色';
                    return;
                }

                if(!memory){
                    nextBtn.disabled = true;
                    nextBtn.innerHTML = '请选择手机内存';
                    return;
                }

                if(!number){
                    nextBtn.disabled = true;
                    nextBtn.innerHTML = '请填写手机数量';
                    return;
                }

                if( ( (number-0) | 0 ) !== number-0 ){      //用户输入的购买数量是否为正整数
                    nextBtn.disabled = true;
                    nextBtn.innerHTML = '请输入正确的购买数量';
                    return;
                }

                if(number > stock){     //当前选择数量大于库存量
                    nextBtn.disabled = true;
                    nextBtn.innerHTML = '库存不足';
                    return;
                }

                nextBtn.disabled = false;
                nextBtn.innerHTML = '放入购物车';
            }
        }
    })()

    colorSelect.onchange = function(){
        mediator.changed(this)
    }

    memorySelect.onchange = function(){
        mediator.changed(this)
    }

    numberInput.oninput = function(){
        mediator.changed(this)
    }

    //以后如果想要再增加选项,如手机CPU之类的,只需在中介者对象里加上相应配置即可。
</script>
</html>
在实际开发中,还是要注意选择利弊,中介者对象因为包含对象间交互的复杂性,所以维护成本可能也会较高。在实际开发中,最优目的还是要快速完成项目交付,而非过度设计和堆砌模式。有时对象间的耦合也是有必要的,只有当对象间复杂耦合确实已经导致调用与维护难以为继,才考虑用中介者模式。

————————————————
版权声明:本文为CSDN博主「一期一会」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_34832846/article/details/85989945

弹性布局(Flex)+骰子旋转实例^v^

前端达人

弹性布局(Flex)

随着移动互联网的发展,对于网页布局来说要求越来越高,而传统的布局方案对于实现特殊布局非常不方便,比如垂直居中。

2009年,W3C 提出了一种新的方案----Flex 布局,可以简便、完整、响应式地实现各种页面布局。目前,它已经得到了所有浏览器的支持,这意味着,现在就能很安全地使用这项功能。

下面是一些弹性布局的基本语法:

两部分:

1. 语法是添加到父容器上的
        display : flex;(弹性盒子的标志哦!!!)
        flex-direction: row; 布局的排列方向 (主轴排列方向)
             row 默认值,显示为行。方向为当前文档水平流方向,默认情况下是从左往右。
             row-reverse  显示为行。但方向和row属性值是反的
             column  显示为列
             column-reverse 显示为列。但方向和column属性值是反的
        flex-wrap : nowrap; 是否进行换行处理。
             nowrap; 默认值,不换行处理
             wrap; 换行处理
             wrap-reverse; 反向换行
        flex-flow : flex-direction flex-wrap 复合写法 (是有顺序的)。
        justify-content ; 属性决定了主轴方向上子项的对齐和分布方式。  
            flex-start : 子项都去起始位置对齐。
            flex-end : 子项都去结束位置对齐。
            center : 子项都去中心位置对齐。
            space-between : 表现为两端对齐。多余的空白间距在元素中间区域分配,两边没宽。 
            space-around : 边缘两侧的空白只有中间空白宽度一半即每个块都有左右间距。
            space-evenly :每个flex子项两侧空白间距完全相等。
        align-items : 每一行中的子元素上下对齐方式。
            stretch;默认值,flex子项拉伸
            flex-start;容器顶部对齐
            center;容器居中对齐
            flex-end;容器底部对齐
        align-content : 跟justify-content相反的操作。侧轴的对齐方式。(最少需要两行才能看出效果,因为他是多行的一个上下对齐方式)
            默认:多行下,有几行就会把容器划分为几部分,默认就是stretch拉伸的。
            值跟justify-content取值是相同的。

2. 语法是添加到子容器上的?
        order : 排序(值越大越后)
            0:默认值      eg:1234
            1:放在后面    eg:1342
            -2:放在前面   eg:2134
        flex-grow : 扩展 ( 想看到扩展的效果,必须有空隙 )
            0 : 默认值 , 不去扩展
            0.5:占空隙的一半
            1 : 去扩展 , 会把空白区域全部沾满
         ( 注:子元素会按照设置的比例值来分配空隙,如果比例值总和小于1,那么会有空隙,如果比例值总和大于等于1,那么就没有空隙。)
        flex-shrink : 收缩
            正常默认值是1
            0表示不收缩,.5收缩小一些,2收缩大一些。(大小是跟正常缩放1进行比较的)
        flex-basis : 跟flex-shrink/flex-grow很像。
            flex-shrink/flex-grow是设置一个比例值,flex-basis是设置一个具体值。
        flex : 一种复合写法
            flex-grow  flex-shrink  flex-basis
            flex:1;
                flex : 1 1 0    
            flex:0;
                flex : 0 1 0
        algin-self: 跟align-items操作很像,区别就是只是针对某一个子项。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{margin: 0;padding: 0;}
        ul{list-style: none;}
        a{text-decoration: none;}
        img{display: block;}

        .box1{width: 150px;height: 150px;display: flex;border: 1px black solid;margin: 20px auto;border-radius: 10px;justify-content: center;align-items: center;}
        .box1 div{width: 30px;height: 30px;border-radius:50%;background: black;}

        .box2{width: 150px;height: 150px;display: flex;border: 1px black solid;margin: 20px auto;border-radius: 10px;align-items: center;justify-content: space-between;}
        .box2 div{width: 30px;height: 30px;border-radius:50%;background: black;margin: 10px;}
        .box2 div:nth-of-type(1){align-self: flex-start;}
        .box2 div:nth-of-type(2){align-self: flex-end;}

        .box3{width: 150px;height: 150px;display: flex;border: 1px black solid;margin: 20px auto;border-radius: 10px;align-items: center;justify-content: space-between;}
        .box3 div{width: 30px;height: 30px;border-radius:50%;background: black;margin: 10px;}
        .box3 div:nth-of-type(1){align-self: flex-start;}
        .box3 div:nth-of-type(3){align-self: flex-end;}

        .box4{width: 150px;height: 150px;border: 1px black solid;margin: 20px auto;border-radius: 10px;display: flex;flex-direction: column;}
        .box4 div{height: 50%;display: flex;flex-direction: row;justify-content: space-around;align-items: center;}
        .box4 div li{display: block; width: 30px;height: 30px;border-radius:50%;background: black;}

        .box5{width: 150px;height: 150px;border: 1px black solid;margin: 20px auto;border-radius: 10px;display: flex;flex-direction: column;}
        .box5 div{height: 50%;display: flex;flex-direction: row;justify-content: space-around;align-items: center;}
        .box5 div li{display: block; width: 30px;height: 30px;border-radius:50%;background: black;}

        .box6{width: 150px;height: 150px;border: 1px black solid;margin: 20px auto;border-radius: 10px;display: flex;flex-direction: column;}
        .box6 div{height: 50%;display: flex;flex-direction: row;justify-content: space-around;align-items: center;}
        .box6 div li{display: block; width: 30px;height: 30px;border-radius:50%;background: black;}

        #box{width: 400px;height: 400px;margin: 20px auto;border: 1px springgreen solid; 
        perspective: 500px;perspective-origin: right top;}
        #box .main{position: relative;width: 150px;height: 150px;margin: 125px;
        transform-style: preserve-3d;transition: 4s;transform-origin: center center -50px;}
        #box .main .box1{position: absolute;background:limegreen;left: 0;top: 0;
        width: 150px;height: 150px;}
        #box .main .box2{position: absolute;background:limegreen;left: 0;top: 0;
        width: 150px;height: 150px;left: 150px;transform-origin:left; transform:rotateY(90deg);}
        #box .main .box3{position: absolute;background:limegreen;left: 0;top: 0;
        width: 150px;height: 150px;left: -150px;transform-origin:right; transform:rotateY(-90deg);}
        #box .main .box4{position: absolute;background:limegreen;left: 0;top: 0;
        width: 150px;height: 150px;top: -150px;transform-origin:bottom; transform:rotateX(90deg);}
        #box .main .box5{position: absolute;background:limegreen;left: 0;top: 0;
        width: 150px;height: 150px;top: 150px;transform-origin:top; transform:rotateX(-90deg);}
        #box .main .box6{position: absolute;background:limegreen;left: 0;top: 0;
        width: 150px;height: 150px;transform:translateZ(-150px) rotateY(180deg);}

        #box:hover .main{transform:rotateY(360deg);}
    </style>
</head>
<body>
    <div id="box">
        <div class="main">
            <div class="box1">
                <div></div>
            </div>
            <div class="box2">
                <div></div>
                <div></div>
            </div>
            <div class="box3">
                <div></div>
                <div></div>
                <div></div>
            </div>
            <div class="box4">
                <div>
                    <li></li>
                    <li></li>
                </div>
                <div>
                    <li></li>
                    <li></li>
                </div>
            </div>
            <div class="box5">
                <div>
                    <li></li>
                    <li></li>
                </div>
                <div>
                    <li></li>
                </div>
                <div>
                    <li></li>
                    <li></li>
                </div>
            </div>
            <div class="box6">
                <div>
                    <li></li>
                    <li></li>
                </div>
                <div>
                    <li></li>
                    <li></li>
                </div>
                <div>
                    <li></li>
                    <li></li>
                </div>
            </div>
        </div>
    </div>
</body>
</html>
注:默认情况下,在弹性盒子中的子元素的左右排列的。 注: 水平是主轴的时候:默认情况下,当宽高不写的时候,宽度由内容决定,高度由父容器决定。 垂直是主轴的时候:默认情况下,当宽高不写的时候,宽度由父容器决定,高度由内容决定。 注:当子项的总宽度大于父容器的时候,会自动收缩的(弹性的优先级是大于自身固定大小的) 注:当子项的内容已经达到了父容器最小宽高的时候,就会出现溢出的现象。 注:弹性布局中用的频率比较多的语法: display : flex; flex-direction; justify-content; align-items; flex; 注:弹性布局的优势是做一维布局,网格布局的优势是做二维布局。

下面是弹性布局骰子案例代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{margin: 0;padding: 0;}
        ul{list-style: none;}
        a{text-decoration: none;}
        img{display: block;}

        .box1{width: 150px;height: 150px;display: flex;border: 1px black solid;margin: 20px auto;border-radius: 10px;justify-content: center;align-items: center;}
        .box1 div{width: 30px;height: 30px;border-radius:50%;background: black;}

        .box2{width: 150px;height: 150px;display: flex;border: 1px black solid;margin: 20px auto;border-radius: 10px;align-items: center;justify-content: space-between;}
        .box2 div{width: 30px;height: 30px;border-radius:50%;background: black;margin: 10px;}
        .box2 div:nth-of-type(1){align-self: flex-start;}
        .box2 div:nth-of-type(2){align-self: flex-end;}

        .box3{width: 150px;height: 150px;display: flex;border: 1px black solid;margin: 20px auto;border-radius: 10px;align-items: center;justify-content: space-between;}
        .box3 div{width: 30px;height: 30px;border-radius:50%;background: black;margin: 10px;}
        .box3 div:nth-of-type(1){align-self: flex-start;}
        .box3 div:nth-of-type(3){align-self: flex-end;}

        .box4{width: 150px;height: 150px;border: 1px black solid;margin: 20px auto;border-radius: 10px;display: flex;flex-direction: column;}
        .box4 div{height: 50%;display: flex;flex-direction: row;justify-content: space-around;align-items: center;}
        .box4 div li{display: block; width: 30px;height: 30px;border-radius:50%;background: black;}

        .box5{width: 150px;height: 150px;border: 1px black solid;margin: 20px auto;border-radius: 10px;display: flex;flex-direction: column;}
        .box5 div{height: 50%;display: flex;flex-direction: row;justify-content: space-around;align-items: center;}
        .box5 div li{display: block; width: 30px;height: 30px;border-radius:50%;background: black;}

        .box6{width: 150px;height: 150px;border: 1px black solid;margin: 20px auto;border-radius: 10px;display: flex;flex-direction: column;}
        .box6 div{height: 50%;display: flex;flex-direction: row;justify-content: space-around;align-items: center;}
        .box6 div li{display: block; width: 30px;height: 30px;border-radius:50%;background: black;}

        #box{width: 400px;height: 400px;margin: 20px auto;border: 1px springgreen solid; 
        perspective: 500px;perspective-origin: right top;}
        #box .main{position: relative;width: 150px;height: 150px;margin: 125px;
        transform-style: preserve-3d;transition: 4s;transform-origin: center center -50px;}
        #box .main .box1{position: absolute;background:limegreen;left: 0;top: 0;
        width: 150px;height: 150px;}
        #box .main .box2{position: absolute;background:limegreen;left: 0;top: 0;
        width: 150px;height: 150px;left: 150px;transform-origin:left; transform:rotateY(90deg);}
        #box .main .box3{position: absolute;background:limegreen;left: 0;top: 0;
        width: 150px;height: 150px;left: -150px;transform-origin:right; transform:rotateY(-90deg);}
        #box .main .box4{position: absolute;background:limegreen;left: 0;top: 0;
        width: 150px;height: 150px;top: -150px;transform-origin:bottom; transform:rotateX(90deg);}
        #box .main .box5{position: absolute;background:limegreen;left: 0;top: 0;
        width: 150px;height: 150px;top: 150px;transform-origin:top; transform:rotateX(-90deg);}
        #box .main .box6{position: absolute;background:limegreen;left: 0;top: 0;
        width: 150px;height: 150px;transform:translateZ(-150px) rotateY(180deg);}

        #box:hover .main{transform:rotateY(360deg);}
    </style>
</head>
<body>
    <div id="box">
        <div class="main">
            <div class="box1">
                <div></div>
            </div>
            <div class="box2">
                <div></div>
                <div></div>
            </div>
            <div class="box3">
                <div></div>
                <div></div>
                <div></div>
            </div>
            <div class="box4">
                <div>
                    <li></li>
                    <li></li>
                </div>
                <div>
                    <li></li>
                    <li></li>
                </div>
            </div>
            <div class="box5">
                <div>
                    <li></li>
                    <li></li>
                </div>
                <div>
                    <li></li>
                </div>
                <div>
                    <li></li>
                    <li></li>
                </div>
            </div>
            <div class="box6">
                <div>
                    <li></li>
                    <li></li>
                </div>
                <div>
                    <li></li>
                    <li></li>
                </div>
                <div>
                    <li></li>
                    <li></li>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

实际效果:
20200229132935355.png


————————————————
版权声明:本文为CSDN博主「GLINLIND」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/GLINLIND/article/details/104572530



日历

链接

个人资料

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

存档