首页

node系列之数据接口注册接口的实现(token验证登陆)

seo达人

node系列之数据接口注册登陆接口的实现

1、使用express脚手架创建项目

2、了解项目的目录结构

3、准备数据库相关文件

4、编写注册接口

5、编写登陆接口

6、验证登陆实现

7、预告

1、使用express脚手架创建项目

// 安装脚手架,只需安装一次

npm i express-generator -g

// 创建express项目

express myapp --view=ejs

cd myapp

// 安装依赖

npm i 

// 安装需要使用的模块

// 数据库模块 用户唯一id模块 密码加密模块 token模块

npm i mongoose node-uuid bcryptjs jsonwebtoken -S



2、了解项目的目录结构

bin

www ------- 服务器启动

node_modules ------- 项目的依赖文件

public ------- 静态资源文件夹

images ------- 静态图片

javascripts ------- 静态的js文件

stylesheets ------- 静态的样式表文件

routes ------- 路由文件

index.js ------- 默认的路由

users.js ------- 用户相关的路由

views ------- 路由对应的页面

index.ejs ------- 默认的首页

error.ejs ------- 错误页面

app.js ------- 使用中间件,注册路由

package.json ------- 描述文件

3、准备数据库相关文件

大勋在node系列之数据库mongoose的封装中给大家介绍了如何封装mongoose,可以先行查看如何封装,封装的文件夹为sql,如果不想看的,可以直接通过网盘下载该文件夹



将该sql文件放置项目的跟目录下


  • myapp

    - sql

    - collection

    users.js

    db.js

    index.js



    4、编写注册接口

    目标文件: myapp/routes/users.js



    实现思路:使用post提交数据的方式,先以手机号查询有没有该用户,如果有该用户,提示用户该账号已经注册过了;如果没有该用户,则可以完成注册,首先得将密码加密,加密完成后插入数据库



    代码实现:



    // 找到用户集合

    var User = require('./../sql/collection/users');

    // 找到数据库封装文件

    var sql = require('./../sql');

    // 状态码的封装

    var utils = require('./../utils')

    // 用户唯一标识的id

    var uuid = require('node-uuid');

    // 密码加密模块

    var bcrypt = require('bcryptjs');

    var salt = bcrypt.genSaltSync(10); // 加密级别



    // 实现注册接口 -- post提交方式

    router.post('/register', (req, res, next) => {

      // 1、先获取表单信息

      let { username, password, tel } = req.body;

      // 2、根据手机号查询 用户集合中是否有该用户,如果有,返回有该账户,如果没有注册继续

      sql.find(User, { tel }, { id: 0 }).then(data => {

        // 2.1 判断有没有该用户

        if (data.length === 0) {

          // 2.2 没有该用户----继续完成注册操作

          // 2.2.1 生成用户的id

          let userid = 'users
    ' + uuid.v1();

          // 2.2.2 对密码加密

          password = bcrypt.hashSync(password, salt)

          // 2.2.3 插入数据库

          sql.insert(User, { userid, username, password, tel}).then(() => {

            res.send(utils.registersuccess)

          })

        } else {

          // 2.3 已有该用户

          res.send(utils.registered)

        }

      })

    })



    附 状态码封装模块 myapp/utils/index.js

    module.exports = {

      registered: {

        code: '10000',

        message: '该用户已注册,请直接登录' 

      },

      registersuccess: {

        code: '10101',

        message: '注册成功' 

      }

    }



    5、编写登陆接口

    目标文件 myapp/routes/users.js

    实现思路:根据手机号查询有没有该用户,如果没有,提示用户未注册,如果有该用户,使用bcryptjs模块验证密码的有效性,如果有效,生成token,返回给前端相应的token值。

    var jwt = require('jsonwebtoken');

    // 实现登陆功能

    router.post('/login', (req, res, next) => {

      // 1、获取表单信息

      let { tel, password } = req.body;

      // 2、依据手机号查询有没有该用户

      sql.find(User, { tel }, { _id: 0 }).then(data => {

        // 2.1 判断有么有该用户

        if (data.length === 0) {

          // 2.2 没有该用户

          res.send(utils.unregister)

        } else {

          // 2.3 有该用户,验证密码

          // 2.3.1 获取数据库中的密码

          let pwd = data[0].password;

          // 2.3.2 比较 输入的 密码和数据库中的密码

          var flag = bcrypt.compareSync(password, pwd) // 前为输入,后为数据库

          if (flag) {

            // 2.3.3 密码正确,生成token

            let userid = data[0].userid

            let username = data[0].username

            let token = jwt.sign({ userid, username }, 'daxunxun', {

              expiresIn: 606024// 授权时效24小时

            })

            res.send({

              code: '10010',

              message: '登陆成功',

              token: token

            })

          } else {

            // 2.3.4 密码错误

            res.send({

              code: '10100',

              message: '密码错误'

            })

          }

        }

      })

    })



    6、验证登陆实现

    目标文件: myapp/app.js

    实现思路:很多的数据请求都需要登陆之后才能获取到,在此统一封装验证登陆

    // 引入token模块

    var jwt = require('jsonwebtoken');

    // 全局的路由匹配

    app.use((req, res, next) => {

     // 排除登陆注册页面

      if (req.url !== '/users/login' && req.url !== '/users/register') {

      // 不同形式获取token值

        let token = req.headers.token || req.query.token || req.body.token;

        // 如果存在token ---- 验证

        if (token) {

          jwt.verify(token, 'daxunxun', function(err, decoded) {

            if (err) {

              res.send({ 

                code: '10119', 

                message: '没有找到token.' 

              });

            } else {

              req.decoded = decoded;  

              console.log('验证成功', decoded);

              next()

            }

          }) 

        } else { // 不存在 - 告诉用户---意味着未登录

          res.send({ 

            code: '10119', 

            message: '没有找到token.' 

          });

        }

      } else {

        next()

      }

    })




想让视觉层次更加清晰?来看这篇视觉间隔方法完全梳理!

雪涛

在网页和移动端界面中,内容和信息是否能够经过系统性、有效的整理和组织,对于内容的可用性和实用性,都是意义巨大的。而在呈现信息的时候,视觉间隔是组织信息的关键因素。它说起来并不难理解,但是在实际的运用当中,却是千变万化,今天我们来梳理一下流行的视觉间隔的方法。

什么是视觉间隔

视觉间隔是一种布局元素,它有助于将内容分隔成为清晰的分组、选项和部分。它可以让设计师更好地组织内容的视觉体验,处理信息的层级,也有助于用户理解内容,明白内容之间的关系。

视觉间隔和页面上的其他内容在一起,构成视觉层级,这是它最重要的作用。在视觉间隔的帮助之下,用户可以轻松地感知内容之间的关系,明白各个信息片段之间的关系是相似,并列,承袭,从属,还是其他。

视觉间隔的可用性也同样重要:在很多时候,有的视觉间隔元素看起来是可点击,可交互的,这在移动端界面上,是非常重要的。

视觉间隔的种类

谈到视觉间隔,我们可以从两方面来进行拆解分析:视觉间隔的外观和功能。按照视觉特征,视觉间隔有5种基本的类型:

  • 线条
  • 色彩
  • 负空间
  • 阴影/体积
  • 图片

下面我们分别针对这5种类型进行说明。

线条

很长时间以来,在排版印刷领域,线条就一直是一种用来分隔内容的方法。线条的分隔功能是认可度最高的一种间隔方式,用户几乎不用思考,就能够理解和感知它,并且发挥作用。

另一方面,这种间隔方式也很容易显得过于简单,并且和应有的形态相去甚远。这也是为什么设计师在想尽办法去寻求别的视觉间隔形态。太多的线条间隔会让屏幕上的视觉干扰太多,并且带来不必要的视觉噪音。

所以,能够将线条间隔用得微妙、恰到好处、出神入化,是设计师功力的一个重要体现。

在这个网站产品页面中,使用深色的线条间隔来分割产品信息,用来组织和间隔信息内容。

在这个页面当中,线条分隔了不同的内容区块,让页面的结构更易于被扫读。

这个电商网站将不同级别的视觉内容进行了分离,借助简单的水平线将价格、CTA按钮以及承载相关信息的表单分隔到不同的区域。

负空间

负空间,也就是留白,也是最为常见的一种视觉分隔元素。留白绝不是对空间的浪费,和屏幕上其他的元素一样,它同样发挥着重要的作用,拱卫支撑着整个用户体验。负空间是最为流行的视觉分隔之一,尤其是在极简主义风格为主导的设计当中。负空间本身遵循着格式塔原理,尤其是其中「接近原理」和「相似原理」是负空间在设计中,发挥分隔作用的核心所在。合理地运用负空间,还能强化页面的呼吸感。

上面这款旅行规划 APP当中,使用留白将不同的条目分开,没有使用额外的具体视觉元素,仅仅只靠留白。

Health Blog 的列表的排版层次是基于负空间来实现的,看起来清晰又充满呼吸感。

色彩对比

高对比度的色彩,同样能够带来清晰的视觉间隔效果。在 UI 界面中高对比度的色彩有着极为明显视觉表现潜质,它们能够增强网站的信息和内容的表现力,分割区块,营造氛围。对比度是影响页面和屏幕可读性的关键因素之一。在具体的应用当中,不同的色彩会有效地分离不同的选项、条目和区域,这意味着它作为视觉分隔的作用非常强。这也是近年来分屏式设计如此流行的原因所在。

这是一套移动端菜单的概念设计,强烈的色彩对比让信息清晰可见。

即使是在这样的柔和的设计当中,色彩的对比度也发挥了相当的作用:一方面,强烈的色彩对比让CTA按钮和输入框之间有了明显的区分,另一方面,右侧的主视觉元素的背景也同样借由不同色彩的对比,做到了突出的效果。

在 GNO Blankets 这个网站当中,强烈的明暗对比将网站元素分隔成为精美而清晰的区块。

阴影和体积

