首页

如何打造一套属于自己的标签体系?

雪涛

每个平台都会存在标签,我们可以根据自身平台属性,打造一套属于自己的标签体系,几个思路点分享给大家(今天我们仅讨论不可点击标签,也就是展示型标签)。

理解标签作用

咱也没整那么多官方定义了,我个人认为标签就是为了让用户快速看到关键信息,找到感兴趣的内容。

比如,我喜欢看玄幻类漫画,如果看到有「玄幻」的标签:

就会多关注一下。

再比如,我去网上买硬盘,希望质量能有所保证,那「自营」标签,对我来说吸引力就很大:

这就是标签最核心的作用。

整理标签分类

其实分类的方法有很多,产品、交互、视觉都有不同的分类方式,而且每个平台的属性又各不相同。所以这么复杂的情况下,我们必须保持清晰的原则,避免思路混乱。

根据自身平台内容,我尝试了一种分类方式,推荐给大家参考,按照场景与优先级来进行标签分类。

场景分为:

  • 封面上的标签
  • 文字后的标签

优先级分为:

  • 特殊化
  • 强调型
  • 普通型
  • 弱化型

有了这样的划分,我们就可以根据需求进行自由匹配了:

根据平台目前的需求(以后根据需求可以拓展或者合并),我们可以分为6种型式:

1. 封面上的标签(强调型)

我们采用品牌色来强调标签,一般用在首页频道,这种标签不能同时出现太多,否则会太花哨太乱:

2. 封面上的标签(普通型)

多个封面同时有标签的情况也是存在,比如分类页,封面上都有评分,这时候我们就需要采用普通型(非强调)的标签,也就是黑色降低透明度:

封面上的标签暂时就这两种,以后也可以根据需求进行扩展。

3. 文字后的标签(特殊型)

特殊型在视觉上是最重的,因为除了颜色是填充色外,形状也是异形的:

4. 文字后的标签(强调型)

强调型形状上不做异形,但颜色上使用品牌色进行填充:

5. 文字后的标签(普通型)

普通型的标签,标签颜色会用有色相的彩色,文字使用品偏色或者其他辅助色:

6. 文字后的标签(弱化型)

弱化型会对标签的视觉重量再次减弱,采用灰色标签:

我们可以再看下这六种标签的整体视觉策略:

  • 封面上的标签(强调型)
  • 封面上的标签(普通型)
  • 文字后的标签(特殊型)
  • 文字后的标签(强调型)
  • 文字后的标签(普通型)
  • 文字后的标签(弱化型)

我用图片给大家概括一下

两种封面上的标签:

四种文字后的标签:

这种方式可以参考,但还是要根据自身内容来进行实际分类,只要能分得清楚、透彻,那就是好的分类。

细化标签规范

其实整个标签部分,最重要的还是上一步,想清楚如何分类。

有了分类之后,再进行规范的细化,相对来说就没那么复杂了,注意以下几个点即可。

标签的高度,很简单,不解释:

标签的宽度,因为字数不同,所以宽度是不固定的,但我们可以规定文字的左右安全边距:

标签的文字颜色、大小、粗细、极限值,其中极限值就是规定下标签最大字数,一个标签整几十个字,快成作文了,也不太合适,是吧:

标签的背景色,不同类型的标签颜色不同,但需要符合整体视觉策略和设计规范:

这些属性规范好,基本就够用了

文章来源:优设    作者:

规范git commit的提交记录

seo达人

随着项目体积的增加,参与到项目中的同学越来越多,每个人都有自己的打 git log 的习惯:

  • 格式 1: add: 添加...
  • 格式 2: [add]: 添加...
  • 格式 3: Add 添加...

为了形成统一的规范,达成共识,从而降低协作开发成本,需要对 git commit 记录进行规范。

规范 git commit 记录

规范 git commit 记录,需要做两件事情:

  • 通过交互式命令行,自动生成符合指定规范的 commit 记录
  • 提交记录后,在 git hooks 中进行 commit 记录格式检查
问:既然已经交互式生成了规范记录,为什么需要在 hooks 进行检查?

交互式生成 commit 记录,需要用户调用自定义的 npm scripts,例如npm run commit。但还是可以直接调用原生 git 命令 git commit 来提交记录。而检查是在正式提交前进行的,因此不符合要求的记录不会生效,需要重新 commit。

调研:交互式 commit log 规范方案

前期调研结果,关于 commit 提示有两种做法:

  1. 直接使用 commitizen 中常用的 adapter
  2. 根据团队的需要,自定义 adapter

方法 1 的优缺点:

优点 1: 直接安装对应的 adapter 即可

优点 2: 无开发成本

缺点 1: 无法定制,不一定满足团队需要

方法 2 的优缺点:

优点 1: 可定制,满足开发需求

优点 2: 单独成库,发布 tnpm,作为技术建设

缺点 1: 需要单独一个仓库(但开发成本不高)

代码实现

在实际工作中,发现方法 1 中的常用规范,足够覆盖团队日常开发场景。所以,选择了方法 1.

step1: 安装 npm 包

npm i --save-dev commitizen cz-conventional-changelog @commitlint/cli @commitlint/config-conventional husky

添加 package.json 的配置:

"scripts": { "commit": "git-cz" }, "husky": { "hooks": { "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" }
}, "config": { "commitizen": { "path": "./node_modules/cz-conventional-changelog" }
}

在项目根目录下创建commitlint.config.js

module.exports = { extends: ["@commitlint/config-conventional"]
};

使用方法:不再使用git commit -m ...,而是调用npm run commit

<img src="https://tva1.sinaimg.cn/large/006tNbRwly1gbjcfr3xb5j30cw00tjrd.jpg" style="width: 100% !important;"/>

医疗行业的交互设计怎么做

雪涛

医疗行业的交互设计,跟其他行业有何不同?有什么要特别考虑的点?设计师应该注意哪些方面?

X与行业

产品体验设计通道中有条简单好记的定义: 1+X。

「X」这个字母常被定义为更多可能性,它的诞生往往是为了更好地服务行业与产品。

例如在医疗健康行业中,不再只有C端用户,我们要面对医院管理人­­员、患者、医护人员还有企业用户等;环境也不单是线上场景,它可能是医院、企业大楼、社康、疾控中心等等;合作方式同样独特,我们做出的任何一个设计都是需要客户过目的,每一个字段甚至都涉及到生命健康与安全,所以会要求我更高标准地了解行业与用户,促使我们在项目前期去不断学习和应用一些用户研究知识,使设计更加贴近用户。

交互设计师在用户研究领域的探索

过往经历中,总结了用户研究在各阶段的介入场景和方法,接下来会具体讲下在医疗健康项目中的运用。

1. 企业健康场景案例

企业健康项目是从一个合作开始的,公司的行政部门想要通过我们提供的健康管理产品来提升员工整体的健康水平,并将该方案进行复制从而提供一个企业健康管理的行业解决方案。

的确,员工是一个企业的宝贵财富,健康有活力的员工群体对提升企业生命力有着非同一般的影响。通过网络文献调研,我发现国内企业的亚健康状况并不乐观。

△ 国内企业健康现状

第一阶段用研——产品定义与设计方向

为了更了解员工和企业的真实情况和痛点,我们规划了用研计划,列出了三个用研目标:

  • 了解员工们的主要健康问题
  • 了解企业服务存在的问题和改善方向
  • 确立产品目标与设计目标

目标1: 员工们的主要健康问题都是什么?

通过和企业方的沟通,我们发现员工的体检报告是挖掘健康问题的源头,于是我们由此开始研究。

首先,我们拿到了历年的公司员工体检数据统计(脱敏分析),整理出体检问题的Top10。

△ 腾讯2018年体检数据统计

获许可,我们也随机向外发放问卷,了解到一些公司职工最想要改善的问题。

△ 某大厦的用研报告(仅作为分析用)

目标2:企业现在所提供的服务有哪些问题,该如何改善?

B端: 由于这是一个B to C的项目,我们优先会去采访企业端遇到的问题,沟通发现企业都会投资提供的健康设施(体检,食堂,健身房等),其中很多设施并没有被充分利用,或是没有得到合理的分配,现有的线上预约流程也存在很大的后台计算成本。

△ 腾讯提供的健康服务与设施(非疫情期间拍摄)

C端: 通过公司内部招募和访谈了20名员工,我们总结为三个主要痛点:

  • 体检套餐不知怎么选最适合自己,体验不流畅
  • 体检后看不懂报告也不知道该如何改善
  • 知道改善方向却不知如何落地和规划,或是没有坚持下去。

