首页

2020年的8种UI/UX设计趋势

ui设计分享达人

世界和技术正在飞速发展,每年都会影响设计趋势的走向。作为设计师,我们需要了解现有和即将到来的设计趋势,不断学习,改进和扩大我们的知识储备,以便与时俱进。

根据研究、经验和观察,我们非常仔细地选择了2020年应该注意的8种UI / UX设计趋势。那就让我们开始吧~


简介:2020年8种UI / UX设计趋势


1. 动画插图

通过对插图,或者让插图进行运动,可以使我们的设计脱颖而出,并使其栩栩如生-增加额外的细节和个性。


2. 微交互

微交互完美证明了:着重于细节和发扬这些细节可能会大大改善你的APP的用户体验,并将使之更高能/更。


3. Web和移动界面中的3D图形

新的Web浏览器功能为3D图形打开了大门,作为设计师可以在现代Web和移动界面中创造和实现惊人的3D图形。


4. 虚拟现实(VR)

游戏行业常将创新、和新技术带入产品设计中。


5. AR技术

在AR空间中,有无数令人兴奋的体验机会。AR的UI设计将成为2020年的主要趋势之一,因此,作为设计师,我们应该做好准备,并主动在创建AR体验时学习新的工具和原理。


6. 新拟物

VR / AR技术的增长,以及最流行的设计平台上显示的那些优秀的设计告诉我们:设计趋势可能会使拟物设计在2020年卷土重来,但这一次,它会加入更多现代时尚。


7. 不对称布局

非对称布局有很大的创造空间,不过创建优秀的非对称布局需要我们有一定的经验和时间去处理它。


8. 讲故事

讲故事就是以最佳的信息和创意方式将数据传输给用户。讲故事也是一种出色而有效的营销工具,可以极大地提高你的产品/服务的销售额。




1. 动画插图

插画在产品设计中已经存在了很长时间。最近几年的发展更是令人瞩目。插画作为非常流行的设计元素,为我们产品的整体UX添加了「自然的感觉」和「人性化的感觉」。插画也是吸引注意力的焦点:通过对这些插画进行动效的展示,可以使我们的产品栩栩如生,并使它们脱颖而出-增加更多的细节和个性。

欢迎来到我们的商店!



入职动画



动效展示的另一个好处是可以吸引用户的注意力并使用户与您的产品互动。动画也是讲述您的品牌、产品或服务故事的最有效方法之一。




2. 微交互

微交互几乎存在于每个APP或网站中。每次打开喜欢的APP时,你都会看到它们。例如,Facebook有大量不同的微交互,其中「赞」功能就是一个很好的例子。虽然有时我们甚至不会特意感知到它的存在,因为它非常明显的、自然的「融合」到用户界面中去了。但是如果你从界面中删除它们,你将很快意识到,某些重要的功能丢失了。

菜单切换关闭动画



标签栏活动动画



一般来说,在UI / UX设计中,有时即使很小的更改也可能产生巨大的影响。微交互完美证明了细节和发扬它们可能会大大改善你的APP的整体用户体验,并将其置于更高能/更的层次。在每一年,每种新设备都会带来新的创造全新的微交互的机会,当然,2020年也不例外。


















3. Web和移动界面中的3D图形

3D图形几乎无处不在-在电影,视频游戏,街头广告中。3D图形是几十年前才被引入到产品设计中的,从那时起,它已经得到了极大到改善,并得到了高速的发展。移动和网络技术也在快速增长。新的Web浏览器功能为3D图形打开了大门,我们作为设计师可以在现代Web和移动界面中创建和实现炫目的3D图形。

3D翻转菜单



汽车健康报告用户界面



创建3D图形并将其实现到Web和移动界面中需要一些特定的技能和大量的工作,但是通常结果是非常有意义的。

Apple AirPods Pro登陆页面



3D图形以一种更具交互性和吸引力的方式来展示产品或服务:例如,可以以360度演示方式查看3D图形,从而改善了产品的用户体验。

在2020年,更多的品牌将使用3D模型来展示产品或服务,打通线上线下,以模拟现实世界(店内)的购物体验。



4. 虚拟现实(VR)

2019年对于VR来说,是重要的一年。在过去的几年,我们见证了VR技术的发展和其不可思议的效果,其中大部分是在游戏行业。游戏行业通常会首先在产品设计中引入创新和新技术。研究证明VR也不例外,2019年Oculus Quest推出后,其他行业也尝试了很多可能性。Facebook首席执行官马克·扎克伯格(Mark Zuckerberg)已经测试了令人兴奋的手部交互功能,并于2020年初正式宣布了Quest的手部跟踪更新!

Oculus Quest-手互动功能



PlayStation虚拟现实网站设计



索尼和微软将在2020年发布其新一代游戏机。这些将为虚拟现实技术带来很多机遇和增长空间。




5. AR技术

过去几年中,我们看到了AR的许多发展和改进。世界领先的科技公司在AR开发方面投入了数百万美元,我们应该期望在2020年行业会扩展和发展此项技术。甚至苹果公司也推出了自己的AR工具包ARKIT 3,以帮助设计人员和开发人员构建基于AR的产品。


ARKit 3 苹果


公共交通应用



Nathan Riley的植物之家AR概念



在AR空间中,有无数令人兴奋的体验机会。AR的UI设计将成为2020年的主要趋势之一,因此,作为设计师,我们应该做好准备,并主动在创建AR体验时学习新的工具和原理。




6. 新拟物

一般来说,拟物设计是指以逼真的样式/方式创建的设计元素,以匹配现实生活中的对象。VR / AR技术的增长和最流行的设计平台(Dribbble,Behance等)上显示的设计趋势显示:拟物设计可能会在2020年卷土重来,但这一次,它会加入更多现代时尚。同时有了一个略作修改的名称:“新拟物” (也称为Neumorphism)。

Skeuomorph手机银行的黑暗模式



音乐播放器



睡眠周期应用程序



我们可能已经注意到:「新拟物设计」代表非常详细和的设计风格。高光,阴影,发光都被运用在设计中去。他们对细节的关注令人非常印象深刻。这已经启发了来自世界各地的许多设计师,并且很有可能成为2020年最大的UI设计趋势。




7. 不对称布局

在过去的几年中,我们注意到产品设计中大量使用不对称布局。基于  传统/模板 的布局渐渐消失。2020年将依旧如此,因为这一趋势将继续保持。正确使用非对称布局会为我们的设计增加很多特征、动态和个性,或许它们将不再拘泥于模板。


Limnia高级珠宝首饰网格



卡琳时装商店



创建非对称布局时、有很大的创造空间。尽管创建成功的非对称布局需要一定的经验和时间、将元素随机放置在网格上当然是不行的)  此外,应谨慎使用和实现它们-因为我们要始终牢记用户的需求:我们不希望用户使用我们产品的时候感到困惑。



8. 讲故事

故事在产品设计中的用户体验中扮演着非常重要的角色。可能会在登录页面上经常看到它们,作为对品牌,产品或新功能的介绍。讲故事就是以最佳的信息和创意方式将数据传输给用户。这可以通过「版权(品牌)保护」与「强大而平衡的视觉等级」(印刷术,插图,高质量照片,大胆的色彩,动画和交互式元素)混合来实现。

讲故事就是以最佳的信息和创意方式将数据传输给用户。 



「本周青年实验室」页面故事动画


讲故事确实有助于在品牌和用户之间建立积极的情感和关系。讲故事还可以使您的品牌更令人难忘,并使用户觉得他们是我们产品或服务的一部分,因此他们希望与他们建立联系。话虽如此,讲故事还是一种出色而有效的营销工具,可能会大大提高您的产品/服务的销售额。作为非常成功的工具,讲故事将在2020年继续并扩大。

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

文章来源:站酷  作者:一个辛普森



JavaScript中的缓存API

seo达人

了解如何使用JavaScript中的Cache API缓存资源。


Cache API允许服务工作者对要缓存的资源(HTML页面、CSS、JavaScript文件、图片、JSON等)进行控制。通过Cache API,服务工作者可以缓存资源以供脱机使用,并在以后检索它们。


检测Cache支持

检查 caches 对象在 window 中是否可用。


let isCacheSupported = 'caches' in window;

caches 是 CacheStorage 的一个实例。


创建/初始化Cache

我们可以使用 open 方法创建一个具有 name 的缓存,这将返回 promise。如果缓存已经存在,则不会创建新的缓存。


caches.open('cacheName').then( cache => {

});

你不能访问为其他源(域)设置的缓存。

你正在创建的缓存将为你的域创建。

你可以为同一个域添加多个缓存,可以通过 caches.keys() 访问。

将项目添加到缓存

可以使用三种方法 add,addAll,set 来缓存资源。 add() 和 addAll() 方法自动获取资源并对其进行缓存,而在 set 方法中,我们将获取数据并设置缓存。


add

let cacheName = 'userSettings';

let url = '/api/get/usersettings';

caches.open(cacheName).then( cache => {

  cache.add(url).then( () => {

      console.log("Data cached ")

   });

});

在上面的代码中,内部对 /api/get/usersettings url的请求已发送到服务器,一旦接收到数据,响应将被缓存。


addAll

addAll 接受URL数组,并在缓存所有资源时返回Promise。


let urls = ['/get/userSettings?userId=1', '/get/userDetails'];

caches.open(cacheName).then( cache => {

cache.addAll(urls).then( () => {

      console.log("Data cached ")

   });

});

Cache.add/Cache.addAll 不缓存 Response.status 值不在200范围内的响应,Cache.put 可以让你存储任何请求/响应对。


put

put 为当前的 Cache 对象添加一个key/value对,在 put 中,我们需要手动获取请求并设置值。


注意:put() 将覆盖先前存储在高速缓存中与请求匹配的任何键/值对。


let cacheName = 'userSettings';

let url = '/api/get/userSettings';

fetch(url).then(res => {

 return caches.open(cacheName).then(cache => {

   return cache.put(url, res);

 })

})

从缓存中检索

使用 cache.match() 可以得到存储到URL的 Response。


const cacheName = 'userSettings'

const url = '/api/get/userSettings'

