首页

从总统级厨师到奥美创始人,他是如何构建广告帝国的?

资深UI设计者

广告圈「门槛低」、「是个人都能做」,这种印象可能来源于,世界上最出名的广告公司之一——奥美的创始人,他是个厨师。除了当过厨师,还做过推销员,调查员,政治秘书,还种过几年地,最后成了 1960 年代,极负盛名

阅读文章 >>

1914 年夏天,一战爆发了。在伦敦郊区的萨里郡,一个商人正脸色凝重坐在椅上发呆。他破产了,战争将一切都化为乌有,这对商人的儿子而言,意味着再也吃不到冰淇淋了。这个孩子刚满 3 岁,名字叫大卫·奥格威。

作为英格兰的名门望族,奥格威一家都不是吃素的。父亲和兄弟是名人,爷爷是富商。所以即使破产了,奥格威也能上贵族学校,先后受教于艾丁堡斐特思公学及牛津大学,成为众人眼中的「明日之星」。

然而他并没有毕业,他用自己的行动证明了自己是个弟弟,两年的大学时光,奥格威逢考必挂,最后被牛津大学扫地出门。他既没有文凭,也没有钱,索性在美琪饭店当起了实习厨师。

凭着天生的聪明才智,奥格威很快在美琪饭店混得风生水起。1932 年,一个月黑风高的晚上,法国总统保罗·杜梅像往常一样,来到了饭店享用晚餐,当吃到奥格威做的一款甜品后,不自觉地发出了由衷的赞叹:「C’est bon!」(法语:好吃死了!)

三周后,杜梅总统就死了,当然这不是因为吃了奥格威的甜点,而是吃了一个苏联人的子弹。

面对闷热的后厨,繁重的工作压力,让奥格威苦不堪言。奥格威选择结束了厨师生涯,回到了英国推销起了炉具,这个炉灶,就是鼎鼎大名的 AGA(雅家)。2015 年 3 月,AGA 曾在北京举办过一场发布会,现场一套蓝色 AGA TC 炉灶售价人民币 28 万元。

每天出入饭店、古堡、修道院的奥格威,业绩月月拿销冠,公司还委托他写了一本销售手册。奥格威当时甚至想过把「如何将炉具卖给盲人主妇」这些细节也写下来,这份推销书后来被《财富》称为「有史以来最好的销售手册」。

1936 年,他的哥哥为他在伦敦一家广告公司谋得实习的机会。此时的奥格威还是个广告菜鸟。他的创作「秘诀」,是从芝加哥订购一份美国剪报,挑选好广告一字不落抄袭,然后提交给他的英国客户。

由于表现出色,公司决定送他到国外学习美国广告技术,为时一年。这一年,他收获颇丰,不仅学业有成,而且邂逅了 18 岁的女学生。二战爆发的那一年,他们喜结连理。

△ 奥格威和他太太合照

1938 年,奥格威移居美国,在盖洛普咨询公司任研究员,为好莱坞制片商做民意调查。天赋异禀的奥格威能在开拍前预测出电影的票房,误差<10%。一时间迪士尼、华纳、米高梅纷纷上门求合作。

△ 在街头做民意调查的奥格威

1939 年 9 月,二战爆发,次年法国沦陷。凭借数据领域的造诣,奥格威受邀加入英国情报机构,出任英国驻美使馆二秘。战后他辞去了公务员工作,做起了农民,农作物是大烟。奥格威甚至迷上了这段采菊东篱下的农耕日子,但他深知自己无法以务农为生。

于是 1948 年,奥格威回到纽约,用 6000 美刀创办了自己的公司,取名「奥美广告」。在麦迪逊大街贴出一个别出心裁的招聘海报,上面传达了三点内容:

  • 公司新近成立,员工需要加班工作,工资则低于一般水平。
  • 招聘精力充沛,有头脑的年轻人。
  • 在 1960 年之前,这必将成为一家大公司。

至此,奥美广告公司正式成立。算上奥格威共两名员工,整天大眼瞪小眼。为了活下去,奥格威接了当时能够接到的所有订单。包括一个毫不知名的小制衣厂哈撒韦。当时他们告诉奥格威,只有 3 万美元预算,却想和知名衬衣品牌竞争。

当时奥格威都快哭了。预算少要求极高,还不因为效果而解约。但谁让他叫大卫呢,过人的天赋让他的广告在全国走红,仅用 3 万美元,让销售额翻了三番。使这家默默无闻了 100 多年的衬衫品牌,一夜之间闻名全国。更令人无法想象的是,这个创意被沿用了 25 年。

广告为产品增添了来自远方的神秘感,激发读者对狂野的无限遐想。「传达一种特别的信息以取悦读者」。这本来是奥格威准备的 18 个方案中被否决的一个,但他想,给其中一只眼睛戴个眼罩也无妨,于是在影棚的路上买了个眼罩交给模特。

随后,劳斯莱斯花了 5 万美元找奥格威做的一支广告再次成为经典,在时速 60 英里时,这辆新款劳斯莱斯车内最大的噪声,来自它的电子钟。不用多说了,时至今日这依然是最有名的汽车广告之一。这些广告让奥美的名声如日中天,赢得客户如探囊取物。

后来广告界盛传,说奥格威是一个奇才,好几家大广告公司都提出收购意向时,奥格威却回绝了。多年后他回忆,如果当时诱他以金钱,他肯定就屈服了,但他们却以为奥格威在乎的是「创作的挑战」。

与其说创作是一种挑战,还不如说是一种依据特定原则的模式生产,他甚至禁止员工使用「创作」形容他们的工作。因为在奥格威看来,好的广告是「99% 的调查研究+ 1% 的灵感」。例如奥格威发现标题加入感情色彩的词可强化广告效果,经过几百个词的测试,「Darling」(亲爱的)一词高居榜首。于是他将它运用到多芬的广告,后来多芬成为了同类产品中最畅销的品牌。不久奥格威表示,他并不知道洗澡时使用电话是危险的。

奥格威出生名门,却家道中落,是牛津的明星,却被扫地出门,他为法国总统下过厨,也给国王当过特工。他对市场一无所知,从未写过一篇文案,直至 38 岁尚未正式涉足广告业,口袋只有区区的 6000 美元原始资金……但 3 年之后,这个一度黯淡的男人已在行业发光发热,犹如创造了一个奇迹。

1963 年,奥格威著书《一个广告人的自白》。可以说奥格威是一个超越了时代的牛人,他里面的一些理论,对我们现在做电商一点都不过时,有兴趣的小伙伴可以买一本看看。

奥格威凭借他独特的人格特征和洒脱的世界观征服了许多人,那么他的魅力到底在哪,不妨让我们走进他的思想世界,亲身领略一番这个奥美开山鼻祖的风采。