△ 员工在体检健康中遇到的痛点

以上,我们也对企业客户与员工用户的诉求有了初步的了解。

△ B&amp;amp;amp;amp;C两端诉求分析

目标3:如何定义产品目标与设计目标?

通过以上分析,和其他合作团队一同讨论了体检与健康管理行业的现状和盈利点,我们最终确定了产品方向:通过加入AI技术,分析用户过往体检数据来给用户推荐最合适的体检套餐,帮助用户解析体检报告转化为更加易懂的方式,加强与医疗服务的定制化连接;并智能定制最适合员工的管理方式和行为,充分利用起公司资源。

△ 产品形象与定义

通过对整体流程的用户情绪地图分析,我们得出设计的关键词:专业,贴心,安全

△ 阶段情绪地图分析

知识点1: 访谈与问卷调研

不要一上来就直奔主题,可以先问一些简单回答的问题和闲聊,让用户进入放松状态时再聊重点问题。且要时刻关注受访用户的状态,比如:是不是开始疲惫,回答过于发散以及表达意思模糊等等。遇到这些问题,需要随时做调整。

访谈的时候最好不要单独行动,要有1个主导访谈的,一个记录的。如果访问过程很长,有条件以及受访者允许的情况下,可以进行录音有助于后期的整理。

访谈结束后,最好是当场,或者至少应该是当天就完成本场次的访谈记录和总结工作。因为根据遗忘曲线,人在20分钟后将遗忘42%的内容,而1天后则将遗忘74%。即使有录音笔记录,你也会忘掉很多细节的,诸如表情,用户的潜台词等等。想到的设计解决方案也可以先记录下来但不急于放到总结当中去。

第二阶段用研——产品与设计验证

确立了目标和方向,我开始从体检预约和检后管理两部分来进行设计,由于在前期建立了用研机制,我们会定期对重要版本的内容和信息设计进行测试验证,并让用户基于我们定义的设计标准来打分,判断是否达到了专业,贴心与安全。

卡片分类-测试内容与排序

在检后的体检报告解读中,我们需要对解读结果进行结构化展示,方便用户快速获取有用信息,提高阅读效率,由此我们运用了卡片分类法,让用户对其重要性的排序,得知对用户来说体检异常中的单项的指标解释>危害性>指导措施。

△ 卡片测试与分析

可用性测试-测试架构与信息形态

体检解读的首页我们绘制了三个版本的方案,来突出不同的信息通过制作原型demo来进行可用性测试,让用户选出最喜欢的并说明原因,最终选择出一个最优方案。

△ 体检解读首页可用性测试与分析

从弹窗内容组合到内容的体检解读指标的可视化设计我们都做了用研测试版本

△ 体检解读内页信息测试稿

最终得到更加符合用户认知的体检解读设计。

△ 体检解读设计

灰度测试与深度访谈

由于某些需求时间紧迫,例如体检预约,当时很快就要到体检季,于是我们快速搭建框架和基础功能的设计,细节疑问点列出后进行灰度版本测试,并对前期招募的种子用户进行测试访谈,总结现存版本的问题,同时我们也访问了企业侧,把他们的优化诉求纳入考虑。

△ 体检预约访谈脚本与测试结论

比如企业要求突出安全感,福利感与智能推荐,减少后台结算成本等,我们便通过明确隐私授权认知的全页面弹窗以及简化体检预约流程,2步变1步,增强页面福利与智能推荐的感知渲染来满足客户要求,也得到了满意的赞赏。

△ 隐私授权设计

△ 体检预约设计

以上的用研方法其实可以运用在大多数的项目中,于是我在后续的腾讯健康模块设计中也常会去使用,例如疫苗设计中的闪屏方案测试等等。需要注意的是用研应该被列入到日常的流程中去,而不能作为临时安插,需要在项目实施前就进行用研计划的拟订,才能保证我们和用研同学有条理地客观的进行调研和验证。

知识点2:卡片与可用性测试

  • 研究员不要引导和干扰受访者,特别是不要在过程中对某些词汇进行解释。
  • 开放式卡片分类法中,卡片数量不宜太多,简单的卡片测试建议在20以内。难度会随着数量的新增而成倍增加。
  • 记得要首先询问用户对于卡片上词汇的理解,看是否有偏差。当对方问到的时候,可以先不着急回答,先问问他是如何理解的。内容的设计是设计师容易忽略但非常重要的一点。
  • 可用性测试的环境要保证安静无干扰。自己做的设计往往会容易有一些主观的想法和情绪,需要尽量克制,比如可以让用研同学做主导,自己做记录和观察即可。
2. 就医服务场景案例

就医流程是看似并不陌生的场景,痛点也非常明显,就是常被提到的「三长一短」问题(挂号时间长,支付时间长,问诊时间短),于是在进行线上就医服务设计时,很多人会认为没什么好特别调研的,竞品也非常多。

然而其实在设计中,最害怕的就是「我以为」。记得在做某医院的就医服务项目时,由于就医环境和用户非常复杂,所以我们在做这个项目时坚持去到了前线进行了实地考察与影子观察法,才发现了新的洞察。

实地考察中的望闻问切

说来很巧,现场的调研方法其实和中医中的「望闻问切」有异曲同工之妙。

△ 医疗场景用研方法

「望」:可理解为影子观察法:选择最能反映问题的时间和场景去观察用户行为,发现痛点,经过几天的观察我们发现早上8-10点是医院看病的高峰期,也是排队最严重,院内最拥挤的时期,所以我会在这两个小时集中观察和记录患者以及医生的状态。

「闻」:即为倾听,其实也是访谈法中很重要的一个原则,多让用户去诉说,减少自己的主观判断干扰用户的完整陈述,如果记不下可以录音。

「问」:根据我们想要了解和观察到用户的行为进行提问。

「切」:这里和中医中的切诊接触不同。是指切身去体验患者的感受,比如我会根据自己身体的某些不舒服去挂号体验流程,情景带入。

以上的实地考察后,我在第一时间用我们设计师的手法来记录整理:体验地图分析,并通过讨论提炼出设计的关键点:引导,连接,合并与转化。

△ 用户体验地图与关键点分析

知识点3:影子观察法

  • 需要选取事件发生的典型场景和时间,即所观察的场景和用户是最具有代表性的,才能最反映问题所在。
  • 像一个隐形人一样去观察,不要主动打扰和询问用户,才能最客观的记录状态和行为,避免变形。

用户体验地图的落地应用

这四个设计关键点其实来源于痛点描述中的一些高频提到的情况,拿引导和连接这两个点来说明。

引导:通过观察发现,用户在嘈杂的就医环境中本处于极度焦虑紧张的状态,对信息阅读和处理的速度低于平时的好几倍,因此我们需要提供具体的,正向的引导。

△ 精准预约设计

连接:通过访谈和自己实际的体验发现,许多线上和线下的服务之间是断层的,一方面需要流程上连接我付了款下一步要去哪,怎么拿药;另一方面我们也发现线下的引导设计是一个非常重要的连接机会点。

于是我们从线上和线下两方面进行了连接,提供了一套整体的解决方案。

△ 候诊与取药签到设计

△ 医院物料布局与落地布置

通过用户关系图了解了每个相关利益人的人群要素和诉求,在设计中不仅会考虑针对他们的设计,也结合体验地图中的机会点引出了设计原则,作为设计的指导和验证标准。

△ 相关利益人分析与设计原则

测试与收获

上线后,我们穿上志愿者的衣服,去往前线进行现场解说和用户测试,经过一个月的努力,真实感受到了现场效率的提升和满意度的提高,院方和使用过的用户都非常满意,这也让我们设计师切实感受到了欣慰和成就感。

△复旦大学附属肿瘤医院病理会诊 整体服务上线前后对比

这得益于我们能长时间与用户在一起,真实地听到了他们的声音与感受,也把想法落地去帮助他们解决了问题。这个过程中,让我们发现类似的垂直领域需要去到前线自己去感受,而不是隔着屏幕去观察,每个人的思考角度会不同,会发现新的问题和洞察。

知识点4:用户体验地图

  • 不要为了画流程而画,最终还是要通过图形化的记忆更好的还原记忆细节。
  • 重点要放在痛点与机会点的一些突出共性上,提炼是关键步骤。
  • 不要忽略不同接触点的洞察,它们均可以作为设计的载体。