caches.open(cacheName).then(cache => {

 cache.match(url).then(settings => {

   console.log(settings);

 }

});

settings 是一个响应对象,它看起来像


Response {

 body: (...),

 bodyUsed: false,

 headers: Headers,

 ok: true,

 status: 200,

 statusText: "OK",

 type: "basic",

 url: "https://test.com/api/get/userSettings"

}

检索缓存中的所有项目

cache 对象包含 keys 方法,这些方法将拥有当前缓存对象的所有url。


caches.open(cacheName).then( (cache) => {

 cache.keys().then((arrayOfRequest) => {

     console.log(arrayOfRequest); // [Request,  Request]

 });

});

arrayOfRequest是一个Request对象数组,其中包含有关请求的所有详细信息。


检索所有缓存

caches.keys().then(keys => {

 // keys是一个数组,其中包含键的列表

})

从缓存中删除项目

可以对 cache 对象使用 delete 方法来删除特定的缓存请求。


let cacheName = userSettings;

let urlToDelete = '/api/get/userSettings';

caches.open(cacheName).then(cache => {

 cache.delete(urlToDelete)

})

完全删除缓存

caches.delete(cacheName).then(() => {

  console.log('Cache successfully deleted!');

})

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

Vue中使用装饰器,我是认真的

seo达人

作为一个曾经的Java coder, 当我第一次看到js里面的装饰器(Decorator)的时候,就马上想到了Java中的注解,当然在实际原理和功能上面,Java的注解和js的装饰器还是有很大差别的。本文题目是Vue中使用装饰器,我是认真的,但本文将从装饰器的概念开发聊起,一起来看看吧。


通过本文内容,你将学到以下内容:


了解什么是装饰器

在方法使用装饰器

在class中使用装饰器

在Vue中使用装饰器

本文首发于公众号【前端有的玩】,不想当咸鱼,想要换工作,关注公众号,带你每日一起刷大厂面试题,关注 === 大厂offer。

什么是装饰器

装饰器是ES2016提出来的一个提案,当前处于Stage 2阶段,关于装饰器的体验,可以点击 https://github.com/tc39/proposal-decorators查看详情。装饰器是一种与类相关的语法糖,用来包装或者修改类或者类的方法的行为,其实装饰器就是设计模式中装饰者模式的一种实现方式。不过前面说的这些概念太干了,我们用人话来翻译一下,举一个例子。


在日常开发写bug过程中,我们经常会用到防抖和节流,比如像下面这样


class MyClass {

 follow = debounce(function() {

   console.log('我是子君,关注我哦')

 }, 100)

}


const myClass = new MyClass()

// 多次调用只会输出一次

myClass.follow()

myClass.follow()

上面是一个防抖的例子,我们通过debounce函数将另一个函数包起来,实现了防抖的功能,这时候再有另一个需求,比如希望在调用follow函数前后各打印一段日志,这时候我们还可以再开发一个log函数,然后继续将follow包装起来


/**

* 最外层是防抖,否则log会被调用多次

*/

class MyClass {

 follow = debounce(

   log(function() {

     console.log('我是子君,关注我哦')

   }),

   100

 )

}

上面代码中的debounce和log两个函数,本质上是两个包装函数,通过这两个函数对原函数的包装,使原函数的行为发生了变化,而js中的装饰器的原理就是这样的,我们使用装饰器对上面的代码进行改造


class MyClass {

 @debounce(100)

 @log

 follow() {

   console.log('我是子君,关注我哦')

 }

}

装饰器的形式就是 @ + 函数名,如果有参数的话,后面的括号里面可以传参


在方法上使用装饰器

装饰器可以应用到class上或者class里面的属性上面,但一般情况下,应用到class属性上面的场景会比较多一些,比如像上面我们说的log,debounce等等,都一般会应用到类属性上面,接下来我们一起来具体看一下如何实现一个装饰器,并应用到类上面。在实现装饰器之前,我们需要先了解一下属性描述符


了解一下属性描述符

在我们定义一个对象里面的属性的时候,其实这个属性上面是有许多属性描述符的,这些描述符标明了这个属性能不能修改,能不能枚举,能不能删除等等,同时ECMAScript将这些属性描述符分为两类,分别是数据属性和访问器属性,并且数据属性与访问器属性是不能共存的。


数据属性

数据属性包含一个数据值的位置,在这个位置可以读取和写入值。数据属性包含了四个描述符,分别是


configurable

表示能不能通过delete删除属性,能否修改属性的其他描述符特性,或者能否将数据属性修改为访问器属性。当我们通过let obj = {name: ''}声明一个对象的时候,这个对象里面所有的属性的configurable描述符的值都是true


enumerable

表示能不能通过for in或者Object.keys等方式获取到属性,我们一般声明的对象里面这个描述符的值是true,但是对于class类里面的属性来说,这个值是false


writable

表示能否修改属性的数据值,通过将这个修改为false,可以实现属性只读的效果。


value

表示当前属性的数据值,读取属性值的时候,从这里读取;写入属性值的时候,会写到这个位置。


访问器属性

访问器属性不包含数据值,他们包含了getter与setter两个函数,同时configurable与enumerable是数据属性与访问器属性共有的两个描述符。


getter

在读取属性的时候调用这个函数,默认这个函数为undefined


setter

在写入属性值的时候调用这个函数,默认这个函数为undefined


了解了这六个描述符之后,你可能会有几个疑问: 我如何去定义修改这些属性描述符?这些属性描述符与今天的文章主题有什么关系?接下来是揭晓答案的时候了。


使用Object.defineProperty

了解过vue2.0双向绑定原理的同学一定知道,Vue的双向绑定就是通过使用Object.defineProperty去定义数据属性的getter与setter方法来实现的,比如下面有一个对象


let obj = {

 name: '子君',

 officialAccounts: '前端有的玩'

}

我希望这个对象里面的用户名是不能被修改的,用Object.defineProperty该如何定义呢?


Object.defineProperty(obj,'name', {

 // 设置writable 是 false, 这个属性将不能被修改

 writable: false

})

// 修改obj.name

obj.name = "君子"

// 打印依然是子君

console.log(obj.name)

通过Object.defineProperty可以去定义或者修改对象属性的属性描述符,但是因为数据属性与访问器属性是互斥的,所以一次只能修改其中的一类,这一点需要注意。


定义一个防抖装饰器

装饰器本质上依然是一个函数,不过这个函数的参数是固定的,如下是防抖装饰器的代码


/**

*@param wait 延迟时长

*/

function debounce(wait) {

 return function(target, name, descriptor) {

   descriptor.value = debounce(descriptor.value, wait)

 }

}

// 使用方式

class MyClass {

 @debounce(100)

 follow() {

   console.log('我是子君,我的公众号是 【前端有的玩】,关注有惊喜哦')

 }

}

我们逐行去分析一下代码


首先我们定义了一个 debounce函数,同时有一个参数wait,这个函数对应的就是在下面调用装饰器时使用的@debounce(100)

debounce函数返回了一个新的函数,这个函数即装饰器的核心,这个函数有三个参数,下面逐一分析


target: 这个类属性函数是在谁上面挂载的,如上例对应的是MyClass类

name: 这个类属性函数的名称,对应上面的follow

descriptor: 这个就是我们前面说的属性描述符,通过直接descriptor上面的属性,即可实现属性只读,数据重写等功能

然后第三行 descriptor.value = debounce(descriptor.value, wait), 前面我们已经了解到,属性描述符上面的value对应的是这个属性的值,所以我们通过重写这个属性,将其用debounce函数包装起来,这样在函数调用follow时实际调用的是包装后的函数

通过上面的三步,我们就实现了类属性上面可使用的装饰器,同时将其应用到了类属性上面


在class上使用装饰器

装饰器不仅可以应用到类属性上面,还可以直接应用到类上面,比如我希望可以实现一个类似Vue混入那样的功能,给一个类混入一些方法属性,应该如何去做呢?


// 这个是要混入的对象

const methods = {

 logger() {

   console.log('记录日志')

 }

}


// 这个是一个登陆登出类

class Login{

 login() {}

 logout() {}

}

如何将上面的methods混入到Login中,首先我们先实现一个类装饰器


function mixins(obj) {

 return function (target) {

   Object.assign(target.prototype, obj)  

 }

}


// 然后通过装饰器混入

@mixins(methods)

class Login{

 login() {}

 logout() {}

}

这样就实现了类装饰器。对于类装饰器,只有一个参数,即target,对应的就是这个类本身。


了解完装饰器,我们接下来看一下如何在Vue中使用装饰器。


在Vue中使用装饰器

使用ts开发Vue的同学一定对vue-property-decorator不会感到陌生,这个插件提供了许多装饰器,方便大家开发的时候使用,当然本文的中点不是这个插件。其实如果我们的项目没有使用ts,也是可以使用装饰器的,怎么用呢?


配置基础环境

除了一些老的项目,我们现在一般新建Vue项目的时候,都会选择使用脚手架vue-cli3/4来新建,这时候新建的项目已经默认支持了装饰器,不需要再配置太多额外的东西,如果你的项目使用了eslint,那么需要给eslint配置以下内容。


 parserOptions: {

   ecmaFeatures:{

     // 支持装饰器

     legacyDecorators: true

   }

 }

使用装饰器

虽然Vue的组件,我们一般书写的时候export出去的是一个对象,但是这个并不影响我们直接在组件中使用装饰器,比如就拿上例中的log举例。


function log() {

 /**

  * @param target 对应 methods 这个对象

  * @param name 对应属性方法的名称

  * @param descriptor 对应属性方法的修饰符

  */

 return function(target, name, descriptor) {

   console.log(target, name, descriptor)

   const fn = descriptor.value

   descriptor.value = function(...rest) {

     console.log(`这是调用方法【${name}】前打印的日志`)

     fn.call(this, ...rest)

     console.log(`这是调用方法【${name}】后打印的日志`)

   }

 }

}


export default {

 created() {

   this.getData()

 },

 methods: {

   @log()

   getData() {

     console.log('获取数据')

   }

 }

}

看了上面的代码,是不是发现在Vue中使用装饰器还是很简单的,和在class的属性上面使用的方式一模一样,但有一点需要注意,在methods里面的方法上面使用装饰器,这时候装饰器的target对应的是methods。


除了在methods上面可以使用装饰器之外,你也可以在生命周期钩子函数上面使用装饰器,这时候target对应的是整个组件对象。


一些常用的装饰器

下面小编罗列了几个小编在项目中常用的几个装饰器,方便大家使用


1. 函数节流与防抖

函数节流与防抖应用场景是比较广的,一般使用时候会通过throttle或debounce方法对要调用的函数进行包装,现在就可以使用上文说的内容将这两个函数封装成装饰器, 防抖节流使用的是lodash提供的方法,大家也可以自行实现节流防抖函数哦


import { throttle, debounce } from 'lodash'

/**

* 函数节流装饰器

* @param {number} wait 节流的毫秒

* @param {Object} options 节流选项对象

* [options.leading=true] (boolean): 指定调用在节流开始前。

* [options.trailing=true] (boolean): 指定调用在节流结束后。

*/

export const throttle =  function(wait, options = {}) {

 return function(target, name, descriptor) {

   descriptor.value = throttle(descriptor.value, wait, options)

 }

}


/**

* 函数防抖装饰器

* @param {number} wait 需要延迟的毫秒数。

* @param {Object} options 选项对象

* [options.leading=false] (boolean): 指定在延迟开始前调用。

* [options.maxWait] (number): 设置 func 允许被延迟的最大值。

* [options.trailing=true] (boolean): 指定在延迟结束后调用。

*/

export const debounce = function(wait, options = {}) {

 return function(target, name, descriptor) {

   descriptor.value = debounce(descriptor.value, wait, options)

 }

}

封装完之后,在组件中使用


import {debounce} from '@/decorator'


export default {

 methods:{

   @debounce(100)

   resize(){}

 }

}

2. loading

在加载数据的时候,为了个用户一个友好的提示,同时防止用户继续操作,一般会在请求前显示一个loading,然后在请求结束之后关掉loading,一般写法如下


export default {

 methods:{

   async getData() {

     const loading = Toast.loading()

     try{

       const data = await loadData()

       // 其他操作

     }catch(error){

       // 异常处理

       Toast.fail('加载失败');

     }finally{

       loading.clear()

     }  

   }

 }

}

我们可以把上面的loading的逻辑使用装饰器重新封装,如下代码


import { Toast } from 'vant'


/**

* loading 装饰器

* @param {*} message 提示信息

* @param {function} errorFn 异常处理逻辑

*/

export const loading =  function(message = '加载中...', errorFn = function() {}) {

 return function(target, name, descriptor) {

   const fn = descriptor.value

   descriptor.value = async function(...rest) {

     const loading = Toast.loading({

       message: message,

       forbidClick: true

     })

     try {

       return await fn.call(this, ...rest)

     } catch (error) {

       // 在调用失败,且用户自定义失败的回调函数时,则执行

       errorFn && errorFn.call(this, error, ...rest)

       console.error(error)

     } finally {

       loading.clear()

     }

   }

 }

}

然后改造上面的组件代码


export default {

 methods:{

   @loading('加载中')

   async getData() {

     try{

       const data = await loadData()

       // 其他操作

     }catch(error){

       // 异常处理

       Toast.fail('加载失败');

     }  

   }

 }

}

3. 确认框

当你点击删除按钮的时候,一般都需要弹出一个提示框让用户确认是否删除,这时候常规写法可能是这样的


import { Dialog } from 'vant'


export default {

 methods: {

   deleteData() {

     Dialog.confirm({

       title: '提示',

       message: '确定要删除数据,此操作不可回退。'

     }).then(() => {

       console.log('在这里做删除操作')

     })

   }

 }

}

我们可以把上面确认的过程提出来做成装饰器,如下代码


import { Dialog } from 'vant'


/**

* 确认提示框装饰器

* @param {*} message 提示信息

* @param {*} title 标题

* @param {*} cancelFn 取消回调函数

*/

export function confirm(

 message = '确定要删除数据,此操作不可回退。',

 title = '提示',

 cancelFn = function() {}

) {

 return function(target, name, descriptor) {

   const originFn = descriptor.value

   descriptor.value = async function(...rest) {

     try {

       await Dialog.confirm({

         message,

         title: title

       })

       originFn.apply(this, rest)

     } catch (error) {

       cancelFn && cancelFn(error)

     }

   }

 }

}

然后再使用确认框的时候,就可以这样使用了


export default {

 methods: {

   // 可以不传参,使用默认参数

   @confirm()

   deleteData() {

     console.log('在这里做删除操作')

   }

 }

}

是不是瞬间简单多了,当然还可以继续封装很多很多的装饰器,因为文章内容有限,暂时提供这三个。


装饰器组合使用

在上面我们将类属性上面使用装饰器的时候,说道装饰器可以组合使用,在Vue组件上面使用也是一样的,比如我们希望在确认删除之后,调用接口时候出现loading,就可以这样写(一定要注意顺序)


export default {

 methods: {

   @confirm()

   @loading()

   async deleteData() {

     await delete()

   }

 }

}

本节定义的装饰器,均已应用到这个项目中 https://github.com/snowzijun/vue-vant-base, 这是一个基于Vant开发的开箱即用移动端框架,你只需要fork下来,无需做任何配置就可以直接进行业务开发,欢迎使用,喜欢麻烦给一个star。

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




2020-2021 设计趋势报告:用户体验篇

资深UI设计者

前言

身为用户体验设计师,无时无刻不被世界上的新事物冲刷着认知——互联网红利下降带来变化莫测的商业动向、循着摩尔定律野蛮生长日新月异的新技术、各类亚文化群体催生出多元复杂的圈层文化、脑洞口味越来越独特的年轻人,甚至眼下席卷全球的黑天鹅事件……

任何一个新事物的悄悄冒头,都有可能在未知的将来影响着用户体验设计师。我们能做的是,在起初感受到微微震幅时,便沿着震感逐步寻找源头,并思考未来的发展走向。赶在变化降临前先拥抱变化。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

本文通过研究近一两年科技、社会文化以及自身用户体验领域的变化,从用户体验领域关键的用户、媒介(设备与应用)、交互行为、信息与场景的五个角度出发,探索用户体验设计未来的趋势,希望能带来启发。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

更智能的服务提供方式

随着人工时代到来,过去机械的单向交互方式逐渐被打破,机器渐渐演化成了会主动「观察」真实场景,「感受」用户情感,预判用户意图并自动完成任务的贴心小棉袄。机器如何为人们提供更智能便捷的服务,未来还有非常大的想象空间。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

1. 基于真实场景推理用户意图

随着AI技术的发展,智能设备可以越来越无缝地将数字世界和物理世界嫁接起来,主动感知用户所处情境并智能提供相应服务。

在2019的 Google I/O 大会上,Google Lens 展示的AR点菜功能可以智能识别用户扫描的菜单并将美食网站上的相关推荐直接呈现在屏幕上。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

当用 Google Lens 识别到小票信息时,可快速提取小票上的金额,且可自动弹起计算器快速帮助用户计算人均消费,节省人工计算的时间成本。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

随着信息入口从数字空间延伸到周围的物理空间中,未来万物皆可为用户体验的媒介,设计师未来在设计的时候需要注意:

寻找适合的打通真实世界的切入点:在陌生语言、信息复杂或者难以处理等苛刻的环境下,充分发挥智能设备对信息智能读取、批量识别与翻译等强大能力,帮助用户完成任务;

将用户旅程的上下游串联:根据生活常识和经验预判用户行为目的,前置推荐服务;

更加系统细心地考量干扰因素:真实场景是动态变化的,需要更全方位考虑光线的强弱、多源的噪音、实体的可视性、人员和事件的打断等因素。

2. 任务自动化,简化用户旅程

为了完成一项任务,用户往往需要借助多个应用来回切换配合,使用起来琐碎麻烦。如今应用越做越强大也越复杂,过去仅仅解决单一场景的解决方案不再适应于用户对于完成任务的诉求。

Google Assistant 的新能力 Duplex on the web 可以通过自动跨应用任务处理来简化用户旅程。只需要用户发出语音指令「预定一辆去某地的车」,助手便可自动跨邮件、日历、付款等应用调取信息、自动根据使用习惯做选择,并自动填写信息,而用户全程需要的只是在关键节点轻敲「确认」即可。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

2019年随着 iOS 13 的更新,「快捷指令」推出了「自动化」能力,用户通过「if…then…」语法便可为自己的App设计一套程序,实现如:「当我回到公司时提醒我打卡」、「每天早上10点给我的女朋友发送一条表白短信」等能力,将不相关的场景动作串联字一起自动化执行,大大节省人工操作成本。

提升使用效率是用户体验设计孜孜不倦努力的方向之一。在利用新技术进一步简化用户旅程时,设计师可以充分利用以下因素:

借助语音输入:比起界面触控操作,语音交互的直达性可以「穿透」复杂界面,让设备第一时间明确用户目标;

基于用户行为形成习惯记忆:对用户长期重复的行为做分析处理,构建用户习惯模型并主动提供服务;

适当考虑专家级用户:随着部分用户的智能设备使用水平越来越高,可以考虑为专家用户提供自定义操作脚本,满足其自身的独特需求。

3. 基于情感感知,主动理解用户需求

随着人脸识别、表情识别、肢体跟踪等技术的提升,机器逐渐学会感性语言,主动感知用户内在情感和心理需求。

2019年1月的CES展上起亚亮相的互动式「情感驾驶空间」技术,可通过传感器读取用户的面部表情、心率等反应,调整驾驶空间内的灯光、影片类型、音乐风格等,舒缓舱内乘客心情,由此提供更人性化的出行体验。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

用户总是会期待更贴心的服务,设计师未来对同理心的情感嗅觉更加敏锐:

利用感性线索定位用户情绪:需要通过面部表情、特殊时间节点或者识别到的关键词,对用户情绪进行理解和定位,判断用户情感理解用户内心诉求是自由探索、趣味娱乐、或者静谧修行并提供符合用户当下心境的服务。

综合使用感性元素进行设计:通过使用线条、色彩、声音和动作等传达并唤起相对应的情感,提供更加人性化的体验。

4. 小结

更智能的服务提供方式会让人们生活拥有更多可能性,但一旦火候把握不得当,可能就会造成对人们生活的野蛮入侵。关于如何让科技更好造福于人们,早在上个世纪,施乐帕克研究中心提出了宁静技术(Calm Technology)的愿景,认为影响最深远的技术应该是隐匿不见的,它们如纤维般融入日常生活,丝丝入扣,直至不可分辨。

随着科技的发展,设计师对新技术不应是不加克制地应用,而应该润物细无声般地提供服务,帮助人们从繁杂喧嚣的数字世界中解脱出来,将宝贵的注意力资源投放在让生活更美好的事物上。

更自然丰富的交互方式

回顾人类和机器的交流语言,从命令行界面、图形用户界面到自然用户界面,人机交互方式越来越贴合人与人之间更自然的交流方式,其背后是心智模型与实现模型的高度拟合的趋势。

在自然用户界面中,为满足新形态智能硬件对新接口的需求,以及人们对更丰富强大的交互方式的自然诉求,越来越多的自然用户界面被开发出来。语音交互和隔空手势交互便是近几年迅速发展并落地的两种交互方式。

1. 隔空手势交互:更自由、更灵动

为了让机器更好地读懂用户的身体语言,能够感知深度信息的摄像头走进了日常手机。2019年国内外手机厂商的发布大会上,LG 手机 G8 ThinQ 以及华为发布 Mate 30 系列推出的隔空手势,可实现一些简单的诸如滑动、切歌、截屏等效果。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

除此以外,隔空手势支持更加细微的手势,如旋转、揉搓等,可以更直观、更灵活的方式操控界面,让用户获得一种像魔术师用意念控制事物运作的快感。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

对于隔空手势操作网上的言论褒贬不一,其中争议性最大的就是隔空手势宛如「杀鸡用牛刀」,明明可以用更加精准的手势触控,为什么还要用看似很酷炫其实精准度更低的隔空手势操作?

隔空手势并不是要替代触控手势成为主流的人机交互方式,更多是对情境式障碍场景的补充。在某些场景下,用户使用设备的条件可能是充满干扰的。想想看当你边看手机食谱边炒菜的时候、边煲剧边剥小龙虾的时候、疫情期间出门佩戴橡胶手套无法正常触控手机屏幕时…..隔空手势是不是特别好用?

每个人在特殊的场景下都有可能面临感官障碍,未来的设计也应该更多地考虑情境式障碍的场景,让用户无论身处何时何地依旧能一如既往无障碍地使用设备。

2. 语音交互:更精准、更好玩

语音交互作为更趋近于人与人之间最自然的交流方式,近些年有许多发展的突破点。

在发展主线上,语音交互趋向更自然、更人性化、更个性化。过去反人类的一些沟通方式慢慢被「调教」。此外,多人会话场景下的技术方案日渐增多。

2019的 Google I/O 大会展示了一个视频片段,视频中的两位嘉宾相继吐槽,经常出现针锋相对难以听清的时候,这时用户可以调节音源音量选择性增强自己关注的人物声音,让另一个人「静音」。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

△ 滑动选择音源

此外,语音交互除了在智能音箱领域广泛应用以外,也逐渐应用在广告等更多的传播媒介中,刷新人们日常使用体验。2020年2月索尼提交了一项广告播放新专利。当用户在观看电视节目时,如果出现广告,只要站起来大喊广告中对应品牌的名字,便可直接跳过这个广告。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

设计师在语音交互场景下,需要留意以下几个比较容易被忽视的因素:

用户语音交互习惯培养:如今还处于培养用户语音交互使用习惯阶段,设计师需要更多地考虑应用的语音交互规则如何才能更趋近于人们日常的沟通习惯,并进一步为人们的社会习俗所接纳。

真实场景下的多人音源:在现实情境中, 在多人对话场景下将面临音源不清、穿插停顿、噪音过多等影响体验的情况,由于计算机听觉分析能力开始从单人音源拓宽到了多人音源,多人对话解决方案上还有很大想象空间。

改变传统的视听体验:在使用场景上,语音交互接口也将逐渐运用到更多的媒介上,更全面地刷新用户体验。

3. 小结

人类拥有双手、眼睛、耳朵和发声的嘴巴,但是并不总是在每个使用场景下都能自如地使用:在安静的自习室下声音收到限制,在驾驶场景下注意力受到限制,在双手拎着东西场景下双手受到限制……但目前许多产品设计都建立在用户能完整使用感官功能这一理想化的基础上。

未来的发展趋势倾向于将视、听、触、嗅等多通道信息完美整合起来,综合使用多种输入通道和输出通道,根据用户使用场景用最恰当的方式传递服务,满足用户多方位的需求。

硬件形态带来新的挑战

尽管乔布斯曾断言3.5英寸是手机的黄金尺寸,但作为人们日常内容消费与娱乐的窗口,手机屏幕毫无疑问地变得越来越大,甚至超出传统物理限制。人们对大屏享受的追求与设备携带便捷性之间的矛盾由来已久,硬件形态的变化对旧有的用户体验设计思路带来的新的挑战。

1. 大屏幕:单手持握新挑战

屏幕横纵比越来越大,而人类的手部具有先天限制,曾经惯用的界面布局方式在高横纵比的屏幕上可能无法被大拇指无障碍全覆盖,使得越来越多的设计更加重视利用移动屏幕下半部分。

操作与信息进一步下移:

高德地图、苹果地图的搜索框下移,方便单手操作用户快速激活输入框;

影视资讯平台IMDB强化底部标签栏功能,双击「搜索」tab即可激活输入框,无须艰难地触摸顶部。

即时战斗类手游皇室战争的说明卡片主要展示在下半部分,方便用户进行卡片上的相关操作。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

底部导航被赋予更多能力:

Pocket的底部标签栏现在兼任汉堡菜单功能,在激活状态下再次点击主页icon可选择主页上须展示的内容。

利用下滑手势代替点击:

Snapchat的许多表示前后进退关系的页面都不是」返回「按钮,而是向下箭头,用户可下滑退出当前页面。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

2. 折叠屏:新形态的交互方式

为了解决设备形态和人类手部先天限制之间的矛盾,折叠屏诞生浏览并颠覆旧有的界面设计方式。

更灵活的信息布局

过去在单屏设计下,考虑到用户注意力由上到下纵向衰减,因此信息布局更多是按照优先级从上往下排序。而折叠屏中,屏幕展开后便可以开辟出更大的可利用空间,将次级页面或者较为重要的内容曝光在第二屏,对信息的布局将带来全新的变化。设计师为保证大小屏下顺畅的阅读体验,需要对信息模块在不同空间布局下的流动性有更强的把控能力。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

更便捷的多任务操作

在过去的单屏体验中,用户只能将注意力完全集中在当前的界面中,一次只做一件事。但在实际生活中,用户面临的情景往往是主线任务和支线任务的频繁交错,并且根据会任务不同的性质自由调动自己的注意力重心,如边看视频边聊天、边看直播边逛街等等。在折叠屏中,设计师可以探索更多主线和支线交错进行的场景,利用折叠屏带来的更大的屏幕空间,可以让用户在不离开主线场景的基础上进行支线任务的处理,大大节约了在不同App上来回切换的操作成本。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

更直观的拖拽交互

此外,随着多任务处理越来越广泛使用,拖拽交互将成为重要的交互模式之一。文本、表情包、图片、视频等交互对象,不再需要经过复杂的分享转发流程才能在不同App中流转,通过拖拽的方式可以更直观地进行交互。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

双面屏互动玩法

外折叠屏在折叠状态下可转为双面屏,等于是给用户增加多一个观看视角。例如华为 Mate X 的镜像拍摄可以让被拍摄者即时获知自己的镜头影像是否满意,这一拍女友神器有望成为直男拍摄终结者。在未来更多的多人观看和互动玩法将被开拓出来。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

△ 华为Mate X 的镜像拍摄

未来随着5G通讯技术的成长,越来越多的设备可以同时加入物联网,人们的生活将被各种智能设备围绕,设计师需要参与更多屏幕外的设计,让不同设备串联在一起协同合作,让用户能更加自在地享受科技的便利。

疫情催生新的线上体验

席卷全球的新冠疫情让数十亿用户乖乖待在家里。过去需要花费大量精力去教育的用户使用习惯因为疫情纷纷转变。云购物、云蹦迪、云赏樱、云监工……人们足不出户便可还原许多线下场景。随着用户线上和线下生活的界限进一步模糊,用户对于应用的效率和情感诉求也发生了变化。

1. 更关注效率导向

疫情让远程办公学习需求剧增,多人协作场景越来越频繁,许多企业随之升级了电话、视频会议、文档制作等多人协作效率软件。过去仅仅考虑少人场景协作的方式不适用,设计师需要比以往更多地考虑多人协作场景下,如何对海量密集的信息进行分析处理和展示。

在学习方式上,由于线下学习转移至线上,学生群体对于娱乐向软件也有了效率诉求。为了顺应用户诉求变化,2020年5月QQ推出学习模式,屏蔽娱乐性的内容推送,让学生更专注在学习上。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

2. 更注重缓解社交疏离感

除了效率诉求急剧提升以外,随着长时间的线上学习与办公所产生社交疏离感和缺失感,人们对于线上学习工作的情感化诉求也进一步增强。

2020年推出的plagi远程办公软件支持设置每个人的avartar形象,让大家在远程办公时依旧能时刻感受到彼此的存在。在完成任务时还可以放鞭炮庆祝,让员工能感受到亲密无间的线上办公体验。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

设计师需要更加关注如何让线上生活进一步与现实生活圈和时间线接轨,通过拓展真实社交下的更多伴生行为让线上也能还原线下的真实场景细节和互动体验,以弥补用户对真实社交的缺失感。

3. 加速人和信息的强连接

疫情的发生加速了人与信息之间的连接。人们越来越习惯将自身的身体资料、心情状态等信息沉淀在智能设备上。

为了做好广大市民群众的健康监测服务,辅助疫情防控工作,微信和支付宝在2020年年初都上线了健康码服务,不同颜色的健康码代表人们不同的健康情况,市民出入特定场所都需初始健康码。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

随着人的数据化越来越深入,个人身份信息的线上化在各平台上将成为更加通用的能力。设计师需要考虑如何更自然更低成本地将线下动态变化的资料信息线上化,更有效地对用户信息进行加工处理,以及记忆用户的使用习惯和行为,以便帮助用户更地完成任务。

疫情的出现加速了线下生活线上化,短短时间内我们看到日常习以为常的应用为响应疫情下的特殊需求纷纷出现改造,钉钉、QQ群被改造成上网课、批改作业的地方,医疗卫生公众号开辟了实时疫情播报与辟谣通道,无接触设计和服务需求异常突出……这也启发了设计师需要保持对突发事件的敏感力以及应急能力,在日常生活中留心思考,为日后突发事件提供充足的场景支撑。

关注以人为本

在汹涌的资本语境下,互联网设计师裹挟在商业驱动的结果导向中狂奔,对设计的伦理和责任鲜有发声,但伴随着互联网红利退潮,发展放缓,狂奔之下的人本问题也逐渐浮出水面。在大趋势下,UX设计师需要培养自身设计对伦理和责任的敏感度,在满足商业目的外,重拾节操,为多群体,为大社会设计,更加注重「以人为本」。

1. 更包容性的设计

包容性设计师指在做设计产品的时候,考虑到各类用户的诉求,输出具有包容性的设计方案。包容性设计依旧是2020年设计主题之一,伴随着互联网产品全球化,在通用性和包容性上也提出了新的要求。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

为身障人士设计

三星在2019年针对东南亚市场推出了一款让聋盲人士和健全人实时交流的app:Good Vibes,盲聋人轻击屏幕输入摩斯电码,预先连线好的另一台手机就会显示从盲聋人发来的短信。健全人用普通的文字输入回复,在盲聋人这一端就会翻译成摩斯电码、以手机振动的方式读出短信内容。

GOOD VIBES宣传视频:https://v.qq.com/x/page/g3108sr8qc9.html

饿了么:在饿了么送货骑手中,约8%受色盲色弱的困扰(全国男性群体中红绿色盲色弱占比达8%-9%,饿了么骑手男性占比90%),为此饿了么设计团队在2019年对app的进行了重新设计,包括使用WCAG无障碍色彩对比度,以及无障碍色盘,以及调整字阶,使用辅助图形等设计手段来解决部分骑手在送货途中使用APP的痛点问题。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

△ 饿了么UED:《为骑士创造平等 — 配送 App 的包容性设计》

跨年龄段设计

谷歌助手礼貌功能 ( Google Pretty Please ) :开启谷歌助手礼貌功能后,如果使用者在下达指令的语句中包括「Please」,谷歌助手会对礼貌的请求表示感谢,以此培养孩子的礼貌言行。

Google Pretty Please功能宣传:https://v.qq.com/x/page/e3108ue3e2t.html

Swift Playground:当10后小学生VITA君的编程课被「可敬的发量」刷满弹幕时,Swift playgrounds功不可没,这款为儿童新手学习编程的软件,用趣味的游戏方式为4岁以上低龄用户提供了一个学习编程的低门槛平台。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

为性别平等而设计

苹果emoji:回看历年苹果emoji的更新,从肤色平等,到性别、性向平等,再到为残疾人设计,2020年再为跨性别者增加新表情,性别平等依旧是包容性设计中重要一环。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

Airbnb插画:爱彼迎在插画系统中,也为不同肤色,不同职业,不同性别,以及身障人士进行了人物的绘制。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

2. 关注用户隐私

2019是互联网科技隐私问题沉浮的一年,国外有Facebook因泄露隐私收到史上最大罚单,国内则打响了「人脸识别第一案」。笼罩在隐私信任危机下,个人信息和数据立法突飞猛进,美国推动《加州消费者隐私法案》,国内也将在2020年出台《个人信息保护法》和《数据安全法》。

MIUI12推出隐匿面具功能

Android开放生态导致的权限隐私问题一直被用户所诟病,某些APP存在用户不授权就无法使用情况,针对这一情况,MIUI12推出了隐匿面具功能。当用户在开启某些APP要求授权权限时,可以选择空白通行证进行授权,从而保护用户真实信息。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

在MIUI12的更新中,还推出了照明弹、拦截网两项隐私保护功能

iOS 14剪贴板提醒

在iOS 14的更新中,保护用户隐私方面进一步升级。

其中剪贴板提醒设计很贴心,当用户打开应用,如果该应用读取了你剪贴板的内容,会在系统顶部弹出提示,用户能在第一时间意识到剪贴板内容被读取,帮助用户更好的保护自己的隐私内容。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

3. 健康的数码生活方式

科技的发展是一把双刃剑,互联网产品的发展给用户带来便捷和沉浸体验的同时,也使得用户沉溺于科技所带来的惰性和投食之下,逐渐丧失了对真实生活的把控权,被科技绑架。

数字福祉(digital wellbeing)近年被频频提起,指科技产品需要权衡好数码产品和真实生活之间的平衡,防止数码产品过渡分散用户的注意力而影响生活质量。

Android Q 专注模式 Google Android Q Focus Mode

Android Q的更新加入了专注模式,用户在专注模式下,可以在系统层面快捷地关闭使你分心的应用,让你聚焦于更重要的事情。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

防沉迷系统升级

推荐技术的进步,产品体验的升级,给用户带来了更合胃口的菜式和沉浸体验,但同时也被冠上了「电子海洛因」的称号。游戏或者内容产品的防沉迷系统依旧会是数字福祉下不可避免的趋势。

王者荣耀在2020年升级防沉迷系统,对青少年的娱乐时间和点券充值的限制进行了进一步升级。承接话。B站在2019年推出青少年模式,在该模式下,使用时长和内容推荐等做了定制化处理。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

2020年的UI设计趋势,一方面是对往年风格的衍变和细化,另一方面,在扁平克制的界面风格盛行后,设计师们向往更自由、更突破的视觉表达。

UI的继承和创新

1. 深色模式

2019年iOS 13深色模式姗姗来迟,紧接着大厂APP相继推出此功能。在2020年,深色模式会继续普及外,也会在可视性和实现成本方面有更多细节打磨和研究。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

2. 新拟态

设计趋势的发展是螺旋式上升的,在扁平化设计流行之后,对物体的拟真再一次回归设计圈,新拟态以一种对旧拟物风格的再创新,重新流行起来。

新拟物风格(Neumorphism)缘起于设计师Alexander Plyuto发布在dribbble的一组作品,以投影重新对扁平界面进行了塑造,模仿出类似浮雕的视觉效果,感受耳目一新,引起大量设计师相尽模仿。

新拟态的实用性和可落地性有待商榷,但是作为一种新的风格受到设计师拥趸,也不失为下一波风潮到来前的灵感缪斯。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

WWDC2020对mac OS的更新也重新定义了新拟态设计语言,在mac OS新系统Big Sur中,图标的设计增添了轻微的渐变、投影、高光,以此来营造图标内元素之间的纵深关系。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

3. 多彩配色

在扁平简洁UI风格盛行之后,丰富的色彩依旧是设计趋势之一,大面积色块,碰撞配色,带来更具冲击感的视觉体验。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

4. 字体装饰化

UI界面逐渐扁平,色块图标弱化,为突出页面重心和内容,iOS 11在界面标题上使用更大的字号,更粗的字重。近年在大标题的风格衍变下,文字在传达信息外,也开始有了装饰性作用,采用超大字体,成为页面排版美化的一部分。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

5. 更大圆角

大圆角的风格会继续延续,相较以往,卡片的处理圆角会更大,随之带来的是多的留白处理,结合大字号,带来更透气通透的视觉感受。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

Mac OS Big Sur的界面相对旧版本采用了更大的圆角;系统图标的设计统一成圆角矩形。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

6. 更丰富的插图

UI插图的丰富体现在样式和内容上,样式上开始3D化,内容上更注重插图叙事的表达。

7. 3D插图

3D图形往年更多运用在动态影像或运营类设计中,随着3D的普及运用,UI插图也会迎来3D化,给用户带来更立体,更新鲜的视觉感受。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

8. 讲求叙事表意

相较于往年追求形式的UI插图,新趋势下的插图更讲求功能性,每一副插图都承载一定的作用——传达功能信息或透传品牌情感;同时插图更讲求画面表意和情节,给用户叙事性的视觉体验,增进用户和产品之间的情感联系。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

9. 插图组件化

插画的流行,随之而来的是成本的水涨船高——一套系列插图为保持风格统一,往往由唯一设计师绘制,同时为兼容各类场景,设计师往往要绘制多张。

为解决插图的成本和效率,插图开始以组件化的方式进行绘制——插图设计师将插画进行拆分绘制——不同人物,不同场景,不同物件等,再通过组件化的拼接合成,使用组件的设计师可以根据需求场景自由组合,也避免了风格不统一问题。

设计师Pablo Stanley将日常绘制的插画制成一套矢量插图组件库,将人物分为:半身、全身和坐姿3大类。通过不同表情、发型和服装可自由搭配出近60万种组合。

Pablo Stanley人物插画系统:https://v.qq.com/x/page/s3108yeyhmt.html

10. 多维度动画表现

新趋势下,动画一方面回溯复古线描手绘风格,另一方面追求更三维的体验,同时帧率进一步提升,追求更流畅的视觉感受。

11. 手绘动画

手绘插图是往年的热门,其随性自然的笔触,能给用户带来亲切的感受,在新的趋势下,动画的加入赋予手绘插图一份灵性和趣味。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

12. 3D运动

Google Material Design通过卡片投影层级和二维动画规律,赋予扁平界面Z轴的纵深感。随着3D的普及流行,新趋势下的界面,界面的运动从二维走向三维,表现出3D场景下透视感。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

13. 高帧率动画

高帧率影视从线下电影院移步到线上流媒体,手机高帧率屏幕从90Hz到120Hz逐步升级,用户对画面流畅的定义一再刷新,UI动画的帧率升级也会是新的一轮趋势。

Telegram的表情采用了高帧率动画,给用户更流畅的视觉感受。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

更的涉及协作方式

体验的持续升级,产品的高速迭代,对UX设计师的设计师效率提出了更高的要求。的设计方式是一个永恒的趋势。

1. 从本地文件到云端协作

传统的文件交接方式效率低下,导致设计师之间信息不对称,最终影响产品的一致性体验。近些年在线设计协同工具发展迅速,从UI设计、 设计交付以及组件协同等环节上给设计师提供更加实时的协作体验,获得大量UX设计师的簇拥。在2019 uxtool的设计工具调研中,在线设计协同工具佼佼者figma以其协作和性能优势,大有追赶sketch之势。

随着团队对设计效率要求的提高,设计文档从本地走向云端协作是不可逆趋势。不过设计工具的迭代是需要成本的,尤其在大型设计团队,设计工具需要渡过阵痛期来完成迭代,进而提升设计效率和体验一致性。

2. 科学有效的设计系统

UX的发展,从早期的静态规范到当下的动态设计系统,是为解决产品迭代增速后带来的设计效率和产品体验问题。商业驱动下的产品迭代速度有增无减,设计系统依旧会是未来几年的设计趋势之一。

这里说的设计系统不是广义上的设计系统,而是在互联网设计的发展中,对组件化设计逐步迭代升华的一套设计协作方法:

「设计系统(Design systems)是一组为了共同目标而服务的内在相互联系的设计模式和多人协同执行的方法。」(引自《Design systems》,Alla Kholmatova,C7210翻译)。

3. 设计系统历程衍变

组件化的发展历经规范文档到UI组件,再到设计系统,形态从最初对设计一致性的指导规范,到对产品研发流程的规范,以及产品设计价值观的输出,当下的设计系统以集大成者形式影响整个产品的设计形态。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

设计系统的结构见下图:

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

4. 设计系统的求同存异

设计系统并非一成不变的,他是一个动态进化的系统,会根据团队性质、产品特性在内容上有所区分——比如大团队更应该大而全,小团队更倾向小而精;成熟产品的设计系统更倾向于打造完整闭环的合作流程机制,新产品的设计系统应该以小为始,快速迭代……

随着产品的垂直化,细分化,设计系统的趋势会是在趋势大同之下找到适合产品和团队自身的形态和节奏。

Material Design是一个包含了指导规范、组件,以及设计开发工具的自适应性设计系统。

它作为平台型性设计系统,更为大而全的规范了整个生态系统的设计风格,以及提供工具让研发者能快速产出符合规范的产品。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

△ Google生态庞大繁杂,Material Design更为全面

Ant Design作为一个为to B产品提供解决方案的平台,更多从设计可用性和完整性考虑设计系统的搭建。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

△ Ant Design通过模块化解决方案,降低冗余的生产成本,让设计者专注于更好的用户体验

QQ作为一款面向95后的2C社交产品,其设计系统Q语言从风格调性上对设计进行规范,同时给予设计师一定的自由度;也考虑到QQ内兼顾多个产品,以及界面主题样式,对基础组件的使用场景和代码进行了规范,方便设计和开发敏捷开发。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

Q语言,给予产品的自由调性之外,也针对主题和基础组件进行了规范。

每个产品和团队都有自身的特征,设计系统的建设也应该有的放矢,没有可照搬的标准答案,在大方向下找到适合自身的解决方案才是的可行之道,将效率最大化。

5. 科学有效的优化迭代

组件是设计系统中的重要组成部分,但是以往静态的、孤立的协作方式使得组件的更新迭代滞后和阻塞。随着设计系统的发展,设计师组件化思维的普及,组件的更新需要更科学的方式进行管理。

Figma在2019年推出的Design System Analytics功能,组件设计师可以借此查看组件的使用情况,包括引用次数,解组次数等,并可以生成组件使用情况的曲线趋势图,以数据的形式,科学地推动组件的优化迭代。

腾讯万字干货!2020-2021 设计趋势报告:用户体验篇

选择分析的时间段;组件使用的次数曲线图;团队使用情况;所有组件使用情况

后记

未来的用户体验会出现什么新趋势?人工智能等算法的发展、5G技术普及、新的智能设备形态、新的信息处理技术、新一代用户的喜好和口味……这些往后或将影响用户体验发展的走向。未来用户对体验的要求只会越来越高。

用户体验设计师需要了解更多的技术动向,但安身立命之本还是让用户真正受益:立足于用户真实使用场景,在理性价值层面上,打造可用、易用、的设计;在感性需求层上赋予情感上的愉悦性,在反思层面赋予意义价值。

文章来源:优设    作者:腾讯ISUX

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

10 个最佳 CSS 动画库

seo达人

目录

1. Animista

2. Animate CSS

3. Vivify

4. Magic Animations CSS3

5. cssanimation.io

6. Angrytools

7. Hover.css

8. WickedCSS

9. Three Dots

10. CSShake


1.Animista

网站地址:http://animista.net/

网站描述:在线生成 css 动画




Animista是一个在线动画生成器,同时也是一个动画库,它为我们提供了以下功能


1. 选择不同的动画

我们可以选择想要的动画类型(例如entrance/exist),除了可以选择某个动画(例如,scale-in)外,甚至还可以为该动画选择不同的展示效果(例如: scale-in-right)。




2. 定制

Animista还提供了一个功能,允许我们定制动画的某些部分,比如


duration

delay

direction

更好的是,可以选择要设置动画的对象:




3. 生成CSS代码

选择适合自己需要的动画后,我们可以直接从网站上获取代码,甚者可以进行压缩:




4. 下载代码

另一个好用的功能是,可以把自己收藏自己喜欢的动画,然后一起下载下来, 或者,我们也可以选择将这些动画的代码复制到一起。




2. Animate CSS

网站地址:http://daneden.github.io/anim...


网站描述:齐全的CSS3动画库




想必这个不用介绍,大部分人都知道了。Animate CSS 可能是最著名的动画库之一。这里简要介绍一下它的用法:


1. 用法

首先,必须在总需要动画元素上添加类animated ,然后是动画的名字。


<div class="animated slideInLeft"></div>

如果我们想让动画一直持续,可以添加infinite类。


通过 JS 来添加动画:


document.querySelector('.my-element').classList.add('animated', 'slideInLeft')

通过 JQ 来添加动画:


$(".my-element").addClass("animated slideInLeft")

2. 其它功能

Animate CSS提供了一些基本的类来控制动画的延迟和速度。


delay


可以添加 delay 类来延迟动画的播放。


<div class="animated slideInLeft delay-{1-5}"><div>

speed


我们还可以通过添加如下列出的类之一来控制动画速度。


类名 速度时间

show 2s

slower 3s

fast 800ms

faster 500ms

<div class="animated slideInLeft slow|slower|fast|faster"><div>


3. Vivify

网站地址: http://vivify.mkcreative.cz/


网站描述: 一个更加丰富css动画库




Vivify 是一个动画库,可以看作是Animate CSS的增强版。它们的工作方式完全相同,有Animate CSS的大多数类且还扩展了一些。


<div class="vivify slideInLeft"></div>

使用 JS 方式:


document.querySelector('.my-element').classList.add('vivify', 'slideInLeft')

使用 JQ 方式:


$(".my-element").addClass("vivify slideInLeft")

与Animate CSS一样,Vivify 还提供了一些类来控制动画的持续时间和延迟。


延迟和持续时间类在以下间隔中可用:


<div class="delay|duration-{100|150|200|250...1000|1250|1500|1750...10750}"></div>

4. Magic Animations CSS3

网站地址: https://www.minimamente.com/p...


网站描述: Magic CSS3 Animations 是 CSS3 动画的包,伴有特殊的效果,用户可以自由的在 web 项目中使用。




这个动画库有一些非常漂亮和流畅的动画,特别是3D的。没什么好说的,自己去尝试。


<div class="magictime fadeIn"></div>

使用 JS 方式:


document.querySelector('.my-element').classList.add('magictime', 'fadeIn')

使用 JQ 方式:


$(".my-element").addClass("magictime fadeIn")

5. cssanimation.io



网站地址: http://cssanimation.io/index....


cssanimation.io是一大堆不同动画的集合,总共大概有200个,这很强大。如果你连在这里都没有找到你所需的动画,那么在其它也将很难找到。


它的工作原理与 Animista 类似。例如,可以选择一个动画并直接从站点获取代码,或者也可以下载整个库。




用法


将cssanimation {animation_name}添加到指定的元素上。


<div class="cssanimation fadeIn"></div>

使用 JS


document.querySelector('.my-element').classList.add('cssanimation','fadeIn')

使用 JQ


$(".my-element").addClass("cssanimation fadeIn")

还可以添加 infinite 类,这样动画就可以循环播放。


<div class="cssanimation fadeIn infinite"></div>

   

此外,cssanimation.io还为我们提供了动漫字母的功能。使用这个需要引入letteranimation.js文件,然后将le {animation_name}添加到我们的文本元素中。


<div class="cssanimation leSnake"></div>

要使字母按顺序产生动画,添加sequence类,要使它们随机产生动画,添加random类。


<div class="cssanimation leSnake {sequence|random}"></div>

Sequence



Random




6.Angrytools

网站地址: https://angrytools.com/css/an...


如果使用不同的生成器,Angrytools实际上是一个集合,其中还包括CSS动画生成器。


它可能不像Animista那么复杂,但我觉得这个也很不错。这个站点还提供了一些自定义动画的特性,比如动画的持续时间或延迟。


但是我喜欢的是,我们可以在其展示时间轴上添加自定义的keyframes,然后可以直接在其中编写代码。 另外,也可以编辑现有的。




当我们完成的时候,可以得到完整的动画代码,也可以下载它。


7.Hover.css

网站地址: http://ianlunn.github.io/Hover/

网站描述: 纯CSS3鼠标滑过效果动画库


Hover.css是许多CSS动画的集合,与上面的动画不同,每次将元素悬停时都会触发。


一组CSS3支持的悬停效果,可应用于链接、按钮、徽标、SVG和特色图像等。

** 用法


它非常简单:只需将类的名称添加到元素中,比如


<button class="hvr-fade">Hover me!</button>

8.WickedCSS

网站地址: http://kristofferandreasen.gi...


WickedCSS是一个小的CSS动画库,它没有太多的动画变体,但至少有很大的变化。 其中大多数是我们已经熟悉的基础知识,但它们确实很干净。


它的用法很简单,只需将动画的名称添加到元素中即可。


<div class="bounceIn"></div>

** 使用 JS


document.querySelector('.my-element').classList.add('bounceIn')

** 使用 JQ


$(".my-element").addClass("bounceIn")






9.Three Dots

网站地址: https://nzbin.github.io/three...




Three Dots是一组CSS加载动画,它由三个点组成,而这些点仅由单个元素组成。


** 用法


只需创建一个div元素,并添加动画的名称


<div class="dot-elastic"></div>


10.CSShake

网站地址: https://elrumordelaluz.github...




顾名思义,CSShake是一个CSS动画库,其中包含不同类型的震动动画。


** 用法


将shake {animation name}添加到元素中。


<div class="shake shake-hard"></div>

使用 JS


document.querySelector('.my-element').classList.add('shake','shake-hard')

使用 JQ


$(".my-element").addClass("shake shake-hard")

人才们的 【三连】 就是小智不断分享的最大动力,如果本篇博客有任何错误和建议,欢迎人才们留言,最后,谢谢大家的观看。


代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。


原文:https://dev.to/weeb/10-of-the...


交流

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




颠覆性的macOS 11系统有哪些值得关注的设计?

资深UI设计者

苹果WWDC 2020在6月23日通过线上形式召开,本次开发者大会没有发布太多硬件产品。不过macOS的新版本macOS big Sur依旧引来了大波关注,坦诚的讲这次版本更新属实是很震惊,这可能是近10年苹果第二次颠覆性的改变,上次还是2013年的iOS 7开始全面扁平化,从而引发了设计圈「扁平拟物大战」。

颠覆性的macOS 11系统有哪些值得关注的设计?

从系统连续性上看AirPods可以在不同设备上无缝切换,不同设备直接可以复制粘贴等等,显而易见的一件事是,苹果启动了macOS的「 iOS化」,所以回归到设计上,这次的升级对设计语言上的影响概括来说有以下几个方面:

  • 全局设计调整(iOS/iPad化)
  • 拟物设计风格再次复苏了么?
  • 降低视觉复杂性-布局结构的简化处理
  • 重塑feedback设计
  • 信息提取效率进一步优化

全局设计调整

逐步 iOS 化的 macOS

不知道大家有没有这种感觉:以前从诺基亚(或Android手机)切换到iPhone,动机是cool~,漂亮的外观让人第一面就爱上了,恨不得马上就拿起来把玩。现在给你个选择切换回Android手机,不管那款手机有多漂亮多美好看,心里第一句话很有可能是:「XXX手机很棒,但我已经离不开苹果的生态了哦!」(我就是这种德行,尝试了N次还是回来了哈哈哈哈哈。)

这大概就是苹果在系统打通的层面下的功夫,更加注重生态的维护,在不同的设备间寻找更多场景产生更多联系。从设计的层面来看,iOS化的macOS对iPhone用户更加友好,有相同的操作习惯,不必在mac和iOS上来回的切换。其实在Material Design推行的过程中就有相似的做法,Chrome的全面MD化,让整个设计语言贯穿在移动设备和个人电脑中。

1. 完全继承iOS基因的控制中心/通知中心和dock

颠覆性的macOS 11系统有哪些值得关注的设计?

全新的control center,可以看的出继承了iOS/iPad OS的语言,UI和交互几乎是没有任何变化,整合系统一致性的初衷是甚好,在当下这个情况,不得不说亮度和声音的调节我更依赖于物理键盘(或touchBar),不太清楚硬整合在一起的理由(难不成是过度解读了,也许人家就想继承继承)。

从苹果对产品的终局目标来看,也许会在硬件上取消物理控制按键或者更加优化 touchBar 去操控必要的属性(也有传闻说这是在为触控版本的 macOS 做准备)。

颠覆性的macOS 11系统有哪些值得关注的设计?

同样iOS化的通知中心(讲真,用户实际的桌面未必这么干净,真是担心本身在电脑侧使用频率就不是那么高的通知中心被混乱的文件夹淹没)

2. 进一步强调的沉浸式氛围

颠覆性的macOS 11系统有哪些值得关注的设计?

全局设计中最令我欣喜的是menu Bar的更进一步的优化!我在sketch里模拟了下效果(非严谨模拟哦),大概得出的结论是加高了背景模糊值,减少了本身的填充透明度,达到了现在的效果。

感官上来看的话是一个微小的改动,但从层级整合的角度这是苹果设计的一大提升,通过光影等自然世界的隐喻抽象设计来减少硬性层级划分,也符合Alan Dye(苹果用户界面设计副总裁)提出的「深度,阴影和半透明性用于创建层次结构」。

颠覆性的macOS 11系统有哪些值得关注的设计?

拟物设计风格再次复苏?

除了壁纸以外,图标是最引人瞩目的变化啦!iOS化的图标规格的约束不用多说了,还有就是「新拟态」的第一次亮相。新拟态出现一定意义上是对这个时代获取信息时枯燥感的厌烦与反抗,举个例子:就像当你日复一日的穿基本款T恤的时候一定向往印花T恤,不管你是多么的成熟有型哈哈哈哈哈。

颠覆性的macOS 11系统有哪些值得关注的设计?

△ 左图为新拟态,右图为MD

icon的设计植入了新的设计理念,更突出去表现现实环境下的真实状态,注重光影和厚度的变化,尤其是光影。细看每一个icon,严格遵循同一个光源(正顶光)去设计。

颠覆性的macOS 11系统有哪些值得关注的设计?

但话说回来,很难讲这套icon是否成功,有几个明显的弊端也暴露出来了:

1. 可用性与美感的平衡

新拟态更重注光感的细腻程度,但对信息的有效呈现打了一定的折扣,这块苹果权衡决策下放弃了些许的美感,增强了有效的信息传递。

颠覆性的macOS 11系统有哪些值得关注的设计?

△ 图片来源dribbble

2. 统一性

对一个生态来讲,最最理想的是每一个生活在内的成员要和谐的相处,新的拟态风格相比扁平时代的图标显然给第三方开发者增加了难度,这种难度极有可能对没有太多设计资源但又想好好开发应用的创业团队造成一定的打击(换句话说催生了设计外包的工作也不错哈哈哈哈哈)。

总的来说,优势和弊端同时存在吧,啥事都没有完美的不是么~下图是这次改版里我相对还比较喜欢的几组icon了。

颠覆性的macOS 11系统有哪些值得关注的设计?

降低视觉复杂性

布局结构的简化处理

从官方的HIG介绍中,sidebar被重点提到了。透过去看,其实是布局的底层逻辑发生了变化,10.15的时候上下两段左右分栏的方式会存在一定的误区:全局action控制当前试图的交互???

从层级关系上也可以勉勉强强讲得通,但实在是太牵强了,特别是前进后退按钮存在所有文件之上这个蜜汁布局居然维持了这么久。层级清晰的梳理后带来的一大优势就是视觉的复杂性被降低了,借助现在这种列表视图,很大程度上前进后退都用不到了。

颠覆性的macOS 11系统有哪些值得关注的设计?

另外要提及的是设计师可以思考的问题,下一代模糊效果-渐进模糊。这种模拟现实生活的真实模糊包括阴影/反光/相互透出,同时要考虑光源/角度/环境等等,不再单纯的只是黑色/透明度(有兴趣的话可以在sketch里模拟下或者留言讨论讨论~)。

重塑feedback设计

人脑是需要一个提示来识别物体,我们称之为反馈设计,这是人机交互中非常重要的一个环节,这也是为什么许多按钮仍带有阴影的原因。但是,这版本的macOS工具栏图标丢失了形状以消除视觉复杂性,所以重塑后的反馈会鼓励用户去操作。

颠覆性的macOS 11系统有哪些值得关注的设计?

对于设计师来讲,不要害怕不强调所有选项,并非每个按钮都需要具有形状。只要设计足够的反馈一样可以起到被点击的效果,例如当用户将鼠标悬停在其表面上时,可能会出现更多的色彩更有趣的动画,并尽可能消除视觉上的复杂性。

信息提取效率进一步优化

这次升级除了设计上的优化外,safari的变化也足够令人欣喜,可以快速通过 tab 知道当前网页的内容的功能真是令人欣喜(虽然我记得之前Yandex浏览器就是这么做的哈哈哈哈)。

颠覆性的macOS 11系统有哪些值得关注的设计?

可以预知时间地点的apple map:

颠覆性的macOS 11系统有哪些值得关注的设计?

悄悄的说,感觉苹果越来越像腾讯了,有些小微企业的创新功能一受用户喜欢不是买过来就是抄过来,有一种垄断的感觉,想想悲催的Alfred和workflow都是这种命运。

总结

macOS big Sur 的升级可以说是苹果对未来的进一步探索,站在设计师的角度,有几个值得学习的点:

  • 具备完成的设计语言的概念植入执行当中,不管是对真实生活的隐喻(光影)还是高度抽炼(材料设计),要时刻具备宏观视角,不以一两个页面论英雄哈~
  • UI/UX的本质是对信息的规划编排,一定要保证用户的提取效率。

  • 预期与反馈是极重要的一环,包括我在内通常在做设计的时候只沉浸于界面当中,忽视了界面里的互动设计。

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


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

你现在可以使用的10个JavaScript代码段

seo达人

毫无疑问,JavaScript是Web开发中最流行的编程语言之一。无论您使用的是React,Vue还是Angular,都只是JavaScript。围绕JS展开了广泛而重要的生态系统,提供了无数的框架和库,可帮助你更快地开发应用程序。


但是有时候最好退一步,尝试了解如何在没有库的情况下做事。看看下面的代码片段,以优雅的方式解决简单的问题,并在日常项目情况下使用这些知识或为编码面试做准备。


1.反转字符串

在此示例中,我们使用扩展运算符(…),Array的reverse方法和String的join方法来反转给定的字符串。


const reverseString = string => [...string].reverse().join('');


// 例子

reverseString('javascript'); // 'tpircsavaj'

reverseString('good'); // 'doog'

2.计算数字的阶乘

要计算给定数字的阶乘,我们使用箭头函数和嵌套三元运算符。


const factoriaOfNumber = number => number < 0 ? (() => {

 throw new TypeError('No negative numbers please');

})()

: number <=1

? 1

: number * factoriaOfNumber(number -1);


// 例子

factoriaOfNumber(4); // 24

factoriaOfNumber(8); // 40320

3.将数字转换为数字数组

在此示例中,我们使用扩展运算符(…),Array的map方法和 parseInt 函数将给定的数字转换为一个单数的数组。


const convertToArray = number => [...`${number}`].map(el => parseInt(el));


// 例子

convertToArray(5678); // [5, 6, 7, 8]

convertToArray(123456789); // [1, 2, 3, 4, 5, 6, 7, 8, 9]

4.检查数字是否为2的幂

这很简单。我们检查该数字不是伪造的,并使用按位AND运算符(&)来确定数字是否为2的幂。


const isNumberPowerOfTwo = number => !!number && (number & (number - 1)) == 0;


// 例子

isNumberPowerOfTwo(100); // false

isNumberPowerOfTwo(128); // true

5.从对象创建键值对数组

在此示例中,我们使用Object中的keys方法和Array中的map方法来映射Object的键并创建键/值对数组。


const keyValuePairsToArray = object => Object.keys(object).map(el => [el, object[el]]);


// 例子

keyValuePairsToArray({ Better: 4, Programming: 2 });

// [ ['Better', 4], ['Programming', 2] ]

keyValuePairsToArray({ x: 1, y: 2, z: 3 });

// [ ['x', 1], ['y', 2], ['z', 3] ]

6.返回数组中的[Number]个最大元素

为了从数组中返回最大元素,我们使用了一个箭头函数,该函数获取数组和我们希望函数返回的元素数。我们使用扩展运算符(…)以及Array中的sort和slice方法。请注意,如果我们不提供第二个参数,则 number 的默认值为 1,因此仅返回一个最大元素。


const maxElementsFromArray = (array, number = 1) => [...array].sort((x, y) => y - x).slice(0, number);


// 例子

maxElementsFromArray([1,2,3,4,5]); // [5]

maxElementsFromArray([7,8,9,10,10],2); // [10, 10]

7.检查数组中的所有元素是否相等

在这个简短的示例中,我们使用Array中的every方法检查数组中的所有元素是否相等。我们基本上检查每个元素是否等于数组中的第一个元素。


const elementsAreEqual = array => array.every(el => el === array[0]);


// 例子

elementsAreEqual([9,8,7,6,5]); // false

elementsAreEqual([4,4,4,4,4]); // true

8.返回两个数的平均值

在此示例中,我们使用了扩展运算符(…)和Array中的reduce方法来返回两个给定数字或一个数组的平均值。


const averageOfTwoNumbers = (...numbers) => numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0) / numbers.length;