1973 年,奥格威正式退休。他在童话般美丽的法国多佛,买下一座 700 年历史的古堡,过起了隐居生活。从那时起,路过的游客们,时常看到这样一幅画面:一个晴天的午后,阳光透过一棵 17 世纪的冬青树,将星星点点遍洒小径。小径的一旁,一个衣衫褴褛的老头儿,正在仔细地修剪玫瑰花枝。老头儿的嘴里碎碎地念叨着:「终于,可以安心做个农民咯~」

在他的广告帝国之中,他的影响力深广依旧,直至 1999 年最终逝去。奥格威的故事到这就结束了,而离新的篇章,奥美中国的故事也并不遥远了。

让我们把时间拨回到 1979 年,彼时随着改革开放的深入,《文汇报》宣布了商业广告的正式回归。奥美广告快速响应政策的变化,于同年推出中国大陆地区的第一支作品——雷达表广告正式出道。如今再提起雷达表,相信很多 60、70 后依然对当年那则「轰动」的老广告印象深刻。

1997 奥美中国在华推出大众桑塔纳,这款车型很快红遍大江南北。当时的广告语「拥有桑塔纳,走遍天下都不怕」使用了近十年。在 1978 年年底,中国改革刚刚拉开崭新的序幕,当时的德国大众是唯一既愿意提供技术,又肯投入资金的汽车公司,可以说大众陪伴中国人从贫穷走向富裕,国人对着大众品牌有着不同的感情。

再把时间轴往后拨一下,来到千禧年的后 4 年,2004 年「我的地盘听我的」成为了年轻人最潮流、最个性的语言之一,奥美为中国移动「动感地带」所做的数字营销战,为奥美中国赢得了第一座戛纳国际创意节狮子奖杯。

作为客户品牌,「动感地带」并不是中国移动的第一个品牌,早在「动感地带」之前,「全球通」和「神州行」两大品牌早已存在,可以说,中国移动当时非常精准地找到了年轻人这个用户群体。在「动感地带」推出的第一年,中国移动就快速发展了 1000 万「动感地带」用户。

在 2011 年,大卫·奥格威迎来百岁诞辰,奥美进驻中国 20 周年,作为创始人的奥格威应该十分欣慰。而在 2012 年奥美中国凭借 「可乐手」在戛纳国际广告节首次斩获奥美亚太区首个「全场大奖」。

这个新颖的平面设计是可口可乐公司「快乐畅开」营销活动的环节。「快乐畅开」旨在为全世界人们的生活带来欢笑和快乐。这个标新立异的设计清晰地传达了分享的概念。整个视觉表达仅仅由两个显而易见的独特元素组成:「动感飘舞的丝带」和「经典曲线瓶」, 它们都是可口可乐全球使用的商标元素。

不得不羡煞旁人的是,这个广告是一个 20 岁仍在设计学校念书的香港设计师完成的。

奥美中国的故事也差不多完结了,最后放一些我收集的奥美广告,或许里面的 idea 会让你拍案叫绝。

由香港奥美公司为肯德基制作的平面广告,利用鸡翅的外形和火焰联系起来,用视觉暗喻突出肯德基鸡翅的热,辣的卖点。

由泰国奥美公司为乐高制作的平面广告,小孩通过玩乐高玩具拼凑自己的梦想。

由巴西奥美公司为 Petz 创建的平面广告,宠物可以成为一个很好的伴侣,去倾听主人的说话。

Amnesty International,德国奥美公司为国际特赦组织制作的平面广告,难民看窗外的景象像在看电视一样,我们可以关掉它,但他们不能。

德国奥美公司为海洋守护者协会制作的平面广告,塑料垃圾正在淹没我们的海洋,他们吃什么你就吃什么。

美国奥美公司为海明威基金会制作的平面广告,再现了书本里的故事,《老人与海》、《死在午后》。

印度奥美公司为曼妥思公司制作的平面广告,恶魔附身都被酸得逃之夭夭。

法国奥美公司为可口可乐公司制作的户外广告,两只手的负空间形成了可口可乐最经典的曲线瓶。

由印度奥美公司为世界自然基金会制作的平面广告,利用树的外轮廓,拼凑出三只可爱的小动物,树木拯救野生动物,野生动物拯救树木。

日本奥美为 ADOT 制作的平面广告,语言可以消灭战争。

泰国奥美公司为 Poly-Brite 制作的印刷广告,高吸水性抹布,强调产品的卖点。

由泰国奥美公司为乐高制作的平面广告,对于任何大小的想象。

奥美中国为 Saky 设计的平面广告,刮掉顽固食物。

越南奥美为世界自然基金会制作的平面广告,犀牛角和人的指甲是完全一样的材料,还想要吗?

由巴西奥美为克拉罗制作的平面广告,只需要一个字母就能造成车祸,请不要开车发信息。


文章来源:优设    作者:研习社

返回、取消与关闭的使用逻辑

资深UI设计者

在页面导航栏中,常会见到返回、取消与关闭三者按钮。许多同学会弄混它们的使用逻辑,所以写一篇小文帮助各位梳理下。

返回和关闭

先抛开图标,我们回到功能本身的含义上看。如果我们不在产品的语境里,就单看「返回」和「关闭」这两个词,你首先会想到什么呢?

当我这么去问自己的时候,脑子里出现的并不只是零碎的词语,而是一些场景和画面。比如我走错路了,需要原路返回;公司复工了,我要返程回去。或者,睡觉时间到了,我该关闭电脑了;饭菜烧好了,我得把油烟机关掉,等等。

如果仔细去想的话就会意识到,语义衍生出来的,都是我们日常生活中的经验和对世界的认知。产品中使用的各种语言,不管是文字也好,或者图标图形也罢,一直都是以我们对它最本能的理解为基础的。所以只要你联想自己对「返回」和「关闭」的看法,就能知道它应该在什么样的产品情境中出现,以及它为什么会出现。

于是,很自然的,我们会把「返回」和「路径」联系在一起,所以「返回」在导航设计中不可或缺。并且「返」也预示着我们会回到之前的路径节点,整个过程是连续性的,不被切断的。而「关闭」就完全不一样了,它一般和我们的动作有关,是一个短暂性的操作,相比返回也显得更为独立。

根据我们对语义的判断,再结合实际产品中「返回」的场景,我们可以概括出「返回」和「关闭」的特征差异。

1. 返回

连续性:按照产品的页面层级顺次跳转。但存在特殊情况,因为有些产品定义的功能出入口是不一致的,在信息架构层级已经做了一定的优化,所以返回不一定会按原来的路径回去,可能会按产品既定的路径。比如网易云音乐歌曲播放页进入直播后返回不是到播放页。

整体性:在产品功能页面关联性较强的功能中,「返回」需要连接各个页面与层级之间的架构关系,因此「返回」作为操作节点,可以帮助产品功能的各个页面之间建立联系,维持产品的整体性。

