首页

设计师要懂的“产品导流”背后知识点。

鹤鹤

设计师不仅要低头画图,也要了解“图”背后的逻辑和需求本质 。嗯,下面用直白的语言跟大家聊一波相关知识点。




说到产品导流,大家都不陌生。



身为设计师,应该经常听到产品同学提需求:“在这里给XX功能加个入口吧”,“这个宣传新产品的banner可以再大一些吗”,“这个场景可以宣传下我们的新功能诶”…


很多设计师在不了解背景的情况下往往内心是排斥的,心想怎么老是在犄角旮旯里加这么多小广告啊,都不关心用户体验的嘛,balabala...



但是有谁在吐槽时,深究其背后的原因呢,举起小爪子让大牙康康。比如:什么是产品导流?为什么需要产品导流?它有哪些的形式?如何做效果好又能兼顾产品体验呢?



最近正好在搞相关的事情,所以撸一篇文章,分享一波相关思考。





什么是产品导流? 



“产品导流”指的是:一款产品采用某种形式,增加对另一款产品/功能的曝光,使自己的用户群体(流量)去使用或探索另一款产品/功能。



眉头一紧,感觉上面的描述有点拗口,善良的牙尝试着用大白话,把导流和被导流的关系,分为两种形式解释下:1.父子关系;2.兄弟关系。

1.父子关系


画风是:“爸爸,大腿借我一抱吧”,比如:“抖音”里增加“多闪”入口,“微信”里增加“微视”入口,通过自家体量大的产品(爸爸)给自己导流。



2.兄弟关系


画风是:“外面环境恶劣,是好兄弟,就互导一下吧”,比如:京东的会员可以享受爱奇艺的会员福利,同辈之间互相导流。



所以,这么说就好理解什么是产品导流,和它们之间的关系了吧。






产品为什么需要导流? 


产品之间导流的目的,大致分为两种:1.获得新增;2.企业生态。




1.获得新增



试想你费劲巴拉的搞了个新产品,没人知道,也没人来用,就算你产品做的再妖娆,是不是也白搭,更不用说后续的商业变现之类的。


所以,这个时候如果你有一个相对成熟的产品(爸爸)大腿,让它给你导流,实现一波冷启动,是顺利迈过第一个坎儿的手段。


当然,在目前激烈的竞争环境下,不仅是新产品需要导流,扩大规模和获得新增流量,是每一个互联网企业里产品或运营同学OKR中必不可少且另他们头秃的一项指标。



所以,不管是新产品,还是相对成熟的产品,都需要通过导流的手段,来获得新增用户。





2.企业生态


“产品导流”除了为了获得新增,还有就是为了企业生态的体验闭环。


做成一款产品的公司很牛逼,但是如果能够持续做出一系列牛逼产品的公司,一定有成功的基因,或者有一套做事儿的逻辑。


比如:亚马逊的飞轮效应,要想形成飞轮,打造自己的生态,业务上就得有自己的闭环,并且闭环上的每一个步骤都可以为其它步骤助力,其次就是以第一个飞轮作为根据地,拉动周边其它业务,形成第二个或者更大的飞轮。


这个时候,就需要各个业务线之间的互通及联动(互相导流)了。






比如,阿里也是在打造自己的生态,产品之间相互赋能和联动,一旦建立起来这些基础设施后,壁垒和护城河就非常坚固。



整体来看,“产品导流”不仅有助于新产品获得冷启动,还有助于相对成熟的产品扩大规模,同时从整个企业生态来看,矩阵产品的互相导流,协同发挥优势,也有利于打造体验闭环,建立企业壁垒。





产品导流的形式有哪些? 



目前,市面上导流形式大致有以下几种:1.场景化导流;2.会员制捆绑;3.固定入口扶持;4.广告位推荐。


1.场景化导流


场景化导流,翻译成大白话就是,让导流的过程更加无缝衔接。


这种做法,能兼顾用户体验,同时对导流量也更有利,一般用于“功能”层面的互通。比如,用户正好需要XX产品或功能,你见缝插针的增加导流入口,同时功能和设计元素也跟母产品保持一致,这样用户不会觉得干扰或反感。


类似这种做法的产品比如:QQ&微云,抖音&剪映;视频号&公众号...


QQ&微云


我们用QQ聊天时,好友之间总会有一些分享文件的行为,有“分享”就有“接收”,有“接收”就有“保存”的诉求,在这种场景下,QQ聊天页面里用户长按当前“文件”,就可以将文件保存到“微云”上。






除此之外,QQ首页点击左上角的侧边栏,能看到一列与“我”相关的功能入口,其中有一项是“我的文件”,点击进去后就能看到“我”在QQ里消费过的历史文件。


同时还有“微云”小程序的入口,点击直接跳转至微云小程序(做的很服帖,跟自体脂肪填充似的,导流过程不会让用户感到突兀)。




除此之外,微云作为基础的云存储能力,也在跟腾讯系的QQ音乐互通,满足用户将下载的歌曲保存到“微云”。





这么做,不仅满足了QQ音乐用户的存储诉求,还提升了QQ音乐的登录率(用户想要使用音乐网盘,必须先登录),同时增加了QQ音乐用户粘性(用户一旦在一款产品上存下自己的东西,就会存在迁移成本),最后还为微云带来了新增用户(更多QQ的用户使用微云进行存储),扩大其规模。


这样的互通/导流手段,就实现了产品间1+1大于2的效果。





抖音&剪映


刷抖音的兄弟们应该经常见很多视频下面有一个小标签,叫“剪映-抖音出品”(意味着博主的那条短视频是用剪映做的)。


很多人看到好玩好看新奇的短视频,都会觉得真香我也要剪同款,因此抖音就是这种恰到好处的投喂给你,点击标签,直接跳转到下载页,如果已经安装了的用户,可以直接进行剪同款。




抖音不仅送你出去,还负责接你回来,一条龙服务给你安排(导)的明明白白的。


比如,当你剪辑完成后,就引导你回抖音里分享,毕竟他们不希望你剪完之后保存到本地然后美滋滋去竞品(快手之类的)分享吧。





他们的目的就是,不管你怎么折腾,也逃不出我大字节的手掌。


包括,最近的视频号,发完视频号还能附带公众号的链接,高频带低频,通过公域流量,帮助作者往私域导流(顺便做个广告,快去关注我的视频号:大牙兄,哈哈哈)。





所以微信现在的导流方式是:视频号能够链公众号,公众号能够挂小程序,小程序又能开直播,直播又能去变现。


整体来看,场景化的进行导流,更适合“功能”层面的互通,满足用户和企业的诉求,还平衡了产品体验,相对更加丝滑。





2.会员制捆绑


会员制捆绑,已经成为互联网常见导流+变现的方式了,指的就是用户在你这买了会员,在别的合作产品里也享有它们的特权福利。利用用户“爱占小便宜”的心理,产品间互相导流。


比如我们常见的方式有:88会员、联合会员...

88会员


开过88会员的同学举个爪!好,放下吧,反正我也看不到。


88会员算是阿里生态体系的重要布局了,也就是你开通了88会员,阿里系的很多产品你可以劈着叉去用,而且很划算。