3. 医疗数据分析场景案例

在医疗数据分析的场景中,我们面对的客户是政府和医院领导。相信在做TO B设计的小伙伴经常会遇到这样的问题:客户时间比较难约,给的调研时间有限;决策层客户思考的比较广而泛,很难深入用研。

基于这样的问题,我们想出了一个根据客户群体层级,区别调研的方法。

梳理角色

去年年初,我们曾走访多家公立和私立医院,优先通过管理层梳理出了关于数据处理上报的流程。他们对数据的关注度和处理顺序往往是有一个自下而上的上报过程,基层人员进行每个月度和季度的数据汇总,分析与简单的可视化表现,上报给部门管理和上级管理者进行审核提炼,最终给到管理决策者一些关键现象和趋势和对比。

由此提醒了我们,想要提供一个完整的数据解决方案,就需要绘制角色面板,区别调研目的与手段。

△ 医院层针对数据的处理流程

分角色的沟通用研

我们确立了针对基层人员,中层管理者以及决策管理者的用研目标并展开了差异化的沟通用研,我们会每个角色找1-2人和我们3-4个同事坐在一起,以焦点小组的方法一同脑暴某一数据场景和所需数据。

  • 基层人员 用研目标:了解常用基础数据的模块与细节汇总
  • 中层管理 用研目标:常关注的关键指标模块与提炼形态(对比,警示,峰值,占比)
  • 决策管理者 用研目标:看数据的目的,常关注的关键指标与形态的验证,后续操作

△ 医院数据现场用研

数据研究与总结应用

根据对医院不同角色的沟通梳理出了一些总结点,运用到了产品和设计中。

第一:我们发现了管理者们最关注的一些医院数据的形态,并打算把基础数据尽量以对比,警示等手段进行分析与场景描述。便于管理者直观获取他想要获取的辅助决策信息。

第二:根据不同角色提供针对性的角色面板,并梳理出个角色关注的数据模块和现象。

第三:各角色具体数据字段的梳理与总结,并进行了频率的标注便于后续的设计面板规划。

第四:调研中发现领导层在看数据时需要来回切换系统,且看起来没有一个统一的路径和条理,因此我们也和对方沟通,通过故事化的手法进行数据分析的流程体验设计,层层深入和下钻,从现象挖掘到问题本质。更加符合了用户看数据的顺序和认知。

△ 长沙超脑项目设计版图

除此之外,我们后面的产品和设计的汇报也会根据角色的差异来进行内容的调整,让听我们说话的人可以快速理解我们想要达成共识的内容,加快沟通效率,提升了在客户心里的印象。

这个过程中,通过用研让用户感觉到我们懂他们,并让其增加了参与感,对产品和设计都是一个推进器。

知识点5:TO B/G客户用研

  • 事前理清楚项目中会接触的各个角色,并进行初步了解,制定不同的用研目标再进行沟通。
  • 探讨的过程,要给足客户参与感,例如使用焦点小组的调研方式,提升好印象。

如何持续提升技能——读书有感

说了那么多设计师在用研技能上的应用,也许有人会有这样的疑问:如何可以不断提升自己在各方面学到的技能呢?一年前读到《刻意练习》这本书,给了我一些启发,在此总结给大家,希望对你们有帮助:

1. 制定具有定义明确的特定目标

「提升专业」是个很大的词,所以我们往往定了一个很大的目标,然后被各种事情拖着然后抛之脑后。因此拆分目标才是第一步。比如最开始做交互时我发现自己在归纳场景时总会缺失,再比如每次自己在汇报总结时,耗时过长,缺乏重点,那么这些都可以被列入要提升的小目标,总之目标不要太泛太难实现,这样实现起来会更加容易,也更容易坚持和自我激励。

2. 持续学习与专注练习

研读多本相关专业书籍,并应用的项目中去。这是我的一个目标也是方法。投入项目后,我们往往会陷入事件当中,甚至会就一个点和产品争论不休。但其实跳出来,去看些新思路不妨为一个好方法。

比如我最近在读《感官心理学》这本书,提到人们对于「软」和「硬」的触感印象会延伸到女性和男性的联想上,提到女性人们自然都会有柔软的印象,男性则会有刚硬事物的联想,这也就充分佐证了对于不同性别上的设计形态差异。类似的小实验可以帮助我们的设计更有说服力。

大多时候理论知识很枯燥,也难以一时间就可以用到,但只要你读过,在需要的时候它就会突然跑出来给你灵感。

专注是我一个单线程人的特点,我很难在一个时间里同时处理多件事,所以我会每天根据要完成的训练目标,把时间进行划分,个人感觉这的确产出效率也会高一些。

3. 一定要有反馈

每一次的练习必须要得到反馈,这也是评审的重要性。但其实不同的目标点可以对应方面的专家,不仅限于leader了,同事也是很好的老师,比如我会去发现身边汇报比较厉害的同事,帮我把关。只要遇到问题,一定不会放过去问用户研究同学的机会。

某方面没有老师怎么办?让用户告诉你!首先我会常用可用性测试的方式去检测自己的方案中的信息传达,交互反馈等等在进步,另外我也会在每个项目后整理一个小总结,来记录自己的思考与进步

另外,以下是我在用户研究学习中读过的几本书,推荐给大家~

结语

面对飞速发展的现在,各行业的产品也都在积极转型,例如开始涉足TO B行业和客户,开始研究00后的新生代用户,面对新事物我们设计师更要保持敏锐的眼光,利用自身的设计洞察能力去挖掘新的问题与方法,于是新的技能和方式也开始出现,所以我们一直认为产品体验设计师没有一个固定的能力模型,还是要根据你所从事的行业和产品来发现所需的技能点去发挥价值。学习的过程中,我们成就项目的同时也在慢慢成就自己。

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

PC端表单设计的研究:如何设计一个优秀的表单页面

前端达人

1.jpg

最近身边的一些小伙伴,总会遇见B端设计工作,对于这种偏后台设计的B端设计,总会有大量的表单设计需要做,结合以前自己也有过不少表单设计的工作,在这里给大家分享一下自己对于PC端表单设计的研究,聊一聊表单在PC端中的运用。


表单的作用

商业离不开数据,而数据总会依赖不同的表现形式,不管是word文档,还是数据可视化,都是浏览者通过表现形式来对数据进行阅读和分析,因此表单的设计就是一种表现形式,我们将捋一捋如何通过表单更好的让用户阅读顺畅、操作方便、总而言之就是更好用啦。

表单信息的分割方式

无线分割:顾名思义,列表的信息之间正常情况下没有分割线等方法来分隔,仅仅是用间距来分隔开内容。好处是元素更少,画面更简洁,但是视觉可能就没那么清晰了,使用的出场率一般。

点击查看原图

点击查看原图

有线分割:同样字面意思,就是通过简单的分割线来分割列表中的信息,让视线左右移动的时候更加稳定、轻松,在表单设计中使用的出场率非常高。

点击查看原图

点击查看原图

斑马线:通过深浅交替的色块,以及色块产生的对比来分隔列表中的信息,深浅深浅的循环就好像斑马线,使用时是通过色块产生对比,所以也可以使用带有适量饱和度的色块来区分,占页面面积比例较大,适当用色可以使得画面更加活泼、丰满,斑马线也是出场率极高的一种展现形式。

点击查看原图


斑马线+分割线:很容易理解,就是斑马线风格+分割线的结合,用色块区分的同时又加了分割线,信息之间的区分对比更加强烈,但是画面层级就多了一些,没有其他的看起来简洁,使用出场率也一般。


点击查看原图


卡片式:跟卡片式风格其他设计一样,分别用悬浮的色块来区分,间隔的地方是背景色,分隔的力度比较强,内容区分的很清晰,弊端是更加占画面的位置,尤其在信息很多列的时候,会增加大量的高度,用户需要更多时间进行下翻的操作。使用出场率相对其他形式来说稍低。

点击查看原图


可控制页面显示数量

场景:用户需要阅读大量的表单数据,且需要频繁的翻页、跳转。

如图,左下角可以设置界面中每页显示信息数量的多少,用户可以根据自己的需要自由设置,当浏览的数据较多的时候,不再需要频繁点击下一页来浏览信息,只需把每页显示的数量调高,如此便减少了大量的操作次数。

点击查看原图


