首页

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

涛涛

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

从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界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务

损失厌恶心理是如何影响我们的决策

涛涛

损失厌恶心理在设计中的应用以及是怎么影响我们的决策

前言:

前几天在一篇文章中看到“损失厌恶”这个心理学现象,就上网查阅了一些相关资料,以及它在设计中是如何运用,又是如何影响我们的决策,总结一点自己的观点。


一、损失厌恶


对于损失厌恶,先来做几个实验,来帮助我们更好的理解。

如果我给你一个苹果,你应该会感到高兴吧!现在换一下,我给你两个苹果,接着我向你拿回了一个。

请问,你更喜欢哪一个场景?我想多数人的答案是第一个,而不喜欢第二个场景。

这个实验两个场景的结果都是一样的,都得到了一个苹果,但是在第二个场景中,因为得而复失,损失了一个苹果,这严重影响并拉低了获得一个苹果的幸福感。


丹尼尔·卡尼曼(Daniel Kahneman)曾经设计了一个掷质硬币的实验,硬币是均质的。如果是正面,你将得到150美元;如果是背面,你将输掉100美元。这个赌局对于参与者来说,长期下注的话,肯定是稳赚不赔的,毕竟输赢概率相同,赢的收益大于输的损失。

但是实验结果却是,大多数人仍然拒绝了这个赌局,因为对于多数人来说,损失100美元的痛苦远远大于得到150美元的快乐。最少收益多少,快乐才能弥补普通人是失去100美元的痛苦呢?答案是,200美元。


由上述实验我们可以看出:


损失厌恶是指人们面对同样数量的收益和损失时,认为损失更加令他们难以忍受。同量的损失带来的负效用为同量收益的正效用的2.5倍。损失厌恶反映了人们的风险偏好并不是一致的,当涉及的是收益时,人们表现为风险厌恶;当涉及的是损失时,人们则表现为风险寻求。


二、坚持中庸最好


我们在进行网购的时候,比如看上一件很喜欢的衣服,追求高性价比的用户会通过图片在淘宝进行搜索,进行价格的对比,从而选择一款销量高、评价好、价格又合理的款式。

“损失厌恶心理”在其中发挥着它的作用,人们害怕价格太低,买到的商品没有自己预期的好,质量得不到保障,害怕价格太高,买到的商品不值这个价格。感觉自己会买亏,所以我们总是选择规避这样的风险,去选择一个中间价位的作为目标购买, “坚持中庸最好”。   



三、电商中的应用


每逢换季、过节时一些电商平台经常会搞一些促销活动,比如

  1. 2件8折,3件7折,预计到手XX元;

  2. 现价99,倒计时x小时恢复199;

  3. 线下店面到期最后一天全场5折的海报(每次路过的时候都是最后一天)

商家都是为了营造现在不买就没的“稀缺感”对你刺激消费,套路还是老套路,但是一直都很有用。如果我们真喜欢这件物品,即使凑单也要享受7折优惠去购买,因为你会感觉便宜很多,省下了不少钱;


还有一年一次的店庆,淘宝的双11,京东的618,也以用户的“损失厌恶”心理为基座。

用户从第一个角度想,能在这样的狂欢节中买到如此实惠的产品,一定要抓住机会,熬夜也要买买买!

用户从第二个角度想,一年一次,要是错过这个机会,如此实惠的产品可只有明年才有了,越累越多的人有这种心理,所以淘宝双十一的总额年年都在刷新记录。


再就是拼团功能的应用,单买价格可能对你来说不贵,但拼团会让你感觉更划算,能省则省,中国有14亿人,有那么3 4亿消费者是不追求高质量、高标准的,对于他们来说便宜就行,也正是因为这样一拨人,才促使了拼多多的在短短的3 4年就可以做到上市的原因之一。



在二手平台,有个估价的功能,当我们输入我们产品的各种信息后,会出现一个大概的市场价,下面会提示我们预计下周跌幅150元、一周后在降低200元等信息,这些细节设计的很到位,都是利用了人们的损失厌倦心理去促成交易。



四、股票市场中的应用


“损失厌恶”心理往往深刻影响这人们的投资决策。例如,你手中有两只股票,一只涨了100块,另一只跌了100块。现在你因急事需要用钱,必须卖掉一只,那么你会卖掉哪一只?调查显示,大多数人会选择卖掉上涨的股票。因为股票上涨是收益,赚了白不赚,一定要先落袋为安,却没有考虑它继续上涨的可能性。而股票下跌是损失,面临损失大多数人是不可接受的,总希望它能涨回来避免损失,如果卖掉那损失就永远不可挽回了。事实上正确的操作应该是卖掉跌的股票,及时止损,不然损失越来越大的概率要更高。


作者在支付宝里买了两支基金,在探索阶段,所以少买了一些在试水,第一支波动比较大,会有亏损,第二支,比较平稳基本就是定期的会有收益,即使没有,也几乎没有亏损的情况,而对我这种金融小白来说会卖掉亏损比较大的,用这些钱去买稳定一些的产品。



五、不要被蝇头小利蒙蔽


养孩子最贵的莫过于尿不湿和奶粉了当然除了学费,对于一个追求高性价比的人来说,孩子的尿不湿我会在闲鱼淘一些宝妈们转卖的全新产品,从下面这个对话来看,我们两个都会呈现出明显的“损失厌恶心理”,卖家不愿意放弃自己眼里的利益,认为自己可以减少损失,而我之前因为花了同样的钱买了同样数量的同样的品牌,所以也不想做出让步,最终也没完成交易。



六、间断造成的损失


一些app中的签到、金币购买皮肤等这些常见的功能就是利用了用户的损失厌恶心理来增加用户粘性,当用户连续签到多少天才可以赢得红包或礼品,中间只要一间断不仅领不到奖励还要重新开始签到,所以一些用户为了减少自己的损失,就会连续签到,还有QQ退出时的提示语也是利用了用户的这种心理,从而能很好的增加留存。



掌上生活app中的积分抽奖活动,1分、9分,一点点的花光都没抽中你想要的,内心的不服输,又抱着侥幸的心理再来一次,可能你把积分花光了也不一定能中奖;

像这样的情况,我们很容易被眼前的利益所蒙蔽,我们不愿意放弃对未来会有更大利益的收获,所以不断投入“沉没成本”,令损失加倍。



七、在产品中的植入


最常见的就是“购物车”功能,我们女生都爱买买买,也常把购物车当作收藏来使用,放进购物车,就感觉这件商品自己的,过两天在看,已经下架就会感觉自己像失去了一件宝贝似的

还有就是VIP体验功能,我们通过百度云盘上传或者下载文件的时候,会有一个免费体验300秒的极速下载的功能,先让你体验了最为VIP的待遇,体验过后,开始给你限速;


苏宁易购APP中非会员用户可以免费享受一个月SUPER VIP,并购买商品时返现2%到个人账户中,让用户感觉我买东西的同时还可以剩下2%,像是自己赚到的一样,体验期过后,你会感觉自己买东西亏了很多;


这些产品都是先让你免费试用付费的VIP,待你用习惯了,VIP也停了,大部分人都会乖乖付费,这也是损失厌恶的一种应用。



八、不敢轻易尝试