比如,饿了么会员每年108元,虾米每年128元,优酷每年也差不多180元,还不算其它的,这些价格在用户心中已经是锚定价格,加到一起怎么着也大1000了吧,跟88元一比,稳赚不赔啊!






我们来看看88会员里包含什么,各种阿里系的七大姑八大姨的产品都包含进去了,从吃饭、购物、娱乐、旅行再到看病,生活里的方方面面都包含了。





所以,我身边的人开了88会员后,画风是这样的:明明想用QQ音乐听歌呢,不!我是88会员!我要去用虾米!明明想用美团点个外卖呢,不!我要去饿了么!明明我想去爱奇艺看看视频呢,不!我要去优酷看!(不过他们如果想看“淡黄色长裙蓬松的头发”还是得去爱奇艺)。


可以看出,阿里用这套会员体系,把用户死死的框在(导流)自己的产品矩阵中了,产品群们被自己爸爸carry的明明白白的。





联合会员


联合会员跟上面说的88会员有点类似了,只是88是自己企业内产品的互相导流,而很多联合会员是跨公司,跨界整合资源。 

比如,京东的PLUS京典卡,就是跨公司跟别人合作,有和腾讯视频、酷狗音乐、喜马拉雅、携程、爱奇艺的联合会员。 





其实也能看出,京东和其它产品这么搞,也是对阿里系的反击,没有爸爸,只能兄弟之间互相导流,抱团取暖,一致对外了。



3.固定入口扶持


固定入口扶持,一般出现在规模较大的平台级产品上,它们利用自己的流量优势,在固定位置给自己的子孙/兄弟产品们导流。


扶持下一代,努力做到子又生孙,孙又生子,子子孙孙无穷尽也。



比如:淘宝、支付宝、美团,在首页金刚位给自己企业相关产品导流,同时也补足/丰富自己产品的其它场景。






比如,各家的小程序,也是相对固定的入口给自己的产品或第三方产品进行导流,完善自己的产品生态。






4.广告位推荐


广告位推荐的导流方式应该是大家非常熟悉的了,它区别于上面的导流方式的核心点在于一般是产品/活动的介绍,引导安装之类的,形式大致分为:闪屏、 banner、角标、feed流...




闪屏

闪屏指的是用户在使用产品时,打开的第一个启动页。


用它进行导流的优点就是全屏沉浸展示,用户的目光就聚焦到这里了,但缺点是:时间短,如果在短时间内传达不清晰的话,很容易一闪而过,钱就白花了。



所以,闪屏的导流,最好找重叠用户较高的产品,比如,在汽车之家闪屏投个刮胡刀啊,在亲宝宝闪屏投奶粉啊之类的,用户在短时间内好接受好理解。


投放越精准,对产品体验和对广告主的导流效果越好。





角标

角标导流这种形式,在电商类平台搞活动的时候经常见,各种小角标纷纷出来拉客,角标的着陆页一般都是活动H5类型的居多。




这种形式的优点在于能够一直常驻,不像闪屏,闪一下就没了,它只要用户不手动关闭就一直在这杵着。


但对于设计师的挑战就是,如何在小小的区域里,把被导流的产品/活动核心利益点传递清楚,吸引用户点击。

而且,这种形式也要谨慎使用,如果乱八七糟的飚小角标也挺伤害体验的。





Banner


Banner位的导流大家更常见了,一般都是自己家产品/业务,夹杂着第三方广告推广,无限轮播着进行导流,大家都太熟悉了,我就不啰嗦的说了。





Feed流


一般资讯类或者社区类产品,喜欢用这种方式进行导流,因为用户在其产品上的核心操作就是撸Feed。


所以,撸着撸着给用户投喂一个通过算法推荐的广告,然后再把广告包装成跟Feed内容很相近的设计,吸引(pian)用户点进去,从而进行导流。


比如: 知乎、最右、百度、头条 ...




不得不说第二张“最右”的推荐内容,让我不禁抚摸了下自己的胡子。

不过除了最右给我推“大胸妹子”,百度给我推“游戏”,头条给我推“汽车”,难道在他们的算法中,我是个油腻中年男???


看来他们的人工还不够智能,机器还得再学习学习,大牙对你萌hin失望。





总结  


总的来说,“产品导流”不仅有助于新产品获得冷启动,还有助于相对成熟的产品扩大规模,同时从整个企业生态来看,矩阵产品的互相导流,协同发挥优势,也有利于打造体验闭环,建立企业壁垒。


形式大致分为:1.场景化导流,无缝衔接式的体验,让用户在产品功能间丝滑的流转;2.会员制捆绑,低价获得跨产品福利,利用用户占小便宜的心理跨界导流;3.固定入口扶持,平台型产品常用手段,丰富自己产品场景又能给自己小弟带流量;4.广告位推荐,灵活可配形式多变的导流方式(闪屏、 banner、角标、feed流)但搞不好很伤用户体验。



但是,不管什么导流形式,导进来的用户,只有看到满足他们诉求和预期的着陆页才是最关键的,不然就算给你再大的流量入口,用户搞不明白该走还是会走。


同时,也不能为了导流而不分场景的尬导,这样很容易伤害原有产品的用户体验,捡了芝麻,丢了西瓜。

转自:站酷-苏大牙


交互问答 | 产品设计的稀缺性 & 截图功能 & 分页与无限滚动加载差异

鹤鹤

通过交互思维,从常见功能模式梳理产品设计的底层逻辑。

通过读者提出的三个问题,我们从交互设计的角度来聊聊它们的底层逻辑。


稀缺性的正反价值


读者提问:

呆总,有什么心理学或经济学的概念是在产品设计上也被沿用的?


当然有,比如稀缺性。


让我们从你的生活小故事开始讲起。


在某个饿着肚子的下午,你走进一家超市,想要买桶泡面充饥,但是各式品牌与类型的泡面让你应接不暇,于是纠结起来,正犹豫不决中,一款所剩无几的泡面在茫茫商品中跳进了你的视野,不禁心中窃喜,“没错,就是它了!卖得这么好,味道一定不错~”。


回到家里,你一边吃着泡面一边刷着手机,突然看到了节假日商品促销的广告,于是打开了购物车,果然每件商品上都赫然标着今日满减的红字,让你蠢蠢欲动,之前嫌贵的商品突然在今天有了剁手的理由。不仅如此,其中你的最爱竟然显示库存紧张,如何能忍,赶紧结账下单,在付完款的最后一刻,你终于松了口气并开始暗自庆幸自己的英明决策。


这时,你的舍友突然推门而入,迫不及待地告诉了你她偶然得知的一个八卦消息,之前从未听闻的你感到激动不已,能够获得鲜见的信息让你感到无比地满足,两人就此事展开了激烈地讨论....


以上。


就像故事中描绘的那样,我们的生活就是由这些琐碎的片段重复构成,在无数个场景中,我们做着自觉或不自觉的思考和判断,它们影响着我们的感知,主导着我们的行为。其中,稀缺性就是我们估值的必要条件和决策的重要基础,那些热销的商品、限时的促销和不为人知的秘密唤起了我们内心的需求与渴望,催促着我们去行动。在设计产品功能时,产品人员也总是会刻意营造给用户一种稀缺的感知来突出其价值,以引导用户进行点击、浏览、购买等一系列行为。