像这样允许用户可以自由编辑来改进体验的方式还有很多,比如可以设置显示密度,就是以一样的方式自由调整信息与分割线的间距。除了行间距,有的可以自由设置每一列的列间距,用户可以根据自己的习惯来设置。

列表+可视化

场景:用户需要浏览大量的数据,并需要对数据反复进行计算、分析。

在使用大量的文字列表展示数据的同时,使用数据可视化加以配合,用户可以更好的预览到数据的大致情况,又可以在列表表单中阅读到详细的数据。

点击查看原图


点击查看原图


根据条件排序

场景:用户想根据某种条件的大小排序,来先后阅读数据。

通过点击第一排小标题行,可以选择不同的方式调整信息的排序方式,就和电商商品排序一样,可以选择金额高到低或者低到高排序,也可以选择别的方式进行排序,从而更快找到自己所需要的内容。

点击查看原图



筛选过滤

场景:从一大堆混杂的数据当中,寻找符合条件的自己所需要的数据。

添加筛选功能,过滤掉自己不想浏览的内容,通过条件筛选,更快的更的找到自己想要的内容、缩小查找范围、减少达到目的所花的时间。一般通过下拉按钮的形式选择不同的条件来进行筛选过滤。

点击查看原图



关键字搜索

场景:已知列表中某信息的名称关键字,想从大量混杂的列表中快速找到。

跟筛选过滤一样,添加关键字搜索功能,用户提供部分关键字,可通过关键字查询,最快最的找到想要的那一条内容。一般该目标内容是用户已知的,有时候是针对性的。

点击查看原图



悬停展现操作

场景:精简设计风格的界面,不想界面中内容过于繁多。

如图,鼠标悬停在哪一行,哪一行才会显示该列表后面的操作按钮,好处是减少了视觉干扰,能更快的找到捕捉到操作位置,弊端是用户不进行交互的时候无法发现操作按钮如何出现。


点击查看原图



可展开列表

场景:想快速获取列表中某信息的其他附属内容。

如图,点击某一行后,展现该行的一些附属信息。可以不用跳转页面而进一步了解该行信息的详情。

点击查看原图



可编辑列表

场景:在浏览列表的同时,需要频繁的对列表中的信息进行编辑。

用户可以直接对列表信息进行修改、编辑,省去了跳转再编辑的麻烦步骤,更节约时间,用户操作起来更加方便。

点击查看原图



快速预览

场景:需要充分了解列表中不同信息的详细说明,频繁跳转又过于麻烦。

和可展开列表的作用类似,但是可展开列表显示的内容有限,快速预览的功能可以用侧弹框的方式、弹出对话窗口的方式、以及其他方式对选中的内容直接展示详细信息。用户不需要跳转至详情页就可以了解到大量信息,省去繁琐的交互流程。不再需要频繁的跳转到详情-返回-跳转到另一个详情-返回-跳转-返回。使用快速预览的功能就可以很好的解决这一问题。

(PS:弹出对话窗口的方式,可以同时弹出好几项列表的详情信息进行对比,但是侧弹框因为高度优势,可以展现更多内容)


点击查看原图


点击查看原图



自定义列

场景:列表中每条内容显示信息参数过多,且很多不想浏览。

自定义列表功能是用户可以自由设置每行信息参数的内容,比如我不想列表中显示金额这一项,就可以删除,想要的时候可以添加回来,这样用户可以保留自己想要的那几项内容,可以更快更方便的阅读到自己关心的那几项参数,节省了用户的有效时间。

固定头部

场景:列表横向或者纵向过多,下翻或横拉的时候标题头被隐藏,不知道自己当前浏览到的参数属于哪一项。

交互过程中,可以把第一排重要的东西固定,列表内容翻动的同时,第一排仍然在原位不移动而且覆盖列表中的其他信息,很多自带的框架都是这样的形式,使用的出场率也是非常高,这样用户可以随时查看到自己看到的内容是属于哪一项属性,或者是属于哪一条信息,可以是横向固定,也可以固定竖直的第一排标题,也可以固定最后一块操作点击区域,具体如何固定、是否固定,根据整体的需求来选择。

间距的规则

通常表单都是大量的文字,大多数的文字高度都在该行高度的三分之一左右。过于紧密用户浏览不顺畅,过于分开显得画面过于松散,不同的分割方式,间距也会有所不同。

总结

其实上面的每一条都是一个小总结,每一条在大部分的列表中都可以用到,主要还是根据实际需求来运用这几点,比如分割的方式根据主体风格来搭配,不要为了设计而设计盲目运用,毕竟设计都是以内容为主,尤其是表单设计,本身就是更好的表达内容。


本文发布于人人都是产品经理。




为了设计更好的深色模式

分享达人

通过一些案例进行比较与实验,探索如何将UI深色模式设计的更好。

iOS作为UI/UE设计的风向标,一直是行业的引领者,不管你愿不愿意承不承认,他的每一次更新变化总能带动UI设计行业的一些大大小小的变革,并且产生更多的追随者,比如当年的iOS7开始的扁平化设计风格,对后续设计风格的影响直到现在已经7年了。



在最近半年,iOS在UI设计风格上最大的变革莫过于DarkMode(深色模式),在DarkMode之前,我们熟悉的UI界面往往都是浅白色界面为主,而从iOS13开始正式使用了DarkMode,界面突然可以变深色了,苹果官方说这样设计可以让眼睛更舒服的长时间阅读,为革命保护视力,而且更加省电增长续航,具体结果我们不得而知,需要科学家们去验证了,但是对于我们设计师来说带来的挑战就是要“黑白无常”了。



其实DarkMode从测试版算起已经差不多推出了有半年的时间了,一些知名的APP产品早已经有了自己的兼容方案,同时iOS原生界面也给了我们很多最佳实践案例,按道理大家对于DarkMode的设计方式方法应该已经掌握了差不多了,但直到这几天微信正式推出了自己的DarkMode兼容方案,才发现对DarkMode的探索还需要设计师们多多努力。谨以此文表达一下自己的观点,不妥之处敬请海涵。


从一个“列表页面”说起:

列表试图(TableView)是iOS中最常见的界面组件,一般常见于设置与栏目列表页面


iOS设置界面的浅色模式和深色模式看起来都非常协调。

下面我们看看微信发现页面,这个页面和iOS设置是很相似的。


如果单独看微信发现页面的浅色模式实际效果还是不错的。

但是直接转换到深色模式下就感觉突然差的很多了,甚至可以说是有点难看,这次微信真的做了一次黑天鹅?

 

到底是什么原因让微信发现页面在深色模式下视觉体验如此之差呢?

我们不妨将两个功能布局都相似的深色进行放在一起进行一下比较


组成色彩分析:

在色彩这块在这两个页面中微信和iOS基本保持一致,四层灰度设计能更好的保持页面整体干净整洁且层次分明,但是被A背景色上,微信的背景色选择了黑色偏绿的颜色,应该是微信设计师还是想体现出产品的标志色原色。

文字的颜色也较iOS略微深一点,但是在整体上影响并不大。


看来在主要色彩上并没有什么问题,那么为什么微信这个界面与iOS界面比起来视觉上要感觉差一些呢?

下面来看一下图标


图标设计分析:


图标上的差别主要在于线宽与外框,微信采用无外框统一线宽的线形图标,iOS采用的是有外框剪影图标。

我们我们把图标进行互换会怎么样呢?



观察到了吗?别看错了!

是的,我把故意位置做了对调,左边是iOS,右边是微信。替换图标后的微信明显加分不少,整个界面都整齐多了,而iOS换了图标后明显变得不够整齐了,潦草很多。


那么结论是微信的无框线性图标在深色模式下兼容有问题?是的的确如此。但是等一下,还有一些细节你注意到吗?换了图标的微信界面和之前的iOS界面比起来明显还是有点不够整齐,为什么呢?

来我们回过头来从细节再看一下iOS界面。


我们按照这个思路把刚才微信替换图标界面再排序一下!

界面视觉体验明显整齐了很多是不是!


疑问:

为什么细线图标和无框图标会在深色背景表现不够好,而在浅色背景下就没问题呢?

是不是所有的UI都会存在这样的问题呢?

我们再来看一些例子:


看来结论是一样的,线性图标在深色背景下的表现都是差强人意,反观带框图标适应性很强,浅色和深色模式下均能良好的适配,我来分析一下原因。


当年伽利略用望远镜往天上看,发现木星比金星大,换成肉眼看后金星则比木星大。他认为是眼睛的某种视觉特性造成了这种现象。