阴影和体积也是一种非常常见的视觉间隔方式,通过营造在「高度」或者说高程上的视觉差异,从而达到分层的效果,而这种设计也是符合人类一直以来的认知习惯。这种方法有利于保持整个设计的平衡和易读性,另一方面,它又能保持足够的微妙和自然,不会那么引人瞩目从而让人觉得出戏或者受到干扰。

这个APP的目录页面所有元素都采用了白色的背景,而阴影让布局呈现出了纵深层次,让内容足以展现又不显突兀。

这款提供定制化花束服务的APP也采用了类似的阴影元素,让整体看起来清晰又通透。

图片

图片在 UI 界面当中,同样也是一种非常有效的视觉间隔,尤其是在包含大量文本内容的界面中。无论是博客、在线媒体网站还是其他类型的网站当中,图片的间隔作用都非常明显。无论是照片、插画、3D图形,它们作为图片都可以很好的平衡文本内容,提高内容的识别度和可读性,有效地划分层级,并且提高情感吸引力。

这个比特币网站的着陆页就使用了带有3D效果「了解更多」动态图片,图片和文本在内容和功能上都清晰地分隔开来。

在这个餐厅 APP 当中,图片作为划分内容的关键元素而存在。

按照功能划分

如果从功能的角度上来划分视觉间隔,可以根据它所处的层次来进行划分。

全出血间隔

使用线条作为全出血间隔是最为常见的,它会很跨整个屏幕布局来作为信息层级的划分。

这个画廊图库 APP 的艺术家目录当中,使用线条作为全出血间隔,来区分艺术家。

这个名为完美食谱的APP也使用了全出血间隔线来区分内容。

在这个财务APP当中,也使用了全出血间隔线来区分条目。

在这个电影APP的结帐页面当中,也使用了线条来作为全出血间隔。

嵌入式间隔

嵌入式间隔的功能是将相关性较高的内容分割开,并且它通常会和标题或者其他的特定元素保持对齐或者对应,它们通常是进行某个大区块内不同组件的分隔,或者将多个同类的元素分隔开。

这个网站当中,使用横向的短分隔线来区分表单中的参数条目。

中间分隔

这种分割线通常会置于布局的中间某处,同样是分隔相关的内容,但是通常它们在属性上不一定是一致的,但是层级近似。

在这个出售草药的电商网站的右侧,使用中间分隔线将文本和可交互的区域清晰地分隔开。

值得思考的问题

上面对于不同类型的视觉分隔方式都有描述,在此之外,还有两个问题需要注意:

  • 保持微妙:视觉分隔不应该醒目、太过引人瞩目,它们不应该分散用户的注意力,它们应该支撑布局的同时,微妙而不那么抓人眼球。

  • 中等频率:这和上一点是相辅相承的,过多的分隔线会变成视觉噪音,让用户浏览的时候感到疲倦。因此,应该仔细考虑使用频率,尽可能使用负空间,而不是线条。不要过度使用太多色彩,应该尽量保持整体的协调一致。

文章来源:站酷

通知系统的设计规则全面分析

雪涛

我们通过门铃声儿得知门外有人来访,也能通过电话铃声得知正被人呼叫。短信通知也有着类似的作用,包括各类产品的消息推送。

但不同的是,消息推送的重要性随着「通知」被滥用而变得不那么重要了。它们变得不像门铃或电话铃声起到的作用性那么大,包括短信现在也大多是垃圾信息。

而且,通知越来越多地通过各种方式去触达用户。比如消息未读的红点提示,或者显示消息的数字统计,以及手机使用过程中的顶部提示与声音或震动的提醒,等等。

但我们还是无法抑制点击图标的冲动,这仅仅是因为它具有未读的计数或红点提示,即使我们已经知道当中的内容并不重要。

而我要说的是,当通知内容变得次要且被滥用之后,它仿佛成了一种违背设计原则的功能 —— 中断用户当前行为。因为它打破了用户与产品之间的层级关系,破局至产品之外来吸引用户的注意力,这是一个非常打扰的行为。如果我在看书,突然收到一条并不重要的消息,那我一定会非常反感。

所以,为了不被「红点」支配,以及不让通知所打扰,我会把手机里所有产品的消息推送都给关了。

但是,以上内容并不能说明通知的无用论。同样有许多用户还是沉迷于通知的使用上,它所控制的是用户对于某个产品的控制欲,担心错过某条消息,就好像我在豆瓣写了篇随笔,就想看别人给我点赞评论的消息,但我又不可能一直盯着,所以通知这时候就起到了一个很好的作用。

以至于对于优秀的产品人或设计师,包括运营来说,利用好通知,就能掌握用户心理,巧妙的将用户留在产品中。它们甚至有助于与打算放弃产品的用户建立联系并促进互动。

那么,我们应该如何更合理的设计通知呢?下面我们通过「通知的组成部分」以及「通知的使用类型与规则」来详细做一次拆解。

通知的组成部分

关于通知的简单定义:它是一种吸引用户注意的功能模式,让用户获悉新事件的信息动态。产品将其发送给用户并与用户产生交流。

因此从这个定义中我们可以知道,通知有两种形式,分别是被动只读型和操作反馈型。

被动只读型,是指该信息可读,但不可进行操作;操作反馈型,是指用户可对该通知进行操作,如某宝订单支付成功后的地址信息确认通知。

所以在梳理组件的时候也要注意掉这个差异。

1. 消息中心

这里的消息中心,是一个信息汇总中心,但并不一定是信息来源。意思是,信息来源可能是有很多用户在你的文章下面点赞了,而这个点赞行为被汇总到了消息中心,再用消息中心指引作者去到文章页面查看具体详情。

所以它是一个汇总表。但也有可能它就是信息来源点,比如一些系统通知,告知要升级,因为它没有其他功能可承载,所以只会在消息中心里出现。

或者类比 iOS 系统的通知中心,如果通知是 App 推送的,那么它会指引用户进入某个 App;如果通知是系统行为,如勿扰模式,「6:00 前来电和通知将会静音」这个通知,是只可在通知中心进行操作的。想要更改,就需要手动打开设置。

2. 通知指示符

它可以是点,也可以是计数器,只要表明目前消息中心有新的信息就可以。我个人一直觉得这就是让我们多数人养成强迫症的罪魁祸首。

3. 信息标题

它主要是指该信息来自于谁或属于什么子类型,比如用户互动点赞消息,评论消息,系统消息等等。用户可以通过标题来获悉该信息类型,再通过内容摘要来判断内容是否重要。

当然,这里的摘要如果过长,就需要省略处理,引导用户进入消息源或消息中心。

4. 推送时间

推送时间是一个看起来简单,实际上也好像不是很复杂的逻辑。只要说明该通知的发送时间即可,但是需要注意的是时间段问题。比如几分钟前,几小时前,几天前,这里的逻辑是按照时间推进规则持续增加来告知用户该消息的推送时间节点的。也就是过得越久,时间概念就越大。

5. 通知图标

上面讲到消息类型,我们也经常会在各类产品中发现不同通知的类型会汇总在各自的类型下。包括用户所接收到的信息,通常也会告知用户该信息属于什么类型。有时候,标题可能会更细,但是用户通过图标可以判断该信息属于什么类型,甚至都不需要仔细查看标题与内容。

但是,并不是所有产品的信息都可以通过图标来判断,有时候图标只是一个大方向,如果手机锁屏,相对于用户来说,这条通知只是告诉用户该信息是由什么产品推送,而并不能指向至该产品的什么类型的信息。所以在使用的过程中,同样需要根据业务的场景,谨慎地选择图标。

6. 阅读指示器

它就像是上面提到的红点,这里指的是进入 App 的消息中心之后,所显示的内容。

7. 操作行为

这里的操作行为分两种,分别是 App 外与 App 内,它们之间的操作逻辑是不同的。iOS 系统通知的清除操作,只是在系统的通知中心将该信息清除,进入具体 App 后,这条消息还是会存在。而在 App 内删除该条信息,则该信息才会真正消失。

所以从上面可以看到,通知推送,是有两大类别的,分别是 App 外与 App 内,它们之间的逻辑关系与展示形式会有所差异,需要根据具体情况进行设计分析。

8. 小结

对上面的内容进行总结,可以得到这样一幅画像:

大部分系统或产品的通知组成,都可以通过此图概括,唯一不同的是,它们会随着不同的业务而发生变化。

比如豆瓣的推送消息告知用户近期有新的电影上映,那么通知来源要么是电影模块的功能详情页,要么是通知中心的系统消息;而通知类型就是内容更新;详情则根据具体内容来组合排列;最后送达至用户。

而其中的差别就是,如果是通知中心推送的,用户点击之后则是进入通知中心列表。如果是具体功能推送的,那么用户点击进入的就是具体功能页面。如下图所示:

从这里可以看出,通知是有具体模式的。

一旦确定了通知的主要目标,以及想要解决的问题,包括它们如何对业务产生作用以及对用户形成吸引力,就可以确定通知的具体样式了。

在这一节里只要知道通知的组成部分与通知模式如何指引用户进入 App 即可。后面我来带大家理一遍逻辑,以及在设计通知时要注意哪些问题。

通知的使用方法

聊完上面的内容之后,我相信大家对通知的组成与使用模式已经有了全新的认识,但也仅此而已,我们还是不知道一个优秀的通知功能应该从哪些方面去提升用户体验。这里面所包含的不止是表象,还有内在的规则逻辑。所以从这一节开始,我们仔细来梳理一遍。

从我们平时使用到的,以及上文提到的,可以大概先梳理出几类常见的通知类型。

1. 用户信息类通知

这种类型的通知有很多,比如微信消息发送,知乎私信,手机短信等等,它们主要由用户主动生成发送至其他用户被动接收,作用就是促进用户与用户之间的互动关系,以提升用户使用产品的频率与时长。

这种通知,可给予用户操作也可不给予操作,不操作就是读取,并回复;操作就是可对该用户的信息进行屏蔽、已读、删除等设置。