稀缺的分类


总的来说,我们对稀缺性的利用大致体现在三个方面:时间、产品、信息。


时间的紧迫感。


这一点经常应用在电商产品中,比如特定节日内的商品限时优惠、抢购活动等等。对时间的限制能够传递给用户一种紧迫感,暗示他们尽快购买,从而减少他们的决策时间,达到促销的目的。

产品的缺失。


我们经常能在电商产品中看到商品库存的数量,特别是当库存较少时,能起到刺激用户的购买欲望。谷歌早前在发布线上邮箱的时候也充分利用了类似的手段,因为个人测试版的邮箱受技术的限制,不能为每个人开放足够大的储藏空间,于是他们采用了「邀请制」来推动这项服务,结果非常有效。


当你成为了其中一员,就能够再邀请 2-3 个朋友,这项服务的「供应不足」在推荐系统的支持下得到了病毒式的传播。类似的,知乎早期也利用了邀请的方式去帮助自己获得初期的忠实用户,产品的不易得性反而让人更看重它,间接提高了产品的价值,达到了意想不到的效果。


再比如部分商品「限购 2 件」,会让用户产生再买一件的念头 —— 其实原本就只想买一件。


信息的限制。


因为我们总是假定少的东西更具价值,所以对于审查和限制我们获得信息的动作尤为敏感,我们更渴望得到那些被禁的隐秘信息而不是唾手可得的信息。这种稀缺性所起的作用甚至比法律还要强,我们会本能地认为它更有说服力。这也是一些新奇罕见的消息更容易传播的原因之一,得到不常见的信息能够使人享受到额外资源的优越感。一些媒体恰恰利用了这一点,常通过夸张的新闻标题去抓住人们的注意,试图扩大其影响力。


或者一些特权(虚拟)商品,譬如 VIP。就是提供给用户部分信息,再告知用户 VIP 权限更高,能获得多有「价值」信息,诱导购买。


稀缺作用的原理


天然的,出于原始的不断追逐猎物、获取资源的本能,我们总是格外珍惜稀缺资源,并认为它们更具价值。稀缺性在一定程度上鼓动了我们内心贪婪的欲望,除此之外,我们还有「喜欢走捷径」的弱点,同时「厌恶失去」。


一方面,当事物很难被获取的时候,我们通过易得性进行快速的价值判断,遵循这样的方式我们总能地做出决定。

另一方面,我们讨厌失去选择的自由,所以常倾向于快速地决策来留住一些东西,甚至想要得更多。

虽然我们的这些本能,在帮助我们快速行动,但却不一定会做出最适合自己的选择。毕竟人的判断大多偏向于主观,一些用心不良的企业,可能会利用它让一些人做出错误的决定。


稀缺作用的条件


相比于一些错误所导致的稀缺,比如最近由于猪瘟造成的猪肉供应量的减少,在有限资源的竞争中由社会需求导致的稀缺能够发挥更强的效应,零售商早已充分洞悉了我们的这种倾向,所以常告诉我们产品正在热销当中,应尽快购买。这不仅是社会认同在发挥作用,即我们认为其他人认同的产品是好的,而且我们正参与到产品的竞争当中。

稀缺原则的应用焦点在于利用紧张的时间或者强调某些东西未来的不可得性,防止用户花很多的时间做出决策,推动用户马上做出对商家有利的决定。如果给人们这个世界上的所有时间去做出决定,他们要不花上所有的时间,要不根本不做决定。


通过应用稀缺性的技巧,可以从根本上迫使人们采取对策。人们在稀缺性原则的压力下反应更快,因为他们害怕永远失去机会。稀缺性使得他们优先做出决定,所以这些决定相比无限制的决策变得更重要,更紧急,更被需要。


但是仅仅告诉人们他们将要获得的利益是不够的,如果他们选择你的产品或者服务,你还需要指出其特别之处以及被放弃时的成本。

月活超10亿的微信,是如何做好用户体验的

涛涛

微信是一种生活方式。作为月活超 10 亿的国民级产品,它有着独特的设计之道。

同时,微信也是互联网界的一个异类,张小龙曾在微信公开课上回应道:「我们只是守住了做一个好产品的底线,居然就与众不同了」。

好产品自然是体验和价值至上。下面,我就为大家解读微信的用户体验设计。

二次确认的微创新

先从最简单的二次确认讲起。

微信针对首页消息和收藏列表的删除操作,做了二次确认的微创新。像同类 IM 聊天工具,如 iOS 短信、Facebook Messenger、飞聊等等,二次确认都是采用底部系统弹窗。这样做,从程序架构的角度来看兼容性和通用性更强。

而从体验设计的角度来看,则刚好相反,因为从第一次删除操作,到第二次确认系统弹窗。之间的目标距离太长,耗时也就变长了。根据菲茨定律(Fitts’ Law),获取目标的时间取决于目标的距离和大小。这意味着提升交互的效率,不仅需要减少距离,同时还要增加目标大小。

△ 收藏列表

回过头看来微信,就是这样设计的。二次确认是在第一次的基础上延展,距离几乎为 0,同时,目标按钮的宽度也增加了几倍,大大地提升了交互效率。

互动体验广告

其实,商业和用户体验往往是有冲突的。而微信广告很好的平衡了这一点。

通过丰富有趣的互动体验式创意,或画圆、或画方、或画爱心,吸引大家主动参与互动。

1. 开放首条评论

另外,首条评论功能让品牌像朋友一样与大家对话,利用明星效应,从而带动更多人参与评论,有效提升评论区活跃度和广告点击率。

△ 朋友圈刘雯广告

以刘雯发布的朋友圈广告为例,大表姐把款的 vivo X30 系列手机交到你手中,并在首条评论中邀请你帮她拍照。数十万用户积极回复刘雯,评论率高于历史均值 40 倍+,「你这么漂亮怎么拍都好看」、「天天给你拍」,大表姐的魅力折服了众多用户,有效提升了品牌的亲和力与好感度。

2. 打开仪式 · 最强震动级别

在交互方面,如果你是 iPhone 用户,可以体验到 Taptic Engine 线性震动马达,通常力度由轻到重分别是 Light、Medium、Heavy。在打开广告的那一刻,它给你的是最强震动级别,满满的仪式感!整个微信应该找不到第二个这样级别的震动了。

提供反馈信息

再举一个震动的例子,当你的好友拍摄了时刻视频后,可以看到 TA 的头像右上角多了一个蓝色的小圈圈,双击它就能看到好友的时刻视频了。

当然,你双击没有拍摄时刻视频的好友,TA 的头像会左右晃动,并且会有 Failure 的震动反馈,动画和震动节奏完美匹配,这个体验就像你解锁 iPhone 输错密码时的震动是一样的。

△ 没有时刻视频时的反馈

我们做产品设计时也一样,对于用户的操作,应当给予清晰明了的反馈,帮助用户更好地理解信息。