// 例子

averageOfTwoNumbers(...[6,7,8]); // 7

averageOfTwoNumbers(6,7,8,9); // 7.5

9.返回两个或多个数字的总和

要返回两个或多个给定数字或一个数组的总和,我们再次使用扩展运算符(…)和Array中的reduce方法。


const sumOfNumbers = (...array) => [...array].reduce((accumulator, currentValue) => accumulator + currentValue, 0);


// 例子

sumOfNumbers(5,6,7,8,9.10); // 45

sumOfNumbers(...[1,2,3,4,5,6,7,8,9,10]); // 50

10.返回数字数组的幂集

在最后一个示例中,我们要返回数字数组的幂集。因此,我们使用Array中的reduce,map和concat方法。


const powersetOfArray = array => array.reduce((accumulator, currentValue) => accumulator.concat(accumulator.map(el => [currentValue].concat(el))), [[]]);


// 例子

powersetOfArray([4, 2]); // [[], [4], [2], [2, 4]]

powersetOfArray([1, 2, 3]); /

// [[], [1], [2], [2, 1], [3], [3, 1], [3, 2], [3, 2, 1]]

如你所见,使用JavaScript和一些ES6魔术来解决这些任务并不总是困难的。

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



JavaScript中的map()和forEach()有什么区别?