2. 关闭

非连续性:用于产品中的临时内容或临时动作,比如弹窗或活动页,与上一级页面没有直接关系。

独立性:非产品原生内容或是产品内的独立内容。比如小程序、浏览器标签等。

3. 返回和关闭的使用场景

知道了返回和关闭的特征后,我们可以从两者的使用角度上再去梳理一下。

现在产品中关于返回和关闭有三种状态:

  1. 只有返回
  2. 只有关闭
  3. 返回和关闭同时存在

1 和 2 的情况很好理解,我们只要根据前面各自的特征去看就能够理清场景。

3 的情况会有特殊性,因为它同时具有返回和关闭这两种看起来相矛盾的特性。其实这是由内容决定的,当内容同时具有独立性和整体性时,就需要支持两种操作。如小程序可以作为一个独立功能,但其本身又可以看作是一个完整的小产品,具有自己的页面结构和页面层级。所以小程序对于它所属的产品,我们有关闭的需要,小程序内的页面导航又需要返回来实现。

除此之外,产品可能开始只有返回,后面临时出现关闭按钮,比如微博「疫情地图」中使用「小区疫情查询」和「7×24 小时疫情快讯」后会出现关闭功能(帮助用户快速退出)。

这里我们可以从连续性和非连续性的角度看,产品针对具有复杂层级和内容的页面设计了顺次(返回)和跳页(关闭)的导航方式,其中关闭随实际情境出现。以此为用户提供了更为灵活的导航路径,来同时满足用户逐级深入、连续返回浏览和选择性查看、临时关闭的需求。

取消和关闭

针对于「关闭」,它和「取消」会有重叠的含义,所以有时并不能很好地去区分这两个功能表达的应用场景。于是,我们可以借用之前的方式,先把「取消」单独拿出来理解。

一般来说,「取消」意味着行为过程中,还有后续行为,整个过程没有完成,当下后悔了,因此取消了当前操作。它更倾向于表达我们主动去做了什么改变,然后中途放弃了。

比如,想煮个饭,于是下了米,倒了水,定时,确认(取消),完成(关闭)。

这时候中间如果突然不想煮饭了,在定时之后,就停止当前行为,那就是取消。但点了确认并完成煮饭之后,这个行为就结束了,只能关闭。因此,它们之间就是行为上的差异。

就好比,打开微信公众号文章,内容已经加载出来,行为已经产生并结束,这时候左上角就一定是关闭。而发朋友圈的时候,左上角是取消,那是因为行为过程还在继续,没有发布,所以可以取消。而发布之后,就无法取消,想要关闭,也就只能删除这条朋友圈了。

所以在操作行为中的页面,左上角最好是使用「取消」。

当我们对词的含义有了进一步思考后,就可以去看它们在产品中的表现了。

比如广告的关闭、推荐内容的关闭。都是产品自身提供的内容,用户不想看到就选择关掉了,没有试图去改变什么。

包括内容页面,或者活动页面,被点开,且加载完成呈现出来之后,这个行为就结束了,没有取消的概念,只有关闭。

再比如,选择图片文件时的取消,微信发朋友圈、微博发帖时的取消等等,我们能发现都是用户主动采取了什么措施,但是又后悔了所以选择取消。

或者如游戏设置,就不适合用关闭,会让用户在理解上产在歧义,比如用户设置到一半,不想设置了,那现在关闭的话,设置是生效了么?所以用取消会更合适。

这些时候,不存在关闭的概念,因为没有内容可以关闭,只能是取消当前行为。如果使用关闭,与该场景下的用户行为不符,反而增加了用户对文案的理解成本。

简单来说,取消强调的是放弃改变,关闭强调的就只是抉择。

不过这里也有一个特殊例子,就是,微信公众号文章转发给好友,左上角是关闭,而钉钉里面内容转发给朋友,就是取消。为什么呢?

在一些特殊场景之下,「关闭」是包含「取消」的。

好比刚才煮饭的例子,现在的电饭煲很高级,如果在过程中不想继续了,拔掉电源就是完全关闭了,但同时这个行为也包含了人不想继续煮饭这个行为,想取消掉了,所以这时候关闭是包含取消的。它跟文章加载完成,已经呈现出来,是不一样的。

而上面这个微信与钉钉的例子,就存在这种包含关系。比如,内容已经加载完,要分享给好友,这时候加载出来的好友列表已经出现,只是选择发送给谁的问题,用户可以关闭已经加载完成的好友列表页面,或者理解为用户打算取消当前行为。

不过这样的设计并不建议大家将其定义为关闭,因为毕竟行为还在继续,使用取消反而更容易理解也更符合场景定义。

譬如,PC 的弹窗经常会同时出现叉(指代关闭)和取消,虽然操作的结果都是使弹窗消失,但是用户的操作目标是不一样的,事实上这里提供了两种选择,即我不想做决定,我要关掉弹窗,以及我决定现在不这么做,我要取消这个动作,这里的关闭其实就暗含了取消的动作。

在 PC 端,我们有足够的空间为用户提供不同的选择,给予用户充分的自主控制权,以满足他们对功能的不同期待。而在移动端,我们需要删减或合并功能,所以当用户同时产生重叠的诉求时,我们往往会选择当下最符合用户心境的功能,这是「场景细化」的结果。这也能解释为什么现在很多 PC 产品的弹窗中也只会保留取消,而不提供叉(指代关闭)的选择。因为用户面对功能不知所措、不做决定的情况已经越来越少,更多的用户已经明确地知道自己应该怎么做。

这就是「取消」和「关闭」的差异,以及移动产品对两者的取舍的根本原因。

同样的,有一些页面,取消和关闭都会用叉的图标来表示,只是在不同情境中,这个叉同样可以理解为取消,关闭,以及取消或关闭。差异点跟上述内容相同。

结语

返回、取消和关闭看起来简单,深入分析后又显得复杂,但相对复杂的分析都只是为了能简单地去运用。在这个问题中,每个人都可以从自己日常的经验出发,然后在产品不同的语境里去体会一个词语、一个图标背后隐藏着我们什么样的认知和使用的习惯。

那由这个问题延伸的,其实还有产品的导航方式,页面出入口的设计差异,产品中整体与独立,连续与非连续的内容结构,原生与非原生页面的差异等等。

小问题同样可以见大,但我们也不需要过度思考,本来问题的解读角度就是因人而异的,也无法面面俱到,上面的只是我的理解方式。设计还是需要回归到用户和产品的目标,再去结合场景和产品业务的使用模式才能得出合理有价值的方案。

文章来源:优设    作者:呆呆U理

方正集团濒临破产,以后字体能否免费用?

资深UI设计者

方正集团倒闭?