跨平台能力

微信的起步阶段是基于手机来做 App,不基于 PC 来做,PC 端只是辅助,而现在,它的跨平台能力也逐渐增强。

一周前,微信 PC 版「微信测试版 for Windows」发布了 2.9.0 的内测,同步了移动端的新功能,主要有两点:

支持打开小程序,也可以玩「贪吃蛇」「跳一跳」等小游戏了。

△ Windows 微信客户端

另外,此前的微信 PC 端只支持引用文字消息,也没有达到手机上引用消息的视觉效果。此次更新中,还新增了很多支持的应用类型,包括但不限于图片/视频、表情包、公众号链接、小程序、文件等。

如此看来,Mac 端的更新也不远了,可以期待一下。

语音实时翻译

最近的微信更新了,除了引入深色模式之外。值得一提的是,语音消息的交互体验得到了优化,上滑转文字更方便了。

此前的方式是按住说话,滑到转文字按钮,说完松开手指后,才把语音解析成文字。

现在交互则少了一步操作,达到了实时边说边转文字的功能。别小看这一步界面上的优化,它背后代表的是微信语音识别能力上的技术突破。

△ 语音实时转文字

锚点定位

微信有很多隐性和显性的锚点,隐性锚点就比如你打开的这篇文章,关闭后,再重新点进来,还是显示上次阅读的位置。

△ 订阅号列表

显性的锚点就比如上面这个:当你刷公众号列表时候,如果有新文章更新,标题栏会出现一个锚点按钮,点击它让你快速回到顶部,方便查看文章。

△ 朋友圈「跳到还没看的位置」

基于此,在新版微信朋友圈中,增加了一个「跳到还没看的位置」。很多信息流产品是往下刷内容,直到给你一个分界线提示:下面内容已经看过了。而微信这是一个逆向操作,我认为这个功能还是很有必要的,因为经常会有刷朋友圈刷到一半聊天退出去,当回来查看朋友圈时,需要重新拉到底部,费时费力。

自然的语音听筒播放

《在你身边,为你设计》一书中有提到语音听筒播放的优化。大家都知道,手机带有距离感应器,在感应到耳边贴近时,屏幕会关闭以节省电力,并且避免由于耳朵与屏幕的触碰导致的误操作。

微信在聊天界面中,也启用了距离感应,以实现手机贴近耳边时,自动将语音从扬声器切换到听筒进行播放,这样你可以用最自然的姿势来听语音,这是一个很好的体验。

但要完美地实现这个体验,就需要解决距离感应器的时延问题。播放语音时,如果你非常迅速地将手机移至耳边,这时候距离感应器并不会同样迅速地对这个动作产生反馈。大约在延迟了 300 毫秒后,感应器发出信号,微信将 iPhone 的屏幕关闭。而在这个时间内,你的耳廓极有可能已经触碰到了 iPhone 的屏幕上。触碰的位置大部分时候是左上角的返回按钮区域。于是很容易出现手机移至耳边,语音戛然而止。

△ 延时响应判断流程图

为了解决这个问题,微信设计了一个解决办法:在响应返回操作时,先等待 500 毫秒,这时候如果侦听到距离感应器有发出信号,则认为是贴耳的动作,此情况下不执行返回操作,如上图所示。而 500 毫秒的延时大部分时候你是不会感知到的。这一解决办法极大降低了贴耳时候的误操作。

总结

在微信的产品设计中,我们看到了交互的细微迭代和背后的技术突破,我们看到了商业创意与用户体验的平衡。给用户带来希望,让创造者体现价值,这就是微信的设计之道。

文章来源:优设    作者:洋爷

vue + vuex + koa2开发环境搭建及示例开发

seo达人

写在前面

这篇文章的主要目的是学会使用koa框架搭建web服务,从而提供一些后端接口,供前端调用。
搭建这个环境的目的是: 前端工程师在跟后台工程师商定了接口但还未联调之前,涉及到向后端请求数据的功能能够走前端工程师自己搭建的http路径,而不是直接在前端写几个死数据。即,模拟后端接口。

当然在这整个过程(搭建环境 + 开发示例demo)中,涉及到以下几点知识点。
包括:

  • koa2的知识点
  • node的知识点
  • 跨域问题
  • fetch的使用
  • axios的使用
  • promise的涉及
  • vuex -> state、mutations、actions的使用

第一部分:环境搭建

vue + vuex环境

首先是vue + vue-router + vuex的环境。我们用vue-cli脚手架生成项目,会用vue的同学对这块应该很熟了。

// 全局安装脚手架工具 npm i vue-cli -g // 验证脚手架工具安装成功与否 vue --version // 构建项目 vue init webpack 项目名 // 测试vue项目是否运行成功 npm run dev

因为脚手架生成的vue项目不包含vuex,所以再安装vuex。

// 安装vuex npm i vuex --save

koa2环境

前端项目构建好了,就开始构建我们的后端服务。

首先在你的开发工具(不管是webstorm还是sublime)里新建一个目录,用来搭建基于koa的web服务。

在这里,我们不妨给这个目录起名为koa-demo。

然后执行:

// 进入目录 cd koa-demo // 生成package.json npm init -y // 安装以下依赖项 npm i koa npm i koa-router npm i koa-cors

安装好koa和两个中间件,环境就算搭建完成了。

第二部分:示例开发

搭建环境是为了使用,所以我们立马来写一个demo出来。
demo开发既是一个练习如何在开发环境中写代码的过程,反过来,也是一个验证环境搭建的对不对、好不好用的过程。

后端接口开发

本例中,后端我们只提供一个服务,就是给前端提供一个返回json数据的接口。代码中包含注释,所以直接上代码。

server.js文件

 // server.js文件 let Koa = require('koa'); let Router = require('koa-router'); let cors = require('koa-cors'); // 引入modejs的文件系统API let fs = require('fs'); const app = new Koa(); const router = new Router(); // 提供一个/getJson接口 router
    .get('/getJson', async ctx => { // 后端允许cors跨域请求 await cors(); // 返回给前端的数据 ctx.body = JSON.parse(fs.readFileSync( './static/material.json'));

    }); // 将koa和两个中间件连起来 app.use(router.routes()).use(router.allowedMethods()); // 监听3000端口 app.listen(3000);

这里面用到了一个json文件,在'./static/material.json'路径,该json文件的代码是:

// material.json文件 [{ "id": 1, "date": "2016-05-02", "name": "张三", "address": "北京 清华大学",
}, { "id": 2, "date": "2016-05-04", "name": "李四", "address": "上海 复旦大学",
}, { "id": 3, "date": "2016-05-01", "name": "王五", "address": "广东 中山大学",
}, { "id": 4, "date": "2016-05-03", "name": "赵六", "address": "广东 深圳大学",
}, { "id": 5, "date": "2016-05-05", "name": "韩梅梅", "address": "四川 四川大学",
}, { "id": 6, "date": "2016-05-11", "name": "刘小律", "address": "湖南 中南大学",
}, { "id": 7, "date": "2016-04-13", "name": "曾坦", "address": "江苏 南京大学",
}] 