seo达人

阅读之前

基本上,在JavaScript中遍历对象取决于对象是否可迭代。默认情况下,数组是可迭代的。map 和 forEach 包含在Array.prototype 中,因此我们无需考虑可迭代性。如果你想进一步学习,我推荐你看看什么是JavaScript中的可迭代对象!


什么是map()和forEach()?

map 和 forEach 是数组中的帮助器方法,可以轻松地在数组上循环。我们曾经像下面这样循环遍历一个数组,没有任何辅助函数。


var array = ['1', '2', '3'];

for (var i = 0; i < array.length; i += 1) {

 console.log(Number(array[i]));

}

// 1

// 2

// 3

自JavaScript时代开始以来,就一直存在 for 循环。它包含3个表达式:初始值,条件和最终表达式。


这是循环数组的经典方法。从ECMAScript 5开始,新功能似乎使我们更加快乐。


map

map 的作用与 for 循环完全相同,只是 map 会创建一个新数组,其结果是在调用数组中的每个元素上调用提供的函数。


它需要两个参数:一个是稍后在调用 map 或 forEach 时调用的回调函数,另一个是回调函数被调用时使用的名为 thisArg 的上下文变量。


const arr = ['1', '2', '3'];

// 回调函数接受3个参数

// 数组的当前值作为第一个参数