在生活中我们吃饭、逛街也是一样,尤其是吃饭,我们通常会选择口味、价格、服务、环境等都比较熟悉的地方吃饭,对一些不熟悉的饭馆,会比较谨慎,这也是损失厌恶心理在“作祟”担心陌生的餐馆饭菜不好吃还贵;


生活中还有很多常见的损失厌恶心理作祟的例子:比如吃自助餐,虽然过食伤胃的道理大家都懂,人们依然觉得已经花了这么多钱,就该敞开肚子吃才算有“赚到”;比如花30块买了张电影票,但看了20分钟后觉得无聊至极,但想着已经花了30块,不看完整场会很“亏”,选择继续呆在影院,即使电影带来的效益为负……有些时候,哪怕是很小的损失。


总结:


我们每个人都有损失厌恶心理,可以说是天性,也是本能,我们要尽可能去找到一些产生损失厌恶的边界,让自己坦然面对损失,规避“损失厌恶”。

点击遮罩层的背景关闭遮罩层

seo达人

开发工具与关键技术:Adobe Dreamweaver CC

作者:黄灿

撰写时间:2019.1.16



在模仿华为官方网页的练习当中我发现华为官网中有一个遮罩层是随便点击遮罩层的背景也能关闭掉遮罩层,但唯独点击内容区域不会关闭掉遮罩层。于是我开始模仿这个写案例,连内容也一模一样(因为这个练习就是要写出和华为关一样的效果或则比它更好的效果),一开始我是这样子写的(图1)



图1



class=Select_Region_bj 我给了一个灰色半透明的背景样式,后来在Javascript中写onclick事件无论这么写,点击内容区也是会关闭掉遮罩层。我百思不得其解到底怎么样写才能点击内容区不会关闭遮罩层,后来下课期间我看见我同学他写的带能点击内容区不会关闭遮罩层。我问他你是这么写的,他告诉我:“把他们分离就可以的了。”我思考了一会,脑补:分离?怎么分离?补着补着补着就补出了背景和内容区分离。分离写(图2)

图2



把背景层和内容区分开来写,不要在背景层中包裹内容,这样子点击内容区就不会关闭掉遮罩层了!

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

深入理解vue中的slot与slot-scope

seo达人

写在前面

vue中关于插槽的文档说明很短,语言又写的很凝练,再加上其和methods,data,computed等常用选项使用频率、使用先后上的差别,这就有可能造成初次接触插槽的开发者容易产生“算了吧,回头再学,反正已经可以写基础组件了”,于是就关闭了vue说明文档。

实际上,插槽的概念很简单,下面通过分三部分来讲。这个部分也是按照vue说明文档的顺序来写的。

进入三部分之前,先让还没接触过插槽的同学对什么是插槽有一个简单的概念:插槽,也就是slot,是组件的一块HTML模板,这块模板显示不显示、以及怎样显示由父组件来决定。 实际上,一个slot最核心的两个问题这里就点出来了,是显示不显示怎样显示

由于插槽是一块模板,所以,对于任何一个组件,从模板种类的角度来分,其实都可以分为非插槽模板插槽模板两大类。
非插槽模板指的是html模板,指的是‘div、span、ul、table’这些,非插槽模板的显示与隐藏以及怎样显示由插件自身控制;插槽模板是slot,它是一个空壳子,因为它显示与隐藏以及最后用什么样的html模板显示由父组件控制。但是插槽显示的位置确由子组件自身决定,slot写在组件template的哪块,父组件传过来的模板将来就显示在哪块

单个插槽 | 默认插槽 | 匿名插槽

首先是单个插槽,单个插槽是vue的官方叫法,但是其实也可以叫它默认插槽,或者与具名插槽相对,我们可以叫它匿名插槽。因为它不用设置name属性。

单个插槽可以放置在组件的任意位置,但是就像它的名字一样,一个组件中只能有一个该类插槽。相对应的,具名插槽就可以有很多个,只要名字(name属性)不同就可以了。

下面通过一个例子来展示。

父组件:


  1. <template>
  2. <div class="father">
  3. <h3>这里是父组件</h3>
  4. <child>
  5. <div class="tmpl">
  6. <span>菜单1</span>
  7. <span>菜单2</span>
  8. <span>菜单3</span>
  9. <span>菜单4</span>
  10. <span>菜单5</span>
  11. <span>菜单6</span>
  12. </div>
  13. </child>
  14. </div>
  15. </template>

子组件:


  1. <template>
  2. <div class="child">
  3. <h3>这里是子组件</h3>
  4. <slot></slot>
  5. </div>
  6. </template>

在这个例子里,因为父组件在<child></child>里面写了html模板,那么子组件的匿名插槽这块模板就是下面这样。也就是说,子组件的匿名插槽被使用了,是被下面这块模板使用了。


  1. <div class="tmpl">
  2. <span>菜单1</span>
  3. <span>菜单2</span>
  4. <span>菜单3</span>
  5. <span>菜单4</span>
  6. <span>菜单5</span>
  7. <span>菜单6</span>
  8. </div>

最终的渲染结果如图所示:



  1. 注:所有demo都加了样式,以方便观察。其中,父组件以灰色背景填充,子组件都以浅蓝色填充。

具名插槽

匿名插槽没有name属性,所以是匿名插槽,那么,插槽加了name属性,就变成了具名插槽。具名插槽可以在一个组件中出现N次。出现在不同的位置。下面的例子,就是一个有两个具名插槽单个插槽的组件,这三个插槽被父组件用同一套css样式显示了出来,不同的是内容上略有区别。

父组件:


  1. <template>
  2. <div class="father">
  3. <h3>这里是父组件</h3>
  4. <child>
  5. <div class="tmpl" slot="up">
  6. <span>菜单1</span>
  7. <span>菜单2</span>
  8. <span>菜单3</span>
  9. <span>菜单4</span>
  10. <span>菜单5</span>
  11. <span>菜单6</span>
  12. </div>
  13. <div class="tmpl" slot="down">
  14. <span>菜单-1</span>
  15. <span>菜单-2</span>
  16. <span>菜单-3</span>
  17. <span>菜单-4</span>
  18. <span>菜单-5</span>
  19. <span>菜单-6</span>
  20. </div>
  21. <div class="tmpl">
  22. <span>菜单->1</span>
  23. <span>菜单->2</span>
  24. <span>菜单->3</span>
  25. <span>菜单->4</span>
  26. <span>菜单->5</span>
  27. <span>菜单->6</span>
  28. </div>
  29. </child>
  30. </div>
  31. </template>

子组件:


  1. <template>
  2. <div class="child">
  3. // 具名插槽
  4. <slot name="up"></slot>
  5. <h3>这里是子组件</h3>
  6. // 具名插槽
  7. <slot name="down"></slot>
  8. // 匿名插槽
  9. <slot></slot>
  10. </div>
  11. </template>

显示结果如图:


可以看到,父组件通过html模板上的slot属性关联具名插槽。没有slot属性的html模板默认关联匿名插槽。

作用域插槽 | 带数据的插槽

最后,就是我们的作用域插槽。这个稍微难理解一点。官方叫它作用域插槽,实际上,对比前面两种插槽,我们可以叫它带数据的插槽。什么意思呢,就是前面两种,都是在组件的template里面写


  1. 匿名插槽
  2. <slot></slot>
  3. 具名插槽
  4. <slot name="up"></slot>