然后我们是用以下命令将服务启动

node server.js

测试接口是否良好

打开浏览器,输入http://127.0.0.1:3000/getJson。看一看页面上是否将json文件中的json数据显示出来,如果能够显示出来,则说明这个提供json数据的服务,我们已经搭建好了。

前端调用后端接口示例

为突出重点,排除干扰,方便理解。我们的前端就写一个组件,组件有两部分:首先是一个按钮,用来调用web服务的getJson接口;然后是一个内容展示区域,拿到后端返回的数据以后,将其在组件的这块区域显示出来

首先我们看组件文件

<template> <div class="test"> <button type="button" @click="getJson">从后端取json</button> <div class="showJson">{{json}}</div> </div> </template> <script> import {store} from '../vuex' export default { computed: {
          json(){ return store.state.json;
          }
        }, methods: {
          getJson(){
              store.dispatch("getJson");
          }
        }
    } </script> <style scoped> .showJson{ width:500px; margin:10px auto; min-height:500px; background-color: palegreen;
  } </style> 

非常简单,就不多解释了。
然后看我们的vuex文件

import Vue from 'vue' import Vuex from 'vuex';

Vue.use(Vuex) const state = { json: [],
}; const mutations = {
  setJson(state, db){
    state.json = db;
  }
} const actions = {
  getJson(context){ // 调用我们的后端getJson接口 fetch('http://127.0.0.1:3000/json', { method: 'GET', // mode:'cors', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json',
      },
    }).then(function (res) { if(res.status === 200){ return res.json()
      }
    }).then(function (json) { //console.log(typeof Array.from(json), Array.from(json)); context.commit('setJson', Array.from(json));
    })
  }
}; export const store = new Vuex.Store({ state: state, mutations: mutations, actions: actions,
})

ok, 代码撸完了,获取后端数据之前是这样的。

获取后端数据之后是这样的。

说说axios

想要把本demo的fetch改为axios方式,要做的工作有以下几处:
1、安装axios、在vuex文件引用axios

npm i axios import axios from 'axios'

2、将fetch部分代码替换为:

const actions = {
  getJson(context){
    axios.get('/json', { method: 'GET', // mode:'cors', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json',
      },
    }).then(function (res) { if(res.status === 200){ return res.data
      }
    }).then(function (json) { //console.log(typeof Array.from(json), Array.from(json)); context.commit('setJson', Array.from(json));
    })
  }
};

3、又会遇到跨域,在webpack中修改,路径config/index.js文件中添加proxyTable项的配置:

proxyTable: { '/json': { target: 'http://127.0.0.1:3000', changeOrigin: true, pathRewrite: { '^/json': '/json' }
      }
    },

后记

基于vue脚手架搭建的项目,模拟异步取数据,也可以直接在脚手架生成的static文件夹下放置数据,假装是后台拿过来的数据。

不过搭建一个基于express或者koa的web服务,确实也该是一个前端工程师应该掌握的。

OK,以上就是全文了。
如果这篇文章使你有所收获,不胜荣幸。
欢迎点赞,以期能帮助更多同学!

GitHub如何配置SSH Key

前端达人

文章目录

    • 步骤


    • https://github.com/xiangshuo1992/preload.git
      git@github.com:xiangshuo1992/preload.git
      这两个地址展示的是同一个项目,但是这两个地址之间有什么联系呢?
      前者是https url 直接有效网址打开,但是用户每次通过git提交的时候都要输入用户名和密码,有没有简单的一点的办法,一次配置,永久使用呢?当然,所以有了第二种地址,也就是SSH URL,那如何配置就是本文要分享的内容。
      GitHub配置SSH Key的目的是为了帮助我们在通过git提交代码是,不需要繁琐的验证过程,简化操作流程。
      
      步骤
              

      一、设置git的user name和email

      如果你是第一次使用,或者还没有配置过的话需要操作一下命令,自行替换相应字段。
      git config --global user.name "Luke.Deng"
      git config --global user.email  "xiangshuo1992@gmail.com"
            
              

      二、检查是否存在SSH Key

      cd ~/.ssh
      ls
      或者
      ll
      //看是否存在 id_rsa 和 id_rsa.pub文件,如果存在,说明已经有SSH Key
      如果没有SSH Key,则需要先生成一下
      
      
      ssh-keygen -t rsa -C "xiangshuo1992@gmail.com"
            
              

      三、获取SSH Key

      cat id_rsa.pub
      //拷贝秘钥 ssh-rsa开头
            
              

      四、GitHub添加SSH Key

      GitHub点击用户头像,选择setting
       
      新建一个SSH Key 
      取个名字,把之前拷贝的秘钥复制进去,添加就好啦。
            
              

      五、验证和修改

      测试是否成功配置SSH Key
      
      
      ssh -T git@github.com
      //运行结果出现类似如下
      Hi xiangshuo1992! You've successfully authenticated, but GitHub does not provide shell access.
      之前已经是https的链接,现在想要用SSH提交怎么办?
      直接修改项目目录下 .git文件夹下的config文件,将地址修改一下就好了。
            
              


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



深入理解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搭建工程。

https://github.com/cunzaizhuyi/vue-slot-demo

你真的了解重排和重绘吗?

前端达人

做过前端开发的小伙伴就算不是非常理解重排与重绘,但是肯定都听过这两个词。那为什么这两个东西这么重要?因为他与我们的页面性能息息相关,今天,我们就来好好研究一下这两个东西。



浏览器的渲染流程

在讲解重排和重绘之前,我们有必要说一下浏览器的渲染流程。下面是浏览器渲染过程中最关键的几个部分。如果想了解完整的浏览器渲染流程,推荐大家去阅读李兵老师的浏览器工作原理实践,需要付费阅读。后期我也会整理一下再出一篇博客详细介绍浏览器的渲染过程。


点击查看原图


JavaScript:一般来说,我们会使用 JavaScript 来实现一些视觉变化的效果。比如用 jQuery 的 animate 函数做一个动画、对一个数据集进行排序或者往页面里添加一些 DOM 元素等。当然,除了 JavaScript,还有其他一些常用方法也可以实现视觉变化效果,比如:CSS Animations、Transitions 和 Web Animation API。
样式计算:此过程是根据匹配选择器(例如 .headline 或 .nav > .nav__item)计算出哪些元素应用哪些 CSS 规则的过程。从中知道规则之后,将应用规则并计算每个元素的最终样式。
布局:在知道对一个元素应用哪些规则之后,浏览器即可开始计算它要占据的空间大小及其在屏幕的位置。网页的布局模式意味着一个元素可能影响其他元素,例如 元素的宽度一般会影响其子元素的宽度以及树中各处的节点,因此对于浏览器来说,布局过程是经常发生的。
绘制:绘制是填充像素的过程。它涉及绘出文本、颜色、图像、边框和阴影,基本上包括元素的每个可视部分。绘制一般是在多个表面(通常称为层)上完成的。
合成:由于页面的各部分可能被绘制到多层,由此它们需要按正确顺序绘制到屏幕上,以便正确渲染页面。对于与另一元素重叠的元素来说,这点特别重要,因为一个错误可能使一个元素错误地出现在另一个元素的上层。
其中,重排和重绘影响的就是其中的布局和绘制过程。