最近方正集团负债千亿,被银行申请破产重整的消息让众多设计师兴奋不已,心里暗自在想,那方正字库一万多款字体是不是就可以免费使用了?醒一醒,不太可能,身为设计工作者,尊重他人的设计和拥有版权意识是很重要的。

方正字库属于北京北大方正电子有限公司,而这个公司是方正集团的子公司。就算方正集团真的破产倒闭了,根据我国法律,方正字库何去何从也跟这两家公司的法人是否一致有关,如果一致,那么就可能被收购重组,如果不一致,那么就继续独立运营。关键是,无论是什么结果,方正字库里所有的字体都是有版权的,如果随意商用,就会导致侵权,乃至把整个公司都赔进去。

如何避免字体侵权

直接去网页搜索,便有数不清的方正字体侵权案例。大到电影和游戏的宣发,小到淘宝店铺的页面,只要你使用了方正字库的必须购买版权才可商用的字体,都有可能收到来自方正字库的律师函。那么该如何避免字体侵权呢?其实最好的方法就是使用免费可商用的字体,或者乖乖去买下字体的使用权。

一篇文章告诉你,该怎么判别字体是否侵权:

方正免费字体

如果你实在要免费用方正字库的字体的话,那么就选择「方正黑体简体、方正书宋简体、方正仿宋简体、方正楷体简体」这四种字体吧,已经向方正字库授权服务官方求证过,这四款字体可以直接免费商用,不需要书面授权。

免费可商用字体推荐

不过有那么多免费、适用度广、并且可以商用的字体,为什么要执着于方正呢?优设标题黑和优设好身体这两款字体,无论是做 banner、海报还是文字设计都很合适,还没拥有的设计师们快来下载。

优设标题黑:

优设好身体:

还有优设精心为大家挑选整理成的 2020 年免费可商用中文字体最全合集,链接给你们,正好需要的话,就快去下载使用。

字体网站推荐

最后,介绍两个可以查询和下载免费可商用字体的网站。

1. 字由网 

网站链接:https://www.hellofont.cn/home

第一个是字由网,虽然需要下载客户端激活字体进行使用,不过截至今日,字由拥有 511 款免费可商用字体,对比一下乱用字体可能产生的侵权费用和烦恼,还是下载客户端性价比比较高。

网站及使用介绍:

2. 猫啃网

网站链接:http://novicehou.gz01.bdysite.com/

第二个是猫啃网,是免费开源可商用的公益字体网站,截至今日,网站上共有 155 款字体,可供设计师们选择和下载使用。

文章来源:优设   

导航栏设计知识点

资深UI设计者

讲一个老东家的故事。一次产品迭代会上,老板在台上讲到打算重构 C 端产品框架,想重整标签栏的标签设定。可在讲到这一部分的时候卡壳了,迟迟说不出「标签栏」这个控件名,气氛有些尴尬。这时一名产品经理说道:底部导航栏!会议得以继续。

不全错,这么说也算能理解。控件在界面底部,能引导用户切换页面。但如果标签栏把导航栏的名字占了……那原本的导航栏应该叫什么呢?顶部标题栏?那导航栏里的内容控件又应该叫什么?左上角或者右上角的按钮?

接地气的名称让我们一听就懂,直到有一天你打算跳槽,你拿着自己的作品到下家面试,设计总监几个术语啪啪把你问得不知所云。这些「死控件」、「死栏目」在页面上不可或缺,在设计每一个页面时你以为对它们早已了如指掌,偏偏在关键时刻,它们却六亲不认了。

「我又不走形式主义,为什么一定要说专用名词呢?接地气的名称不是挺好吗,沟通。」很简单的道理,如果名词和概念都混淆不清,有没有花功夫在 UI 设计领域进行深度专研也就一目了然了,还何以谈论如何将它们运用自如呢?

这样的经历,让我产生了一个想法。是时候做一些知识内容沉淀与分享了,不能让更多的人走我踩过的坑。第一期我们便来讲一讲导航栏。

导航栏究竟在哪里

导航栏 Navigation Bar,也简称为 Navbar。一定会有不少刚入门的 UI 新人,在诸多的 Bar 控件中,难以区分它所指代的区域。

在 iOS 上,导航栏是指显示在应用程序顶部,位于状态栏下方的容器区域,层级应高于当前页面内容。

在安卓上,Google 公司在 Material Design 中也赋予了它同样的定义,但是却给了它另一个名称,顶部应用栏(Top App Bar)。

△ iOS与安卓的规范与命名区别

请务必要记住:导航栏是用于构架当前屏幕的内容,阐述当前屏幕的状态,并且起到连接父子级页面层次结构的作用。所以回到开头的小故事,为什么标签栏不能叫做底部导航,因为标签栏是构架了多个屏幕之间平级页面的内容切换,和「导航」的定义没有关系。

规范里告诉我们该怎么做 vs 实际项目我们该怎么做

一个基本的导航栏容器一般承载的信息可能会有:标题、导航按钮、内容控件按钮、其他控件(比如搜索栏、分页标签或分页控件等),千万别忘了还有分割线。(比如微信的导航栏)

1. 导航栏标题

时间倒退回 2017 年以前,这时候的移动端规范下的导航栏还是循规蹈矩的,样式单一。但随着 iPhone X 等一系列全面屏手机相继问世后,移动设备在屏幕高度上有了进一步的扩展,界面设计在一屏内的发挥空间也随之增加。iOS11 发布后,大标题导航栏设计风格兴起,随后被引入平台规范。

于是现在 iOS 与 Material Design 在导航栏上也都定义了两种导航栏标题规范,常规标题与大标题。

常规标题是指在高度为 88px(iOS@2x下)的导航容器中,居中放置一个当前页面的标题。标题字号一般为 34px-38px(34px 为 iOS 标准规范,但实际项目中可以尽量在不小于 34px 标准的情况下根据设计需求确定)。

△ 常规导航不同标题字号的案例及视觉效果

大标题是将导航栏高增加到 192px(iOS@2x),保留高度为 88px 的导航容器来承载内容控件按钮,将标题下坠居左。iOS 的标准规范定义大标题的字号为 68px。但由于英文有大小写区分,在视觉上有一定的层次表现,而中文因为缺少一定的层次结构,并且相同字号的中文视觉大小大于英文,所以大多数时候我们在进行大标题设计时,会适当缩小,一般为 56px-64px 居多。

△ 大标题不同标题字号的案例及视觉效果

大标题导航栏的优点毋庸置疑,页面留白更多,呼吸感更强,大气现代、格调更高,因为页面标题巨大,能够帮助用户快速确认当前所处位置。采用统一的大标题,让页面布局风格快速统一。但缺点也显而易见,因为增加了导航栏的高度,导致屏幕利用率降低,一些通过广告变现或更加注重一屏内内容呈现的应用便中和了常规导航与大标题导航的优缺点,进行了风格改进。