德国物理学家赫尔曼把这种错觉称为辐照错觉,就是说在黑暗背景下,亮度越高的物体看起来面积越大。


再来看一张图片


哪个圆圈看起来更大,显然是黑色背景下的白色圆形,实际上这只是一种错觉,所有圆圈是一样大。


光亮刺激会使得神经元产生非线性放大作用,导致刺激比实物本身看起来更大,白色圆形更亮,所以看起来更大一些。


线性图标是用线条勾画图案达到隐喻效果,一般线粗是2px~6px像素。



设计师在设计时候都是以最终视觉作为参考,而设计稿本身多是浅色背景,所以在浅色背景的映衬下图标视觉会显得稍大,视觉基本是平衡的,假如设计是4px而呈现出的效果其实是6px左右。


是不是觉得哪里有点不对了?按照这个逻辑黑色背景下白色线图标不应该是视觉更大、更明显吗?


我们还需要考虑一个因素,那就是色彩,之前的几个界面案例的线性图标都是彩色的,特别是黑色背景下,不同色彩的图标放在一起,会有明显的忽大忽小的感觉,会让界面感觉非常凌乱。


是不是感觉黄色最大,红色的最小?但是其实是一样的,这还是相同形状的,要是图标形状不同感受会更明显


看一个实际中的例子:

由于都是单色线性图标,在浅色和深色下表现还都不错的,但是单色图标略显界面单调,并不太建议这么设计。


毫无疑问,未来的UI场景需要适配多背景色风格,图标除了具备好看隐喻之外,更需要具备抗干扰性

带框图标是一个不错的解决方法,大胆预测带框图标会将成为未来一段时间图标设计主流!



结论

1:深色模式中灰度色阶在一个界面最多可分为四层。

2:为了适配深色模式,今后有框图标将会成为图标设计风格主流。

3:同样为了适配深色模式,细线图标将会被淘汰,剪影和粗线图标会流行起来。

4:图标除了个体设计上用心,在排列上也会极大影响到页面的整合视觉,光谱排列法是个不错的选择。



转自:站酷-

APP常见的8种导航模式

分享达人

合理的导航设计,会让用户轻松达到目的而又不会干扰和困扰用户的选择。



优秀的APP导航设计,能够合理地完美展示产品的功能,并快速引导用户使用,增强用户的识别度。合理的导航设计,会让用户轻松达到目的而又不会干扰和困扰用户的选择。 

网上对介绍导航文章已经有很多,有部分已过时,今天自己再重新整理一遍,方便自己也方便更多人理解。


为什么需要导航?
-
1、我可以去哪?
导航为了清晰指引用户完成任务。建立合理的导航系统,设计顺畅的任务路径,让用户不再像无头苍蝇一样,在各模块之间迷失。一个好的导航,能够扁平化用户的任务路径,减少用户操作成本,从而提高用户体验。 

2、我现在在哪?
用户当前位置要有清晰的标记,从哪里来,到哪里去。 



常见的8种导航形式
- 

标签式导航可分为 底部标签式 、舵式导航、Tab标签式导航。 

一、底部标签式导航
-
底部标签导航是目前最常见的导航形式。底部导航 一般采用3-4个标签,最多不会超过5个。
优点: 
1、入口直接清晰,操作路径短,便于在不同功能模块进行跳转 
2、直接展示入口内容,内容曝光度高 
缺点:
1、功能之间无主次 
2、扩展性差,不利于后期的功能扩展 


二、舵式导航
-
舵式导航是 底部导航的一种扩展形式,像轮船上用来指挥的船舵,两侧是其他操作按钮。 
普通标签导航难以满足导航的需求,就需要一些扩展形式,和标签导航相比,舵式导航 把核心功能放在中间,标签更加突出醒目,同时对主功能标签做了扩展功能。 

使用场景:
如1、产品需要特殊的引导,如58同城,引导用户发布任务。 

如2、社区产品引导用户发帖子

如3、凸显核心功能,如百度地图、高德等

优点: 
1、在默认加载的页面之外,又能够突出强调中间的入口 
2、入口直接清晰,操作路径短,便于不同功能模块进行跳转 
3、直接展示入口内容,内容曝光率高 
缺点:(与标签导航存在同样的弊端) 
1、功能之间无主次 
2、扩展性差,不利于后期的功能扩展 



三、Tab标签式导航
-
一般 用于二级导航,当内容分类较多的时,一般采用 顶部标签导航设计模式。 

使用场景:
如:为当前界面内不同模块的切换,或者查看不同的分类内容 
优点:
标签数量可以随意根据需求变化,可以左右滑动,衍生更多标签。 
缺点:
操作热区较小,有APP设计的交互前与后的样式差异不大,容易造成误操作的困惑。(不知道当前在哪个标签下) 


四、抽屉式导航
-
抽屉式导航的核心思路是“隐藏”。 隐藏非核心的操作与功能,让用户更专注于核心的功能操作上去, 一般用于二级菜单。  

优点: 
1、节省页面展示空间 
2、注意力聚焦在当前页面 
缺点:
1、左上角的按钮存在于单手操作热区难以触达; 
2、降低了用户对产品部分功能的参与度。 


五、宫格式导航
-
主要将入口全部集中在主页面中,各个 入口相互独立,没有太多的交集,无法跳转互通。 
采用这种导航的应用已经越来越少,往往用在二级页作为内容列表的一种图形化形式呈现,或是作为一系列工具入口的聚合。 

优点:
1、将入口进行聚合,入口也清晰直接 
2、操作路径较短,用户可以便捷的在不同的功能模块之间进行跳转 
3、扩展性好,方便增加多个入口 
缺点:
1、用户无法第一时间看到内容或者执行操作,选择的压力会比较大。 
2、返回路径较长,容易产生用户不良情绪。 


六、轮播式导航
-
采用Banner轮播导航,当应用信息足够扁平, 内容比较单薄时使用。特别是在产品初期,缺乏用户和内容,这种导航目前已经很少用。 
该方式就可以 凸显产品核心功能给予用户使用。(如:较早时腾讯极光APP、应用市场等) 

优点:

1、展示清晰直观,美观度高 
2、内容曝光度高,突出强调了展示内容 
3、交互动画可多样化 
缺点:
1、展示内容数量有限 


七、列表式导航
-
现有APP中一种主要的信息承载模式,列表导航和宫格导航类似,属于二级导航。 
列表式导航分为3类: 标题式列表、内容式列表、嵌入式列表。 
标题式列表:一般只显示一行文字,有的显示一行文字加一张图片等等。 
内容式列表:主要以内容为主,所以在列表中就会体现出部分内容信息,点击进去就是详情。 
嵌入式列表:嵌入式其实就是由多个列表层级组合而成的导航。 

优点:
1、结构清晰,易于理解; 
2、使用,能够帮助用户快速的定位去到对应的页面 
3、能够在列表上直接给出关于活动、更新的提示 
缺点:
1、排版方式单一 
2、多个入口之间不分级,没优先级之分 


八、组合式导航
-
多用于产品本身 功能较为复杂,既需要用户能 聚焦于内容,又需要给出用户不同页面之间的入口,以便用户进行直接跳转,那就采用组合式导航,利用不同导航的特性来满足产品需求。 
组合式导航目前最常见的导航方式。 
如: 标签式导航+列表式  ;标签式+宫格式  ; 舵式+列表式+标签式  等等; 

优点: 
1、组合式多样化 
2、能给出用户不同页面之间的入口,方便跳转 


总结
-
根据自己的产品功能和特性,采用不同导航模式。 

每个产品迭代发展和变化,也会导致产品导航在过程中不停的产生变化,就必须依据用户属性和使用场景进行调整。不拘泥任何模式,解决问题才是根本.




使用scss开发小程序(各种小程序平台通用)

seo达人

微信小程序的wxss、阿里旗下淘宝、支付宝小程序的acss等等语法很类似原生css,但是在web开发里用惯了动态css语言,再写回原生css很不习惯,尤其是父子样式的嵌套写法非常繁琐。

因此,我希望能有一个自动化构建方案,能够简单地将scss转换成小程序的样式语言。

方案1

以前写微信小程序的依赖库时用过,使用gulp编译,将源码和编译后的代码分别放到src和dist两个目录。gulp会处理src下面的所有文件,将其中的scss转换成css,并将其他所有文件原封不动挪到dist下相应位置。

这里就不详细说了,代码参考Wux

方案2