什么是重排和重绘制
重排:当DOM的变化引发了元素几何属性的变化,比如改变元素的宽高,元素的位置,导致浏览器不得不重新计算元素的几何属性,并重新构建渲染树,这个过程称为“重排”。
重绘:完成重排后,要将重新构建的渲染树渲染到屏幕上,这个过程就是“重绘”。
简单来说,涉及元素的几何更新时,叫重排。而只涉及样式更新而不涉及几何更新时,叫重绘。对于两者来说,重排必定引起重绘,但是重绘并不一定引起重排。所以,当涉及重排时,浏览器会将上述的步骤再次执行一遍。当只涉及重绘时,浏览器会跳过Layout步骤,即:


点击查看原图


而如果既不需要重排,也不需要重绘,那么就是下面这样:


点击查看原图



浏览器会直接跳到合成阶段。显然,对于页面性能来说,不重排也不重绘 > 重绘 > 重排。

什么操作会引起重排和重绘
显然,触发重排的一般都是几何因素,这是比较好理解的:

页面第一次渲染 在页面发生首次渲染的时候,所有组件都要进行首次布局,这是开销最大的一次重排
浏览器窗口尺寸改变
元素位置和尺寸发生改变的时候
新增和删除可见元素
内容发生改变(文字数量或图片大小等等)
元素字体大小变化
还有其他一些操作也可能引发重排

查询某些属性或调用某些方法
offset(Top|Left|Width|Height)
scroll(Top|Left|Width|Height)
client(Top|Left|Width|Height)
getComputedStyle()
我们可能不太理解为什么这些操作也能引起重排,这里我先简单解释一下。因为现在的浏览器已经非常完善了,会自动帮我们做一些优化。当我们用js操作DOM的时候,浏览器并不是立马执行的,而是将操作存储在一个队列中。当达到一定数量或者经过一定时间以后浏览器再统一的去执行队列中的操作。那么回到我们刚才的问题,为什么查询这些属性也会导致重排?因为当你查询这些属性时,浏览器就会强制刷新队列,因为如果不立马执行队列中的操作,有可能得到的结果就是错误的。所以相当于你强制打断了浏览器的优化流程,引发了重排。下面我们通过一些小例子来进一步理解这段话:

首先我们来一个显然会引发重排的操作

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    #test {
      width: 100px;
      height: 100px;
      background-color: red;
      position: relative;
    }
  </style>
</head>
<body>
  <div id="test">

  </div>
  <button onclick="reflow()">click</button>
  <script>
    function reflow() {
      var div = document.querySelector("#test");
      div.style.left = '200px';
    }
  </script>
</body>
</html>



把时间轴往后拉,可以看到这几个过程,先简单介绍一些这些名词代表的含义:

Recalculate Style:这个过程就是生成CSSOM的过程
Layout:这就是布局阶段,即重排的过程
Update Layer Tree:这个阶段是更新层树的过程
Paint:该阶段是为每一层准备绘制列表的过程
Composite Layers:该阶段是利用绘制列表来生成相应图层的位图了,还涉及到合成线程和光栅化,performence面板中的Raster就是光栅化线程池 。
这里只做一个简单的介绍,对其中内容不太明白的同学可以参考李兵老师的文章或者在我的下一篇介绍浏览器渲染过程的文章中会详细解释。

那通过这个图我们可以看到,我们改变了div的left之后就触发了Layout,即重排的过程。下面我们仅改变div的背景颜色,给大家一个对比。


即不重排也不重绘
说完了重排和重绘,不要忘记我们最开始提到的,最的方式就是跳过重排和重绘阶段。你可能会想,什么情况下可以做到这一点?其实这就是我们平时说的GPU加速,具体是如何实现呢?在开发过程中,如果我们使用了某些属性,浏览器会帮助我们将使用了该属性的div提升到一个单独的合成层,而在后面的渲染中,提升到该层的div将跳过重排和重绘的操作,直接到合成阶段。在stack overflow上有问题提到了这块内容。我们翻译一下就是:
下面几个属性能让浏览器帮助我们将div提升到一个单独的合成层:

图层具有3D或透视变换CSS属性
使用加速视频解码的 video 元素
拥有 3D(WebGL) 上下文或者加速 2D 上下文的 canvas 元素
混合插件(Flash)
对自己的 opacity 做 CSS 动画或使用一个动画 webkit 变换的元素
图层使用加速的CSS过滤器
层具有作为合成层的后代
图层具有较低z索引的同级元素,该同级元素具有合成层(换句话说,该层在合成层的顶部渲染)
css will-change属性
最后一点是我加上去的,同时根据文中的内容我们可以知道,css3硬件加速是浏览器的行为,所以在不同浏览器下可能会有不同的表现形式。下面我们用一个例子来理解一下。这是李兵老师在他的专栏中提出的一个例子,我拿过来借用一下,注意box中的will-change属性:

<html>

  <head>
      <title>观察will-change</title>
      <style>
          .box {
              will-change: transform, opacity;
              display: block;
              float: left;
              width: 40px;
              height: 40px;
              margin: 15px;
              padding: 10px;
              border: 1px solid rgb(136, 136, 136);
              background: rgb(187, 177, 37);
              border-radius: 30px;
              transition: border-radius 1s ease-out;
          }

          body {
              font-family: Arial;
          }
      </style>
  </head>

  <body>
      <div id="controls">
          <button id="start">start</button>
          <button id="stop">stop</button>
      </div>
      <div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
          <div class="box">旋转盒子</div>
      </div>
      <script>

          let boxes = document.querySelectorAll('.box');
          let boxes1 = document.querySelectorAll('.box1');
          let start = document.getElementById('start');
          let stop = document.getElementById('stop');
          let stop_flag = false

          start.addEventListener('click', function () {
              stop_flag = false
              requestAnimationFrame(render);
          })

          stop.addEventListener('click', function () {
              stop_flag = true
          })

          let rotate_ = 0
          let opacity_ = 0
          function render() {
              if (stop_flag)
                  return 0
              rotate_ = rotate_ + 6
              if (opacity_ > 1)
                  opacity_ = 0
              opacity_ = opacity_ + 0.01
              let command = 'rotate(' + rotate_ + 'deg)';
              for (let index = 0; index < boxes.length; index++) {
                  boxes[index].style.transform = command
                  boxes[index].style.opacity = opacity_
              }
              requestAnimationFrame(render);
          }
      </script>
  </body>

  </html>



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

【CSS基础学习】复杂选择器

前端达人