△ 改进的大标题案例

那我们如何在常规标题和大标题之间抉择呢?这可不单单是设计风格的问题,还受产品定位与功能的影响。苹果的设计师在 Apple Music 中实验并验证了一条结论——在内容非常丰富、层级结构较深的产品当中,大标题能够帮用户快速确认自己的位置。

所以我理解的适合使用大标题风格的产品一定是:突出内容呈现而不是功能繁琐的;产品定位更偏向于现代或文艺艺术的;需要快速统一界面风格的。而层级结构需不需要很深,这并不一定,我反而觉得功能越单一、产品体量级越轻的应用,越适合大标题。

所以如此看来,国内使用大标题成功的案例就为数不多了,这可能与中文字体还有国内 app 产品功能都比较繁琐的原因有关,真正做到了使用大标题快速帮助用户确认自己位置,并且结合了产品特性与风格的,我认为人人都是产品经理的移动端在这方面做得非常棒。

2. 导航按钮及内容控件按钮

iOS 规定导航按钮位置仅能用于放置返回按钮,可以添加一个层级的面包屑,帮助用户有效地明确当前页面层级;Material Design 中,不仅可以放置返回按钮,还另有作用,菜单图标-用于打开导航抽屉或者关闭图标-关闭工具栏。

△ iOS与安卓的导航按钮区域区别

这一点与 iOS 的定义有着天壤之别,iOS 非常明确地赋予了工具栏的定义,并且将导航栏和工具栏(Toolbars)彻底地分离开,典型案例就是 Safari。

△ iOS明确地将导航栏与工具栏分离开

在内容控件上 iOS 与 Material Design 也大相径庭,Material Design 不去限制你的内容控件多少,因为它提供了溢出菜单,并可以根据屏宽的变化,自适应释出和收纳溢出菜单中的控件。

而 iOS 则规定我们,要给内容控件按钮足够多的空间,必要的时候,隐藏导航栏标题也未尝不可。

那么真实的项目中,我们往往为了快速落地,会存在一稿适配双平台的情况。这时候我们应该遵从哪一个平台的规范呢?答案是:许多大厂的做法已经向我们验证,规范不分家。

在 iOS 诸多的应用中溢出菜单早已普及,尽管这是 Material Design 提出的设计理念。

△ Material Design的溢出菜单也被运用在iOS端

虽然国内遵从 Material Design 进行 Android 应用设计的情况相对较少,但它提供的设计理念与方案却并不局限在安卓平台。

3. 分割线

分割线只是一种体现形式,我想要表达的是,别忘记区分导航栏与内容界面的视觉层级关系。Matetial Design 提醒我们,顶部应用栏可以与内容位于同一高度,但滚动时,请增加导航栏的视觉高度,让内容在其后方滚动。而 iOS 则默认采用了背景模糊的方式区分了导航栏与内容区域的层级关系。

△ 区分导航栏与内容区域的层级关系

缺少视觉分割会让用户分不清导航栏与内容界面,它们看起来会更像一个平级。对用户视觉区分内容主次其实是极不友好的。

4. 其他控件

关于其他控件,iOS 只在规范中提及到了分页控件。苹果设计师考虑到部分场景在当前页面中还存在信息层级结构划分,此时建议可以在导航栏中使用分段控件。

但国内的应用程序早已将导航栏容器的作用发挥到,基于导航栏层级始终高于内容区域的特性,我们通常可以将分段控件、分页标签、搜索栏等等用户可能随时使用的工具放在导航栏中。

△ 导航栏通常会承载的其他控件

总结

导航栏是几乎每一个界面都必定存在的控件,正因为无法轻易删减,逃不掉就必须用好它,不然很容易沦为页面的减分项。

设计好导航栏不仅仅是视觉上的工作,表现的方式、承载的按钮与组件、滚屏时的组合操作还能给用户带来极大的体验增益。

文章来源:优设    作者:

前端基础-HTML文字滚动

seo达人

1.文字滚动

<html>

<head>

<title>我的第一个页面</title>

</head>

<body>

<marquee behavior="scroll" direction="up" height="30" style="overflow:hidden;" scrollamount="1" width="300" onMouseOver="stop()" onMouseOut="start()">

雷电黄色预警!<br />

大雨黄色预警!<br />

</marquee>

</body>

</html>



direction:方向



up:上 down:下 left:左 right:右



scrollamount:滚动速度-----------------scroll:滚动 amount:数值



width:宽度 height:高度



onmouseover:当鼠标移上去



onmouseout:当鼠标离开



stop():停止



start():开始



behavior:



scroll 循环滚动



alternate 来回滚动



slide 滚动一次停止




简单的验证跳转

seo达人

一.有关于内置对象的作用域

主要说明2个对象,request,session

1、request 对象

request 对象是 javax.servlet.httpServletRequest类型的对象。 该对象代表了客户端的请求信息,主要用于接受通过HTTP协议传送到服务器的数据。(包括头信息、系统信息、请求方式以及请求参数等)。

request只在2个页面之间传递,每一次新的请求都会新建一个request对象,也就是说可能会request对象不一致导致空指针异常。

2、session 对象

session 对象是由服务器自动创建的与用户请求相关的对象。服务器为每个用户都生成一个session对象,用于保存该用户的信息,跟踪用户的操作状态。session对象内部使用Map类来保存数据,因此保存数据的格式为 “Key/value”。 session对象的value可以使复杂的对象类型,而不仅仅局限于字符串类型。

session对象在整个会话只有一个,也就是说session对象的数据会一直保留直到主动进行数据更改。



二.表单提交

在index.jsp中使用form进行数据的提交,action的目标是check.jsp,method是post



三.验证跳转

当form提交信息后交给check.jsp验证,使用getParameter来得到form的信息,并使用setAttribute保存。在check.jsp中判断账号密码是否正确后,使用



<jsp:forward page=".jsp"></jsp:forward>

1

进行跳转,
.jsp是想要跳转的页面路径。



四.详细代码

index.jsp



<%@ page language="java" import="java.util." pageEncoding="UTF-8"%>

<%

String path = request.getContextPath();

String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

%>



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <base href="<%=basePath%>">

    

    <title>登陆</title>

    

<meta http-equiv="pragma" content="no-cache">

<meta http-equiv="cache-control" content="no-cache">

<meta http-equiv="expires" content="0">    

<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">

<meta http-equiv="description" content="This is my page">

<!--

<link rel="stylesheet" type="text/css" href="styles.css">

-->



  </head>

  

  <body>



   <form action="check.jsp" method="post">

请输入用户名:

<input type = "text" name = "username"><br/>

请输入密码:

<input type = "password" name = "passwd"><br/>