非常简单直接,使用Webstorm/IDEAFile Watchers功能实时转换。

安装Ruby和sass

确保命令行输入sass -v能出现版本号,安装过程略。

安装File Watchers

到插件市场上搜索并安装(已安装则跳过)

1.png

添加scss的转换脚本

现在安装完插件打开项目会自动弹出scss转css的向导,方便了很多。但还需要做一些修改,配置如下:

2.png

首先要将生成文件的后缀名改掉,比如这里我的淘宝小程序就得是acss

其次,将Arguments改为:

$FileName$:$FileNameWithoutExtension$.acss --no-cache --sourcemap=none --default-encoding utf-8 --style expanded

如果不加--no-cache,scss文件同目录下会出现一个.sass-cache目录。

如果不加--sourcemap=none, scss文件同目录下会出现一个.map文件。

如果不加--default-encoding utf-8, scss文件如果有中文注释转换就会报错。

style可不加,这里用的是无缩进和压缩的风格,反正小程序打包发布时还会压,这里保持可读性。

现在这个scss转换是单独作用于项目的,如果新建一个小程序项目,就需要重新添加(不建议设置成global,容易误伤)。

注意到File Watchers列表的右侧操作栏下方有导入导出按钮,可以将现在配好的设置导出保存,将来新建项目时只要导入一下就行了。


之后还有一个问题,如果我手动将编译后的css(即wxss或者acss,下略)文件删除,scss文件不改动的话,就不会重新编译出css文件。
或者万一监听失效或者不够及时,css还有可能是旧的。
所以还需要一个命令,用来将整个目录下的scss文件统一转换,确保没有遗漏和保持代码。

不过我看了半天sasssass-convert的文档,没有找到一个可用的写法,能让命令行遍历指定目录下的所有scss文件,将其转换成css放到源文件所在目录,并且将后缀名改为wxss或者acss

所以遍历这个行为只能交给nodejs来实现,代码如下:

创建编译脚本build/scss-convert.js

var path = require("path") var fs = require("fs") const { exec } = require('child_process') const basePath = path.resolve(__dirname, '../') function mapDir(dir, callback, finish) {
  fs.readdir(dir, function(err, files) { if (err) { console.error(err) return }
    files.forEach((filename, index) => { let pathname = path.join(dir, filename)
      fs.stat(pathname, (err, stats) => { // 读取文件信息 if (err) { console.log('获取文件stats失败') return } if (stats.isDirectory()) {
          mapDir(pathname, callback, finish)
        } else if (stats.isFile()) { if (!['.scss'].includes(path.extname(pathname))) { return }
          callback(pathname)
        }
      }) if (index === files.length - 1) {
        finish && finish()
      }
    })
  })
}

mapDir(
  basePath, function (file) { const newFileWithoutExt = path.basename(file, '.scss') if (newFileWithoutExt.startsWith('_')) { return // 按照scss规则,下划线开头的文件不会生成css } // exec可以让nodejs执行外部命令 exec(`sass --no-cache --sourcemap=none --default-encoding utf-8 --style expanded ${file}:${newFileWithoutExt}.acss`, { cwd: path.dirname(file) // 不写这个会导致生成的文件出现在根目录 }, (err, stdout, stderr) => { if (err) { console.log(err) return } console.log(`stdout: ${stdout}`)
    })
  }, function() { // console.log('xxx文件目录遍历完了') }
)

package.json里添加一条script:

 "scripts": { "scss": "node build/scss-convert",
  },

ES6数据的解构赋值使用及应用

前端达人


定义


ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)



本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值

如果解构不成功,变量的值就等于undefined

解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错、



解构赋值的用途:

交换变量的值

例如:let x=1,y=2;[x,y] = [y,x]



从函数返回多个值

函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便



函数参数的定义

解构赋值可以方便地将一组参数与变量名对应起来



提取 JSON 数据,很多接口数据只需要其中某部分

例如aa.axios.get(res=>{let {data:result}=res;}),则res.data.result = result了



函数参数的默认值

指定参数的默认值,就避免了在函数体内部再写var foo = config.foo || ‘default foo’;这样的语句



遍历 Map 结构

Map 结构原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便



输入模块的指定方法

加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。* const { SourceMapConsumer, SourceNode } = require(“source-map”);


1、数组的解构赋值


左右两侧数据解构须得吻合,或者等号左边的模式,只匹配一部分的等号右边的数组(属于不完全解构)



特殊情况使用…扩展运算符,无值是空数组



左右两边等式的性质要相同,等号的右边不是数组(或者严格地说,不是可遍历的结构),那么将会报错,只要某种数据结构具有 Iterator



接口,都可以采用数组形式的解构赋值,例如Set结构



解构赋值允许指定默认值,当一个数组成员严格等于undefined,默认值才会生效,否则取赋值的值;如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值;默认值可以引用解构赋值的其他变量,但该变量必须已经声明



// 数组的解构赋值
 let [a,b] = [1,2];
 console.log([a,b],a);//[1, 2] 1
 let [aa] = [11,22];
 console.log(aa)//11
 let [aaa,bbb] = [111];
 console.log(aaa,bbb)//111 undefined
 let [head, ...tail] = [1, 2, 3, 4];
 console.log(head,tail)//1,[2,3,4]
 let [x, y, ...z] = ['a'];
 console.log(x,y,z)//a undefined []
 // 等号右边不是数组会报错
 // let [ab] = 121;
 // conosle.log(ab)//TypeError: 121 is not iterable
 // let [abc] = {}
 // conosle.log(abc)//TypeError: {} is not iterable
 // 默认值赋值
 let [zz = 1] = [undefined];
 console.log(zz)//1
 let [zzz = 1] = [null];
 console.log(zzz)//null
 let [foo = true] = [];
 console.log(foo)// true
 let [xxx, yyy = 'b'] = ['a'];
 console.log(xxx,yyy)//a,b
 let [xxxx, yyyy = 'b'] = ['a', undefined]; 
 console.log(xxxx,yyyy)//a,b
 function f() {
   console.log('aaa');
 }
 let [xx = f()] = [1];
 console.log(xx)//1
 let [qq=ww,ww=11] = [23,44];
 console.log(qq,ww)//23,44,因为ww申明比qq晚所以是undefined;

2、对象的解构赋值
对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者

数组是按照位置区分,对象则是按照键名区分的,同样的解构失败则为undefine
可将已有方法对象解构赋值
嵌套赋值,注意是变量是否被赋值是模式还是键值
对象的解构赋值可以取到继承的属性
如果要将一个已经声明的变量用于解构赋值,必须非常小心
let xx; // {xx} = {xx: 1}这样会报错,

解构赋值允许等号左边的模式之中,不放置任何变量名。因此,可以写出非常古怪的赋值表达式
({} = [true, false]);//可执行

由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构

objFuc(){
            // 对象解构赋值
            let {b,a} = {a:1}
            console.log(a,b)//1 undefined
            // 已有对象解构赋值
            let { sin, cos } = Math;//将Math对象的对数、正弦、余弦三个方法,赋值到对应的变量上
            console.log(sin);//log() { [native code] }
            const { log } = console;
            log('hello') // hello
            // 
            let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
            console.log(baz);//aaa
            // 嵌套赋值
            let obj = {
              p: [
                'Hello',
                { y: 'World' }
              ]
            };
            let { p,p:[x, { y }] } = obj;
            console.log(x,y,p)//Hello World p: ['Hello',{ y: 'World' }]
            //继承赋值
            const obj1 = {};
            const obj2 = { foo: 'bar' };
            Object.setPrototypeOf(obj1, obj2);//obj1继承obj2
            const { foo } = obj1;
            console.log(foo) // "bar"
            // 默认值
            // 错误的写法
            let xx;
            // {xx} = {xx: 1};// SyntaxError: syntax error,Uncaught SyntaxError: Unexpected token '='
            ({xx} = {xx: 1});//正确写法
            console.log(xx)
            // 古怪的,等式左边可为空
            // ({} = [true, false]);
            // 对象可解构数组
            let arr = [1, 2, 3];
            let {0 : first, [arr.length - 1] : last} = arr;
            console.log(first,last)//1 3
        },


3、字符串的解构赋值

  • 字符串赋值
  • 类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值
strFuc(){
            // str:'yan_yan'
            let [a,b,c,d,e,f,g] = this.str;
            console.log(a,b,c,d,e,f,g)//y a n _ y a n
            // 对数组属性解构赋值
            let {length} = this.str;
            console.log(length)//7
        },

    