文章目录

    • CSS第二课-复杂选择器
      • 群组选择器
      • 属性选择器
      • 派生选择器
      • CSS第二课-复杂选择器

        群组选择器

        格式

        选择器1,选择器2,,,选择器n{声明的属性和属性值}

        p,h1{
            color: blue;
        }


        用于对于多个选择器进行样式修改,由简单选择器组合而成的选择器,可以是简单选择器中的任意组合,如上面代码例,就是修改了p标签和h1标签的字体颜色。

        属性选择器

        根据属性名查找元素

        格式

        元素[属性名]{
            声明的属性和属性值;
        }


        p[id]{
            color: blue;
        }


        前面添加元素的名字,然后后面加上属性名,比如上例,就是p标签,其中带有id的元素,然后把字体颜色设置为蓝色。

        根据属性值查找

        格式

        元素[属性名=属性值]{
            声明的属性和属性值;
        }


        p[class = 'p2']{
            color: blue;
        }


        和上面的根据属性名查找差不多,只不过更加了,到了属性名后面的属性值,上例就是作用于p标签,只不过条件是为带有class属性,并且属性值为p2的p标签。

        多属性选择器

        格式


        元素[属性名或属性表达式][属性名或属性表达式]..{
            声明的属性和属性值;
        }
        p[title][class]{
            color: blue;
        }



        元素后面加。属性名或属性表达式,可以加+∞个,但是没必要。上例为:设置title属性和class属性的段落p标签的样式

        根据属性值近似查找

        格式


        元素[元素名~=属性值]{
            声明的属性和属性值;
        }


        元素[属性名|=值]{
            声名的属性和属性值;
        }


        p[class~='red']{
            color: blue;
        }



        注意,这里是~=,为约等于,就是找满足符合约等于条件的标签,上例为:设置class属性的值,包含red属性名的标签

        根据标签查找

        格式


        元素名1~元素名2{
            声名的属性和属性值;
        }


        a~p{
            color: blue;
        }


        a标签后面的每一个p标签,都进行了样式的修改。

        派生选择器

        后代选择器

        格式


        父类标签 子类标签{ /*注意俩标签中间有空格*/
            声名的属性和属性值;
        }


        div strong{
            color: blue;
        }


        相邻兄弟选择器

        格式


        父标签+子标签{
            声名的属性和属性值;
        }


        #div1 + p{
            color: blue;
        }


        相邻兄弟选择器可选择紧接在另一个元素后的元素,且二者具有相同的父亲元素。注释:与子结合符一样,相邻兄弟结合符旁边可以有空白符。




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

B端系统设计全方位指南

涛涛

什么是B端产品?

B 端产品也叫 2B(to Business)产品,使用对象一般为企业客户或组织。B 端产品帮助企业或组织通过协同办公,解决某类管理问题,承担着为企业或组织提升效率、降低成本、控制风险从而提高企业收入,减少企业内部损耗的重要职责。B 端产品的工作是合理实现企业需求,提高产品核心竞争力,并提升市场价值。在国内互联网语境中,B 端产品的狭义解释也基本可以和面向企业的 「网页程序」 等同,用更接地气的称呼可以叫「管理平台」、「管理端」 。

B 端产品大致分为两类,一种是支撑前台产品的,一种是管理各种资源的,前者就是我们熟悉的后台产品,后者就是给各个企业服务,提高各个企业工作效率的 B 端产品。

1. 支撑前台产品的:

C 端产品线的后台产品,比如我们常用的淘宝、微信、饿了么、美团这种 C 端产品,他都需要有个后台进行各种前端信息的管理。

平台级工具产品,比如微信公众号、头条号等对用户和文章的数据实时统计,可编辑文章,回复消息等

2. 管理各种资源的:

  • OA 办公系统(OA 系统是通过程序的形式使办公流程自动化的解决方案)
  • CRM 系统 (CRM 是企业专门用来管理客户的工具)
  • SaaS 系统(SAAS 通常它指第三方提供给企业的线上软件服务,它既可以包含前面几种服务类型,也可以是一些更细化的需求。)
  • ERP 系统(ERP 是对企业所拥有、调动的资源进行统一管理的平台)
  • WMS 系统(WMS 是仓库管理系统的缩写,通过入库业务、出库业务、仓库调拨、库存调拨和虚仓管理等功能,综合批次管理、物料对应、库存盘点、质检管理、虚仓管理和即时库存管理等功能综合运用的管理系统)
  • TMS 系统(TMS 是运输管理系统能够对物流公司的所有车辆进行实时跟踪(结合 GPS 系统),保持信息流和物流的畅通。)
  • 呼叫中心客服系统
  • FMS 财务管理系统

B端和C端的区别

1. 从定义上:

  • B 端:To B 就是 To business,面向企业或者特定用户群体的企业级别产品;
  • C 端:To C 就是 To customer,产品面向普通大众消费者。

2. 从用户群体上:

  • B 端:产品一般是多种角色,有决策者、管理者和执行者,B 端往往是基于公司层面多人对某一问题解决方案进行整体评估。
  • C 端:用户群体较单一,或者是专注于某一领域群体,可根据性别,职业或行为偏好等关键属性进行分类。

3. 业务场景

  • B 端:业务场景多、逻辑复杂,根据每个人角色需要有不同的解决方案
  • C 端:业务场景较单一,或者专注于某个垂直的使用场景。

4. 用户的诉求:

  • B 端:控制成本、提率,注重安全和稳定
  • C 端:重视人性和用户体验

5. 盈利模式:

  • B 端:有明确的盈利模式和用户群体。
  • C 端:大部份 C 端产品都是使用免费,以此吸引用户使用,等积累到一定数量需要探索变现的路径,或者寻找其他变现的路径。

B端产品该如何设计?

了解了 B 端和 C 端的区别,B 端产品的实用性大于美观性,能切实解决问题、配置资源的 B 端产品才是一个好的 B 端产品。在设计上对于操作和展示内容无关的元素,越少越好。很多人刚开始接触 B 端,会热衷于以 C 端视觉标准进行设计,对于真实的使用体验来说显得过于冗余、炫技。那么在 B 端设计中该如何思考去设计呢?下面我以设计前、中、后的三个方向去阐述我在做 B 端设计中的一些思考:

1. 设计前:

需求分析

  • 分析产品的背景是什么,要做什么,要给用户怎样的视觉感受?他的竞品状况是怎样的进行一些分析(一般 b 端的产品竞品是极少的),了解一些行业内的资料。
  • 目标用户群有哪些?不同角色的用户有哪些具体的权限?(这里简要了解下大概的人群,没必要像 c 端产品那种那么明确)
  • 设计的产品主要解决用户或者业务上的哪些具体痛点,复现分析下使用场景,在需求分析阶段,要对产品本身和行业本身有一些基本的认知。

使用场景、硬件情况

  • 了解用户的使用场景,可以有助于我们复现分析用户是如何使用我们设计的界面的。
  • 用户的硬件情况,了解主流用户的屏幕分辨率是多少,根据主流分辨率做设计稿。现在 PC 主流的分辨率占比排名前三的是 1920*1080、1366*768、1440*900,以 1440 来设计的话,向上适配或者向下适配误差会比较小。这里也不是必需,如果用户全部都是用小屏笔记本办公,在 1920 设计稿上做适配可能小屏幕上展示会出现滚动条,会比较拥挤。

梳理交互流程:拿到需求后切勿打开花瓣站酷一阵撸,一定要对需求进行梳理(有的公司有专门的交互设计来做)做 B 端产品最重要的是对业务的理解,在梳理过程中一定要跟产品随时沟通,产品的业务流程是怎样的?有哪些同类型的产品?和他们相比我们的产品有什么特色和特点?充分理解了业务再去做设计就会有事半功倍的效果。