<input type="submit" name="submit" value="登录">

</form>

 

  </body>

</html>





check.jsp



<%@ page language="java" import="java.util.
" pageEncoding="UTF-8"%>

<%

String path = request.getContextPath();

String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

%>



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <base href="<%=basePath%>">

    

    <title>验证</title>

    

<meta http-equiv="pragma" content="no-cache">

<meta http-equiv="cache-control" content="no-cache">

<meta http-equiv="expires" content="0">    

<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">

<meta http-equiv="description" content="This is my page">

<!--

<link rel="stylesheet" type="text/css" href="styles.css">

-->



  </head>

  

  <body>

   

<%

  String username = (String)request.getParameter("username");

  String passwd = (String)request.getParameter("passwd");

  request.setAttribute("username", username);

  request.setAttribute("passwd", passwd);

 

  if(username.equals("admin")&&passwd.equals("123")){

%>

<jsp:forward page="succeed.jsp"></jsp:forward> 

<%}else{ %>

<jsp:forward page="failed.jsp"></jsp:forward> 

<%} %>

  </body>

</html>



succeed.jsp



<%@ page language="java" import="java.util." pageEncoding="UTF-8"%>

<%

String path = request.getContextPath();

String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

%>



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <base href="<%=basePath%>">

    

    <title>登陆成功</title>

    

<meta http-equiv="pragma" content="no-cache">

<meta http-equiv="cache-control" content="no-cache">

<meta http-equiv="expires" content="0">    

<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">

<meta http-equiv="description" content="This is my page">

<!--

<link rel="stylesheet" type="text/css" href="styles.css">

-->



  </head>

  

<body>

<% 

String username = (String)request.getAttribute("username");

String passwd = (String)request.getAttribute("passwd");



%>

<%=username %>登陆成功



</body>

</html>



failed.jsp



<%@ page language="java" import="java.util.
" pageEncoding="UTF-8"%>

<%

String path = request.getContextPath();

String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

%>



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <base href="<%=basePath%>">

    

    <title>登陆失败</title>

    

<meta http-equiv="pragma" content="no-cache">

<meta http-equiv="cache-control" content="no-cache">

<meta http-equiv="expires" content="0">    

<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">

<meta http-equiv="description" content="This is my page">

<!--

<link rel="stylesheet" type="text/css" href="styles.css">

-->



  </head>

<body>

<% 

String username = (String)request.getAttribute("username");

String passwd = (String)request.getAttribute("passwd");



%>

<%=username %>登陆失败

</body>

</html>



五.注意事项

在jsp中使用form提交表单不能直接进行跳转,否则操作不慎就容易出现空指针异常,建议交由单独的跳转页面处理


【HTML&&CSS】CSS解决高度塌陷问题&&实现简单的导航效果

seo达人

下面这段代码是实现简单的导航效果:



在这里插入代码片<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<title></title>

<style>

*{

   margin:0px;

   padding:0px;

   list-style:none;

}

.nav{

width:700px;

margin:100px auto;



}



.nav ul li{

float:left;

margin-right:5px;

}



.nav ul li a{



width:100px;

height:30px;

color:#fff;

display:block;

line-height:30px;

margin-right:5px;

text-decoration:none;

background:red;

text-align:center;



}

.clearfix:after {

content: ".";

display: block;

height: 0;

clear: both;

visibility: hidden;

}

.nav ul li a:hover{

background:yellow;

color:blue;

text-decoration:underline;

}



</style>

</head>

<body>

<div class="nav">

<ul class="clearfix">

<li><a href="#">导航</a></li>

<li><a href="#">导航</a></li>

<li><a href="#">导航</a></li>

<li><a href="#">导航</a></li>

<li><a href="#">导航</a></li>

</ul>

</div>

</body>

</html>





实现效果如图:

容易犯错的地方:刚开始我把display:block;属性写在最前面,结果一直出不来,后来发现display属性应该放在height和width属性后面



我还学到一个知识点:关于父元素塌陷问题:



在文档流中,父元素的高度默认是被子元素撑开的,也就是说父元素多高,子元素就多高



但是为子元素设置浮动以后,子元素就会完全脱离文档流,此时将会导致子元素无法撑起父元素的高度,导致父元素的高度塌陷



由于父元素的高速塌陷了,则父元素下所有的元素都会向上移动,这样会导致页面布局混乱



  所以我们在开发中一定要避免出席那高度塌陷的问题,这时候我们可以将父元素的高度写死,这样可避免塌陷的问题出现,但是一当高度写死,父元素的高度将不能自动适应子元素的高度,所以这种方式是不推荐使用的

1

解决的方案:

根据W3C标准,在页面中元素有一个隐含的属性叫做Block Formatting Context



方案一:*(设置zoom为1和overflow为hidden)

当开启元素的BFC后,元素会有以下特性:



父元素的垂直外边距不会和子元素重叠

开启BFC的元素不会被浮动元素所覆盖

开启BFC的元素可以包含浮动的子元素

那如何开启元素的BFC呢?



设置元素浮动

设置元素的绝对定位

设置元素为inline-block(但是设置inline-block可以解决问题,但是会导致宽度丢失,所以不推荐使用这种方式)

将元素的overflow设置为一个非visible的值(推荐方式:将overflow:hidden这个是副作用最小的开启BFC方式,所以可以这么说,以后若是再塌陷,就给父元素加上overflow:hidden属性)

但需要注意的是:



在IE6以及以下的浏览器中并不支持BFC,所以使用这种方式并不能兼容IE6,在IE6中虽然没有BFC,但有另一个隐藏属性叫做hasLayout该属性作用和和BFC类似。但在IE6浏览器可以通过开hasLayout来解决问题

开启方式很多,我们可以直接用一种副作用最小的直接将元素的zoom设置为1,比如父元素是box1,我们可以在父元素中加上zoom:1;



在这里解释一下zoom表示放大的意思,后边跟着一个数值,写几就可以将元素放大几倍,所以zoom:1表示不放大元素,但是可以通过该样式可以开启hasLayout.

但需要注意的是zoom属性放IE6可以,别的浏览器比如Chrome就不行