这是最常见的通知类型,在多数社交产品与有社交特性的产品里都能看到。

说明

之所以给予用户信息的操作行为,是因为用户信息可分为感兴趣的与不感兴趣的,它主要取决于人。不感兴趣的人,频繁的发送信息,会影响用户对产品的好感度,毕竟有很多用户消息并不是用户想要接收的,所以在社交产品里,用户可删除好友,或拉黑好友;在有社交属性的产品里,用户可拉黑账户,以达到不被骚扰的诉求。

如果没有到达删除好友的程度,也可对该好友的信息进行屏蔽,甚至对该好友信息做已读而实际上未读的处理;或者对重要信息做未读而实际上已读的处理。

当然,用户还能对群消息做更复杂的设置。这就是产品对这类通知的一种优化方式。

2. 系统推送类通知

我们经常会在手机上收到一种系统类通知,或者在 App 中也会收到类似的系统通知。大多是关于系统升级,密码更新等。

这类通知多数是用户被动接收,且对于系统与用户来说是较为重要的。当然也有不重要的,比如 App 更新说明的通知,告知用户新功能有什么变化,或系统更新了什么等等。

对于这类通知,用户大多无法进行设置,因为它们比较强制,没有可以商量的余地,类似于告知用户:我们有新的消息,比较重要,你来看看,即使你不打算更新或执行也来看下。

说明

系统类通知,通常来说较为被动,要么强制用户执行操作,要么就是提醒用户系统近期做了更新,或者是一些并不重要的信息提示,比如勿扰模式。

强制类系统通知不能频繁,否则会给用户造成控制欲反制的副作用。类似于本身用户使用产品需要对产品享有控制权,现在反而被产品控制了。这是不行的。

3. 通用推送类通知

这类通知就是第一节中提到的那些,比如点赞/评论,内容更新等等,这类通知如果是忠实用户,那么或许不会反感它的频率,当然还是需要适当。但如果是普通用户,那么造成的影响就是直接关闭该 App 的所有通知。

我们现在的很多人,之所以开始反感通知的主要原因,就是这类通知所造成的。内容不断更新,随着时间的推移,每天推送多条对于该用户来说无用的通知。包括只适合一些符合条件的用户参与的活动通知也推送给所有人,那么用户就会逐渐对这类产品的通知失去兴趣,造成无法弥补的损失。

即便像某团一样,经常弹出开启通知的弹框,也依然无法召唤回用户。这就是很典型的下场。

说明

通用型通知,如果是业务很复杂的产品,就必须建立通知推送的功能模块,给予用户进行选择接受哪类信息的权力。允许用户进行相应的设置,如活动类推送可拒绝接收。

在很多产品中都已经置入这样的推送模块设置,如下图。

这类内容就是针对于产品的具体业务进行细分。

比如兴趣精选,私信消息等做好类别划分。用户可对自己感兴趣的通知做选择性的推送接收。

另外就是,在相同账户的不同设备之间,推送应该同步推送与被处理。不能这边推送了,那边没推送,或者这边处理了,那边没被处理。

4. 智能推送类通知

不知道大家是否有印象,在使用如大众点评等产品时,只要你切换了城市,产品就会推送通知告知用户该城市有哪些值得游玩的景点与品尝的美食。

虽然这类通知还算不上多少智能,但至少在用户群体中是存在这类诉求的。而这类诉求有时候并不能主动感知,因为用户可能会想不起来通过哪类产品来查找附近美食。当这么一条通知出现的时候,正好解决了用户的问题,反而提升了用户对于产品的好感度。

现在很多产品的通知都逐渐智能化,不会像以前那样,三更半夜发来一条无关紧要的通知。而出现这类问题的主要原因还是在于产品、设计、运营,在这方面没有下过功夫,只将通知作为一种普通的工具来使用。导致用户开始排斥通知,将其强制关闭。之后,就很难再让用户开启了。同理心效应,当做这类功能的时候,可以回想一下自己是如何被其他产品打扰的。

随着大数据的发展,我相信未来的通知系统会更加全面,且能做到千人千面的模式,不过在此之前,各位产品设计师,还需要对通知下一番功夫才是。

5. 小结

我们还可以继续举例说明,但是基本大同小异,所以到这里为止,我再对上面的内容做一次总结,梳理出一个好的通知应该是如何设计的。

干扰最小化:通知本身具有强制性和干扰性。它的目的是把用户的注意力吸引到产品上来,所以要认真思考发送通知的内容、时间、频率;不要提醒用户当前屏幕上已经处于展示状态的内容;也不要推送与用户无关的系统信息。

跨设备:当用户读过了某条信息,这条信息应该不再做展示。同理,用户也应该能够在其它更适合接收消息的设备上找到已读信息。用户通知应该在所有设备上进行同步。

允许设置:允许用户在「设置」中禁止或调整通知的形式。如案例一,通过选择推送内容,来影响接收推送的频率。案例二,可选消息提醒的形式是红点+数字,或仅是红点。

时效性:良好的通知应尽可能实时推送。而不是等这件事情都过去很久了,才推送给用户知道。

支持汇总:把同类型的通知合并为一条,并显示信息未读数量。也可以考虑一键展开通知,显示信息详情。

可操作性:把通知和操作结合在一起,让用户不需要打开首页就能对特定通知进行常规操作。操作应该清晰明了,且仅在未重复默认操作时提供。同时操作应该是有意义、实时、和内容对应的,并且能让用户完成某个任务。如案例一,可以在不打开邮件的情况下,直接对通知进行管理、查看和清除。案例二中的操作针对的是未读邮件,可便捷地在通知板面进行回复、删除、标为已读或垃圾邮件。

总结

对本篇文章的拓展总结:

  • 通知具有召唤属性,但是频率过多就会变成打扰,所以要注意通知的频率与内容重要性;
  • 设计师或产品经理应该将通知的内容分类梳理出来,以便维护或新增必要需求可能需要用到的推送信息。
  • 通知一般为两种类型,一类是推送只读型,一类是操作反馈型;设计师需根据不同类型的通知做好对应的设计,针对具体问题具体分析;
  • 想要利用好「通知」,也需要对业务有详细的了解,再代入本文所列举的注意点,就可以设计出一个体验更佳的通知模式。
  • 通知规则不会脱离本篇文章的范围,所以只要详细研读,必会有所收获。

文章来源:站酷

如何创建精致的UI界面布局篇

分享达人

前言

前面已经完成这个系列的 “排版和图形”两篇文章,本周接着后面的 布局篇幅,我们知道布局的好坏直接影响产品美观度,不同形式的布局,给用户带来的感受是不一样的,产品也将会有不一样的性格,因为布局直接影响界面空间疏密程度,不同产品都有着不同空间,那么我们要如何做,才能更好的去布局,并且能在激烈的竞争中脱颖而出,现今大部分产品基本都是长得差不多,作为设计师更应该去多研究一些布局趋势,并能将其融汇在自家产品中。 




为什么要重视布局

- 
布局对界面设计来说十分重要,不仅是我们常说的在移动端或者web端的设计中,他在车载中、电视端UI或者VR设计同样有很大影响。我们知道界面设计中最关键的五大基础语言;形,色,字,质, ,其中 构(结构)即是我们所说的布局,五个维度之前已经和大家分享了 图形和字体篇,今天我们可以看下布局对界面设计的影响,以及我们该如何通过布局来使界面设计看起来更加有范,更有自己的视觉特征点在里面。 




目前主流布局趋势是怎样的

-

前面在向大家介绍布局的重要性和他对界面设计的影响,那么如果我们需要做出一些比较有创新的布局来提高界面精致度,该如何去下手呢?我们可以通过观察目前主流一些趋势做法,了解国外设计师如何找到更有创意的方式来设计他们的布局 - 并将一些创意运用到界面设计中的,下面我们一起看下。 





偏移与叠加网格布局

-

网格布局我相信大部分人都知道,很熟悉,那么今天所说的偏移叠加网格布局是什么样子的呢?其实就是我们在设计界面时候,把最底层基础网格搭建好后,上层的内容排版,通过错落叠加方式来布局,这种布局的优点是留白空间大,呼吸感强,图文错落交织一起,形式感增强。缺点是,运用的范围会小一些,承载内容少,一般Web端运用比较多。当然也有一些移动端设计个性化产品存在这样的布局 (Rover APP)可以去下载体验下。 


上图文字与图片交叠错落排版,图片与图片之间也是网格交错



上面移动端设计,设计师通过留出左侧空网格,整体内容往右侧偏移,导航相对内容来说做了差异化设计,并未进行偏移设计(看我上图红框部分)  。这样做的目的是因为,我们点击汉堡菜单的时候,本来整体就要往右侧移动,如果再继续移动,那么内容会显示不下,同时视觉效果并没有很好



半偏移网格布局,界面中并非所有的内容都偏移底层网格,而是部分模块这样去做,原因是内容多的情况下。





分屏布局

- 

分屏布局,顾名思义就是将屏幕进行几种不同区域的划分,然后内容分布排版在里面,分屏布局解决的主要问题将屏幕大的设备进行合理划分空间设计,一般是在横屏运用比较多,比如PAD,或者WEB或者车机中控屏,下面一起看下分屏布局在实际设计中的具体表现



上图界面设计采用了1/2分屏布局,将图片与内容文字进行区域划分,下图是将主文案摆放在分割区域中间(文字较少情况下可以这样去做)增强形式感。当然分屏布局可以有多重形式,列如,2/3,1/3,3/4等等,可以根据内容进行选择合适分屏





Z轴视差布局

-

视差布局,在web app或者web端布局常用比较多的一种,运行方式当滑动页面内容时内容与内容之间运动速率会有时间差,同时Z轴空间位置也会有深度差异,这样就形成了视差效果,视差布局一般在H5界面出现比较多,用于营销场景会多一些,当然WEB端倒是比较常见 


地址:https://www.stereo.ca/project/clinique-dentaire-gagnon/





内容重叠布局