情绪版,定义风格:梳理完需求就可以定义设计风格了,在设计风格上尽量做到简洁,B 端产品实用性大于美观性,减少不必要的装饰元素给用户操作上带来干扰。这里可以运用情绪版去定义设计风格,大概的流程就是,根据产品业务背景定义设计关键词、根据关键词去找参考图片定义设计风格,产品的主题色也可以根据情绪版来去定义。

2. 设计中:

布局上根据导航可分为以下三种:

水平导航布局:类似于普通网页的布局样式导航,顺应了从上至下的正常浏览 顺序,方便浏览信息;顶部宽度限制了导航的数量和文本长度。适用于导航较少,页面篇幅较长的产品。

垂直导航布局:可将导航栏固定在左侧,提高导航可见性,方便页面之间切换;顶部可放置常用工具,如搜索条、帮助按钮、通知按钮等。菜单栏还可以展开收起,适用于结构简单的产品。

混合导航布局:结合了水平导航和垂直导航的特点,层级可以扩展到二、三级菜单,且能够更加清晰地区分常用业务功能操作和辅助操作。适用于功能模块较多、较复杂的工具类型后台。

不同形态的布局,适配方式也不同。在做设计之前了解下适配的原理,避免在不同设备上出现视觉上的误差。水平导航布局,在适配方案中做法是对两边留白区域进行最小值的定义,当留白区域到达限定值之后再对中间的主内容区域进行动态缩放。如图:

垂直导航布局和混合型导航布局,在适配方案中常见的做法是将左边的导航栏固定,对右边的工作区域进行动态缩放。如图:

最后说一下布局上的栅格,栅格会使整体页面更加工整简洁,内容区域采用 24 栅格(并非固定数值,参照案例 24 栅格布局),就不一一叙述栅格的定义与运用了,大家可以参考下网上有好多关于栅格的文章,如图:

颜色

颜色上大致分为品牌色(可以结合业务属性)、功能色(比如红黄绿蓝灯成功、出错、失败、提醒、链接等。功能色的选取需要遵循用户对色彩的基本认知)、 中性色(如深灰中灰浅灰,文字部分应用居多,此外背景、边框、分割线、等场景中也非常常见) 其他色如统计图、数据可视化、多个标签的不同配色方案根据项目情况单独设定。

字体

在 B 端系统中优先使用系统默认的界面字体,常用中文字体有微软雅黑、苹方、思源黑体,英文字体有 Arial、Helvetica 系统不同展示的字体也不相同。

字体大小常见的有 12px、13px、14px、16px、20px、24px、30px 等。

规范

一份好的规范能够让设计和开发更加的工作,并且能够指引一些设计的细节,通过对大小、颜色、边距等、呼吸感等一些细节点的标注,可以让新加入的设计师快速上手设计。一个项目会有多个设计师的参与,规范化的设计语言,避免因设计控件混乱而影响设计输出。好的设计规范还能统一在产品中不同页面的相同板块的样式问题,为开发组件库奠定基础。

如何建立一份规范呢?大概总结以下几点:

  • 首先是要梳理产品中不同板块所出现的场景进程收集(收集产品所有出现过的场景进行整理)
  • 其次是把收集完的板块归纳分类(不同的样式、状态等可以分成不同的种类)
  • 最后就可以定义规范了。

定义好设计规范能大大提高设计师的工作效率,在同一个项目中也能更好的把控项目的视觉规范,帮助设计师复用及设计延展。

组件

B 端产品的决策方是老板和管理层,在设计 B 端产品中往往也是大多数情况下会有接到比较紧急的需求的情况,所以在设计过程中就需要我们设计师更加去注重效率,提高产能。做东西时要有组件化思维,去总结分析页面模块中的一些共性,跟开发共同完成产品的组件库。

如果没有前端工程师,我们的设计组件库就是 PNG。所以,在开工前,一定要和那个技术不错的前端工程师聊聊做设计组件库的事情,其中最重要的是确定好:选择什么样的前端框架。

如果组件库服务的是 B 端或者中后台系统,那其实有很多可参考的开源组件框架:Ant Design、ElemetUI、Layui 等,注意不同的框架用到的前端技术不一样,兼容的浏览器版本也不一样,这要根据你们技术情况做选择。如果觉得开源框架的风格和你们的产品不统一,那就需要二次设计和开发封装。

下面是蚂蚁金服组件库,如图根据组件的功能特点做出了分类:通用、布局、导航、数据录入、数据展示、反馈、其他等。大家可以去官网查看,这里就不再一一做阐述了。

这个是饿了么的组件库:

推荐几个官方组件库:

做之前大家一定要去多去查看这些大厂做的已成型的开源组件库,然后再结合工作业务特色做出自己公司特有的定制化组件库。有了组件库之后,再接到紧急需求,我们就可以做到事半功倍的效果。先去分析页面的构成,然后花费 80% 的时间去设计需求中 20% 的页面,剩下的通用型页面就可以直接用组件库堆出来了。

3. 设计后:

设计走查

在完成设计后,要整体对设计页面进行走查。从信息层级、文字、图标、图片等方面进行多次设计验证与测试。

高质量设计交付

设计稿命名一定要清晰规范,现在好多切图标注的插件,一键生成切图标注。现在就没有必要单独整理切图标注了,但是设计稿在交付前切图的命名一定要在设计稿里整理清楚,规范命名方便开发查阅。

推荐几款比较常用的切图标注的插件:

设计追踪、校验

设计稿给到开发在设计过程中,要随时跟开发沟通。项目上线后要对线上效果进行实时 UI 校验,保证开发同学对设计稿的高度还原。还有就是对设计上线后的验证工作,用户使用和反馈是优化产品的重要途径,针对性地在一些主流的页面模块按钮进行一些数据的埋点,统计下用户的点击状况,实时对数据进行一些跟进,为下次页面改版优化,提供有力的数据支撑,提升产品的用户体验。

总结

不管 B 端还是 C 端,设计的价值在于通过视觉表现的方式去助力公司、助力产品实现用户的需求、帮助用户解决问题。B 端产品相对而言,场景、功能、业务流程、信息架构要比 C 端更复杂,面对的异常情况也比较多,所以 B 端在设计风格上尽量做到简洁,B 端产品实用性大于美观性,在每一个功能的设计都需要你去思考很多方面:用户易用、信息层级、未来扩展,你都要做出取舍,而对于每个模块都需要你思考、结合用户场景。所以想要做好 B 端设计,一定要去了解业务,了解用户需求。

文章来源:优设    作者:小六可视化设计

爱奇艺 VR 设计实战案例:界面文字篇

涛涛

本系列文章旨在由浅入深、由理论到实践地介绍 VR 设计。无论你在做哪个领域的设计,都能通过这个系列了解 VR 设计的特点。本文是第一集,深入分析 VR 界面的文字设计。


文章来源:优设    作者:爱奇艺XRD

日历

链接

个人资料

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

存档