但是作用域插槽要求,在slot上面绑定数据。也就是你得写成大概下面这个样子。


  1. <slot name="up" :data="data"></slot>
  2. export default {
  3. data: function(){
  4. return {
  5. data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
  6. }
  7. },
  8. }

我们前面说了,插槽最后显示不显示是看父组件有没有在child下面写模板,像下面那样。


  1. <child>
  2. html模板
  3. </child>

写了,插槽就总得在浏览器上显示点东西,东西就是html该有的模样,没写,插槽就是空壳子,啥都没有。
OK,我们说有html模板的情况,就是父组件会往子组件插模板的情况,那到底插一套什么样的样式呢,这由父组件的html+css共同决定,但是这套样式里面的内容呢?

正因为作用域插槽绑定了一套数据,父组件可以拿来用。于是,情况就变成了这样:样式父组件说了算,但内容可以显示子组件插槽绑定的。

我们再来对比,作用域插槽和单个插槽和具名插槽的区别,因为单个插槽和具名插槽不绑定数据,所以父组件是提供的模板要既包括样式由包括内容的,上面的例子中,你看到的文字,“菜单1”,“菜单2”都是父组件自己提供的内容;而作用域插槽,父组件只需要提供一套样式(在确实用作用域插槽绑定的数据的前提下)。

下面的例子,你就能看到,父组件提供了三种样式(分别是flex、ul、直接显示),都没有提供数据,数据使用的都是子组件插槽自己绑定的那个人名数组。

父组件:


  1. <template>
  2. <div class="father">
  3. <h3>这里是父组件</h3>
  4. <!--第一次使用:用flex展示数据-->
  5. <child>
  6. <template slot-scope="user">
  7. <div class="tmpl">
  8. <span v-for="item in user.data">{{item}}</span>
  9. </div>
  10. </template>
  11. </child>
  12. <!--第二次使用:用列表展示数据-->
  13. <child>
  14. <template slot-scope="user">
  15. <ul>
  16. <li v-for="item in user.data">{{item}}</li>
  17. </ul>
  18. </template>
  19. </child>
  20. <!--第三次使用:直接显示数据-->
  21. <child>
  22. <template slot-scope="user">
  23. {{user.data}}
  24. </template>
  25. </child>
  26. <!--第四次使用:不使用其提供的数据, 作用域插槽退变成匿名插槽-->
  27. <child>
  28. 我就是模板
  29. </child>
  30. </div>
  31. </template>

子组件:


  1. <template>
  2. <div class="child">
  3. <h3>这里是子组件</h3>
  4. // 作用域插槽
  5. <slot :data="data"></slot>
  6. </div>
  7. </template>
  8. export default {
  9. data: function(){
  10. return {
  11. data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
  12. }
  13. }
  14. }

结果如图所示:

github

以上三个demo就放在GitHub了,有需要的可以去取。使用非常方便,是基于vue-cli搭建工程。

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

开发过程中积累的CSS样式(持续更新)

seo达人

前言:平时写页面的时候有些样式使用完发现没过多久就忘记了,这篇文章主要是用来记录开发过程中容易忘记的CSS样式,与其总是去网上查,还不如一个一个记录下来,虽然说之前的都没有记录,但是知识的累积不论什么时候开始做都不会晚的。



首先 记录几个好用的插件网站:



layDate日期与时间组件: https://www.layui.com/laydate/

Vant移动端插件库: https://youzan.github.io/vant/#/zh-CN/intro

Element组件库: https://element.eleme.cn/#/zh-CN/component/installation

Vue.js框架: https://cn.vuejs.org/v2/guide/

Bootstrap框架: https://v2.bootcss.com/index.html

菜鸟教程官网: https://www.runoob.com/

w3school官网: https://www.w3school.com.cn/

下面是遇到的一些想累积的css样式:(内容会随时间累积的越来越多)



1、一个 div 中的内容实现上下滑动效果(而不是超出body的高以后上下滑动):overflow:auto;

简单的描述:body 中的一个 div 内,如果设置了固定的 height,而内容的总 height 超出了 div 的高,则超出的部分就会被覆盖,而想实现超出的部分变成滑动的效果而不被覆盖,则用 overflow:auto; 实现。



2、修改 前端框架封装好的css样式: border-radius: 20px!important;(注意使用英文的 ! 叹号)

简单的描述:在开发过程中经常使用一些前端框架(bootstrap,vue.js,laydate,Vant等等),在使用link导入css文件以后,发现有些css是在标签内使用内嵌的方式实现的,优先级最高,那么我们怎么修改呢?

比如:css文件中的边框弧度样式为10px:border-radius: 10px;

我们想改成20px,则在后面加上 !important 即可:border-radius: 20px!important;



这篇文章主要是以后回头复习或者忘记了的时候给我自己看的,但是如果恰好也帮助到了你,那是更加的有意义,在以后的开发过程中,该文章的内容一定会累积的越来越多

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

产品设计核心三要素

涛涛

先问一个问题:怎么样衡量一个设计好与不好?工作中实践越多次,越会发现华丽的设计稿并不是体现设计师专业能力的唯一标准。普通设计师和高级设计师区别在于,设计方案是否具备完整设计思路;设计对于业务有没有真正的价值体现;以及设计方案的推动落地的完整性到底有多少。设计越往后走,越考验产品思维,设计思维,以及设计推动能力。这是产品设计师需要关注的核心三要素。


设计师在工作中接到设计需求会不自觉的第一时间想着如何去进行视觉表达,视觉表达确实非常重要,也是公司对于设计师的核心价值的定位之一,但视觉表达只是其中设计专业本职工作中的一个环节。设计师还要应该能够站在产品、设计、技术等不同维度去思考设计方案的可行性。产品打磨-视觉呈现-落地执行,在这三个核心点里面设计师分别有不同的定位和价值所在。 


  一. 产品“双标”满足   

产品打磨包含产品规划,内容组成,界面布局,交互梳理等等…所有环节的工作是为了符合产品最终的目标。产品所有的能力会核心围绕两个点:1商业变现 2用户需求满足。这两个目标在产品执行的环节有时候会有一些冲突,在产品打磨阶段设计师通过怎样的方式,做到既满足产品商业目标又满足用户体验需求?可以按照以下几个步骤进行分析寻求切入点: 


Image title



这里用腾讯动漫付费模块举例说明: 项目背景是腾讯动漫产品要做付费体系升级设计,接到需求先有由产品源头一步步深入,逐步展开设计方案的规划。 


 01 产品目标确认  

通过对项目背景的解读和产品方案的深入了解,以及总结当前存在的一些问题,可以明确得到项目中产品核心目是什么。付费升级核心原因是付费转化低,用户付费意愿不够强烈。此次升级的核心目标是促进内容消费,提升付费率。 


Image title



 02 分析用户路径  

确认目标之后从哪个模块儿开始进行首要需要考虑的。对于现有现有功能的升级,建议核心从产品本身着手,可以根据用户行为分析,获取用户常规使用路径,找到用户使用场景下的核心目的,从而去挖掘用户在付费路径下的诉求点,根据诉求点找到付费升级的触点。这里我们罗列了用户阅读产品的路径。 