- 
内容重叠布局,打破了传统平整的极简注意风格,扁平化设计将会加入Z轴空间元素,使得整体设计有了新颖的布局方式,这也是一种区分竞争产品的布局方式,一般内容重叠产品大多出现在偏杂志化设计的产品中,如之前我介绍图形篇时候提到 韩国29cm
他们详情页,运营页面运用了重叠布局。 



地址:https://www.stereo.ca/project/clinique-dentaire-gagnon/






卡片布局

- 
为什么要把卡片布局拿出来讲?卡片布局应该是我们见过最多的布局了,卡片布局也会有很多种方式去布局,根据产品内容复杂程度去建立卡片容器大小,卡片作为承载内容的容器,对于响应式布局也是非常有利的支持,我们看appstore,behance的移动端,都是卡片布局。 



卡片布局还有一个最大好处就是,他能够封装内容,使得画面布局整洁,所有内容都往容器里面放,信息之间保持很好的区分



全封闭卡片布局,内容之间通过卡片封装,中间无空隙





自由式网格布局

- 
这种网格布局相对来说比较开放性的,布局上多以卡片承载内容为主,卡片跟随隐形网格随机分布在画板中,有点类似我们说的暴瀑流布局方式,这种会比较灵活,一般会在摄影类,杂志类,文艺类产品居多。 







如何运用这些布局进行创新设计

-

上面已经列举了目前比较流行的一些布局,可能部分人还是感觉不会使用,也不会很好的去利用在自己设计中。要么就直接把别人布局抄袭过来,其实是有方法的,我们可以把自己认为比较好的一种布局拿出来,然后拆解他,拆解完后,再来重新组装,组装的时候,你可以参考下其他布局,两者集合起来,就像乐高积木一样,你可以有很多种组合方式。 


上面利用乐高积木思维重新对布局进行拆解组合,当然一切的布局都是基于当前你的主旨,你的产品内容,找到合适布局,然后去研究他,并且拆解,然后重新搭建属于自己产品一套布局规则





总结

-

全文向大家介绍5种布局思路,当然其实不止这5种,但是其他布局相对来说会运用少一些,这些布局我们可以加以学习利用,可以运用在任何设计中去,当然运用的时候,一定要清晰知道自己产品的主旨目标,用户群体,合理运用布局,做出创新设计!


转自:站酷-设计TNT 

如何让你的设计更有说服力?掌握这五个体验设计原则··

分享达人

从数个项目中总结出的体验设计原则,包括详细的举例说明

李笑来说过一句话:审美常常并不需要知道原理,但创造美的人必须有方法论,否则不可能持续创造。但是很多人总觉得背方法论是笨工夫,高手难道不应该根据场上局面随机应变吗?但事实是,随机应变才是笨办法,方法论和成语典故、数学定理一样,是人脑思维中的快捷方式,“聪明人”之所以能做到随机应变,是因为他们脑中存有足够多方法论,当遇到事情时,这些方法论像神经一样互相连接,给出最优的解决方案。

 

今天就跟大家分享设计的方法论——设计原则,在方案输出时,可以将设计原则作为方案的自检工具,这样在方案内审时,面对领导和同事的质疑,除了说“大厂都是这么做的”这样苍白无力的解释外,还有更多的设计原则做支撑。

 

一、一致性

一致性的益处:对用户来说,一致性可以降低学习成本,对开发团队来说,可以减少错误,降低产品的维护成本,提高代码和设计的复用率。对企业来说,一致性意味着产品的不同模块要有相似的外观、感觉和行为,这种特性会被扩展到企业其他产品中(比如Adobe旗下的产品都严格保持着相同的标准),有利于强化用户对品牌的认知,建立品牌忠诚度。

 

一致性的弊端:很多设计师容易被这一原则而禁锢,进而成为设计师偷懒的借口,设计师有时为了强调一致性而忽略了特定情境下的用户行为和使用模式,所以在设计时不能只关注用户的感觉和品牌认知,要根据特定场景敢于创新。

 

一致性可以从以下几个维度分析:

 

1、交互行为一致性,交互行为一致性又包括操作方式,控件,控件位置等。拿最近做的项目举例,「转到银行卡」和「信用卡还款」虽两个不同功能,但尽量使模块内控件,控件位置及操作方式保持统一。


2、视觉表现一致性,包括风格,色彩,文字,图标,图片等。风格和色彩的统一比较容易理解,这里详细说一下图标和图片如何保持统一。


图标的统一性:

1)一款产品在各个平台上的图标要一致

2)多款产品在一个平台上的图标之间的风格或规范要一致

3)一款产品的每个图标的风格、细节、体量感上要一致


如何做到每个图标风格,细节,体量感上的统一?

1)保持图标的复杂程度或简约程度统一

2)不使用潦草、手绘的造型,几何形更容易达到统一

3)保持图标的维度统一(二维/三维)

4)保持图标阴影、渐变等样式统一或均无样式

5)保持图标颜色或图标背景的颜色统一

6)保持图标的尺寸和比例统一(体量感)

7)保持图标线的粗细统一

8)保持图标圆角大小统一


如何做到图片的一致性:

1)图片的处理方式一致(尺寸比例,圆角,投影)

2)图片的风格一致,图片风格是否保持统一视产品属性而定,像淘宝这样的电商平台想要保持图片风格的统一性简直要了店家的命,但是图片的处理方式可以做到统一,比如淘宝的商品图大部分是灰色背景等。

 

3、文案的一致性,文案的人称,风格保持一致,网易云音乐的文案都是用的第二人称,且具有很强的趣味性。

二、优先级

优先级可以从以下几个维度分析:


1、功能优先级:把握核心需求,突出亮点功能,拿最近做的项目举例:转账主页面功能优先级最高的是「转到银行卡」「微转账」,所以在页面布局、所占比重上强调这两个功能,同时上滑时两个按钮变小冻结在页面顶部,方便用户快捷使用。


2、内容优先级:内容分级,突出核心内容。拿最近做的项目举例:代金券详情页,根据用户使用卡券的场景,以及数据分析得出的内容优先级对内容进行布局与设计。将优先级最高的代金券二维码放在用户视线触达的位置,当用户上滑时,底部出现全局浮动的按钮,可快速显示二维码。


再比如,转账后的状态页面,用户最关心的内容是转账后的状态及转账金额,其次是收款方信息以及转账备注,将信息进行整理、归类、隐藏、删减,避免不重要信息对用户获取重要信息时的干扰。点击箭头可查看更详细的转账信息,最后的页面设计如下:


3、交互优先级:主要路径清晰,减少干扰和分支。如下转账流程中,根据用户每一步骤的目的与使用场景进行信息呈现,该出现的时候出现,不该出现时隐藏,分步骤进行,使转账这一主路径清晰明了,减少其他信息对用户的干扰。


4、视觉优先级:重要的视觉信息第一眼看到,主要次要信息有所区分。如微信钱包页面,收付款和钱包的视觉优先级明显高于下方的腾讯服务。美团首页上方虽都是功能按钮,通过图标的体量、大小、位置拉开彼此层级,突出展示「扫一扫」「付款码」「红包/卡券」「骑单车」这些功能,很好的引导了用户视线,完成产品目标和用户目标。


三、易读性

易读性可以从以下几个维度分析:


1、使用用户语言而不是开发者语言,贴近生活实际而不是学术概念。图1是改版前的页面,页面的核心目的是通过图表、止鼾次数、分贝向用户传达止鼾器的止鼾效果,呈现方式不直观,且用户对分贝并没有确切的概念,图二将分贝巧妙的转化成蜜蜂的声音,增强了易读性,在这里蜜蜂的声音就是用户语言,分贝即开发语言。


2、符合用户认知与心智,延续约定俗成概念。苹果的首席设计师乔纳森·艾弗说:“好的设计无需认知门槛”,好的设计不需要任何指示用户就知道如何操作。如下图苹果系统的亮度设置,向上滑动是提高亮度,向下滑动是降低亮度,而不是向下是提高,向上是降低。


再比如,根据我们的正常认知,下一步应该在右,上一步在左。


3、保持简洁,不给用户造成困扰与疑惑。还是拿之前做的项目举例:微转账不同于普通的银行卡转账,需要给用户进行解释说明,改版前的说明直接将大段的解释文字展示给用户,可读性差,改版后将大段的解释转化成4个直观的步骤,对用户来说更容易理解。

四、容错性

容错性可以从以下几个维度分析:


1、操作前可预知:有预防用户出错的措施,关键操作有确认提示,及早消除误操作。如图1输入转账金额时提前告知用户银行卡余额,避免余额不足让用户重复输入;图2提前告知用户提取的金额是50的倍数,避免用户出错。



分期还款时,提前告知用户一个账单周期只能申请一次分期,且在用户二次确认的弹出框再次提示。



2、操作中有反馈:给用户明确的错误信息,并协助用户方便从错误中恢复工作。如在分期金额输入错误时及时告诉用户出错的原因。



3、操作后可撤消:允许用户撤消错误操作,如mac系统垃圾箱中「放回原处」功能:



微信对话中的「撤回」功能,这些都体现了系统的容错性。


五、可控性

可控性可以从以下几个维度分析:


1、记忆及预测用户行为,帮助用户做些事情,减轻用户记忆负担。如mac系统的密码管理可以帮助用户记住常用的账户密码:

邮件中,输入收件人的姓,软件能自动检索出该姓下曾出现过的所有用户的邮件地址。


2、对操作给予及时反馈,用户能了解操作是否已生效,用户在界面上的任何操作,不论是单击、滚动还是按下键盘,或者操作状态变化,界面应及时给出反馈。


3、将操作状态或进度显示出来,用户能了解当前系统状况,如让用户实时了解货物的物流信息,会减轻用户等待的烦躁感,同时增加可控感。


4、用户清楚知道自己当前在哪里,退路在哪里,可以去哪里,如分页控件就能明确的告诉用户自己在哪,退路在哪,还能去哪。