4、数值和布尔值的解构赋值

  • 解构赋值时,如果等号右边是数值和布尔值,则会先转为对象
  • 解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错

let {toString: s} = 123;
console.log(s === Number.prototype.toString,s)//true ƒ toString() { [native code] }
let {toString: ss} = true;
console.log(ss === Boolean.prototype.toString,ss)// true ƒ toString() { [native code] }
// 右侧必须是数组或对象,undefined和null无法转为对象,所以对它们进行解构赋值,都会报错
// let { prop: x } = undefined; // TypeError
// let { prop: y } = null; // TypeError


    

5、函数参数的解构赋值

  • 也可使用默认值,注意默认值是指实参的默认值而不是形参的默认值
// 函数的解构赋值可使用默认值,注意默认值是指实参的默认值而不是形参的默认值
            function move({x=1, y=1}={}) {
              return [x, y];
            }
            function move1({x, y} = { x: 0, y: 0 }) {
              return [x, y];
            }
            function move2({x, y=1} = { x: 0, y: 0 }) {
              return [x, y];
            }
            console.log(move({x: 3, y: 8})); // [3, 8]
            console.log(move({x: 3})); // [3, 1]
            console.log(move({})); // [1, 1]
            console.log(move()); // [1,1]
            console.log(move1({x: 3, y: 8})); // [3, 8]
            console.log(move1({x: 3})); // [3, 1]
            console.log(move1({})); // [undefined, 1]
            console.log(move1()); // [0,0]
            console.log(move2({x: 3, y: 8})); // [3, 8]
            console.log(move2({x: 3})); // [3, 1]
            console.log(move2({})); // [undefined, 1]
            console.log(move2()); // [0,0]

6、圆括号问题
解构赋值虽然很方便,但是解析起来并不容易。对于编译器来说,一个式子到底是模式,还是表达式,没有办法从一开始就知道,必须解析到(或解析不到)等号才能知道。
由此带来的问题是,如果模式中出现圆括号怎么处理。ES6 的规则是,只要有可能导致解构的歧义,就不得使用圆括号。
可以使用圆括号的情况只有一种:赋值语句的非模式部分,可以使用圆括号
总结:
不管是哪一类的解构赋值,等式右边的数据必须是对象形式(数组也是一种对象形式)
————————————————
版权声明:本文为CSDN博主「Yan_an_n」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44258964/article/details/105643553

浅析HTTP协议

前端达人

目录

HTTP协议

HTTP请求:

HTTP响应:

会话与会话状态:

Cookie

Session

Cookie和Session的区别

HTTP协议


 HTTP请求:
Post /test.php HTTP/1.1                               //请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本

Host: www.test.com                                       //请求头

User-agent:mozilla/5.0(windows NT 6.1: rv: 15.0)

Gecko/20100101 firefox15.0

                                                                                    //空白行,代表请求头结束

Username=admin&passwd=admin                             //请求正文

HTTP请求方法



GET       请求获取Request-URI所标识的资源

POST     在Request-URI所标识的资源后附加新的数据

HEAD    请求获取由Request-URI所标识的资源的响应消息报头

PUT       请求服务器存储一个资源,并用Request-URI作为其标识

常用的为GET和POST;GET和POST的区别:

GET提交的内容会直接显示在URL中,私密性较差,可以用于显示一些公共资源;但是GET效率会比较高。

POST不会将内容显示在URL中,可以用于提交一些敏感数据,例如用户名或密码。

HTTP响应:
HTTP/1.1 200 OK                                         //响应行由协议版本号,响应状态码和文本描述组成

Data:sun,15 nov 2018 11:02:04  GMT    //响应头

Server:bfe/1.0.8.9

……

Connection: keep-alive

                                                                      //空白行,代表响应头结束

<html>

</html><title>index.heml</title>                  //响应正文

HTTP的状态码:

状态代码由三位数字组成,第一个数字定义了响应的类别,且有五种可能取值。

1xx:指示信息 —— 表示请求已接收,继续处理。

2xx:成功 —— 表示请求已被成功接收、理解、接受。

3xx:重定向 —— 要完成请求必须进行更进一步的操作。

4xx:客户端错误 —— 请求有语法错误或请求无法实现。

5xx:服务器端错误 —— 服务器未能实现合法的请求。

常见状态代码、状态描述的说明如下。

200 OK:客户端请求成功。

400 Bad Request:客户端请求有语法错误,不能被服务器所理解。

401 Unauthorized:请求未经授权,这个状态代码必须和 WWW-Authenticate 报头域一起使用。

403 Forbidden:服务器收到请求,但是拒绝提供服务。

404 Not Found:请求资源不存在,举个例子:输入了错误的URL。

500 Internal Server Error:服务器发生不可预期的错误。

503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常。

会话与会话状态:
       Web中的会话是指一个客户端浏览器与web服务器之间连续发生一系列请求和响应过程。会话状态是指在会话过程中产生的状态信息;借助会话状态,web服务器能够把属于同一会话中的一系列的请求和响应关联起来。

Cookie
概述

       Cookie是一种在客户端保持HTTP状态信息的技术,它好比商场发放的优惠卡。在浏览器访问Web服务器的某个资源时,由Web服务器在在HTTP响应头中附带传送给浏览器一片数据,web服务器传送给各个客户端浏览器的数据是可以各不相同的。

       一旦Web浏览器保存了某个Cookie,那么它在以后每次访问该Web服务器是都应在HTTP请求头中将这个Cookie回传个Web服务器。Web服务器通过在HTTP响应消息中增加Set-Cookie响应头字段将CooKie信息发送给浏览器,浏览器则通过在HTTP请求消息中增加Cookie请求头字段将Cookie回传给Web服务器。

       一个Cookie只能标识一种信息,它至少含有一个标识该消息的名称(NAME)和和设置值(VALUE)。一个Web浏览器也可以存储多个Web站点提供的Cookie。浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。

传送示意图



特点

存储于浏览器头部/传输与HTTP头部,写时带属性,读时无属性。由三元【name,domain,path】唯一确定Cookie。

Set-Cookie2响应头字段

Set-Cookie2头字段用于指定WEB服务器向客户端传送的Cookie内容,但是按照Netscape规范实现Cookie功能的WEB服务器, 使用的是Set-Cookie头字段,两者的语法和作用类似。Set-Cookie2头字段中设置的cookie内容是具有一定格式的字符串,它必须以Cookie的名称和设置值开头,格式为"名称=值”,后面可以加上0个或多个以分号(;) 和空格分隔的其它可选属性,属性格式一般为 "属性名=值”。

除了“名称=值”对必须位于最前面外,其他的可选属性可以任意。Cookie的名称只能由普通的英文ASCII字符组成,浏览器不用关心和理解Cookie的值部分的意义和格式,只要WEB服务器能理解值部分的意义就行。大多数现有的WEB服务器都是采用某种编码方式将值部分的内容编码成可打印的ASCII字符,RFC 2965规范中没有明确限定编码方式。

举例:   Set-Cookie2: user-hello; Version=1; Path=/

Cookie请求头字段

Cookie请求头字段中的每个Cookie之间用逗号(,)或分号(;)分隔。在Cookie请求字段中除了必须有“名称=值”的设置外,还可以有Version、path、domain、port等属性;在Version、path、domain、port等属性名之前,都要增加一个“$”字符作为前缀。Version属性只能出现一次,且要位于Cookie请求头字段设置值的最前面,如果需要设置某个Cookie信息的Path、Domain、Port等属性,它们必须位于该Cookie信息的“名称=值”设置之后。

       浏览器使用Cookie请求头字段将Cookie信息会送给Web服务器;多个Cookie信息通过一个Cookie请求头字段会送给Web服务器。

浏览器会根据下面几个规则决定是否发送某个Cookie信息:

       1、请求主机名是否与某个存储的Cookie的Domain属性匹配

       2、请求的端口号是否在该Cookie的Port属性列表中

       3、请求的资源路径是否在该Cookie的Path属性指定的目录及子目录中

       4、该Cookie的有效期是否已过

Path属性的指向子目录的Cookie排在Path属性指向父目录的Cookie之前

举例: Cookie: $Version=1; Course=Java; $Path=/hello/lesson;Course=vc; $Path=/hello

Cookie的安全属性

secure属性