Image title



 03 观察用户核心需求是否被满足 

 用户在每个场景下都会有“痛点”和“痒点”。比如在阅读前,核心目是想快点看到漫画内容;阅读过程中,想要及时宣泄对漫画的故事情节的感受;阅读后,希望找到更多相关内容或者能够和内容有更多的互动。目前产品在这三个关键的路径节点都存在一些问题,阅读前对于付费缺乏正向引导,阅读过程中互相行为较少,阅读后没有更多延展内容可供消费等。 


Image title



 04 洞察设计切入点  

根据用户在阅读 “前 中 后” 关键路径的节点的不同情绪反馈,我们可以做出找到相应情感满足切入点,并且制定解决方案 


Image title



 05 制定设计方案  

将之前找到的设计情感切入点用交互和视觉的形式呈现出来,尽可能完整的表达清晰。下面展示是关于付费升级优化的完整视频DEMO。整个方案采用趣味情感化形式为核心设计思路,逐步去引导用户付费。让用户在趣味互动中完成产品的商业转化目标。 


https://v.youku.com/v_show/id_XNDM0NDg1MzY2MA==.html


 二. 设计呈现的“差异化”   

视觉呈现是设计师们都比较擅长的工作,但不同专业高度要求下方案最终呈现出的效果是完全不一样的。好的设计方案,需要在设计上做出明显的“差异化”,这里的差异化是指要区别于常规输出一般的水平。差异化的可以从多个点入手:


Image title



优质的设计美感

美感是作为设计师首先需要培养的技能之一,也是在后续职业生涯的一直需要用到的技能。设计师被神职化的很大一个原因就是因为设计师的美感比一般人要好,有懂得欣赏美、鉴别美、以及创造美的能力。单一从视觉层面,设计作品是合格品还是精品,最终取决于画面的精美程度。项目不分大小,再小的一个项目都可以做出精致品质,这也是体现设计师专业度的核心衡量之一。


Image title



完整设计思路:

设计方案的完整性也能够很好的设计师专业度的差异化,几张图的设计稿和一个有完整设计思路的设计方案在品质上自然是明显差别的。设计师不光需要将设计呈现出来,更需要有严谨的设计思路并且表达出来让受众到你的设计想法。设计前期分析、中期执行、后期落地以及迭代优化,能够让设计师有意识的锻炼和提升自己的设计思维,对于设计师能力提升有必然的帮助。 


Image title



独特创意:

设计差异化呈现上,创意是一个非常好的切入点。行业大趋势的前提下,现在同类产品越来越趋于同质化,受众使用产品的时候都会有一些常规认知,关于功能的、交互操作的、内容组成的等等,淘宝和京东、大众和美团、甚至QQ音乐和网易音乐在产品使用体验上都有高度重合的地方,这些已经在用户心智中形成习以为常的认知感受。如果能够在用户的常规认知里,用创意手法呈现出超出他们预期的内容使其惊喜,产品设计就会有明显差异化体现。 


Image title



善用情感化:

具备美感的设计能让作品看起来有高级感,但更为高级且有效的是能够引起用户情感共鸣的设计。设计是主观的,对于设计每个人都有自己的想法,也正是因为主观的设计感受,能让设计在情感化打造方面可以有很多的尝试方向。能够引起受众主观情感上的共鸣和认同的设计,会形成产品的核心记忆点之一。设计师对于情感化设计往往会有一些误区,认为图形可爱,色彩羡慕,动效流畅且能够形成一套视觉体系,就能够算情感设计。真正的情感设计是需要从用户角度出发,挖掘用户的认知领域和喜欢,从而去进行符合用户情感诉求的呈现。 


Image title


三. 方案推动的效能管理 

 

设计方案输出只是整个产品生产流程中的一个核心环节,产品上线后体验如何最终取决于落地实现的程度。在方案落地支持过程中,效率协调和实现能力是保证设计方案贯彻一致执行的关键因素:


 协作  

产品设计师工作协调分为内部协作和外部协作。内部协作即设计师之间的沟通协同,主要内容是如何保持设计语言一致性,除了制定设计规范,还可以建立公共控件库,线上调用。控件库能够使设计师协作无学习成本,设计师输出设计稿效率也能够大大提升,同时保一致性。


外部协作主要是和下游的技术同事直接的工作对接,设计方案的交接方式以及开发获取信息的效率很关键。在开发接收设计方案的时候,尽能力降低获取成本以及理解成本。比如设计稿的标注,在标注上设计师一般会花很长时间,开发也需要逐步查看,偶尔还会有标注遗漏的地方。我们团队会直接采用插件,设计稿及时同步,并且开发可以自己随时查看每个元素的标注信息,便捷。


这里推荐两款协调软件:一款是InVision可以在sketch里进行控件协同调用,所有想用的元素直接源文件调用,不需要再问同事要源文件!另一款是Zeplin技术同学可以直接查看元素属性以及间距等,设计师解放双手不再需要标注!


Image title



官网链接: 

https://login.invisionapp.com/auth/sign-in   

https://zeplin.io/


实现能力   

专业技术之间的壁垒,也会成为设计方案实现的阻力。同样的界面,设计人员用设计软件实现,技术人员用逻辑代码实现,实现的方式和成本存在很大的差异性,所以往往设计师认为很简单的需求在开发层面的确非常难实现。当然,不是所有需求都是无解的,设计师在技术实现层面还是可以做一些事情:


01 方案前置沟通

设计一个新的功能的时候,如果有非常规的设计方案,可以提前和技术人员沟通实现的难易程度,让技术人员有前期预判和预演的时间。并且,可以将设计做成简易DEMO方便技术人员快速理解,避免双方存在信息不对等的情况。


02 搭建开发控件库

开发控件库和设计规范一样,是最基础但应用最为频繁的模块儿。开发控件库可以将最基础的元素形成固有规范,所有开发实现都用同一套规范,以确保实现的高度一致性,同时也能够提升实现效率和设计还原。设计可以辅助开发一起制定开发控件库,确保控件库和设计规格的一致性。


03 寻求技术语言共通性

尽量将设计方案转化为技术能够理解和复用的形式进行对接。除了静态设计稿的标注,设计和技术实现最大的难点在于动态交互的实现上,对于动态设计,将设计方案转换为代码文件交付给技术实现,这样能确保功能的正常实现同时减少后期设计还原性的偏差。


以上初步总结的关于产品设计师在设计过程中从前期产品规划到中期设计执行再到后期开发落地应该注意的一些核心点:

第一条,设计方案既要满足产品目标又同时要兼顾用户体验;

第二条,优秀的设计师,会保持设计方案的“差异化”;

第三条,设计师职责除了确保设计方案完整性,更重要的是推动设计方案的完整落地。


在产品设计过程中,设计师需要关注还有很多关键点,这里也欢迎大家一起补充交流,正是这些关键点,将设计师的思维逐步打开,使其成为一个具有全链路思维的设计人才。 

文章来源:UI中国

JS--普通数字格式与会计金额格式之间的转换

seo达人

普通数字转会计金额格式(保留两位小数)

我们可以用数字的toLocaleString()方法将普通数字转为会计金额格式,但是这种方式无法保留两位小数(四舍五入),如果是整数或者小数长度只有一位的时候无法自动补0



例如:





思路:

利用toLocaleString()以及toFixed()先对数字进行一个转换得到最多保留了2位小数的金额,然后判断数字是为整数还是带有小数,如果带有小数则进行切割,判断小数长度为1时自动补0