5、提供适时帮助、必要的信息提示,如最常见的功能引导



回顾:


一、一致性

1、交互行为一致性:操作,控件,位置。

2、视觉表现一致性:风格,色彩,文字,图标,图片。

3、文案措辞一致性:提示语,功能按钮等。


二、优先级

1、功能优先级:把握核心需求,突出亮点功能。

2、内容优先级:内容分级,突出核心内容。

3、交互优先级:主要路径清晰,减少干扰和分支。

4、视觉优先级:重要的视觉信息第一眼看到,主要次要信息有所区分。

 

三、易读性

1、使用用户语言而不是开发者语言,贴近生活实际而不是学术概念

2、符合用户认知与心智,延续约定俗成概念。

3、保持简洁,不给用户造成困扰与疑惑。

 

四、容错性

1、操作前可预知:有预防用户出错的措施,关键操作有确认提示,及早消除误操作。

2、操作有反馈:给用户明确的错误信息,并协助用户方便从错误中恢复工作。

3、操作后可撤销:允许用户撤销错误操作。



五、可控性

1、记忆及预测用户行为,帮助用户做些事情,减轻用户记忆负担。

2、对操作给予及时反馈,用户能了解操作是否生效。

3、将操作状态或进度显示出来,用户能了解当前系统状况。

4、用户清楚知道自己当前在哪里,退路在哪里,可以去哪里。

5、提供适时帮助、必要的信息提示。


-希望此文对你有一点帮助


转自:站酷-poppy



干货|尼尔森十大可用性原则案例解析

分享达人

尼尔森的十大可用性原则,它们被称为「启发式」,<br>被奉为交互设计师的入门法则。

开篇灵魂拷问:


你认为一个怎样的产品才算是一个好的产品?

这个问题耳熟吗?面试的时候是不是有被问到过?
我们经常使用的那些产品,哪些是好的产品呢?

当我们谈论一个 APP 产品时,
作为用户你最关心的是什么?
一般都是是这个产品好用吗?功能复杂吗?
而不是这个产品用户界面颜色好看吗?
交互的动效酷炫吗?

互联网已经深入到每个人的生活当中,
时刻影响着我们;
一个好的产品会给我们带来便捷,
使我们的生活变得简单而又美好;
也会有一些产品使用时会感到不舒服,
糟糕的产品体验会让我们的生活变得复杂而又烦恼。
所以,决定一个产品好不好用,
能不能长期使用都是用户体验直接决定的。
用户体验关注的是在满足用户需求的同时带给用户美好的感受。

接下来我们来聊一聊「尼尔森十大原则」,
这十大原则是具体而又全面的用户体验可行性检验方法。

    
尼尔森是谁?
雅各布·尼尔森(Jakob Nielsen)是毕业于哥本哈根的丹麦技术大学的人机交互博士,他拥有79项美国专利,专利主要涉及让互联网更容易使用的方法。于1995年1月1日发表了「十大可用性原则」。1995年以来,他通过自己的 Alertbox 邮件列表以及 useit.com 网站,向成千上万的 Web 设计师传授 Web 易用性方面的知识,尽管他的一些观点可能带来争议,至少在 Web 设计师眼中,他是 Web 易用性领域的顶尖领袖。2006年4月,并被纳入美国计算机学会人机交互学院,被赋予人机交互实践的终身成就奖。他还被纽约时报称为“Web 易用性大师”,被 Internet Magazine 称为 “易用之王”。
        
尼尔森的十大可用性原则,它们被称为「启发式」,      
    
    
是广泛的经验法则,而不是特定的可用性指导原则。
虽然是1995年提出来的,
但是至今仍然被奉为交互设计师的入门法则,
我们不能把它上升为一种标准,
而只当做一种经验来学习,
然后跟现实中的设计结合来使用。
因为尼老师是从 web 设计提出的十大可用性原则,
我们要结合的是目前移动互联网的特点,

然后在「尼尔森十大原则」的结构下探讨在用户体验上达到的目标。


尼尔森十大可⽤用性原则为:

01. 状态可见原则 

02. 环境贴切原则 

03. 撤销重做原则

04. 一致性原则 

05. 防错原则

06. 易取原则 

07. 灵活原则 

08. 易扫原则 

09. 容错原则 

10. 人性化帮助原则


下面我们就针对每一条来单独分析一下吧~


 ·.  状态可见原则 
系统应该让用户知道发生了什么,
在适当的时间内做出适当的反馈。
不要蒙蔽用户;
沟通是所有关系的基础,无论⼈还是设备。

示例:在淘宝里,我下拉时他告诉我「松开刷新」,也就是现在还没有开始刷新;我松开后状态变更成「刷新中」,表示现在正在刷新。
这样的设计告诉我们,界面现在是什么状态,现在在干嘛,在整个功能的变化过程中我们都能看到对应的文字描述。


其他示例:下拉刷新时的加载中,加载完成提示,收藏成功、支付成功、实付失败等提示。


·. 环境贴切原则

功能和服务贴近用户使用的场景,

符合当前场景用户的体验。

产品的功能和服务应该贴近真实世界,

让信息更自然,逻辑上也更容易被用户理解。


示例:我们在店里买东西的时候经常会听到这样的声音「支付宝导致:5元」就是贴近环境的设计。
商家需要确认你是否付钱,
但是又经常忙于手头的事情无法及时查看;
而这样功能的设计,商家即使在忙着手头的事情依然能通过声音来确认已经收到你的钱了。
这样的设计对于商家和消费者是友好便捷的。


 ·.  撤销重做原则 

在使用产品时了解和掌控当前页面。

如果用户误操作,可以随时撤销,用户在使用产品时足够自由。


示例1:我们用微信和对方聊天时,当我们写了很多字,发出去时却发现其中有错误,这时我们可以使用微信的撤回功能,体验更好的是,撤回消息旁边有「重新编辑」功能,可以让之前编辑的文本回到对话框重新编辑再发送。如下图:


示例2:iOS系统照片的删除和撤回


·. 一致性原则

同样的文字、状态、按钮,都应该触发相同的事情,遵从通用的平台惯例。也就是,同一用语、功能、操作保持一致。主要包括以下五个方面:


1. 结构一致性

保持一种类似的结构,新的结构变化会让用户思考,规则的排序能减轻用户的思考负担。

示例:微信中每个模块的条目都有统一的「图标+文字信息」的结构样式,能让用户快速了解每一个模块;


2. 色彩一致性

产品所使用的主要色调应该是统一的,而不是换一个页面,颜色就不同。

示例:淘宝的图标颜色与界面的主色均为橙色,也包括其中一些标签和强调的文字颜色都是橙色色。整个界面除了图片的有效信息外,都通过灰、白、橙色色来呈现,界面保持了很好的一致性;


3. 操作一致性

能在产品更新换代时仍然让用户保持对原产品的认知,减小用户的学习成本。

示例:微信在对话框和通讯录都采用了左滑出操作的交互,如下图:


4. 反馈一致性

用户在操作按钮或者条目的时候,点击的反馈效果应该是一致的。

示例:QQ的每个分组点击后都是向下展开组内成员列表;


5. 文字一致性
产品中呈现给用户阅读的文字大小、样式、颜色、布局等都应该是一致的。
示例:例如微信几个关键界面的字体:三个主界面内容结构不尽相同,但是,列表的标题字体和间距都一样,这样让整个APP视觉上看起来很舒服;


 ·.  防错原则
比出现错误信息提示更更好的是,用设计防⽌止这类问题发生。在用户选择动作发⽣生之前, 就要防止用户容易混淆或者错误的选择。

1. 限制操作范围与条件;
示例:未输入验证码前,底部的登录按钮是置灰不可点击的,只有填写完整,底部的登录按钮才会变为可点击状态。这就是为了防止用户犯更多错误;


2. 对有风险的操作进⾏二次确认;
示例:删除个好友时,通过二次弹窗给出防错措施。

·. 易取原则

减少用户记忆负荷,在适合的时机给用户需要获取的信息。
1. 为用户提供历史记录、关注、收藏等功能;
示例:爱奇艺为用户提供了看过记录和我的收藏,帮助用户记忆:



2. 选择而不是输入,尽量降低输入成本;

示例1:打车软件自动获取当前位置;

示例2:iOS系统收到验证码后自动带入到键盘,点击直接输入;


·. 灵活原则

对于新用户来说,需要功能明确、清晰,对于老用户需要快捷使用高频功能。不可为了某一种用户,把不必要的信息占据重要部分。主要体现在3个方面:

1. 自定义功能或模块的展示位置;

示例:支付宝首页的应用是可以根据自身喜好自定义的,包括定义常用应用、排序、删除、新增等等。这样用户可以根据自己的个人兴趣定制自己适合的应用分布方式,这就叫做用户定制常用功能,如下图:


2. 将“常用”自动归纳以提升使用效率;

示例:微信聊天界面表情弹窗中会有一个「最近使用」的模块,它把个人平时使用频率或者次数最多的表情进行归类。当用户使用的时候,能很快的找到自己喜欢或者常用的表情,提高了聊天效率;包括饿了么的「我的订单」里的每一个订单都可以通过再来一单重新一键下单,如下图:


3. 缩短操作路路径,提升使⽤用效率与体验;

示例:微信的对话框,当点击「+」调出下面的操作选项时,会默认弹出刚截图或拍照的照片,方便用户直接调取,还有APP长按后出来的快捷操作列表,如下图:


·. 易扫原则

直译:美学和简约的设计;页面不应包含不相关或很少需要的信息,页面中的每个额外信息都会降低主要内容的相对可见性。

示例:如下图列表中出现的信息都是用户比较关注的信息,比如配送费,配送时间,距离等;携程的选择机票界面讲最重要的时间和机票价格放大突出,让用户能一眼看到,如图:


 9 ·. 容错原则

直译:帮助用户识别、诊断和从错误中恢复;我们尽量避免用户出现错误,但当出现错误时,我们应该尽量去安抚用户的挫败感。