// 当前值在数组中的位置作为第二个参数

// 原始源数组作为第三个参数

const cb = (str, i, origin) => {

 console.log(`${i}: ${Number(str)} / ${origin}`);

};

arr.map(cb);

// 0: 1 / 1,2,3

// 1: 2 / 1,2,3

// 2: 3 / 1,2,3

回调函数可以如下使用。


arr.map((str) => { console.log(Number(str)); })

map 的结果不等于原始数组。


const arr = [1];

const new_arr = arr.map(d => d);


arr === new_arr; // false

你还可以将对象作为 thisArg 传递到map。


const obj = { name: 'Jane' };


[1].map(function() {

 // { name: 'Jane' }

 console.dir(this);

}, obj);


[1].map(() => {

 // window

 console.dir(this);

}, obj);

对象 obj 成为 map 的 thisArg。但是箭头回调函数无法将 obj 作为其 thisArg。


这是因为箭头函数与正常函数不同。


forEach

forEach 是数组的另一个循环函数,但 map 和 forEach 在使用中有所不同。map 和 forEach 可以使用两个参数——回调函数和 thisArg,它们用作其 this。


const arr = ['1', '2', '3'];

// 回调函数接受3个参数

// 数组的当前值作为第一个参数

// 当前值在数组中的位置作为第二个参数