// 普通数字转会计金额格式 第一种

    function toThousandsFormates(num) {

        // 判断传进来的数字是否为非空数字

       if (!isNaN(parseFloat(num))) {

            var reg = /./g

            var newNum = Number(Number(num).toFixed(2)).toLocaleString()

            // 判断转换后的数字是否带有小数

            if (reg.test(newNum)) {

                var numArr = newNum.split('.')

                // 判断小数点后数字长度为1,则自动补0

                numArr[1] = numArr[1].length === 1 ? numArr[1] + '0' : numArr[1]

                return numArr.join('.')

            } else {

                // 整数直接在后面补上0.00

                return newNum + '.00'

            }



        } else {

            return ''

        }

    }

    console.log(toThousandsFormates('0')); // 0.00

    console.log(toThousandsFormates('')); // ''

    console.log(toThousandsFormates(966)); // 966.00

    console.log(toThousandsFormates(966.3)); // 966.30

    console.log(toThousandsFormates(9669228.55)); // 9,669,228.55

    console.log(toThousandsFormates(96566.56954)); // 96,566.57



经过查阅资料后,发现toLocaleString()它里面自带属性可以检查到最少保留了几位小数,不够自动补0,这样我们上面的代码其实可以更加简单,如下:

// 普通数字转会计金额格式 第二种

function toThousandsFormates2(num) {

    // 判断传进来的数字是否为非空数字

    if (!isNaN(parseFloat(num))) {

        var newNum = Number(Number(num).toFixed(2)).toLocaleString('zh', { minimumFractionDigits: 2 })

        return newNum



    } else {

        return ''

    }

}



console.log(toThousandsFormates2('0')); // 0.00

console.log(toThousandsFormates2('')); // ''

console.log(toThousandsFormates2(966)); // 966.00

console.log(toThousandsFormates2(966.3)); // 966.30

console.log(toThousandsFormates2(9669228.55)); // 9,669,228.55

console.log(toThousandsFormates2(96566.56954)); // 96,566.57



// 结果一模一样



会计金额格式转普通数字(利用正则)

// 会计金额格式转为普通数字

    function rMoney(num) {

        return parseFloat(num.replace(/[^\d\.-]/g, ''))

    }

    console.log(rMoney('96,566.57')); // 96566.57

    console.log(rMoney('966.30')); // 966.3

    console.log(rMoney('9,669,228.55')); // 9669228.55

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

交互手势的容错性和逻辑性

涛涛

交互手势是用户操作的重要部分,交互手势的设计好坏非常影响用户体验,那么,交互手势的设计上对于容错性和逻辑性需要注意什么?

随着用户体验被愈发的重视,更多的 APP 偏向于使用多手势优化用户的操作流程,降低使用阻力。

点击某个确定的按钮的手势操作虽然被普遍使用并被用户熟知,但是增加更快捷的手势操作可以大大增大操作热区,提高操作效率,如下图。

交互手势的容错性和逻辑性

然而,我们可以发现由于不同产品的设计师对于用户体验的理解不同、交互层面的思考不同,导致设计的交互手势也不同。

有时同一种操作在不同的 APP 中交互手势也是不统一的,这无疑增加了用户的学习成本和记忆成本。

举个例子,iOS 端的得到和有书的播放页的打开和关闭方式。

得到有两种方式打开和关闭页面,用户可以通过点击控件或上滑控件打开播放页,通过点击收起按钮或下拉页面关闭播放页。但是有书只有一种方式打开和关闭,用户只能通过点击控件打开播放页,通过点击返回图标关闭播放页。

这让习惯了使用得到的我去使用有书时,感觉非常别扭,每次都尝试用得到的手势去操作但是都失败了,失败后我下一次并没有记住仍然用手势去操作,如此反复令我相当沮丧。

交互手势的容错性和逻辑性

容错性

容错性是一个很大的话题,今天我们仅仅在交互手势层面上讨论。

上面的例子中,有书并没有设计滑动手势去打开和关闭播放页,那么我以我的经验去进行的滑动滑操作在有书这个产品中就是错误的和不被产品识别的。但是这种手势又广泛存在于大量的音频播放 APP 中,如喜马拉雅、荔枝 FM 等。

一旦用户从这些 APP 迁移到了有书,本来养成的操作习惯在有书就失效了,用户就会感觉“这个 APP 很难用,用起来很不舒服”,进而可能放弃有书转而投向其他产品怀抱。

与手势设计类似,这也是为什么现在的同种类型的 APP 的信息架构设计越来越同质化,当我们打开淘宝、天猫、京东时我们有时感觉就像是同一个 APP ,本质上也是为了降低用户的迁移、记忆和学习成本。

如下图所示,提高手势的容错性对用户的意义。

交互手势的容错性和逻辑性

很多优秀的产品考虑到了上述问题,设计了多手势来优化用户体验。

举个例子,在 APP Store 的首页点击一个推荐卡片后进入详情页,由于详情页是直接由卡片放大转场的,不同于传统的新页面右侧进入和从底部弹出。

在用户的使用习惯和认知中新页面如果从右侧进入就可以通过右滑返回,从底部弹出的话就可以下拉返回。因此,当用户面对卡片放大进入新页面这种全新交互时可能会疑惑如何返回,对此理解不同的用户可能会尝试右滑,也可能尝试下拉。

APP Store 的设计在此就有很好的容错性,用户可以通过三种方式返回首页,分别是、右滑返回、下拉返回和点击叉号返回,这不但降低了用户的记忆和学习成本,也便于不同习惯的用户使用。

交互手势的容错性和逻辑性

针对不同的场景,手势的使用也会有不同。

一个很好的案例是知乎的评论:知乎的评论的关闭方式有三种,分别是下拉、右滑和点击叉号。

用户观看评论的场景有两种,第一种是只想看一下精选评论然后关闭,第二种是被评论吸引后一直往下看。当用户单手操作不方便点击叉号时,下拉对应的是第一种用户;右滑对应的是第二种用户,不管用户看了多少屏的评论,随时可以通过右滑关闭评论(因为用户翻阅了很多屏评论后需要下拉到第一条评论时,下拉关闭评论手势才会生效,所以第二种用户一般不使用下拉去关闭评论)。

可能你会心生疑惑:“第一种用户也可以使用右滑来关闭评论呀”,确实可以,但是对于人的操作习惯来说,上下滑动会比左右滑动更方便。

交互手势的容错性和逻辑性

还值得讨论的是苹果自 iPhone 6s 开始加入的新交互方式 3D Touch,它允许用户通过更大力度的重按呼出情景菜单快捷地使用高频功能而不用先打开 APP,对于追求效率的用户来说简直不要更方便,但是对于不支持 3D Touch 的机型则无法使用情景菜单。

因此,在生活中我发现这样的现象,很多使用惯了3D Touch 的用户换到无 3D Touch 的苹果机型后很不习惯,总是尝试去重按但是是无效的。

其实在很多安卓手机上也有情景菜单这一功能,它巧妙地将卸载也加到了情景菜单中,因此用户只需要通过长按就可以获得所有需要的功能,而不是像苹果那样长按是卸载而重按是情景菜单。