⽤配图+文字代替「404」,明确告诉用户哪⾥错了和解决方案。

示例:界面加载失败时的刷新提示,还有登录时的手机号码校验,如果手机格式错误会出现会提示用户手机格式不正确和正确的格式。


 10 ·. 人性化帮助

帮助性提示最好的方法是:

1.无需提示:非常简单易懂,用户看界面就知道怎么操作,无需提示;

2.一次性提示:只需要一次提示用户就懂如何使用;

示例:常见的新功能引导、引导⻚等,示例:


3.常驻提示: 较重要的提示,用于指导或帮助用户;

示例:支付宝转账时,常驻在顶部的安全确认提示,还有转账时的服务费提示,如图:


4.帮助文档:稍微复杂一点的软件,虽然要让他尽量简单但帮助文档都是必要的;

示例:微信设置界面里的「帮助与反馈」,还有支付宝转账时弹出来的「求助反馈」,点进去后的常见问题界面;


以上就是我对Jakob Nielsen(雅各布·尼尔森)的十大交互设计原则的理解和实例解读,希望对大家有所帮助。如果大家同样对这些方面有些兴趣或者看了后有些什么想法,欢迎一起讨论。

转自:站酷-搞设计的月野兔



Vue源码剖析(三)patch和Diff算法

seo达人

Patch和Diff算法

网上看了好多的博客和源码教程,感觉很多仔细的地方没有说清,而且在一些复杂的部分加了好多的描述,所以就想自己也写下心得, 方便自己, 方便他人,有兴趣的同学可以关注我的github里面有我之前一些博文 github/193Eric



我们知道的,在数据更改后,会触发getter,然后通过dep.notify()来通知watcher触发update进而更新视图,最终是通过Diff算法来对比新老Vnode的差异,并把差异更新到Dom视图上



Diff

我们知道的,Virtual DOM是一颗树,而diff算法主要把两颗树进行对比,找出之间的差异,来渲染页面



diff 算法是通过同层的树节点进行比较而非对树进行逐层搜索遍历的方式,所以时间复杂度只有 O(n),是一种相当的算法



1.调用patch函数比较Vnode和OldVnode,如果不一样直接return Vnode即将Vnode真实化后替换掉DOM中的节点



2.如果OldVnode和Vnode值得进一步比较则调用patchVnode方法进行进一步比较,分为以下几种情况:



Vnode有子节点,但是OldVnode没有,则将Vnode的子节点真实化后添加到真实DOM上



Vnode没有子节点,但是OldVnode上有,则将真实DOM上相应位置的节点删除掉



Vnode和OldVnode都有文本节点但是内容不一样,则将真实DOM上的文本节点替换为Vnode上的文本节点



Vnode和OldVnode上都有子节点,需要调用updateChildren函数进一步比较



updateChildren比较规则



提取出Vnode和OldVnode中的子节点分别为vCh和OldCh,并且提出各自的起始和结尾变量标记为 oldS oldE newS newE



如果是oldS和newE匹配上了,那么真实dom中的第一个节点会移到最后



如果是oldE和newS匹配上了,那么真实dom中的最后一个节点会移到最前,匹配上的两个指针向中间移动



如果都没有,在没有key的情况下直接在DOM的oldS位置的前面添加newS,同时newS+1。在有key的情况下会将newS和Oldch上的所有节点对比,如果有相同的则移动DOM并且将旧节点中这个位置置为null且newS+1。如果还没有则直接在DOM的oldS位置的前面添加newS且newS+1

直到出现任意一方的start>end,则有一方遍历结束,整个比较也结束



updateChildren例子:



假设:



真实dom为 A、B、C

oldDom为 A1、B1、C1

newDom为 A2、D2、C2、B2



先确定oldS = A1 ; oldE = C1; newS = A2; newE = B2



先对比oldS和newS,oldE和newE,发现oldS = newS 所以真实dom的A固定不动。排序为 A、B、C

然后oldS = B1 ; oldE = C1; newS = D2; newE = B2



对比发现 oldS = newE , 所以真实dom,B要插入到后面去



真实dom排序为:A、C、B



然后oldS = C1; oldE = C1; newS = D2; newE = B2



对比发现两两都不对等,所以走第三步。

假设有key存在,所以newS直接和oldDom里面的所有节点对比,发现没有存在,然后插入到oldS前面,且newS+1

真实dom排序为:A、D、C、B

然后重新开始,oldS++ > oldE-- ,结束了。



这就是updateChildren,之后就是一直遍历,运行updateChildren直到没有


一文秒懂 ajax, fetch, axios

seo达人

1, JavaScript的Ajax

Ajax的全称是Asynchronous JavaScript and XML,意思就是用JavaScript执行异步网络请求,而不需要重载(刷新)整个页面。

Ajax使用XMLHttpRequest对象取得新数据,然后再通过 DOM 将新数据插入到页面中。另外,虽然名字中包含 XML 的成分,但 Ajax 通信与数据格式无关; 这种技术就是无须刷新页面即可从服务器取得数据,但不一定是 XML 数据。

对于IE7+和其他浏览器,可以直接使用XMLHttpRequest对象,对于IE6及以前的浏览器,使用ActiveXObject对象。



使用方法如下:



var xhr;

if (window.XMLHttpRequest) {

    xhr = new XMLHttpRequest();

} else {

    xhr = new ActiveXObject('Microsoft.XMLHTTP');

}

1

2

3

4

5

6

启动请求:



xhr.open(method, url, boolean);     

xhr.send();

1

2

注:

1,xhr.open参数含义:

method:请求方式,post、get等

url: 请求链接,只能向同源的url发送请求

boolean:是否异步请求,true:异步, false: 同步,默认为true

2,调用 open()方法并不会真正发送请求, 而只是启动一个请求以备发送。

3,send()方法接收一个参数,即要作为请求主体发送的数据(post方法会使用,get方法直接传null)。如果不需要通过请求主体发送数据,则必须传入 null,因为这个参数对有些浏览器来说是必需的。调用send()之后,请求就会被分派到服务器。



XMLHttpRequest对象的异步请求示例如下:



function success(text) {

    console.log(text);

}



function fail(code) {

   console.log(code);

}



var xhr = new XMLHttpRequest();     // 新建XMLHttpRequest对象

xhr.onreadystatechange = function () { 

    // 状态发生变化时,函数被回调

    if (xhr.readyState === 4) { // 成功完成

        // 判断响应结果:

        if (xhr.status === 200) {

            // 成功,通过responseText拿到响应的文本:

            return success(xhr.responseText);

        } else {

            // 失败,根据响应码判断失败原因:

            return fail(xhr.status);

        }

    } else {

        // HTTP请求还在继续...

    }

}



// 发送请求:

xhr.open('get', '/api/categories');

xhr.send(null);

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

xhr的属性含义如下:

responseText: 作为响应主体被返回的文本。

responseXML: 如果响应的内容类型是"text/xml"或"application/xml",这个属性中将保存响应数据的 XML DOM 文档。

status: 响应的 HTTP 状态。

statusText: HTTP 状态的说明。

readyState :表示请求/响应过程的当前活动阶段。可取值如下。

0: 未初始化。尚未调用 open()方法。

1: 启动。已经调用 open()方法,但尚未调用 send()方法。

2: 发送。已经调用 send()方法,但尚未接收到响应。

3: 接收。已经接收到部分响应数据。

4: 完成。已经接收到全部响应数据,而且已经可以在客户端使用了。

只要 readyState 属性的值由一个值变成另一个值,都会触发一次 readystatechange 事件。可以利用这个事件来检测每次状态变化后readyState 的值。通常,我们只对 readyState 值为 4 的阶段感兴趣,因为这时所有数据都已经就绪。不过,必须在调用 open()之前指定 onreadystatechange事件处理程序才能确保跨浏览器兼容性。



另外,在接收到响应之前还可以调用 abort()方法来取消异步请求:



xhr.abort();

1

调用这个方法后,XHR 对象会停止触发事件,而且也不再允许访问任何与响应有关的对象属性。在终止请求之后,还应该对 XHR 对象进行解引用操作。由于内存原因,不建议重用 XHR 对象。



2, jQuery的Ajax

$.ajax({

        url:"",

        type:"GET",

        contentType: '',

        async:true,

        data:{},

        dataType:"",

        success: function(){

        }

});

1

2

3

4

5

6

7

8

9

10

url 必填项,规定把请求发送到哪个 URL。

type 以什么样的方式获取数据,是get或post

contentType:发送POST请求的格式,默认值为’application/x-www-form-urlencoded;

charset=UTF-8’,也可以指定为text/plain、application/json

async 是否异步执行AJAX请求,默认为true,千万不要指定为false

data 发送的数据,可以是字符串、数组或object。如果是GET请求,data将被转换成query附加到URL上,如果是POST请求,根据contentType把data序列化成合适的格式;

dataType

接收的数据格式,可以指定为’html’、‘xml’、‘json’、'text’等,缺省情况下根据响应的Content-Type猜测。

success 可选。执行成功时返回的数据。

缺点:

是基于XHR原生开发的,目前已有的fetch可替代。本身是针对mvc的编程模式,不太适合目前mvvm的编程模式。jQuery本身比较大,如果单纯的使用ajax可以自己封装一个,不然会影响性能体验。



3,Axios

Vue2.0之后,axios开始受到更多的欢迎。其实axios也是对原生XHR的一种封装,不过是Promise实现版本。它是一个用于浏览器和 nodejs 的 HTTP 客户端,符合的ES规范。



axios具有以下特征:



从浏览器中创建 XMLHttpRequest

支持 Promise API

客户端支持防止CSRF

提供了一些并发请求的接口

从 node.js 创建 http 请求

拦截请求和响应

转换请求和响应数据

取消请求

自动转换JSON数据

PS:防止CSRF:就是让你的每个请求都带一个从cookie中拿到的key, 根据浏览器同源策略,假冒的网站是拿不到你cookie中得key的,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。