// 原始源数组作为第三个参数

const cb = (str, i, origin) => {

 console.log(`${i}: ${Number(str)} / ${origin}`);

};

arr.forEach(cb);

// 0: 1 / 1,2,3

// 1: 2 / 1,2,3

// 2: 3 / 1,2,3

那有什么不同?


map 返回其原始数组的新数组,但是 forEach 却没有。但是它们都确保了原始对象的不变性。


[1,2,3].map(d => d + 1); // [2, 3, 4];

[1,2,3].forEach(d => d + 1); // undefined;

如果更改数组内的值,forEach 不能确保数组的不变性。这个方法只有在你不接触里面的任何值时,才能保证不变性。


[{a: 1, b: 2}, {a: 10, b: 20}].forEach((obj) => obj.a += 1);

// [{a: 2, b: 2}, {a: 11, b: 21}]

// 数组已更改!

何时使用map()和forEach()?

由于它们之间的主要区别在于是否有返回值,所以你会希望使用 map 来制作一个新的数组,而使用 forEach 只是为了映射到数组上。


这是一个简单的例子。


const people = [

 { name: 'Josh', whatCanDo: 'painting' },

 { name: 'Lay', whatCanDo: 'security' },

 { name: 'Ralph', whatCanDo: 'cleaning' }

];


function makeWorkers(people) {

 return people.map((person) => {

   const { name, whatCanDo } = person;

   return <li key={name}>My name is {name}, I can do {whatCanDo}</li>

 });

}


<ul>makeWorkers(people)</ul>

比如在React中,map 是非常常用的制作元素的方法,因为 map 在对原数组的数据进行操作后,会创建并返回一个新的数组。


const mySubjectId = ['154', '773', '245'];


function countSubjects(subjects) {

 let cnt = 0;

 

 subjects.forEach(subject => {

   if (mySubjectId.includes(subject.id)) {

     cnt += 1;

   }

 });

 

 return cnt;

}


countSubjects([

 { id: '223', teacher: 'Mark' },

 { id: '154', teacher: 'Linda' }

]);

// 1

另一方面,当你想对数据进行某些操作而不创建新数组时,forEach 很有用。顺便说一句,可以使用 filter 重构示例。


subjects.filter(subject => mySubjectId.includes(subject.id)).length;

综上所述,我建议你在创建一个新的数组时使用map,当你不需要制作一个新的数组,而是要对数据做一些事情时,就使用forEach。


速度比较

有些帖子提到 map 比 forEach 快。所以,我很好奇这是不是真的。我找到了这个对比结果。






该代码看起来非常相似,但结果却相反。有些测试说 forEach 更快,有些说 map 更快。也许你在告诉自己 map/forEach 比其他的快,你可能是对的。老实说,我不确定。我认为在现代Web开发中,可读性比 map 和 forEach 之间的速度重要得多。


但可以肯定的是——两者都比JavaScript内置的 for 循环慢。

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




细聊Concent & Recoil , 探索react数据流的新开发模式

seo达人

序言

之前发表了一篇文章 redux、mobx、concent特性大比拼, 看后生如何对局前辈,吸引了不少感兴趣的小伙伴入群开始了解和使用 concent,并获得了很多正向的反馈,实实在在的帮助他们提高了开发体验,群里人数虽然还很少,但大家热情高涨,技术讨论氛围浓厚,对很多新鲜技术都有保持一定的敏感度,如上个月开始逐渐被提及得越来越多的出自facebook的状态管理方案 recoil,虽然还处于实验状态,但是相必大家已经私底下开始欲欲跃试了,毕竟出生名门,有fb背书,一定会大放异彩。


不过当我体验完recoil后,我对其中标榜的更新保持了怀疑态度,有一些误导的嫌疑,这一点下文会单独分析,是否属于误导读者在读完本文后自然可以得出结论,总之本文主要是分析Concent与Recoil的代码风格差异性,并探讨它们对我们将来的开发模式有何新的影响,以及思维上需要做什么样的转变。


数据流方案之3大流派

目前主流的数据流方案按形态都可以划分以下这三类


redux流派

redux、和基于redux衍生的其他作品,以及类似redux思路的作品,代表作有dva、rematch等等。


mobx流派

借助definePerperty和Proxy完成数据劫持,从而达到响应式编程目的的代表,类mobx的作品也有不少,如dob等。


Context流派

这里的Context指的是react自带的Context api,基于Context api打造的数据流方案通常主打轻量、易用、概览少,代表作品有unstated、constate等,大多数作品的核心代码可能不超过500行。


到此我们看看Recoil应该属于哪一类?很显然按其特征属于Context流派,那么我们上面说的主打轻量对

Recoil并不适用了,打开其源码库发现代码并不是几百行完事的,所以基于Context api做得好用且强大就未必轻量,由此看出facebook对Recoil是有野心并给予厚望的。


我们同时也看看Concent属于哪一类呢?Concent在v2版本之后,重构数据追踪机制,启用了defineProperty和Proxy特性,得以让react应用既保留了不可变的追求,又享受到了运行时依赖收集和ui更新的性能提升福利,既然启用了defineProperty和Proxy,那么看起来Concent应该属于mobx流派?


事实上Concent属于一种全新的流派,不依赖react的Context api,不破坏react组件本身的形态,保持追求不可变的哲学,仅在react自身的渲染调度机制之上建立一层逻辑层状态分发调度机制,defineProperty和Proxy只是用于辅助收集实例和衍生数据对模块数据的依赖,而修改数据入口还是setState(或基于setState封装的dispatch, invoke, sync),让Concent可以0入侵的接入react应用,真正的即插即用和无感知接入。


即插即用的核心原理是,Concent自建了一个平行于react运行时的全局上下文,精心维护这模块与实例之间的归属关系,同时接管了组件实例的更新入口setState,保留原始的setState为reactSetState,所有当用户调用setState时,concent除了调用reactSetState更新当前实例ui,同时智能判断提交的状态是否也还有别的实例关心其变化,然后一并拿出来依次执行这些实例的reactSetState,进而达到了状态全部同步的目的。




Recoil初体验

我们以常用的counter来举例,熟悉一下Recoil暴露的四个高频使用的api


atom,定义状态

selector, 定义派生数据

useRecoilState,消费状态

useRecoilValue,消费派生数据

定义状态

外部使用atom接口,定义一个key为num,初始值为0的状态


const numState = atom({

 key: "num",

 default: 0

});

定义派生数据

外部使用selector接口,定义一个key为numx10,初始值是依赖numState再次计算而得到


const numx10Val = selector({

 key: "numx10",

 get: ({ get }) => {

   const num = get(numState);

   return num * 10;

 }

});

定义异步的派生数据

selector的get支持定义异步函数


需要注意的点是,如果有依赖,必需先书写好依赖在开始执行异步逻辑

const delay = () => new Promise(r => setTimeout(r, 1000));


const asyncNumx10Val = selector({

 key: "asyncNumx10",

 get: async ({ get }) => {

   // !!!这句话不能放在delay之下, selector需要同步的确定依赖

   const num = get(numState);

   await delay();

   return num * 10;

 }

});

消费状态

组件里使用useRecoilState接口,传入想要获去的状态(由atom创建而得)


const NumView = () => {

 const [num, setNum] = useRecoilState(numState);


 const add = ()=>setNum(num+1);


 return (

   <div>

     {num}<br/>

     <button onClick={add}>add</button>

   </div>

 );

}