我猜测苹果为了适配所有机型,提高容错性,从今年的发布会的 iPhone 11 和iPhone 11 pro 开始,取消了 3D Touch,转而使用 Haptic Touch (有震动反馈的长按)代替。当你长按某个图标时,感受到震动后松开,即可呼出二级菜单;如果震动后仍不松开,则进入到卸载 APP 时的抖动状态,使得之后的即使不支持 3D Touch的机型可以使用便捷的情景菜单了。

对于不支持 3D Touch 的老款机型会不会在 iOS 13 更新后也可以使用 Haptic Touch 呢?

如果一致统一的话,容错性将大大提高,我们将拭目以待。

不仅仅是 iOS ,Android 的版本 Android 10经历了 6 个测试版迭代后正式发布,我们发现交互手势是 Android 10 的一个巨大亮点。Android 10 在第三版内测系统开始引入全局手势操作,用户启用后,屏幕底部便不会再出现虚拟按键和导航栏,只会剩下一个指示条,上滑返回主屏、侧滑返回上一层的操作逻辑也均和 iOS 保持一致。

这可能标志着安卓手机一直以来在国内各家厂商的各种创新手势的割裂生态中即将重归统一,并和 iOS 保持一致。

这种妥协将大大提高在用户使用一款新安卓手机时的容错性,同时降低了今后用户在两大系统之间的迁移成本。

逻辑性

再谈谈逻辑性,在交互手势的层面上,如果用户能够通过某个手势进行某个操作后,按照逻辑,用户也可以通过反向的手势或对应的手势进行逆向操作。

比如,在微信首页下拉调出小程序页面,之后可以通过上拉返回首页。点击加号呼出更多操作,再次点击加号收起更多操作。

如果违背了用户的心理模型和逻辑性,用户就会感觉到混乱和不适。

这里举一个反例, Uki 的个人主页可以通过点击或下拉底部的固定底板收起更多信息,但是收起后只能通过点击展开更多个人信息而不能上拉,不符合逻辑与用户的心理模型。

交互手势的容错性和逻辑性

如下图所示,逻辑性对用户的意义。

交互手势的容错性和逻辑性

有的时候,我们会发现为了提高容错性,我们会牺牲一部分逻辑性。

就像上文提到的知乎关闭评论弹出框,逻辑上它是从底部弹出的,但是不但能够下拉关闭还可以右滑关闭。尽管右滑关闭有些违背用户的心理模型,但是确实给用户带来了很多操作上的便捷。

如何设计

1. 是否需要加入多手势操作的考虑因素

我们需要考虑的因素包括使用频率、危险程度和特殊体验。

  1. 使用频率:当一个功能的使用频率足够高时,我们加入多手势操作去提高用户操作效率才是有意义的。一个低频的功能的特殊手势操作很容易被用户遗忘。
  2. 危险程度:如果一个操作不可撤销且存在危险性质,我们最好不要加入多手势操作。此时我们需要用户更加专注,如果加入多手势操作可能会增加误操作的概率。
  3. 特殊体验:当我们需要加入特殊的模拟体验时,此时我们可以加入多手势操作。如探探左滑无感右滑喜欢,给用户带来的“翻牌子”感觉是点击操作无法替代的。QQ 阅读下拉拟物绳灯进行日间和夜间模式切换,这种存在我们记忆中的交互方式能够唤起我们的情感。

2. 评估所选手势的考虑因素

1)考虑不同平台的硬件系统和操作系统特性

由于硬件与操作系统差异,iOS 系统支持很多手势,但是安卓系统在手势支持方面就不如 iOS 丰富。

安卓硬件设备的差异比较大,不同安卓手机厂商会在安卓系统的基础上自定义系统的手势操作,因此对于手势的支持也有较大的差异。对于这种情况我们需要熟悉相应平台的规范,做到心中有数。

2)考虑所选的手势的学习成本和记忆成本,用户是否已经被教育

如下图所示,尽管设备支持的手势数量多不胜数,但是日常使用 APP 时,大部分用户习惯使用的手势很少,比如单击、双击、滑动、上拉、下拉、双指扩张和收缩等。除此之外的手势教育成本和学习成本很高。

一般比较通用的功能是没有必要在此处创新的,但是如果一些特殊的操作确实需要加入时,我们就需要考虑下面的问题。

交互手势的容错性和逻辑性

a. 如果没有教育成熟,考虑加入教学或搭配简易的操作方式

对于我们需要加入的手势操作当前用户并未被教育成熟时,我们需要考虑加入手势教学,具体的手势教学类型下一部分会详细讨论。

然而,大部分情况下用户的记忆是短期的,教学内容可能会被快速遗忘,下次用户使用 APP 时仍然不会使用特殊手势。此时我们应该将一些比较难以记忆的手势操作搭配一个简单的手势操作。

比如 QQ 阅读的下拉拟物绳灯切换夜间模式的手势操作设计,其考虑到了有些用户在现实生活中并未见过拟物绳灯,并不知道是要进行下拉才能触发操作。因此,QQ 阅读贴心地搭配了一个简单的点击操作,用户通过点击绳灯也可以切换夜间模式,如下图。

交互手势的容错性和逻辑性

b. 考虑所选手势是否可能导致冲突和误操作,如果导致了,考虑如何避免和折中

最常见的手势冲突情况就是 APP 的手势与操作系统的全局手势冲突。

解决方案有两个,一是避免设计与全局手势一致的手势操作,例如 iOS 的在屏幕边缘右滑返回、全面屏机型的底部上滑退出应用等全局手势操作;二是仍然设计与全局手势冲突的操作,但是将全局手势部分禁用或以其他的方式区分开。

如下图有书播放页的案例,由于进度条滑动控件过于靠左,导致使用 iOS 全局右滑返回手势时有时会产生误操作,即本来想要右滑返回却不小心滑动了进度条。

这种情况下我们可以标注一个右滑手势禁用区域给开发工程师说明情况,将此情况避免掉即可。

交互手势的容错性和逻辑性

误操作指的是,我们设计的手势操作与 APP 内的其他操作或系统全局手势操作接近导致用户触发了非预期的操作。比如 iOS 端的知乎被吐槽的一个右滑返回手势操作,经过研究发现,由于 iOS 端的知乎在浏览回答的页面设计的右滑返回的热区过大,导致用户上滑浏览的时候如果手指的滑动角度变化幅度过大一不小心就触发了右滑返回,再次进入回答后又需要翻页很久才能找到之前离开的地方,很影响体验。

我觉得知乎可以减少热区,将热区调整为 iOS 全局的右滑返回区域即可,如下图所示。

当然,产品设计需要平衡与取舍,如果减少了热区是否会影响其他用户的体验还需要考虑和调研,两者并无绝对的对错

交互手势的容错性和逻辑性

3. 让用户了解并使用新手势

当新手势无法直接让用户感知时,我们需要加入一些手势教学帮助用户快速上手使用。

1)手势教学方式

a. 浮层和动画引导使用静态或动态的手势图片或气泡示例告诉用户使用哪种手势进行操作

相比于静态,动态比静态更为直观和易学。

交互手势的容错性和逻辑性

b. 内容隐喻通过微妙的视觉线索暗示用户此处可以通过某种手势进行操作

由于教学内容难免具有干扰性,对于高级用户来说是不必要的,但是对于初级用户又是必要的,因此以这种内容暗示的方式使教学极为轻量化,在低干扰的情况下使得用户学习了手势操作。