设置全局的 axios 默认值



axios.defaults.baseURL = 'https://api.example.com';

axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;

axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'

1

2

3

注:axios 的 headers的 content-type 默认是 “application/json ”



默认情况下,axios将JavaScript对象序列化为JSON,如果是get请求,对请求参数不用做任何处理,但是如果是post请求,并且Content-Type 为application/x-www-form-urlencoded,需要使用URLSearchParams API格式化请求参数, 否则Content-Type依然是application/json



var params = new URLSearchParams();

params.append('param1', 'value1');

params.append('param2', 'value2');

1

2

3

get请求,以下3中写法完全等价



axios.get('/user?id=12345&name=xiaoming')

.then(function (response) {

    console.log(response);

})

.catch(function (error) {

    console.log(error);

});

1

2

3

4

5

6

7

axios.get('/user', {

    params: {

      id: '12345',

      name: 'xiaoming'

    }

})

.then(function (response) {

    console.log(response);

})

.catch(function (error) {

    console.log(error);

});

1

2

3

4

5

6

7

8

9

10

11

12

axios({

    url: '/user',

    method: 'get',

    params: {

      id: '12345',

      name: 'xiaoming'

    }

})

.then(function (response) {

    console.log(response);

})

.catch(function (error) {

    console.log(error);

});

1

2

3

4

5

6

7

8

9

10

11

12

13

14

post请求,以下2种写法完全等价



axios({

    url: '/user',

    method: 'post',

    headers: {

        'Content-Type': 'application/json'

    },

    data: {

      id: '12345',

      name: 'xiaoming'

    }

})

.then(function (response) {

    console.log(response);

})

.catch(function (error) {

    console.log(error);

});

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

var url = '/user';

var data = {

      id: '12345',

      name: 'xiaoming'

    };

axios.post(url, data, {

       headers: {

        'Content-Type': 'application/json'

    }

})

.then(function (response) {

    console.log(response);

})

.catch(function (error) {

    console.log(error);

});

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

执行多个并发请求



function getUserAccount() {

  return axios.get('/user/12345');

}

 

function getUserPermissions() {

  return axios.get('/user/12345/permissions');

}

 

axios.all([getUserAccount(), getUserPermissions()])

  .then(axios.spread(function (acct, perms) {

    // 两个请求现在都执行完成

}));

1

2

3

4

5

6

7

8

9

10

11

12

创建实例



可以使用自定义配置新建一个 axios 实例



axios.create([config])

var instance = axios.create({

  baseURL: 'https://some-domain.com/api/',

  timeout: 1000,

  headers: {'X-Custom-Header': 'foobar'}

});

1

2

3

4

5

6

配置会以一个优先顺序进行合并,顺序由低到高为

1,在 node_modules/axios/lib/defaults.js 找到的库的默认值

2,实例的 defaults 属性

3,请求的 config 参数



// 使用由库提供的配置的默认值来创建实例

// 此时超时配置的默认值是 0

var instance = axios.create();

 

// 覆写库的超时默认值

// 现在,所有请求都会等待 2.5 秒

instance.defaults.timeout = 2500;

 

// 为已知需要花费很长时间的请求覆写超时设置

instance.get('/longRequest', {

  timeout: 5000

});

1

2

3

4

5

6

7

8

9

10

11

12

拦截器



在请求发出之前或响应被 then 或 catch 处理前拦截它们做预处理。



// 添加请求拦截器

axios.interceptors.request.use(function (config) {

    // 在发送请求之前做些什么

  }, function (error) {

    // 对请求错误做些什么

  });

 

// 添加响应拦截器

axios.interceptors.response.use(function (response) {

    // 对响应数据做点什么

  }, function (error) {

    // 对响应错误做点什么

  });

1

2

3

4

5

6

7

8

9

10

11

12

13

可以在稍后移除拦截器:



var myInterceptor = axios.interceptors.request.use(function () {/.../});

axios.interceptors.request.eject(myInterceptor);

1

2

可以为自定义 axios 实例添加拦截器



var instance = axios.create();

instance.interceptors.request.use(function () {/.../});

1

2

4, fetch

window 自带了 window.fetch 方法, 在版的 Firefox 和 Chrome 中已经提供支持,其他浏览器还有兼容性问题,要做兼容性处理。fetch 是一个 基于promise设计的low-level API,不是ajax的进一步封装,而是原生js,它注定不会像你习惯的 $.ajax 或是 axios 等库帮你封装各种各样的功能或实现.



interface GlobalFetch {

    fetch(input: RequestInfo, init?: RequestInit): Promise<Response>;

}

1

2

3

fetch()是一个全局的函数,返回一个promise对象。它有两个参数,第一个参数是请求的地址,第二个参数是可选,RequestInit是个对象格式如下:



interface RequestInit {

    body?: any;

    cache?: RequestCache;

    credentials?: RequestCredentials;

    headers?: HeadersInit;

    integrity?: string;

    keepalive?: boolean;

    method?: string;

    mode?: RequestMode;

    redirect?: RequestRedirect;

    referrer?: string;

    referrerPolicy?: ReferrerPolicy;

    window?: any;

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

优点:

符合关注分离,没有将输入、输出和用事件来跟踪的状态混杂在一个对象里

更好更方便的写法

更加底层,提供的API丰富

脱离了XHR,是ES规范里新的实现方式

fetch中可以设置mode为"no-cors"(不跨域)



缺点:

fetch不支持同步请求

fetch只对网络请求报错,对400,500都当做成功的请求,需要封装去处理

fetch默认不会带cookie,需要添加配置项

fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了流量的浪费

fetch没有办法原生监测请求的进度,而XHR可以



fetch的使用示例:



window.fetch(url)

    .then(response => {

        if (response.ok) {

            //通过 response 原型上的 json 方法将 response.body 转换为 JS 对象,再返回出去

            return response.json();

        }

    }

).then(result => {

    console.log(result);

}).catch(error => {

    console.log(error);

})

1

2

3

4

5

6

7

8

9

10

11

12

需要注意以下几点:

1,用 response.ok判断fetch请求是否成功

2,服务端只返回了response对象,而真正的请求结果,即 response.body,则是一个 ReadableStream。fetch 将 response.body 设计成 ReadableStream 在请求大体积文件时变得非常有用。然而,在我们的日常使用中,还是短小的 JSON 片段更加常见。而为了兼容不常见的设计,我们不得不多一次 response.json() 的调用。不仅是调用变得麻烦,如果你的服务端采用了严格的 REST 风格,对于某些特殊情况并没有返回 JSON 字符串,而是用了 HTTP 状态码(如:204 No Content),那么在调用 response.json() 时则会抛出异常。

3,Response 限制了响应内容的重复读取和转换,response .json / response.text 方法只能使用一个并且只能使用一次,同时使用两个,或使用两次都会报如下错误:



Uncaught (in promise) TypeError: Failed to execute 'json' on 'Response': body stream is locked

1

为什么不能使用两次?

因为数据流只能读取一次,一旦读取,数据流变空,再次读取会报错。

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

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

原文链接:https://blog.csdn.net/weixin_41480546/article/details/102805864

重磅发布!天猫双十一品牌设计背后的故事

雪涛

一年一度,天猫双十一全球狂欢节,如约而至!

从2015年开始,我们每年都会在双十一期间,将双十一品牌设计的完整思路分享给大家,这已经成为双十一设计团队的传统。不为别的,各位同仁辛苦一年,想跟大家就着新鲜出炉的设计唠唠嗑。

每逢双十一logo出街,都会有热心的朋友帮我们解读,也有人问我们为啥不搞个官方发布?各位朋友,您现在看到的就是官方发布的内容,它不只有logo,而是从头到尾一个完整的故事。

△ 2019天猫双十一主logo

△ 2019天猫双十一主logo多语言版本

今年是双十一的第十一年,当我们接到这个任务的时候,就有机灵的同学提议:「我们用6个1吧,111111,61儿童节!」、「让我们回归购物的纯真快乐!」。

「哈哈哈哈哈哈…」魔性的笑声在整个会议室回荡,看来往年挠破头也解不开的难题,就这么解开了?故事当然不会这么简单,我们还没有往这个方向尝试就被否了。