当设置为true时,表示创建的Cookie会被以安全的形式向服务器传输,也就是只能在HTTPS连接中被浏览器传递到服务器端进行会话验证,如果是HTTP连接则不会传递该信息,所以不会被窃取到Cookie的具体内容。

 HttpOnly属性

如果在Cookie中设置了"HttpOnly"属性,那么通过程序(JS脚本、Applet等)将无法读取到Cookie信息,这样能有效的防止XSS攻击。

总结:secure属性 是防止信息在传递的过程中被监听捕获后信息泄漏,HttpOnly属性的目的是防止程序获取cookie后进行攻击这两个属性并不能解决cookie在本机出现的信息泄漏的问题(FireFox的插件FireBug能直接看到cookie的相关信息)。

Session
使用Cookie和附加URL参数都可以将上一-次请求的状态信息传递到下一次请求中,但是如果传递的状态信息较多,将极大降低网络传输效率和增大服务器端程序处理的难度。

概述

Session技术是一种将会话状态保存在服务器端的技术,它可以比喻成是医院发放给病人的病历卡和医院为每个病人保留的病历档案的结合方式。客户端需要接收、记忆和回送Session的会话标识号,Session可以且通常是借助Cookie来传递会话标识号。



Session的跟踪机制

HttpSession对象是保持会话状态信息的存储结构,一个客户端在WEB服务器端对应一个各自的HttpSession对象。WEB服务器并不会在客户端开始访问它时就创建HttpSession对象,只有客户端访问某个能与客户端开启会话的服务端程序时,WEB应用程序才会创建一个与该客户端对应的HttpSession对象。WEB服务器为HttpSession对象分配一个独一无的会话标识号, 然后在响应消息中将这个会话标识号传递给客户端。客户端需要记住会话标识号,并在后续的每次访问请求中都把这个会话标识号传送给WEB服务器,WEB服务器端程序依据回传的会话标识号就知道这次请求是哪个客户端发出的,从而选择与之对应的HttpSession对象。

WEB应用程序创建了与某个客户端对应的HttpSession对象后,只要没有超出一个限定的空闲时间段,HttpSession对象就驻留在WEB服务器内存之中,该客户端此后访问任意的Servlet程序时,它们都使用与客户端对应的那个已存在的HttpSession对象。

Session是实现网上商城的购物车的最佳方案,存储在某个客户Session中的一个集合对象就可充当该客户的一个购物车。

超时管理

WEB服务器无法判断当前的客户端浏览器是否还会继续访问,也无法检测客户端浏览器是否关闭,所以,即使客户已经离开或关闭了浏览器,WEB服务器还要保留与之对应的HttpSession对象。随着时间的推移而不断增加新的访问客户端,WEB服务器内存中将会因此积累起大量的不再被使用的HttpSession对象,并将最终导致服务器内存耗尽。WEB服务器采用“超时限制”的办法来判断客户端是否还在继续访问如果某个客户端在一定的时间之 内没有发出后续请求,WEB服务器则认为客户端已经停止了活动,结束与该客户端的会话并将与之对应的HttpSession对象变成垃圾。

如果客户端浏览器超时后再次发出访问请求,Web服务器则认为这是一个新的会话开始,将为之创建新的Httpsession对象和分配新的会话标识号。

利用Cookie实现Session的跟踪

如果WEB服务器处理某个访问请求时创建了新的HttpSession对象,它将把会话标识号作为一个Cookie项加入到响应消息中,通常情况下,浏览器在随后发出的访问请求中又将会话标识号以Cookie的形式回传给WEB服务器。WEB服务器端程序依据回传的会话标识号就知道以前已经为该客户端创建了HttpSession对象,不必再为该客户端创建新的HttpSession对象,而是直接使用与该会话标识号匹配的HttpSession对象,通过这种方式就实现了对同一个客户端的会话状态的跟踪。

利用URL重写实现Session跟踪

Servlet规范中引入了一种补充的会话管理机制,它允许不支持Cookie的浏览器也可以与WEB服务器保持连续的会话。这种补充机制要求在响应消息的实体内容中必须包含下一 次请求的超链接,并将会话标识号作为超链接的URL地址的一个特殊参数。将会话标识号以参数形式附加在超链接的URL地址后面的技术称为URL重写。 如果在浏览器不支持Cookie或者关闭了Cookie功能的情况下,WEB服务器还要能够与浏览器实现有状态的会话,就必须对所有能被客户端访问的请求路径(包括超链接、form表单的action属性设置和重定向的URL)进行URL重写。

Cookie和Session的区别
session和cookies同样都是针对单独用户的变量(或者说是对象好像更合适点),不同的用户在访问网站的时候都会拥有各自的session或者cookies,不同用户之间互不干扰。

他们的不同点是:

1,存储位置不同

session在服务器端存储,比较安全,但是如果session较多则会影响性能

cookies在客户端存储,存在较大的安全隐患

2,生命周期不同

session生命周期在指定的时间(如20分钟) 到了之后会结束,不到指定的时间,也会随着浏览器进程的结束而结束。

cookies默认情况下也随着浏览器进程结束而结束,但如果手动指定时间,则不受浏览器进程结束的影响。

总结:简而言之,两者都是保存了用户操作的历史信息,但是存在的地方不同;而且session和cookie的目的相同,都是为了克服HTTP协议无状态的缺陷,但是完成方法不同。Session通过cookie在客户端保存session id,将用户的其他会话消息保存在服务端的session对象中;而cookie需要将所有信息都保存在客户端,因此存在着一定的安全隐患,例如本地Cookie中可能保存着用户名和密码,容易泄露。
————————————————
版权声明:本文为CSDN博主「悲观的乐观主义者」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43997530/article/details/105650267


浅显易懂的cookie的使用(设置和获取cookie缓存)

前端达人

js中cookie的使用(设置和获取cookie缓存)
生为一个已经入职一年多的前端小白,第一次写博客还有点小激动,有不足的地方还希望大家多多指出,因为最近项目有涉及到利用cookie缓存数据,所以在这边再巩固一下。

1、cookie的定义
在使用浏览器中,经常涉及到数据的交换,比如你登录系统账号,登录一个页面。我们经常会在此时设置记住账号啥的,或者自动登录选项。那这些都是怎么实现的呢,答案就是今天的主角cookie了,Cookie是由HTTP服务器设置的,保存在浏览器中,但HTTP协议是一种无状态协议,在数据交换完毕后,服务器端和客户端的链接就会关闭,每次交换数据都需要建立新的链接。
从JavaScript的角度看,cookie 就是一些字符串信息。这些信息存放在客户端的计算机中,用于客户端计算机与服务器之间传递信息。
在JavaScript中可以通过 document.cookie 来读取或设置这些信息。由于 cookie 多用在客户端和服务端之间进行通信,所以除了JavaScript以外,服务端的语言(如PHP)也可以存取 cookie。

2、cookie的使用
设置cookie
function setCookie(c_name, value, expiredays) {
       var exdate = new Date()
       exdate.setDate(exdate.getDate() + expiredays)
       document.cookie = c_name + "=" + escape(value) +
           ((expiredays == null) ? "" : ";expires=" + exdate.toGMTString())+";path=/";
   }
1
2
3
4
5
6
调用该方法如:

var userId="123456";
setCookie("userId", userId, 30);
1
2
下面是里面参数的意义

参数 含义
c_name 自己定义的cookie名称
value 需要放在定义的c_name 中的值
expiredays cookie的有效期
这里有一个要注意点就是 " path=/"
" path=/"是只存下的cookie再该项目所有页面都能去获取,如果你想只存到弄个特定目录可以在path中指定路径,如:“path=/views/myHomePage”,z这样你可以在/views/myHomePage文件下所有页面都能取到你存的cookie了。

取回cookie
 function getCookie(c_name) {
        if (document.cookie.length > 0) {
            c_start = document.cookie.indexOf(c_name + "=")
            if (c_start != -1) {
                c_start = c_start + c_name.length + 1
                c_end = document.cookie.indexOf(";", c_start)
                if (c_end == -1) c_end = document.cookie.length
                return unescape(document.cookie.substring(c_start, c_end))
            }
        }
        return ""
    }
1
2
3
4
5
6
7
8
9
10
11
12
调用该方法如:

var newUserId= getCookie("userId");
console.log(newUserId)
alert(newUserId)
————————————————
版权声明:本文为CSDN博主「前端陈伟霆」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43927397/article/details/105658614







日历

链接

blogger

蓝蓝 http://www.lanlanwork.com

存档