消费派生数据

组件里使用useRecoilValue接口,传入想要获去的派生数据(由selector创建而得),同步派生数据和异步派生数据,皆可通过此接口获得


const NumValView = () => {

 const numx10 = useRecoilValue(numx10Val);

 const asyncNumx10 = useRecoilValue(asyncNumx10Val);


 return (

   <div>

     numx10 :{numx10}<br/>

   </div>

 );

};

渲染它们查看结果

暴露定义好的这两个组件, 查看在线示例


export default ()=>{

 return (

   <>

     <NumView />

     <NumValView />

   </>

 );

};

顶层节点包裹React.Suspense和RecoilRoot,前者用于配合异步计算函数需要,后者用于注入Recoil上下文


const rootElement = document.getElementById("root");

ReactDOM.render(

 <React.StrictMode>

   <React.Suspense fallback={<div>Loading...</div>}>

     <RecoilRoot>

       <Demo />

     </RecoilRoot>

   </React.Suspense>

 </React.StrictMode>,

 rootElement

);



Concent初体验

如果读过concent文档(还在持续建设中...),可能部分人会认为api太多,难于记住,其实大部分都是可选的语法糖,我们以counter为例,只需要使用到以下两个api即可


run,定义模块状态(必需)、模块计算(可选)、模块观察(可选)

运行run接口后,会生成一份concent全局上下文

setState,修改状态

定义状态&修改状态

以下示例我们先脱离ui,直接完成定义状态&修改状态的目的


import { run, setState, getState } from "concent";


run({

 counter: {// 声明一个counter模块

   state: { num: 1 }, // 定义状态

 }

});


console.log(getState('counter').num);// log: 1

setState('counter', {num:10});// 修改counter模块的num值为10

console.log(getState('counter').num);// log: 10

我们可以看到,此处和redux很类似,需要定义一个单一的状态树,同时第一层key就引导用户将数据模块化管理起来.


引入reducer

上述示例中我们直接掉一个呢setState修改数据,但是真实的情况是数据落地前有很多同步的或者异步的业务逻辑操作,所以我们对模块填在reducer定义,用来声明修改数据的方法集合。


import { run, dispatch, getState } from "concent";


const delay = () => new Promise(r => setTimeout(r, 1000));


const state = () => ({ num: 1 });// 状态声明

const reducer = {// reducer声明

 inc(payload, moduleState) {

   return { num: moduleState.num + 1 };

 },

 async asyncInc(payload, moduleState) {

   await delay();

   return { num: moduleState.num + 1 };

 }

};


run({

 counter: { state, reducer }

});

然后我们用dispatch来触发修改状态的方法


因dispatch会返回一个Promise,所以我们需要用一个async 包裹起来执行代码

import { dispatch } from "concent";


(async ()=>{

 console.log(getState("counter").num);// log 1

 await dispatch("counter/inc");// 同步修改

 console.log(getState("counter").num);// log 2

 await dispatch("counter/asyncInc");// 异步修改

 console.log(getState("counter").num);// log 3

})()

注意dispatch调用时基于字符串匹配方式,之所以保留这样的调用方式是为了照顾需要动态调用的场景,其实更推荐的写法是


import { dispatch } from "concent";


(async ()=>{

 console.log(getState("counter").num);// log 1

 await dispatch(reducer.inc);// 同步修改

 console.log(getState("counter").num);// log 2

 await dispatch(reducer.asyncInc);// 异步修改

 console.log(getState("counter").num);// log 3

})()

接入react

上述示例主要演示了如何定义状态和修改状态,那么接下来我们需要用到以下两个api来帮助react组件生成实例上下文(等同于与vue 3 setup里提到的渲染上下文),以及获得消费concent模块数据的能力


register, 注册类组件为concent组件

useConcent, 注册函数组件为concent组件

import { register, useConcent } from "concent";


@register("counter")

class ClsComp extends React.Component {

 changeNum = () => this.setState({ num: 10 })

 render() {

   return (

     <div>

       <h1>class comp: {this.state.num}</h1>

       <button onClick={this.changeNum}>changeNum</button>

     </div>

   );

 }

}


function FnComp() {

 const { state, setState } = useConcent("counter");

 const changeNum = () => setState({ num: 20 });

 

 return (

   <div>

     <h1>fn comp: {state.num}</h1>

     <button onClick={changeNum}>changeNum</button>

   </div>

 );

}

注意到两种写法区别很小,除了组件的定义方式不一样,其实渲染逻辑和数据来源都一模一样。


渲染它们查看结果

在线示例


const rootElement = document.getElementById("root");

ReactDOM.render(

 <React.StrictMode>

   <div>

     <ClsComp />

     <FnComp />

   </div>

 </React.StrictMode>,

 rootElement

);



对比Recoil,我们发现没有顶层并没有Provider或者Root类似的组件包裹,react组件就已接入concent,做到真正的即插即用和无感知接入,同时api保留为与react一致的写法。


组件调用reducer

concent为每一个组件实例都生成了实例上下文,方便用户直接通过ctx.mr调用reducer方法


mr 为 moduleReducer的简写,直接书写为ctx.moduleReducer也是合法的

//  --------- 对于类组件 -----------

changeNum = () => this.setState({ num: 10 })

// ===> 修改为

changeNum = () => this.ctx.mr.inc(10);// or this.ctx.mr.asynCtx()


//  --------- 对于函数组件 -----------

const { state, mr } = useConcent("counter");// useConcent 返回的就是ctx

const changeNum = () => mr.inc(20);// or ctx.mr.asynCtx()

异步计算函数

run接口里支持扩展computed属性,即让用户定义一堆衍生数据的计算函数集合,它们可以是同步的也可以是异步的,同时支持一个函数用另一个函数的输出作为输入来做二次计算,计算的输入依赖是自动收集到的。


const computed = {// 定义计算函数集合

 numx10({ num }) {

   return num * 10;

 },

 // n:newState, o:oldState, f:fnCtx

 // 结构出num,表示当前计算依赖是num,仅当num发生变化时触发此函数重计算

 async numx10_2({ num }, o, f) {

   // 必需调用setInitialVal给numx10_2一个初始值,

   // 该函数仅在初次computed触发时执行一次

   f.setInitialVal(num * 55);

   await delay();

   return num * 100;

 },

 async numx10_3({ num }, o, f) {

   f.setInitialVal(num * 1);

   await delay();

   // 使用numx10_2再次计算

   const ret = num * f.cuVal.numx10_2;

   if (ret % 40000 === 0) throw new Error("-->mock error");

   return ret;

 }

}


// 配置到counter模块

run({

 counter: { state, reducer, computed }

});

上述计算函数里,我们刻意让numx10_3在某个时候报错,对于此错误,我们可以在run接口的第二位options配置里定义errorHandler来捕捉。


run({/**storeConfig*/}, {

   errorHandler: (err)=>{

       alert(err.message);

   }

})

当然更好的做法,利用concent-plugin-async-computed-status插件来完成对所有模块计算函数执行状态的统一管理。


import cuStatusPlugin from "concent-plugin-async-computed-status";


run(

 {/**storeConfig*/},

 {

   errorHandler: err => {

     console.error('errorHandler ', err);

     // alert(err.message);

   },

   plugins: [cuStatusPlugin], // 配置异步计算函数执行状态管理插件

 }

);

该插件会自动向concent配置一个cuStatus模块,方便组件连接到它,消费相关计算函数的执行状态数据


function Test() {

 const { moduleComputed, connectedState, setState, state, ccUniqueKey } = useConcent({

   module: "counter",// 属于counter模块,状态直接从state获得

   connect: ["cuStatus"],// 连接到cuStatus模块,状态从connectedState.{$moduleName}获得

 });

 const changeNum = () => setState({ num: state.num + 1 });

 

 // 获得counter模块的计算函数执行状态

 const counterCuStatus = connectedState.cuStatus.counter;

 // 当然,可以更细粒度的获得指定结算函数的执行状态

 // const {['counter/numx10_2']:num1Status, ['counter/numx10_3']: num2Status} = connectedState.cuStatus;


 return (

   <div>

     {state.num}

     <br />

     {counterCuStatus.done ? moduleComputed.numx10 : 'computing'}

     {/** 此处拿到错误可以用于渲染,当然也抛出去 */}

     {/** 让ErrorBoundary之类的组件捕捉并渲染降级页面 */}

     {counterCuStatus.err ? counterCuStatus.err.message : ''}

     <br />

     {moduleComputed.numx10_2}

     <br />

     {moduleComputed.numx10_3}

     <br />

     <button onClick={changeNum}>changeNum</button>

   </div>

 );

}

![]https://raw.githubusercontent...


查看在线示例


更新

开篇我说对Recoli提到的更新保持了怀疑态度,有一些误导的嫌疑,此处我们将揭开疑团


大家知道hook使用规则是不能写在条件控制语句里的,这意味着下面语句是不允许的


const NumView = () => {

 const [show, setShow] = useState(true);

 if(show){// error

   const [num, setNum] = useRecoilState(numState);

 }

}

所以用户如果ui渲染里如果某个状态用不到此数据时,某处改变了num值依然会触发NumView重渲染,但是concent的实例上下文里取出来的state和moduleComputed是一个Proxy对象,是在实时的收集每一轮渲染所需要的依赖,这才是真正意义上的按需渲染和更新。


const NumView = () => {

 const [show, setShow] = useState(true);

 const {state} = useConcent('counter');

 // show为true时,当前实例的渲染对state.num的渲染有依赖

 return {show ? <h1>{state.num}</h1> : 'nothing'}

}



点我查看代码示例


当然如果用户对num值有ui渲染完毕后,有发生改变时需要做其他事的需求,类似useEffect的效果,concent也支持用户将其抽到setup里,定义effect来完成此场景诉求,相比useEffect,setup里的ctx.effect只需定义一次,同时只需传递key名称,concent会自动对比前一刻和当前刻的值来决定是否要触发副作用函数。


conset setup = (ctx)=>{

 ctx.effect(()=>{

   console.log('do something when num changed');

   return ()=>console.log('clear up');

 }, ['num'])

}


function Test1(){

 useConcent({module:'cunter', setup});

 return <h1>for setup<h1/>

}

更多关于effect与useEffect请查看此文


current mode

关于concent是否支持current mode这个疑问呢,这里先说答案,concent是100%完全支持的,或者进一步说,所有状态管理工具,最终触发的都是setState或forceUpdate,我们只要在渲染过程中不要写具有任何副作用的代码,让相同的状态输入得到的渲染结果幂,即是在current mode下运行安全的代码。


current mode只是对我们的代码提出了更苛刻的要求。


// bad

function Test(){

  track.upload('renderTrigger');// 上报渲染触发事件

  return <h1>bad case</h1>

}


// good

function Test(){

  useEffect(()=>{

     // 就算仅执行了一次setState, current mode下该组件可能会重复渲染,

     // 但react内部会保证该副作用只触发一次

     track.upload('renderTrigger');

  })

  return <h1>bad case</h1>

}

我们首先要理解current mode原理是因为fiber架构模拟出了和整个渲染堆栈(即fiber node上存储的信息),得以有机会让react自己以组件为单位调度组件的渲染过程,可以悬停并再次进入渲染,安排优先级高的先渲染,重度渲染的组件会切片为多个时间段反复渲染,而concent的上下文本身是独立于react存在的(接入concent不需要再顶层包裹任何Provider), 只负责处理业务生成新的数据,然后按需派发给对应的实例(实例的状态本身是一个个孤岛,concent只负责同步建立起了依赖的store的数据),之后就是react自己的调度流程,修改状态的函数并不会因为组件反复重入而多次执行(这点需要我们遵循不该在渲染过程中书写包含有副作用的代码原则),react仅仅是调度组件的渲染时机,而组件的中断和重入针对也是这个渲染过程。


所以同样的,对于concent


const setup = (ctx)=>{

 ctx.effect(()=>{

    // effect是对useEffect的封装,

    // 同样在current mode下该副作用也只触发一次(由react保证)

     track.upload('renderTrigger');

 });

}


// good

function Test2(){

  useConcent({setup})

  return <h1>good case</h1>

}

同样的,依赖收集在current mode模式下,重复渲染仅仅是导致触发了多次收集,只要状态输入一样,渲染结果幂等,收集到的依赖结果也是幂等的。


// 假设这是一个渲染很耗时的组件,在current mode模式下可能会被中断渲染

function HeavyComp(){

 const { state } = useConcent({module:'counter'});// 属于counter模块


// 这里读取了num 和 numBig两个值,收集到了依赖

// 即当仅当counter模块的num、numBig的发生变化时,才触发其重渲染(最终还是调用setState)

// 而counter模块的其他值发生变化时,不会触发该实例的setState

 return (

   <div>num: {state.num} numBig: {state.numBig}</div>

 );

}

最后我们可以梳理一下,hook本身是支持把逻辑剥离到用的自定义hook(无ui返回的函数),而其他状态管理也只是多做了一层工作,引导用户把逻辑剥离到它们的规则之下,最终还是把业务处理数据交回给react组件调用其setState或forceUpdate触发重渲染,current mode的引入并不会对现有的状态管理或者新生的状态管理方案有任何影响,仅仅是对用户的ui代码提出了更高的要求,以免因为current mode引发难以排除的bug


为此react还特别提供了React.Strict组件来故意触发双调用机制, https://reactjs.org/docs/stri... 以引导用户书写更符合规范的react代码,以便适配将来提供的current mode。

react所有新特性其实都是被fiber激活了,有了fiber架构,衍生出了hook、time slicing、suspense以及将来的Concurrent Mode,class组件和function组件都可以在Concurrent Mode下安全工作,只要遵循规范即可。


摘取自: https://reactjs.org/docs/stri...


Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following functions:


Class component constructor, render, and shouldComponentUpdate methods

Class component static getDerivedStateFromProps method

Function component bodies

State updater functions (the first argument to setState)

Functions passed to useState, useMemo, or useReducer

所以呢,React.Strict其实为了引导用户写能够在Concurrent Mode里运行的代码而提供的辅助api,先让用户慢慢习惯这些限制,循序渐进一步一步来,最后再推出Concurrent Mode。