如下图,哔哩哔哩在打开第一篇文章时会平移显示下一篇文章的框架,暗示用户可以通过左右滑动切换文章。

再比如陌陌在打开点点功能时,会在用户进入页面的时候播放一个动画,暗示有很多卡片叠加在了一起,用户可以通过滑动切换卡片。

交互手势的容错性和逻辑性

2)教学的出现时机

a. 操作前当产品中设计了不容易感知的新手势,在用户操作前,通过教学让用户了解和学习新的手势。

b. 错误操作后对于一些与用户的心理模型和习惯不一致的手势,提前预测用户可能输入的错误手势,在用户错误操作后进行提示,规范用户的操作方式。

如下图,由于知乎旧版本是通过左右滑动切换回答的,新版本调整为上下滑动后,需要纠正用户使用习惯。因此,当用户仍然使用左右滑动时,会出现浮层提示用户正确的手势进行教学。

交互手势的容错性和逻辑性

结语

以上是日常思考和总结,有不恰当之处欢迎指出。希望本文在大家进行手势设计的过程中能够帮助做出合理的决策。

文章来源:人人都是产品经理 

nginx配置rewrite的用法详解

seo达人

文章目录

rewrite在if中的用法

rewrite中break和last的用法

1.break和last在location{}外部时

2.break和last在location{}内部时

3.break和last用法总结

return的用法

rewrite的语法规则

rewrite应用实例

1.域名跳转(域名重定向)

2.http跳转https

3.跳转二级目录

4.动静态请求分离

5.防盗链配置

6.伪静态(将静态页面重写为动态)

7.多个if并用

rewrite在if中的用法

格式:if (条件判断) { 具体的rewrite规则 }



if条件判断语句由Nginx内置变量、逻辑判断符号和目标字符串三部分组成。

其中,内置变量是Nginx固定的非自定义的变量,如,$request_method, $request_uri等。

逻辑判断符号,有=, !=, ~, ~, !~, !~

!表示相反的意思,~为匹配符号,它右侧为正则表达式,区分大小写,而~为不区分大小写匹配。

目标字符串可以是正则表达式,通常不用加引号,但表达式中有特殊符号时,比如空格、花括号、分号等,需要用单引号引起来。

1

2

3

4

5

示例1:当http请求方法为post时,返回403状态码



if ($request_method = POST)

{

    return 403; 

}

1

2

3

4

示例2:通过浏览器标识匹配关键字,禁止IE浏览器访问



if ($http_user_agent ~
MSIE) 

{

    return 403;

}

1

2

3

4

限制多个浏览器:



if ($http_user_agent ~ "MSIE|firefox|Chrome")

{

    return 403;

}

1

2

3

4

示例3:当请求的文件不存在时,进行重定向或return状态码等处理操作



if(!-f $request_filename)

{

    rewrite 语句;

}

1

2

3

4

示例4:判断uri中某个参数的内容



if($request_uri ~
'gid=\d{6,8}/') 

{

    rewrite 语句;

}

1

2

3

4

\d表示数字,{6,8}表示数字出现的次数是6到8次,当uri中gid参数的值包含6-8个数字那么执行rewrite语句



rewrite中break和last的用法

两个指令用法相同,但含义不同,需要放到rewrite规则的末尾,用来控制重写后的链接是否继续被nginx配置执行(主要是rewrite、return指令)。



1.break和last在location{}外部时

测试示例:



server{

    listen 80; 

    server_name test.com;

    root /data/wwwroot/test.com;



    rewrite /1.html /2.html;

    rewrite /2.html /3.html;

}

1

2

3

4

5

6

7

8

请求1.html文件时,会被重定向到2.html,然后被重定向到3.html,最后返回的文件为3.html



示例1:在rewrite 指令后面添加break



server{

    listen 80; 

    server_name test.com;

    root /data/wwwroot/test.com;



    rewrite /1.html /2.html break;

    rewrite /2.html /3.html;

}

1

2

3

4

5

6

7

8

请求1.html文件时,会被重定向到2.html,然后直接返回2.html,break在此处的作用就是当匹配第一个rewrite指令成功时,不执行后面的rewrite指令



示例2:当break后面还有location{}的情况



server{

    listen 80; 

    server_name test.com;

    root /data/wwwroot/test.com;



    rewrite /1.html /2.html break;

    rewrite /2.html /3.html;

    location /2.html {

        return 403;

    }

}

1

2

3

4

5

6

7

8

9

10

11

请求1.html文件时,会返回403状态码,当1.html被重定向到2.html时,break不会匹配后面的rewrite规则,但条件2.html匹配location{}定义的文件2.html,所以会执行return 403


以上两个示例中,将break换成last效果一样



2.break和last在location{}内部时

测试示例:



server{

    listen 80; 

    server_name test.com;

    root /data/wwwroot/test.com;

    

    location / {

        rewrite /1.html /2.html;

        rewrite /2.html /3.html;

    }

    location /2.html

    {

        rewrite /2.html /a.html;

    }

    location /3.html

    {

        rewrite /3.html /b.html;

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

请求1.html,会经过两次重定向到3.html,3.html又刚好匹配location /3.html{},所以返回b.html,当请求2.html时,会直接返回a.html,因为location /2.html {} 更精准,优先匹配



示例1:在rewrite后面添加break



server{

    listen 80; 

    server_name test.com;

    root /data/wwwroot/test.com;

    

    location / {

        rewrite /1.html /2.html break;

        rewrite /2.html /3.html;

    }

    location /2.html

    {

        rewrite /2.html /a.html;

    }

    location /3.html

    {

        rewrite /3.html /b.html;

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

请求1.html,会返回2.html,不会返回a.html,当break再location {} 内部时,遇到break后,当前location{} 以及后面的location{} 的指令都不再执行



示例2:在rewrite后面添加last



server{

    listen 80; 

    server_name test.com;

    root /data/wwwroot/test.com;

    

    location / {

        rewrite /1.html /2.html last;

        rewrite /2.html /3.html;

    }

    location /2.html

    {

        rewrite /2.html /a.html;

    }

    location /3.html

    {

        rewrite /3.html /b.html;

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

请求1.html时,会返回a.html,在location {} 内部遇到last,当前location {}中剩下的指令不会再执行,但被重定向的url会重新匹配一遍location {}



3.break和last用法总结

1.当rewrite规则在location{}外,break和last作用一样,遇到break或last后,其后续的rewrite/return语句不再执行。但后续有location{}的话,还会近一步执行location{}里面的语句,前提是请求能匹配该location

2.当rewrite规则在location{}里,遇到break后,本location{}与其他location{}的所有rewrite/return规则都不再执行

3.当rewrite规则在location{}里,遇到last后,本location{}里后续rewrite/return规则不执行,但重写后的url再次从头匹配所有location



return的用法

该指令一般用于对请求的客户端直接返回响应状态码。在该作用域内return后面的所有nginx配置都是无效的,可以使用在server、location以及if配置中,除了支持跟状态码,还可以跟字符串或者url链接。



示例1:直接返回状态码



server{

    listen 80;

    server_name www.test.com;

    return 403;

    rewrite www.test.net;  

}

1

2

3

4

5

6

访问时,直接返回403状态码,return返回内容后,后面的配置rewrite不会执行



示例2:当return在if 判断中时



server {

.....



if ($request_uri ~ ".password|.bak")

{

    return 404;

    rewrite /(.*) /index.html;  

}

.....

}

1

2

3

4

5

6

7

8

9

10

请求的文件包含.password或.bak时,直接返回404,rewrite不会执行,但if {}外的配置会继续执行,return只在当前作用域中生效



示例3:返回字符串



server{

    listen 80;

    server_name www.test.com;

    return 200 "hello";

}

1

2

3

4

5

返回字符串必须加上状态码,否则会报错



示例4:返回nginx变量



location /1.html {

    return 200 "$host $request_uri";

}

1

2

3

示例5:返回url



server{

    listen 80;

    server_name www.test.com;

    return http://www.test.com/index2.html;

}

1

2

3

4

5

返回url时,必须以http://或https://开头



示例6:返回html代码



if ($http_referer ~ 'baidu.com') 

{

    return 200 "<html><script>window.location.href='//$host$request_uri';</script></html>";

}

1

2

3

4

当网站被黑了的时候,从百度点进网站是链接都会跳转到其他网站,可以使用该方法暂时处理

注意:return http://$host$request_uri; 在浏览器中会提示"重定向的次数过多"



rewrite的语法规则

格式:rewrite regex replacement [flag]



rewrite 配置可以在server、location以及if配置段内生效



regex 是用于匹配URI的正则表达式,其不会匹配到$host(域名)



replacement 是目标跳转的URI,可以以http://或者https://开头,也可以省略掉$host,直接写$request_uri部分



flag 用来设置rewrite对URI的处理行为,其中有break、last、rediect、permanent,其中break和last在前面已经介绍过,rediect和permanent的区别在于,前者为临时重定向(302),而后者是永久重定向(301),对于用户通过浏览器访问,这两者的效果是一致的。

但是,对于搜索引擎爬虫来说就有区别了,使用301更有利于SEO。所以,建议replacemnet是以http://或者https://开头的,flag使用permanent。



示例1:域名跳转



location / {

    rewrite /(.*) http://www.test.com/$1 permanent;

}

1

2

3

.*为正则表达式,表示uri,用()括起来,在后面的uri中可以调用它,第一次出现的()用$1调用,第二次出现的()用$2调用,以此类推。



示例2:域名跳转的第二种写法



location / {

    rewrite /. http://www.test.com$request_uri permanent;

}

1

2

3

示例3:文件跳转



server{

    listen 80;

    server_name www.test.com;

    root /data/wwwroot/test.com;

    index index.html;

    if ($request_uri !~ '^/web/')

    {

        rewrite /(.
) /web/$1 redirect;

    }

}

1

2

3

4

5

6

7

8

9

10

将uri请求的文件重定向到web/目录中去寻找



错误写法1:



server{

    listen 80;

    server_name www.test.com;

    root /data/wwwroot/test.com;

    index index.html;

    rewrite /(.*) /web/$1 redirect;

}

1

2

3

4

5

6

7

这样写会反复循环,直到浏览器最大循环限制次数,哪怕uri包含web/目录了,也会继续重定向/web/web/$1



错误写法2:



server{

    listen 80;

    server_name www.test.com;

    root /data/wwwroot/test.com;

    index index.html;

    rewrite /(.*) /web/$1 break;

}

1

2

3

4

5

6

7

添加break后不会导致循环,但如果uri中包含web/目录的情况下也会被重定向一次,重定向后的uri就是web/web/$1



rewrite应用实例

1.域名跳转(域名重定向)

单个域名的情况:



server{

    listen 80;

    server_name www.test.com;

    rewrite /(.) http://www.test.net/$1 permanent;    

}

1

2

3

4

5

多个域名的情况:



server{

    listen 80;

    server_name www.test.com www.test.net;

    if ($host != 'www.test.net')

    {

        rewrite /(.
) http://www.test.net/$1 permanent;

    }

}

1

2

3

4

5

6

7

8

2.http跳转https

server{

    listen 80;

    server_name www.test.com;

    rewrite /(.) https://www.test.com/$1 permanent;

}

1

2

3

4

5

3.跳转二级目录

server{

    listen 80;

    server_name bbs.test.com;

    rewrite /(.
) http://www.test.com/bbs/$1 last;

}

1

2

3

4

5

4.动静态请求分离

server{

    listen 80;

    server_name www.test.com;

    location ~ ..(jpg|jpeg|gif|css|png|js)$

    {

        rewrite /(.*) http://img.test.com/$1 permanent;

    }

}

1

2

3

4

5

6

7

8

假设www.test.com的服务器在国外,访问速度较慢,img.test.com的服务器在国内,访问速度正常,可以将访问www.test.com静态文件的请求重定向到img.test.com,提高文件返回速度



第二种写法:



server{

    listen 80;

    server_name www.test.com;

    if ( $uri ~ 'jpg|jpeg|gif|css|png|js$')

    {

        rewrite /(.
) http://img.test.com/$1 permanent;

    }

}

1

2

3

4

5

6

7

8

5.防盗链配置

server{

    listen 80;

    server_name www.test.com;

    location ~ ^.+.(jpg|jpeg|gif|css|png|js|rar|zip|flv)$

    {

        valid_referers none blocked server_names
.test.com

        if ($invalid_referer)

        {

            return 403;

        }

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

配置防盗链避免别的网站引用www.test.com不想被引用的图片等文件



http_referer表示从哪儿点击进网站的,比如从百度搜索引擎访问的

valid_referers:白名单

invalid_referer:无效的(未在白名单中定义的)

none:允许referer为空(也就是允许直接访问,未从其他站点跳转的请求)

blocked:允许来源地址不含http/https



6.伪静态(将静态页面重写为动态)

location /  {

    rewrite ^([^.])/topic-(.+).html$ $1/portal.php?mod=topic&topic=$2 last;

    rewrite ^([^.]
)/forum-(\w+)-([0-9]+).html$ $1/forum.php?mod=forumdisplay&fid=$2&page=$3 last;

    rewrite ^([^.])/thread-([0-9]+)-([0-9]+)-([0-9]+).html$ $1/forum.php?mod=viewthread&tid=$2&extra=page%3D$4&page=$3 last;

    rewrite ^([^.]
)/group-([0-9]+)-([0-9]+).html$ $1/forum.php?mod=group&fid=$2&page=$3 last;

    rewrite ^([^.])/space-(username|uid)-(.+).html$ $1/home.php?mod=space&$2=$3 last;

    rewrite ^([^.]
)/(fid|tid)-([0-9]+).html$ $1/index.php?action=$2&value=$3 last;

}

1

2

3

4

5

6

7

8

示例为discuz的伪静态配置



7.多个if并用

location /{

    set $a 0;

    if ($document_uri !~ '^/abc')

    {

        set $a "${a}1"; #uri不以/abc开头时,$a的值变为01

    }

    if ($http_user_agent ~ 'ie6|firefox')

    {

       set $a "${a}2"; #浏览器标识包含ie6或者Firefox时,$a的值变为012

    }

    if ($a = "012") #当满足前两个if判断时,重写url

    {

        rewrite /(.
) /abc/$1 redirect;

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

nginx配置文件语法不支持if嵌套,需要通过多个if并用判断时,使用标识变量值的方式处理



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

日历

链接

个人资料

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

存档