  • 其一,双十一是一个深入人心的认知,这四个一已经成为了超级符号,是我们宝贵的品牌资产,而六个一不但不能帮我们强化认知价值,反而会增加认知成本。
  • 其二,六个一是一个纯视觉的创意,他很难支撑起我们要传达的消费者价值,也很难建立起情感连接。

我们应该从哪儿入手?

回归到设计的本质来思考,我们认为,设计的本质是将一个想法或者观点巧妙的表达给目标对象,表达的过程中,形式只是手段,重点在于我们要表达什么。

我们集合了阿里各事业部的设计师代表,让大家回归到一个普通消费者的状态,一起聊一聊各自的双十一故事,把这些故事提炼出来,就是消费者对于双十一普遍真实的认知。在全年最便宜的一天,无论凑热闹也好,跟风也好,贪便宜也好,好像不买点什么总感觉错过了什么。在这一天,「购物」毫无疑问成为头等重要的事情。

△ 阿里巴巴经济体设计师共创

那么我们要对消费者表达「购物」吗,讲我们多么便宜,货品多么丰富,多么物美价廉?这些是消费者早就形成的认知,是我们不用表达大家都知道的事,它看起来并不是一个想法和观点。

还是购物,但肯定不是教大家怎么购物,作为消费者,购物能给我们带来什么?

有人说,购物能让我们吃饱穿暖,让我们出行方便,让我们安居无忧。

如果这些你都有,你为什么还要购物?

因为每个人都向往更好的生活!

为了更好的生活,我们需要通过物品的改善带来心理的满足感。当然也有人会会说,满足感也可以通过其他的方式获取,比如关爱他人、亲近自然、学习、修行、冥想等等,我们非常认同,更好的生活当然不仅仅只有购物。但我们当下探讨的范畴仅仅只是「购物」以及「购物」能带来的满足感,对这种满足感的期待,是每一个消费行为的动因。比如你想要买一件新衣服的时候,其实你已经在期待穿上这件新衣服的样子,你在挑选一件礼物的时候,已经在期待他人收到这件礼物时的反应……

双十一,全年最便宜的一天,无疑让你的期待,变得「更值得」期待,所以「更值得」让大家买得更多。

但,这些洞察还只是帮我们理清了消费行为背后的共性规律,实际上,细分到每个消费者,因为身份角色生活方式的不同,动因各自不同,还不能简单的用向往更好的生活来概括,因为它太抽象,听上去对,但每个消费者更关心的是我的需求是不是被满足,而对于双十一来讲,我们就是要打造属于每一人的双十一,而不仅仅只是购物,这样它才具有节日的文化属性。

所以,我们开始探寻真实的消费者故事,寻找那些通过物品让生活变得更好的故事,这些真实的故事,给了我们很大的感触。我们发现,购物行为下,其实还隐藏了每一个消费者内心更深层的需求,它是一个个藏在心底的愿望,正是这些不同人的愿望,成就了每一个平凡人鲜活的人生。我们想要帮助他们实现自己的愿望。在双十一当天,帮助每个消费者「愿望11实现」!这才是双十一更应该满足的消费者需求,它不仅仅是购物,而是通过物品价值上升到情感价值,这样的品牌,才真正能够让人感受到温度。

在倾听这些故事的时候,我们的阿里女神被感动了,她主动要求帮我们写一首歌,她想把她的感动通过音乐的方式记录下来,配合我们精选出来的11个故事,讲给大家听。

△ 双十一品牌设计概念篇mv

「logo出来了?」低沉而沙哑的声音,把我们从自我陶醉中唤醒,我们找到了想要表达什么,但和怎么表达之间还隔着上百个logo方案。

于是,我们开始了一轮又一轮的打磨,打磨的的重点放在了如何表达「愿望11实现」这一主题,这个过程中,有两个大方向上的分歧:

一个大方向是表现「愿望」,因为它比较有画面感,也比较容易表达。

另一个大方向是表现「实现」,因为它是对结果的描述,更符合消费者对结果的预期。

在纠结挣扎过后,我们选择了把两个方向融合,剧情貌似又回到了熟悉的设计故事,「把这两个方案融合一下!」我相信做设计的朋友,一定反复听过这句话,没听过的朋友,那说明你做设计还不久,我保证在你今后的职业生涯里,这句话一定会反复出现。(一个会心的微笑)

融合说起来容易,这么抽象的文字怎么转换成图形表达,同时还要和猫头+11.11融合,为什么要和猫头+11.11融合呢,因为这是我们重要的品牌形象资产,从2015年开始,猫头+11.11的组合就固定下来了,这意味着logo的80%的主体已经固定,我们的难点就在于在这20%的区域里,如何既要表达主题,还能做出和往年不一样的感觉。我敢向你保证,双十一的logo是所有logo里最难的,没有之一,至少是我十几年职业生涯里最硬的茬。

「愿望、实现、猫头、11.11」这几个词反复在脑海里萦绕,经验告诉我们,当面对如此复杂的局面,我们应该从里面跳出来,换个视角看问题,换什么视角?当然还是再次回到消费者视角,消费者愿望实现时是一种什么样的状态?是愿望实现时的满足?好像还差点意思,愿望平时也能实现,和在双十一实现愿望有什么不同?

我们认为,它应该是超越你期待的表达,从愿望实现时的满足,升级到愿望实现时的惊喜!这才是狂欢节该有的味道。当然,惊喜也有很多种它还不够有体感,如何找准惊喜体感?

答案是感同身受。于是我们开始了场景模拟,模拟消费者逛双十一的场景。

当我们来到双十一的时候:「咦!今年好像真的不一样!」

继续探索的时候:「呀!找了好久的idou同款原来在这里!」

准备下单的时候:「喔!真的很便宜!」

收到快递的时候:「哇!!!!」

听上去有点夸张,但这确实是我们想要营造给消费者的惊喜,当人感到超越期待的惊喜时,会不自觉的放大瞳孔、张开嘴巴脱口而出。这是人类共通的体感,是不用解释就有的共鸣。这让我们瞬间被点亮了,「惊喜到脱口而出!」我们一下子找到了核心创意。

通过反复尝试,我们发现气泡形的表达,不仅能成为承载所有消费者愿望的想法框,同时也能成为表达愿望实现时惊喜到脱口而出的对话框,把这个气泡形和猫头+11.11结合,这就是我们今年双十一主logo的原由,这个logo和以往双十一的logo最大的不同在于,它更像是一个容器,容纳不同人不同的个性化表达。它一改之前一直端着的状态,以一种更加亲民,更加个人化的方式呈现给大家。

△ 2019天猫双十一品牌logo演绎视频

当然,作为容器,我们还要把核心创意延展到线上线下各个场景。

△ 双十一定制礼盒

△ 走向全球的双十一

过去几年,我们向大家介绍过天猫双11的主风格的来龙去脉,一定会在创新的基础上,保持一贯的传承。所以今年波普艺术的主基调还是会延续下去,问题又回到了我们如何在波普艺术这个大的基调下面,通过老元素的新组合,创造出全新的视觉感受。相比符号,视觉风格更容易表现「惊喜到脱口而出!」这个idea,它可以通过形色质构全方位的表达。

当一个人「惊喜到脱口而出!」的时候,快乐的气场围绕在他周围,这些无形的从中心向四周放散的表现,看上去很像是圆形声波,同时它还能根据不同人的状态做动态变化,这就形成了一种设计语言,一种能用固定的形式做出千变万化的效果的语言。

当我们把它和波普艺术的主基调结合的时候,就形成了今年双十一独特的视觉语言,再通过形色质构的拆解,应用到各个场景。

△ 装置应用

△ 天猫双十一发布会现场应用

△ 天猫双十一开幕盛典现场应用

文章来源:优设

JS实现动态星空背景

seo达人



这里我截取的是一个图片,实际上是会动的。废话不多说,上代码。

HTML:



<canvas id="canvas"></canvas>

1

CSS:



/css reset /

body,p,div,ol,ul,li,dl,dt,dd,h1,h2,h3,h4,h5,h6,form,input,iframe,nav {

    margin: 0;

    padding: 0;

}

html,body {

    width: 100%;

    height: 100%;

}

body {

    font: 14px Microsoft YaHei;

    -webkit-text-size-adjust:100%;

    -moz-user-select: none;

    -webkit-user-select: none;

    user-select: none;

    position: relative;

    background: #000;

}


canvas {

    width: 100%;

    height: 100%;

    display: block;

    opacity: .8;

}





// 音量大小,0.01-1





//宇宙

var canvas = document.getElementById('canvas'),

ctx = canvas.getContext('2d'),

w = canvas.width = window.innerWidth,

h = canvas.height = window.innerHeight,



hue = 217,

stars = [],

count = 0,

maxStars = 1100;                //星星数量,默认1300

var canvas2 = document.createElement('canvas'),

ctx2 = canvas2.getContext('2d');

canvas2.width = 100;

canvas2.height = 100;

var half = canvas2.width / 2,

gradient2 = ctx2.createRadialGradient(half, half, 0, half, half, half);

gradient2.addColorStop(0.025, '#CCC');

gradient2.addColorStop(0.1, 'hsl(' + hue + ', 61%, 33%)');

gradient2.addColorStop(0.25, 'hsl(' + hue + ', 64%, 6%)');

gradient2.addColorStop(1, 'transparent');



ctx2.fillStyle = gradient2;

ctx2.beginPath();

ctx2.arc(half, half, half, 0, Math.PI 2);

ctx2.fill();



// End cache

function random(min, max) {

    if (arguments.length < 2) {

        max = min;

        min = 0;

    }



    if (min > max) {

        var hold = max;

        max = min;

        min = hold;

    }



    return Math.floor(Math.random()
(max - min + 1)) + min;

}



function maxOrbit(x, y) {

    var max = Math.max(x, y),

    diameter = Math.round(Math.sqrt(max max + max max));

    return diameter / 2;

    //星星移动范围,值越大范围越小,

}



var Star = function() {



    this.orbitRadius = random(maxOrbit(w, h));

    this.radius = random(60, this.orbitRadius) / 10;       //星星大小,值越大星星越小,默认8

    

    this.orbitX = w / 2;

    this.orbitY = h / 2;

    this.timePassed = random(0, maxStars);

    this.speed = random(this.orbitRadius) / 80000;        //星星移动速度,值越大越慢,默认5W

    

    this.alpha = random(2, 10) / 10;



    count++;

    stars[count] = this;

}



Star.prototype.draw = function() {

    var x = Math.sin(this.timePassed) this.orbitRadius + this.orbitX,

    y = Math.cos(this.timePassed)
this.orbitRadius + this.orbitY,

    twinkle = random(10);



    if (twinkle === 1 && this.alpha > 0) {

        this.alpha -= 0.05;

    } else if (twinkle === 2 && this.alpha < 1) {

        this.alpha += 0.05;

    }



    ctx.globalAlpha = this.alpha;

    ctx.drawImage(canvas2, x - this.radius / 2, y - this.radius / 2, this.radius, this.radius);

    this.timePassed += this.speed;

}



for (var i = 0; i < maxStars; i++) {

    new Star();

}



function animation() {

    ctx.globalCompositeOperation = 'source-over';

    ctx.globalAlpha = 0.5;                                 //尾巴

    ctx.fillStyle = 'hsla(' + hue + ', 64%, 6%, 2)';

    ctx.fillRect(0, 0, w, h)



    ctx.globalCompositeOperation = 'lighter';

    for (var i = 1,

    l = stars.length; i < l; i++) {

        stars[i].draw();

    };



    window.requestAnimationFrame(animation);

}



animation();

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

日历

链接

blogger

蓝蓝 http://www.lanlanwork.com

存档