结语

Recoil推崇状态和派生数据更细粒度控制,写法上demo看起来简单,实际上代码规模大之后依然很繁琐。


// 定义状态

const numState = atom({key:'num', default:0});

const numBigState = atom({key:'numBig', default:100});

// 定义衍生数据

const numx2Val = selector({

 key: "numx2",

 get: ({ get }) => get(numState) * 2,

});

const numBigx2Val = selector({

 key: "numBigx2",

 get: ({ get }) => get(numBigState) * 2,

});

const numSumBigVal = selector({

 key: "numSumBig",

 get: ({ get }) => get(numState) + get(numBigState),

});


// ---> ui处消费状态或衍生数据

const [num] = useRecoilState(numState);

const [numBig] = useRecoilState(numBigState);

const numx2 = useRecoilValue(numx2Val);

const numBigx2 = useRecoilValue(numBigx2Val);

const numSumBig = useRecoilValue(numSumBigVal);

Concent遵循redux单一状态树的本质,推崇模块化管理数据以及派生数据,同时依靠Proxy能力完成了运行时依赖收集和追求不可变的完美整合。


run({

 counter: {// 声明一个counter模块

   state: { num: 1, numBig: 100 }, // 定义状态

   computed:{// 定义计算,参数列表里解构具体的状态时确定了依赖

      numx2: ({num})=> num * 2,

      numBigx2: ({numBig})=> numBig * 2,

      numSumBig: ({num, numBig})=> num + numBig,

    }

 },

});


// ---> ui处消费状态或衍生数据,在ui处结构了才产生依赖

const { state, moduleComputed, setState } = useConcent('counter')

const { numx2, numBigx2, numSumBig} = moduleComputed;

const { num, numBig } = state;

所以你将获得:


运行时的依赖收集 ,同时也遵循react不可变的原则

一切皆函数(state, reducer, computed, watch, event...),能获得更友好的ts支持

支持中间件和插件机制,很容易兼容redux生态

同时支持集中与分形模块配置,同步与异步模块加载,对大型工程的弹性重构过程更加友好


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



大厂如何做好暗黑模式设计?来看 Ant Design 的规范文档

资深UI设计者

近年来暗黑模式的设计趋势开始一点点明显,Ant Design 在这次 4.0 的升级中也对这类暗黑场景化的设计开始进行初步的探索,接下来就让我们一起来看下 Ant Design 这一针对企业级的设计体系是如何设计暗黑模式的。

大厂如何做好暗黑模式设计?来看 Ant Design 的规范文档

什么是暗黑模式

暗黑模式是指把所有 UI 换成黑色或者深色的一个模式。

需要说明的是,暗黑模式不只夜间模式:

暗黑模式更多的目的是希望使用者更加专注自己的操作任务,所以对于信息内容的表达会更注重视觉性;

而夜间模式则更多是出于在夜间或暗光环境使用下的健康角度考虑,避免在黑暗环境中长时间注视高亮光源带来的视觉刺激,所以在保证可读性的前提下,会采用更弱的对比来减少屏幕光对眼睛的刺激。

同时,从使用场景上来说,暗黑模式既可以在黑暗环境,也可以在亮光环境下使用,可以理解为是对浅色主题的一种场景化补充,而夜间模式只建议在黑暗环境下使用,在亮光环境使用时很可能并不保证信息可读性。

为什么 Ant Design 要做暗黑模式

1. 更加专注内容

试想一下,我们在电影院看电影时,为什么要全场关灯?甚至有些 APP,在影片的下方也会又一个模拟关灯效果的操作,来让整个手机屏幕变黑,只剩下视屏画面的部分,这都帮助我们可以更专注、更沉浸在当前的内容下。

色彩具有层级关系,深色会在视觉感官上自动后退,浅色部分则会向前延展,这样对比强烈的层次关系可以让用户更注重被凸显出来的内容和交互操作;尤其在信息负责界面内层级关系的合理拉开对操作效率都有明显的促进作用。

大厂如何做好暗黑模式设计?来看 Ant Design 的规范文档

2. 在暗光环境下更加适用

如今社会我们身处黑夜使用手机、电脑、iPad等设备的次数越来越多,环境光与屏幕亮度的明暗差距在夜间会被放大 ,亮度对比带来视觉刺激也更加明显,使用暗色模式可以缩小屏幕显示内容与环境光强度的差距,同时也可以为设备的续航带来积极影响,可以保证使用者在暗光环境下使用 OLED 设备的舒适度。

3. 大众喜爱

黑色一直以来就可以给人以高级、神秘的语义象征,相比于浅色模式,暗色模式藏着更多可能性。

设计原则

在这次暗黑模式的设计中主要遵循以下两大设计原则

1. 内容的舒适性

不论是颜色还是文字或是组件本身,在暗色环境下的使用感受应当是舒适的,而不是十分费力的,如果一个颜色在浅色下使用正常,在暗色下却亮的刺眼或根本看不见,那必然不够舒适也不可读;所以在颜色的处理上不建议直接使用,这样会让界面变得到处都是「亮点」,让眼睛不适的同时,也会带来许多误操作。

2. 信息的一致性

暗黑模式下的信息内容需要和浅色模式保持一致性,不应该打破原有的层级关系。举个例子,在浅色模式下越深的颜色,与界面背景色对比度越大,也就越容易被人注意,视觉层级越高,比如 tooltip;在暗黑模式下我们同样需要遵循这一规律,所以对应所使用的颜色也就越浅,反之则会越深。

如何设计

1. 界面层级

在大量的企业级产品界面中,我们通常用只用一个白色背景结合分割线就可以搞定所有界面的板块层级,因为在浅色模式下有投影可以借助,然而暗黑模式中投影将不足以起到如此功效,我们需要通过颜色来区分层级关系。

在经过对蚂蚁企业级页面的典型布局结构评估后,我们在中性色中增加了三个梯度,将中性色扩展至 13 个

大厂如何做好暗黑模式设计?来看 Ant Design 的规范文档

并定义出通用情况下页面中的框架层次,主要分为三大块:

  • 应用框架:也就是我们平时定义的导航栏,也是在大结构中最上层的一部分
  • 内容组件:指页面中的具体内容,通常情况下以区块的形式存在,作为第二层级
  • 页面容器:顾名思义,指页面级别的容器盒子,可容纳页面中的所有内容,可以理解为是一个背景板,也就是最末层

在目前的暗黑体系下,我们分别为这三大块从浅到深定义了#1F1F1F、#141414、#000000 三个颜色,在实际应用中,你也可以根据自身业务的需求,从中性色板中直接选用或是依据透明度的思路自定义出合适的中性色彩。当定义出较为明确的框架层次和颜色后,也对后续系统中组件的颜色配置有着重要的指导意义。我们需要考虑组件出现在不同颜色背景下的可能性及其表现,尽量保持一致性。

大厂如何做好暗黑模式设计?来看 Ant Design 的规范文档

2. 色彩

众所周知,暗黑模式与浅色模式最大的不同就在色彩的处理上,在暗黑模式中,我们并不想打破浅色模式下基础色板的配置规律及色值,当一个应用或站点深浅模式并存时,希望在色彩上有一定延续和关联,而不是毫不相关的两套色板,这样一是避免开发及后续的维护成本,二是实际切换和使用时,可以保证一致性,这意味着需要借助一定规则。

这里分享一下我们的处理思路:

基于 Ant Design 自然的设计价值观,我们先从自然界中寻找灵感,如果说浅色模式如同初升时的朝阳,那暗黑模式就是落日下的晚霞,各有各的韵味,同一片天,唯一不同的是,受光线亮度的影响,晚霞整体会暗一些。

大厂如何做好暗黑模式设计?来看 Ant Design 的规范文档

所以我们大体的设计思路也是基于浅色的基础色板,通过结合透明度的转换,去得到一套暗黑模式下的色彩。这样的好处是,深浅模式下的色彩根基是同一个,在这样的基础上经过透明度的变换得到的结果也会相对和谐,同时也符合我们一致性的原则。

这里我们借助下面这两个概念对透明度进行转换:

对比度极性

对比度极性分为正极性和负极性。

  • 对比度正极性:指在电子文本中文本为深色,背景色为浅色
  • 对比度负极性:指在电子文本中文本为浅色,背景色为深色

这里可以给大家分享对比度查阅的一个工具:WebAIM,只要输入色值就可以看到具体的值,十分方便。

正负极性差值

顾名思义便是正负两者的差值,这里取的是绝对值。

根据一致性原则,我们尝试通过对比一套颜色的正负极性变化趋势来找到转换规律。

首先可以看下,如果一个颜色在不做任何修改的前提下直接使用,它的正负极性趋势以及差值趋势的走势和关系是怎么样的,我们尝试描绘出这样的曲线,他们的变化规律也将作为我们规则转换的参考标准。

大厂如何做好暗黑模式设计?来看 Ant Design 的规范文档

经过对比,可以发现一些变化规律:

首先来说下「差值趋势」,横向对比可以发现,不同颜色的正负极性走势是很不一样的,可以看到在黄绿色段差值曲线达到一个变化峰值,这是由于黄绿色本身由于明度、饱和度值相比其他颜色偏高,所以总是有种刺眼的感觉,生活中也会用它来作为警示、提醒的作用,所以在深浅背景下的对比度有一个比较大的差异,可以说这个变化是正常的。

这点也可以从「正负对比度极性趋势」两者间的相对关系反应出来,从红色到洋红,绿线一开始从逐渐在蓝线的上方一点,开始逐渐上移,最后在峰值处开始慢慢下移,在「极客蓝」这个色相中接近重叠,在洋红处又慢慢下移,说明浅色下越深的颜色,在深色中越亮,反之则越暗。

纵向比对单个色板,可以发现,其斜率变化主要受颜色的明度、饱和度影响,可以反应一个颜色的不同梯度在黑白背景下的变化规律。

有了这个大的变化规律,我们便可做到心中有数。首先以 Ant Design 的品牌色「破晓蓝」为例,经过在多个业务、场景中不断尝试与调整,我们得到一个透明度转换规则:

大厂如何做好暗黑模式设计?来看 Ant Design 的规范文档

大厂如何做好暗黑模式设计?来看 Ant Design 的规范文档

并将这个规则应用在其他 11 套色板中,验证其可用性。这个过程确实没有什么快捷通道,唯一的办法就是不断尝试。

大厂如何做好暗黑模式设计?来看 Ant Design 的规范文档

最后,我们将经过规则转换的实色与常规颜色的变化趋势做对比:

大厂如何做好暗黑模式设计?来看 Ant Design 的规范文档

可以看到在大趋势走向上左右两侧图基本一致,这代表两个色板在变化规律接近一致,基本可以证明规则的合理性。区别在于,对比度负极性和差值相对于右侧未经处理的值明显有所下降。这是由于透明度的处理让暗色下的颜色在明度、饱和度上有所下降导致。

再仔细观察可以发现,在左侧的常规颜色中,从破晓蓝-洋红这段偏冷色系几个颜色中,差值趋势变化最平缓的是「极客蓝」这颜色,这说明该颜色在深浅背景下的表现较为稳定,起伏不大,当基于一个统一的透明度规则前提下,会让它在暗色下的对比度减弱,所以反而会导致差值趋势变大,所以我们会发现差值趋势变化较小的颜色转移到了「破晓蓝」、「洋红」中,也是一个正常现象。

最后可以看到颜色在调整过后实际应用的效果

大厂如何做好暗黑模式设计?来看 Ant Design 的规范文档

在官网中点击「切换」即可预览:

如果上述 12 个色板不满足你的业务需求,你也可以在官网上自己选择颜色,我们会根据规则帮你生成一个暗色色板。

大厂如何做好暗黑模式设计?来看 Ant Design 的规范文档

另外,如果在实际应用过程中,你选了色相在 225~325 间的深冷色系作为主色或强调色使用,建议适当提高透明度的值,避免在暗色界面上引起阅读障碍。

大厂如何做好暗黑模式设计?来看 Ant Design 的规范文档

3. 文字

暗黑模式中,文字的使用与浅色模式基本一致,依旧从 85%-65%-45%,唯一不同的地方在 disable 的状态,其透明度值提升为 30%,避免颜色过淡真的「不可见」。另外,对于 #FFFFFF 的纯白色文字,尽量避免大面积使用,尤其对于表格、列表这类偏阅读浏览的场景,如有需要,做小范围强调即可。

大厂如何做好暗黑模式设计?来看 Ant Design 的规范文档

4. 阴影

暗黑模式中的阴影规则与浅色模式基本保持一致,但由于本身的界面背景较深,在阴影色值上也有所加深,帮助层次更好的体现,整体将色值扩大到原先的 4 倍,但在阴影的位移、扩展上均保持不变。

大厂如何做好暗黑模式设计?来看 Ant Design 的规范文档

5. 分割线

分割线在暗黑模式中建议根据界面中常用的背景色,通过透明度换算成实色使用,Ant Design 中分割线主要有 #434343 和 #303030 两种颜色,分别对应浅色模式下的 #D9D9D 和 #F0F0F0,这样做的目的主要是为了避免带来额外的交错叠加,尤其对于表格类以及很多带有 border 属性的组件,实色会更为稳妥便于记忆。

大厂如何做好暗黑模式设计?来看 Ant Design 的规范文档

适应性

适应性方面,Ant Design 的暗黑模式可以与海兔及可视化资产进行无缝衔接,使用时可以任意组合拖拽,你可以下载 Kitchen 插件,获取海量资产。

大厂如何做好暗黑模式设计?来看 Ant Design 的规范文档

结语

暗黑模式最近越来越受到人们的关注,与某一特定产品的暗黑设计不同,Ant Design 的暗黑模式更多以设计体系的角度考虑企业级这个大场景下的内容,在易用性、扩展度、复用度等方面还有许多需要完善和继续研究探索的地方,我们会在未来的迭代中逐步进行,先完成再完善。希望上述内容能对大家在暗黑模式的设计上有所帮助。

文章来源:优设    作者:AlibabaDesign

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

日历

链接

个人资料

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

存档