****所以重头戏来了:若我们想要兼容所有浏览器?


  1. 设置:zoom:1;
  2. 设置overflow:hidden;



    两者缺一不可(zoom这个样式,只在IE中支持)

    1

    方案二:(添加一个空白的div,参考下面的box3)

    我们可以直接在高度塌陷的父元素的最后,添加一个空白的div,由于这个div并没有浮动,所以它是可以撑开父元素高度的,然后再对其清除浮动,这样可以通过这个空白的div撑开父元素的高度,基本没有副作用

    例如:

    *



    <style>

     .box1{border:1px solid red;}

     .box2{

     width:100px;

     hejght:100px;

     background-color:blue;

     }

     .box3{clesr:both;}/
    清除两端浮动对当前元素的影响/

     

    body里面是:

    <div class="box1">

        <div class="box2"></div>

             <div class="box3"></div>

      </div>

      (这里面box3是我们自己添加用来解决高度塌陷问题的)



    但使用这种方法虽然可以解决问题,但会在页面中产生多余的结构,所以此时方法三就出来了,这种方法我们最推荐,因为他没有副作用



    方法三:(通过after伪类)

    我们先来看一段代码:



    <style>

    .clearfix:after{

                       content:" ";/
    添加一个内容*/

                       display:block;

                       clear:both;

                       

    }

    </style>

    <body>

    <div class="box1 clearfix">

    <div class="box2"></div>

    </div>

    </body>



    我来总结一下方法三:

    我们可以通过after伪类向元素的最后添加一个空的块元素,然后对其清楚浮动,这样做和添加一个div原理一样,可以达到一个相同的效果,而且不会在页面中添加多余的div,这是我们最推荐使用的方式,几乎没有任何副作用




uniapp中的一个完全相似Vue-router的路由插件

seo达人



1.引入

三种引用方式

第一种 npm安装

项目根目录命令行执行



npm install uni-simple-router

1

第二种 插件市场(使用HBuilderX导入插件)



第三种 ZIP下载 解压



2.项目中引入



import Vue from 'vue'

import {RouterMount} from 'uni-simple-router';

import Router from './router'

Vue.use(Router)

//...后续代码



引入之后就开始我们的正式使用。

第一步先在项目的根目录下创建一个router文件夹。

格式为:



router

|---modules

|---index.js

|---index.js



router中的modules文件夹是用来放路由表模板的。modules中的index.js内容为



const files = require.context('.', false, /.js$/)

const modules = []



files.keys().forEach(key => {

  if (key === './index.js') return

  const item = files(key).default

  modules.push(...item)

})



export default modules



这个文件用来把同目录下的js文件读取并整合所有路由。

在这里创建的js文件代码示例:



const home = [

{

        //注意:path必须跟pages.json中的地址对应,最前面别忘了加'/'哦

      path: '/pages/home/index',

      aliasPath:'/',  //对于h5端你必须在首页加上aliasPath并设置为/

      name: 'index',

        meta: {

        title: '首页',

    },

    },

    {

    path: '/pages/home/list',

        name: 'list',

        meta: {

        title: '列表',

    },

},

]

export default home



第二步配置router下的index.js



import modules from './modules'

import Vue from 'vue'

//这里仅示范npm安装方式的引入,其它方式引入请看最上面【安装】部分

import Router from 'uni-simple-router'



Vue.use(Router)

//初始化

const router = new Router({

    routes: [...modules]//路由表

});



//全局路由前置守卫

router.beforeEach((to, from, next) => {

  next()

})

// 全局路由后置守卫

router.afterEach((to, from) => {

})

export default router;



第三步 就是配置main.js



import Vue from 'vue'

import App from './App'

import router from './router'

import { RouterMount } from 'uni-simple-router'



App.mpType = 'app'



const app = new Vue({

...App

})

//v1.3.5起 H5端 你应该去除原有的app.$mount();使用路由自带的渲染方式

// #ifdef H5

RouterMount(app,'#app');

// #endif



// #ifndef H5

app.$mount(); //为了兼容小程序及app端必须这样写才有效果

// #endif



这样你的路由就配置好了。



如果不想繁琐的配置modules下的文件,可以用webpack自动构建路由表

安装



npm install uni-read-pages

1

配置 vue.config.js (可能需要手动创建)



const TransformPages = require('uni-read-pages')

const tfPages = new TransformPages({

//如果你需要获取更多参数,那么请配置参数!

includes:['path','name','meta']

})

module.exports = {

    configureWebpack: {

        plugins: [

            new tfPages.webpack.DefinePlugin({

                ROUTES: JSON.stringify(tfPages.routes)

            })

        ]

    }

}



然后去pages.json里面更改配置,加入所需要的内容

最后配置路由表



import Vue from 'vue'

//这里仅示范npm安装方式的引入,其它方式引入请看最上面【安装】部分

import Router from 'uni-simple-router'



Vue.use(Router)

//初始化

const router = new Router({

    routes:ROUTES //路由表

});



//全局路由前置守卫

router.beforeEach((to, from, next) => {

  next()

})

// 全局路由后置守卫

router.afterEach((to, from) => {

})

export default router;




Js闭包

前端达人

所谓闭包就是说,闭包是指有权访问另外一个函数作用域中的变量的函数.可以理解为(能够读取其他函数内部变量的函数)

闭包的三大特点为(既是优点,也是缺点):

1,函数作用域空间不会被销毁

优点是:空间中的内容,永远存在

缺点是:占用大量的内存空间

2,可以从外部访问函数内部的变量

优点是:使用变量数据方便

缺点是:容易泄露数据信息

3,保护私有作用域变量

优点是:确保私有作用域变量一直存在

缺点是:占用内存空间 闭包的最大问题是:有可能造成占用大量的内存空间,降低程序的执行效率,甚至有可能造成数据溢出或者是数据泄露 因为为了保护数据的安全性,特殊情况下,才会使用闭包举例来说:

// 记数器:



//全局变量  全局变量降低函数的独立性

1

// var count = 0;

// function add(){

// return count++;

// }

// console.log(add());

// console.log(add());

// console.log(add());



//局部变量  函数执行外  局部变量销毁

1

// function add(){

// var count = 0;

// return count++;

// }

// console.log(add());

// console.log(add());

// console.log(add());



//plus定义在add的内部,可以访问add局部变量count

//f为一个全局变量,通过赋值后,成为add的返回值,也就是plus方法

//访问到了add中的局部变量count

//所以count虽然是局部变量,但不允许被销毁,plus就是闭包

1

2

3

4

// function add(){

// var count = 0;

// function plus(){

// return count++;

// }

// return plus;

// }

//

// var f = add();

//

// console.log(f());

// console.log(f());

// console.log(f());



//变身

1

// function add(){

// var count = 0;

// return function(){

// return count++;

// }

// }

//

// var f = add();

//

// console.log(f());

// console.log(f());

// console.log(f());



//继续变身

1

// var f = (function (){

// var count = 0;

// return function(){

// return count++;

// }

// }());

//

// console.log(f());

// console.log(f());

// console.log(f());

//JS中,没有块作用域,但是在闭包的写法里,可以体现出来。

function outerFunc(){

var outVar = 10;

var innerF = function (){

var innerVar = 20;//该变量虽然隶属于outerFunc内部,但是它的作用域范围只在innerF对应的函数体内,属于块级作用域

}

alert(innerVar);

return innerF;

}



闭包的作用:

正常函数执行完毕后,里面声明的变量被垃圾回收处理掉,但是闭包可以让作用域里的 变量,在函数执行完之后依旧保持没有被垃圾回收处理掉



可以读取函数内部的变量

让这些变量的值始终保持在内存中。

增加块级作用域

总结:

1、 闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量。

2、 闭包的缺点就是常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。

3、不必纠结到底怎样才算闭包,其实你写的每一个函数都算作闭包,即使是全局函数,你访问函数外部的全局变量时,就是闭包的体现。







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

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

原文链接:https://blog.csdn.net/fie_ld/article/details/104595753

Echarts饼图之数据展示

seo达人

Echarts饼图之数据展示

1、组件简介

ECharts,一个使用 JavaScript 实现的开源可视化库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等),底层依赖矢量图形库 ZRender,提供直观,交互丰富,可高度个性化定制的数据可视化图表。


官网链接:Echarts官网

W3C教程:W3C–Echarts教程


2、前端代码实现

首先,下载库,并引入到项目文件;


话不多说,直接上代码。


/* 封装的组件 HTML代码

<div class="echart-wrap-box">

   <div class="echart-content"></div>

</div>

*/

let echarts = require("echarts/echarts.min");


defaults: {

  option: {

      echartsObj: {},

      tooltip: {//提示框浮层内容。

          trigger: 'item',//数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用。

          formatter: "{b} : {c}万人"//提示框浮层内容格式器,{a}(系列名称),{b}(数据项名称),{c}(数值), {d}(百分比)

      },

      //如果系列没有设置颜色,则会依次循环从默认列表中取颜色作为系列颜色。

      color: ["#369DFD", "#32C8CA", "#49C872", "#F6CE36", "#EE607A", "#935CE3", "#3436C7", "#3E4D86"],

      legend: {//图例组件。

          orient: 'vertical',//图例列表的布局朝向:垂直的

          x: '80%',//图例组件离容器左侧的距离。

          y: '60%',//图例组件离容器上侧的距离。

          // width: 100,

          textStyle: {},//图例文字的样式

          // left: 'right',//图例组件离容器左侧的距离。

          top: 'center',//图例组件离容器上侧的距离。

          data: [],//右侧图例小组件信息数据

      },

      series: [{//饼图信息

          name: '',

          type: 'pie',//饼状图

          radius: 140,//饼图的半径。

          center: ['50%', '50%'],

          minAngle: 5,  //最小的扇区角度(0 ~ 360),用于防止某个值过小导致扇区太小影响交互

          label: {//展示文本设置

              normal: {

                  show: true,

                  formatter: "{b} : {c}万人",//视觉引导线内容格式器,{a}(系列名称),{b}(数据项名称),{c}(数值), {d}(百分比)

              },

              emphasis: {    //文本样式

                  show: true,    //展示

                  textStyle: {    //文本样式

                      fontSize: '16',

                      fontWeight: '600',

                  }

              }

          },

          labelLine: {//视觉引导线设置

              normal: {

                  show: true

              }

          },

          data: [],//饼状图信息数据,value(数量)和 name为默认数据;

          itemStyle: {

              emphasis: {

                  shadowBlur: 10,

                  shadowOffsetX: 0,

                  shadowColor: 'rgba(0, 0, 0, 0.5)'

              }

          }

      }],

  },

  onInit(event) {

      vm = event.vmodel;            

      let data;//假设这里通过ajax获取到了需要展示的数据;

      if (data.length == 0) {

          return

      }

      data = data.sort((a, b) => { return b.number - a.number });//数据根据数量number从大到小排序


      if (data.length > 7) {//从大到小的第八个新增粉丝数量的年份 开始统一归为 其他年份新增粉丝数量

          let arr = data.slice(7);

          let num = 0, rate = 0;

          for (let i = 0; i < arr.length; i++) {//第七个之后累数量和比率

              num += Number(arr[i].number);

              rate += Number(arr[i].rate);

          };

          let objOtherYear = {

              value: num,

              name: '其他年份__nana新增粉丝数量',

              rate: rate

          };

          let arr2 = data.slice(0, 7);

          arr2.push(objOtherYear);

          data = arr2;

          data = data.sort((a, b) => { return b.number - a.number });//数据根据数量number从大到小排序

      }


      this.option.series[0].data = [];

      this.option.legend.data = [];

      for (let i = 0; i < data.length; i++) {

          let seriesData = {

              value: 0,

              name: '',

              rate: ''

          };

          seriesData.value = data[i].number;

          seriesData.name = data[i].year;

          seriesData.rate = data[i].rate;

          this.option.series[0].data.push(seriesData);//给饼图赋值数据


          let legendData = {

              name: '',

              icon: 'circle',//强制设置图形为:圆形

              textStyle: {

                  color: '#000'

              }

          }

          legendData.name = data[i].year;

          this.option.legend.data.push(legendData);//给图例组件赋值数据

      }

  },

  callFun: avalon.noop,//点击饼状图后的回调

  isClickEchartsOUt: avalon.noop,//是否为饼图外的点击,父组件进行判断后传过来

  onReady(event) {

      this.echartsObj = echarts.init(event.target.children[0]);//初始化

      this.echartsObj.setOption(this.option);


      $(window).resize(() => {

          this.echartsObj.resize();

      });


      let dataIndex;//保存选中扇区的序号

      let _this = this;


      this.$watch('isClickEchartsOUt', () => {

          if (this.isClickEchartsOUt) {//如果不是饼状图扇区的点击,则取消选中;

              _this.echartsObj.dispatchAction({

                  type: 'pieUnSelect',//取消选中指定的饼图扇形。

                  // 可选,系列 index,可以是一个数组指定多个系列

                  seriesIndex: 0,

                  // 可选,数据的 index

                  dataIndex: dataIndex,

              })

          }

      });


      // 处理点击饼图内部的事件

      this.echartsObj.on('click', function (params) {


          if (params.dataIndex != dataIndex) {//如果不是前一次选中的扇区,则取消选中

              _this.echartsObj.dispatchAction({

                  type: 'pieUnSelect',//取消选中指定的饼图扇形。

                  // 可选,系列 index,可以是一个数组指定多个系列

                  seriesIndex: 0,

                  // 可选,数据的 index

                  dataIndex: dataIndex,

              })

          }


          dataIndex = params.dataIndex;


          _this.echartsObj.dispatchAction({

              type: 'pieSelect',//选中指定的饼图扇形。

              // 可选,系列 index,可以是一个数组指定多个系列

              seriesIndex: 0,

              // 数据的 index,如果不指定也可以通过 name 属性根据名称指定数据

              dataIndex: dataIndex,

          })


          vm.callFun(params);//回调,传点击获取到的数据给父组件

      });

  },

  onDispose() {}

}


日历

链接

个人资料

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

存档