首页

需求评审后,产品经理要干的6件事

涛涛

有些产品经理会陷入这种误区——需求评审做完了,自己就可以放羊不管了。而本文则认为需求评审完,产品经理还要做这六件事。

需求评审完,产品经理还要干的6件事

1. 确认需求评审的遗留问题并同步各方

2. 制定详细&责任到人的项目计划

3. 完成文案设计

4. 按照项目计划,协同各方,往前推进,关键环节必须与各方确认。关键环节包括:

  • 1)交互评审
  • 2)视觉评审
  • 3)推进联调进度
  • 4)推进测试进度
  • 5)项目showcase
  • 6)项目发布

5. 准备项目review

6. 开始下个需求的方案设计和需求文档准备

这六件事具体怎么做?

产品经理A:需求终于评审完了。有种放飞的感觉,可以休假,去浪了!

产品经理B:你说真的吗?为什么我评审完,还一直在被开发、测试、法务、财务穷追不舍?

产品经理C:你说真的吗?为什么我评审完,从来都是我在穷追不舍开发、测试、法务、财务?

产品经理D:你们开玩笑的吧?就我这么惨!我不但要紧追不舍开发、法务、测试、法务、财务,还要被老板、被客户穷追不舍。

产品经理A、B、C:哥们,来讲讲,最喜欢听惨兮兮的故事了。你的伤痛最能抚平我的内心。

产品经理D:好吧。需求评审只讲清楚了产品的骨架、细节,让各方开始投资源。评审完,产品经理还有一堆事要推进,没法放羊。

要跟的事情主要有下面6件:

1. 确认需求评审的遗留问题并同步各方

需求评审总有一些遗留问题要进一步确认,而后同步给各方。我不是圣人,有时候有些问题或者细节没想到,评审的时候,大家提出来了,得赶快明确。

有时候需求评审中还有很大的bug没想到,必须快速解决,要在开发没动工前,都捋顺。要不然变成需求变更,或者上线后被推倒重来,欲哭无泪。

我这种求生欲这么强,也没人罩着的,必须狠命把需求做到95分以上。100分也不太敢说,毕竟众口难调。

2. 制定详细&责任到人的项目计划

产品经理还得身兼项目管理,项目管理从来都是事有轻重、事无巨细,难以假手他人。虽然我会尽可能调动大家的积极性,让大家自驱管理项目,但还得牵扯不少精力。

项目管理的关键点:明确项目计划、关键节点、每个关键节点的负责人、验收方案。

比如什么时候交互评审、视觉评审、联调、showcase、发布?分别是谁主要牵头负责,哪些人需要参与。

为了防止项目延期,每个节点都还得提前赶。真是操碎了心。

3. 完成文案设计

文案从来不是随便写写。文案是和客户交流的重要途径,整几个客户看不懂的文案上去,后面客户咨询搞死人!

文案设计除了客户视角之外,也不是自己想怎么写就怎么写,还要和法务、客服团队沟通。因为文案被客户投诉的案例,又不是没有。

还有啊,我的产品有3种语言,简体中文、繁体中文、英文,虽然每种语言有专门的文案设计师,但得跟他们说清楚,也要花不少时间、精力。

当然,也有很多产品经理,不管文案这种小事。可我觉得文案体现了产品经理最基本的素养,是产品的底子

4. 按照项目计划,协同各方,往前推进,关键环节必须确认

关键环节有6个:

1)交互评审

一般来说会由交互设计师发起,开发、测试、法务、财务都要参与。

这样能保证大家在说同一件事情,避免我要的是头牛,结果开发给了头驴。

如果设计师项目参与度低,交互评审还得我自己上。哪里缺人,我就得到哪补坑。

2)视觉评审

一般来说,交互和视觉评审会一起。

有时候项目很复杂,或者交互、视觉分工明确,那就得分开了。

通常由视觉设计师发起。同样,如果视觉设计师参与度低的话,我还是得补坑。

3)推进联调进度

联调是很容易扯皮的环节,大家来自不同域、不同职能团队,各有各的小九九,所以得盯着,避免联调成为坑王。

4)推进测试进度

进入到测试就意味着开发的七七八八了,当然有时候为了压缩项目周期,开发、测试会阶段性并行。

除了测试进度,还得关注测试发现的问题,可能开发还得返工,也可能会发现需求评审中大家都没有注意到的问题,得及时补救。

5)showcase

Showcase,说白了就是项目验收。

验收前,得先列出来要验收哪些内容,主流程、分支流程、逆向流程、重大关键节点。Showcase,也有可能发现新的问题,但基本上要避免在showcase环节发现重大问题,不然就得重大需求变更了。

showcase有时候由测试主导,有时候没资源,我得自己上。

6)项目发布

如果一路顺利,就该发布项目了。

项目发布计划虽然也是之前就定好的,但要考虑的方方面面也还挺多的,可以看之前的文章《项目发布要考虑的因素》。

总而言之,要和各方沟通好,要保证项目顺利发布呦。

5. 准备项目review

项目终于上线了,可我得天天得看客户反馈,看数据,跟客户聊,跟业务聊,准备复盘review。

产品狗似乎永远都在准备复盘、复盘中、复盘后反思的路上。

6. 开始下个需求的方案设计和需求文档

项目通常是并行的。在需求评审完后,我已经开始下一个需求的研究、设计了。

开发资源从上一个需求释放出来的时候,产品经理肯定得把下一个需求方案设计好,开始新的需求评审,妥妥的做好资源衔接。资源一旦释放出来,下次想要资源,难上加难啊。

产品也需要持续迭代,让客户感受到,我们的产品在成长、进步,给人希望。

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

以人为中心的设计指南(一)

鹤鹤

前言


《以人为中心的设计指南》是我翻译的第二本完整的设计书籍。在我开始广泛的阅览国外优秀的设计团队、设计公司的沉淀输出后,收获颇丰。我意识到很多年轻的设计师尤其是传统意义上的UI,苦于进阶无门,很难系统的去学习设计理论、设计方法以及设计流程,无法系统化梳理设计知识,就只能在有限的设计范围内修修补补,就像你在局限于视觉时没有意识到体验,在忠实于体验时又忽略了商业,总是无法全面的考虑和输出设计方案,这是源于没有系统化的学习。


国外的人机交互、体验设计领域的确发展较早,有着大量的理论和方法的沉淀,国内各大设计团队虽然也开始持续输出一些本土化的内容,但仍然摆脱不了系统化这个问题。因此我从今年开始,就有了翻译国外设计论论体系及对应的成熟可用的设计方法的冲动。如果你读了我往期的文章,你应该了解到了设计思维的五个步骤、了解了用户体验的七要素、可用性方法以及众多可操作的实践方法。


我翻译的内容既有各大设计机构无私分享的内容,也有我自费购买的设计课程,我希望为大家带来一些真正持续影响设计生涯的内容,要实现这一目标,软件技法做不到,只有思维方法、系统化知识可以做到。


本次翻译的《以人为中心的设计指南》是IDEO出产的一本设计工具书,包括具体的设计思路,规范的设计流程,以及各种关键设计原则。它将结合实例,教授设计师如何解决问题,如何以人为本的解决复杂问题。


本书内容量较大,共有四大模块,及73个小章节,我将以连载的形式发布译文,完整翻译后,为大家排版一份PDF格式的电子书,分享给读者,也分享给国内的所有设计师,每个人都可以尽一份力让国内的涉及环境变得更好。


本篇文章主要翻译介绍部分和第一模块的7个小节(标红部分),阐述了IDEO团队在设计过程中一直坚守的心态。下面开始正文。



介绍


以人为中心的设计师意味着什么?
拥抱以人为本的设计意味着相信所有的问题,即使是那些看似棘手的问题,比如贫困、性别平等。此外,这意味着相信每天面对这些问题的人是掌握答案的人。以人为本的设计为任何类型的问题解决者提供了与社区与用户一起设计的机会,深入了解我们所服务的人,构思各种想法,并根据人们的实际需求创造创新性的解决方案。
在IDEO,我们几十年来一直使用以人为中心的设计来创造产品、服务、体验和社会企业,这些产品、服务、体验和企业之所以被采纳和接受,是因为我们把人们的生活和诉求放在核心位置。社会各个领域的创新时机已经成熟,我们已经一次次证明我们的方法行之有效。作为一名以人为中心的设计师,你要相信,只要你坚持从别人身上学到的东西,你的团队就能找到世界需要的新解决方案。有了这份实地指南,你现在就拥有了将这种信念变为现实所需的工具。

接受不同的心态
以人为中心的设计师不同于其他的问题解决者——我们修修补补,不断测试,我们一开始就失败了,而且经常失败,我们花了大量的时间但可能仍然不知道问题的答案。然而,我们勇往直前。我们是乐观主义者和创造者,是实验者和学习者,我们感同身受,不断重复,我们在意想不到的地方寻找灵感。我们相信解决方案就在那里。
通过专注于我们的目标群体并提出正确的问题,我们将一起达成目标。我们会想出很多点子,有些行得通,有些行不通。我们把我们的想法具体化,这样我们就可以进行测试。


然后我们提炼它们。最终,我们的方法等同于疯狂的创造力,不断地推动创新并给予我们自信,它将我们引向我们开始时从未意识到的解决方案。现在,我们要分享我们的设计哲学和心态。
让我们与众不同的七种心态:同理心、乐观、迭代、创造自信、实践、接受不确定性,以及从失败中学习。

理解的过程
以人为中心的设计并不是一个完美的线性过程,每个项目都有自己的特点,但无论你面临什么样的项目,你都将经历三个主要阶段:灵感、构思和实现。通过依次采取这三个阶段,你将与你为之设计的用户产生深刻的理解;你会弄清楚如何将你学到的东西变成设计新解决方案的机会;在最终将你的产品正式上线之前,你会建立并测试你的想法。在IDEO,我们使用以人为中心的设计来处理大量的设计挑战,尽管我们的项目涵盖社会企业到传播活动到医疗设备各个领域,但这种创造性解决问题的特殊方法每次都能帮助我们度过难关。

灵感
在这个阶段,你将学习如何更好地理解别人。你会观察他们的生活,听到他们的诉求和愿望,并逐渐加深你对这个设计挑战的理解。
构思
在这里,你将理解你所了解的一切,产生大量的想法,确定设计的机会,并测试和改进您的解决方案。
实现
现在是你把你的解决方案带到现实中的机会。你将弄清楚如何把你的想法推向市场,以及如何最大限度地发挥它在世界上的影响力。


使用工具
虽然没有哪两个以人为中心的设计项目是完全相同的,但是我们使用相同的设计流程和工具为每个项目进行设计。


例如,为了与我们要服务的人建立深厚的同理心,我们总是对他们进行访谈。


为了保持创造力和活力,我们总是在进行团队协作。


为了使我们的思维更有创造力、更加敏锐,我们总是把我们的想法做成有形的原型,因为它帮助我们解决问题。


因为我们很少在第一次就成功,所以我们总是分享我们的产出,并根据我们得到的反馈进行迭代。


这本指南中的57种方法提供了一套全面的练习和活动,可以帮助你从制定设计挑战到将其推向市场。有些方法你会用两到三次,有些则不会。但是作为一个整体,他们会让你走上持续创新的道路,同时让你所设计的社区或用户成为你工作的中心。 



相信这个过程,即使它让你感到不舒服
以人为中心的设计是一种独特的解决问题的方法,这种方法有时会让人觉得很疯狂而不像一个方法——但如果你总是使用传统的解决方案,你就很少能找到创新的解决方案。这个过程的目的是让你直接从用户那里学习,敞开心扉,接受各种各样的创造可能性,然后专注于最理想、最可行的方案。你会发现自己在这个过程中频繁地推翻假设,当你完成它的三个阶段时,你会从具体的观察到高度抽象的思考快速变换,然后再回到原型的具体细节。我们称之为发散和收敛(菱形设计法则)。 


在构思阶段,通过更广泛的思考(大范围,多领域),我们想出了各种可能的解决方案。


但因为我们的目标是最具可行性的方案,所以我们必须确定,在这一系列的想法中,哪一个最有可能真正发挥作用。你会发散和收敛几次,每一次新的周期,你会越来越接近一个投放市场级别的解决方案。


创建真正可用的方案
以人为中心的设计是一种独特的定位,最终目的是达成解决方案的可取性(用户角度),技术可行性,商业可行性。
首先从用户开始,了解他们的希望、恐惧和诉求,我们很快就能发现什么是用户亟需的。一旦我们确定了一系列能够吸引用户的解决方案,我们就开始着手于在技术上可行的方案以及如何使解决方案在经济上的可行性。这是一个平衡的过程,但这对于设计成功且可持续的解决方案至关重要。

Image title


一:心态


1.创造性的信心

任何人都可以像设计师一样理解世界。作为一个问题解决者,解锁这种潜力所需要的只是创造性的信心。创造性的自信是指每个人都具有创造力的信念,而创造力不是绘画或构图或雕刻的能力,而是一种理解世界的方式。
创造性信心是以人为本的设计师在实现思维的飞跃,信任他们的直觉以及追求他们尚未完全弄清楚的解决方案时所依赖的品质。我们相信,您可以并且将会为问题提出创造性的解决方案,并且相信所有这一切都需要着手去实践且深入尝试。
它是一种自信,相信你所需要做的只是卷起袖子投入进去。创造性的自信会驱使你去做事情,去测试它们,去不断犯错,然后继续前进,确信你会到达你需要去的地方,并且你一定会一路持续创新。
建立创造性的自信需要时间,实现这一目标的部分原因是相信以人为中心的设计过程将向您展示如何以创造性的方式解决手头的任何问题。从微小的成功开始,然后建立一个更大的目标,你会看到你的创造性信心的增长,不久你就会发现自己变成了一个非常有创造力的人。


2.着手去做

作为以人为本的设计师,我们之所以这样做,是因为我们相信有形(实物、可视化)的力量。我们知道,把一个想法变成现实,可以揭示出许多仅仅靠理论所不能揭示的东西。当目标是将有效的解决方案投入使用时,您不能生活在抽象和理论中。你必须让它们成为现实。 以人为中心的设计师是实干家、修补匠、工匠和建设者。我们使用任何我们可以使用的东西,从纸板和剪刀到复杂的数字工具。我们建立我们的想法,这样我们就可以测试它们,在真正去做一些东西后,我们会发现以前从来没有想到的机会和复杂性。制作也是一种奇妙的思考方式,它有助于我们关注设计的可行性。此外,把想法变成现实是一种非常有效的分享方式。如果没有来自人们的反馈,我们将不知道如何进一步完善我们的想法。



3.从失败中学习


失败是一个非常强大的工具,设计实验原型、交互和测试他们是以人为本设计的核心。要知道并非所有这些能发挥作用,当我们想要解决一个大问题时,我们一定会失败,但如果我们保持良好的心态,我们就会从中受益。


以人为中心的设计是从一个不知道如何解决设计挑战的地方开始的。只有通过倾听、思考、构建和提炼我们的答案,我们才能得到对我们的用户有用的东西。“早失败,早成功”是IDEO的一个常见口号,它的力量之一就是允许出错。由于拒绝冒险,一些设计师实际上与真正的创新机会失之交臂。
托马斯·爱迪生说得好:“我没有失败。我刚刚发现了10000种行不通的方法。对于以人为中心的设计师来说,找出行不通的东西是找到有用的东西的一部分。
失败是以人为中心的设计中固有的一部分,因为我们很少在第一次尝试时就能取得成功。事实上,第一次尝试就做好并不是重点。关键是把一些东西创造出来,然后用它来不断学习,不断提问,不断测试。如果以人为本的设计人员最终取得成功,那是因为他们曾经失败了无数次。


4.同理心


同理心是指站在别人的立场上,理解他们的生活,并从他们的角度解决问题的能力。 
以人为本的设计是以同理心为前提的,你为之设计的用户是你通往创新解决方案的路标。你所要做的就是感同身受,理解他们,并在设计过程中把他们时刻挂在心里。


比如长期以来,国际发展界一直在设计解决贫困问题的方案,却没有真正同情和理解它所要服务的人民。但是,通过设身处地为我们的设计对象着想,以人为中心的设计师可以开始通过一个新的、强大的视角来看待这个世界,以及所有改善它的机会。
让自己沉浸在另一个世界中,不仅会为你打开新的创造可能性,而且它能让你抛开先入为主的理念和过时的思维方式。与你为之设计的用户产生共鸣是真正理解他们生活的背景和复杂性的最佳途径。但最重要的是,它将使你的设计过程完全围绕用户,从而产出对他们来讲真正有用的东西。

5.接受不确定性


以人为中心的设计师总是从不确定的问题开始。在一些注重于快速找到方案的公司文化中,这或许不是一个好的开始。但是从第一步开始,接受不确定性的设计人员会勇敢的走出去,追求很多不同的想法,甚至找到意想不到的解决办法。通过接受这种模糊性,并相信以人为中心的设计过程将引导我们走向一个创新的答案,我们实际上迸发出更强的创新能力。 


将以人为中心的设计师与其他设计师区别开来的一个特点是,我们相信总会有更多的创意。我们不再执着于自己的传统想法,因为我们知道我们会拥有更多新的想法。因为以人为中心的设计是一个如此富有创造力的过程,而且因为我们倡导团队合作构思,所以很容易抛弃不好的想法,保留一些一般的想法,并最终得到最好的想法。
虽然这似乎违反直觉,但这种不确定性实际上促使以人为中心的设计师进行创新。
如果我们一开始就知道答案,我们能学到什么呢?我们怎样才能想出创造性的解决方案呢?我们为之设计的人会在哪里指引我们?拥抱不确定性实际上解放了我们的创造力,鼓励我们去追求一个最初无法想象的答案,这让我们走上了持续性创新的道路

6.乐观

我们相信设计本身就是乐观的。 


为了迎接一个艰难的挑战,特别是像贫困这样巨大而棘手的挑战,我们必须相信,创新是唯一的方法。如果我们不这样做,我们甚至不会去尝试。乐观是对可能性的拥抱,即使我们不知道答案,但我们相信总会有一个方案等待我们去挖掘。
除了推动我们走向解决方案,乐观还使我们更有创造力,鼓励我们在遇到死胡同时继续前进,并帮助项目中的所有参与人员凝聚在一起。从解决问题的角度来处理问题,会给整个过程注入解决最棘手问题所需的能量和动力。
以人为中心的设计师总是专注于可能发生的事情,而不是可能遇到的无数障碍。这是我们的核心信念——每一个问题都是可以解决的——这就是以人为中心的设计师的乐观。

7.迭代

作为以人为中心的设计师,我们采用迭代的方法来解决问题,从我们的用户那里得到反馈是促使解决方案诞生的关键部分。通过不断地迭代、持续改进我们的工作,我们会有更多的想法,尝试各种各样的方法,不断释放我们的创造力,更快地找到成功的解决方案。


迭代使我们保持敏捷、反应灵敏,并训练我们一直专注于核心的想法,经过几次迭代后,每个细节都恰到好处。如果你每次建立一个原型或分享一个想法时都追求完美,那么你就会花很长时间去完善一些不一定有效的东西。但是,通过构建、测试和迭代,您可以不花费过多的时间和资源来推进您的想法,直到您确定它是正确的。


在项目早期,我们不断进行迭代,因为我们知道第一次不会得到正确的结果。迭代让我们有机会去探索,去犯错,去验证我们的直觉,最终会得到一个将被采纳的解决方案。我们进行迭代,因为它让我们不断学习。我们不是躲在工作室里,打赌某个想法、产品或服务会大受欢迎,而是迅速地走出去,让我们的用户成为我们的向导。



第一部分就到这里了,重新回顾下,在本篇文章中,你应该了解到IDEO在设计过程中一直坚守的7个心态。

他们分别是创造性的信心、着手去做、从失败中学习、同理心、接受不确定性、乐观、持续迭代。

数组常用的方法

seo达人

数组常见方法

数组的方法

一、join() 方法 ----->不会改变原数组

二、concat() 方法 ----->不会改变原数组

三、splice(index, num, item) ----->会改变原数组

  1. splice(index, num) 删除功能
  2. splice(index, 0, ...item)
  3. splice(index, num, item)
  4. splice(index)

    四、slice() -----> 不会改变原数组

    五、push() 和 pop() ----->会改变原数组

    六、shift() 和 unshift() -----> 会改变原数组

    七、sort() -----> 会改变原数组

    八、reverse() ----->会改变原数组

    九、indexOf() 和 lastIndexOf()

    十、includes()

    十一、forEach()

    十二、map() -----> 不会改变原数组

    十三、filter() -----> 不会改变原数组

    十四、every()

    十五、some()

    十六、reduce() 和 reduceRight()

    十七、Array.from() 将类数组转化为数组

    十八、Array.of() 方法用于将一组值转化为数组

    十九、数组实例的 find() 和 findIndex()

    二十、扁平化数组 flat() 方法 -----> 不会改变原数组

    数组的方法

    一、join() 方法 ----->不会改变原数组

    该方法可以将数组里面的元素,通过指定的分隔符以字符串的形式连接起来

    返回值:返回新的字符串



    // join() 将数组转化为字符串

    let arr = [1, 2, 3, 4, 5]

    let str1 = arr.join('|')

    console.log(arr) // [1, 2, 3, 4, 5]

    console.log(str1) // 1|2|3|4|5

    // 当传空字符串时

    let str2 = arr.join('') // 12345

    // 当不传时

    let str3 = arr.join() // 1,2,3,4,5

    1

    2

    3

    4

    5

    6

    7

    8

    9

    二、concat() 方法 ----->不会改变原数组

    该方法可以把两个数组里的元素拼接成一个新的数组

    返回值:返回拼接后的新数组



    let arr1 = [0, 1, 2]

    let arr2 = [2, 3, 4]

    let arr = arr1.concat(arr2)

    // 传入二维数组

    let arrCopy = arr1.concat([12, [17, 26]])

    console.log(arrCopy) // [0, 1, 2, 12, [17, 26]]

    console.log(arr) // [0, 1, 2, 2, 3, 4]

    console.log(arr1) // [0, 1, 2]

    console.log(arr2) // [2, 3, 4]



    // ES6 扩展运算符

    let a = [1, 2]

    let b = [2, 3]

    let ab = [...a, ...b] // [1, 2, 2, 3]

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    三、splice(index, num, item) ----->会改变原数组

    index 参数:必传,整数,规定添加或者删除的位置,使用负数时,从数组尾部规定位置

    num 参数:必传,要删除的数量,如果为 0,则不删除项目

    item 参数:可选参数,可以是多个,想数组添加的新项目

    splice 具有删除,插入,替换的功能


  5. splice(index, num) 删除功能

    index 参数:开始位置的索引



    num 参数:要删除元素的个数



    返回值:返回的是包含被删除元素的数组对象



    // 删除功能

    let array = [1, 2, 3, 4, 5]

    let newArr = array.splice(2, 2)

    console.log(newArr) // [1, 2, 5]

    console.log(array) // [3, 4]



    1

    2

    3

    4

    5

    6
  6. splice(index, 0, …item)

    index 参数:插入元素的索引值

    0 参数:不删除

    // 插入功能

    let arr = ['a', 'b', 'c', 'd', 'e']

    let newArr = arr.splice(1, 0, ['插入', 1217])

    console.log(newArr) // []

    console.log(arr) // ['a', ['插入', 1217], 'b', 'c', 'd', 'e']



    1

    2

    3

    4

    5

    6
  7. splice(index, num, item)

    index 参数:开始的索引位置

    num 参数:删除的项个数

    item 参数:替换项

    返回值:返回包含被删除的元素的数组对象

    let arr = [1, 2, 3, 4, 5]

    let newArr = arr.splice(2, 2, '替换', '1226')

    console.log(newArr) // [3, 4]

    console.log(arr) // [1, 2, '替换', '1226', 5]



    1

    2

    3

    4

    5
  8. splice(index)

    当只传一个值时,表示从传入的 index 索引值开始截取到最后

    let arr = [1, 2, 3, 4, 5]

    let newArr = arr.splice(3)

    console.log(newArr) // [4, 5]

    console.log(arr) // [1, 2, 3]

    1

    2

    3

    4

    四、slice() -----> 不会改变原数组

    返回从原数组中指定开始下标到结束下标之间的项组成的新数组

    slice() 方法可以接受一或两个参数,即要返回项的起始位置和结束位置

    array.slice(2) 若只设置一个参数,起始位置为2(包含下标2)开始到数组最后

    array.slice(2, 5) 若设置两个参数,起始下标为2(包含下标2)到结束下标5(不包含下标5)的数组

    当 slice() 参数中有负数时,将负数加上数组的长度值来替换该位置的数

    let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]

    let copyArr1 = arr.slice(2) // [3, 4, 5, 6, 7, 8, 9]

    let copyArr2 = arr.slice(2, 5) // [3, 4, 5] 

    let copyArr3 = arr.slice(-2) // [8, 9]

    let copyArr4 = arr.slice(2, -2) // [3, 4, 5, 6, 7]

    let copyArr5 = arr.slice(-2, -5) // []

    let copyArr6 = arr.slice(-5, -2) // [5, 6, 7]

    console.log(arr) // [1, 2, 3, 4, 5, 6, 7, 8, 9]



    1

    2

    3

    4

    5

    6

    7

    8

    9

    五、push() 和 pop() ----->会改变原数组

    push() 可以接受任意数量的参数,将其逐个添加到数组的末尾,并返回修改后数组的长度(改变了原数组)

    pop() 删掉数组末尾最后一项,改变了数组的 length 值,并返回删除的项

    let arr = [1, 2, 3, 4, 5]

    let count = arr.push(0, 1217)

    console.log(count) // 7

    console.loh(arr) // [1, 2, 3, 4, 5, 0, 1217]



    let item = arr.pop()

    console.log(item) // 1217

    console.log(arr) // [1, 2, 3, 4, 5, 0]

    1

    2

    3

    4

    5

    6

    7

    8

    六、shift() 和 unshift() -----> 会改变原数组

    shift() 删除原数组的第一项,并返回删除元素的值,如果数组为空折返回 undefined

    unshift() 将参数添加到原数组的开头,并返回数组的长度

    let arr = [1, 2, 3, 4, 5]

    let item = arr.shift()

    console.log(item) // 1

    console.log(arr) // [2, 3, 4, 5]



    let count = arr.unshift(0, 'Jack')

    console.log(count) // 6

    console.log(arr) // [0, 'Jack', 2, 3, 4, 5]

    1

    2

    3

    4

    5

    6

    7

    8

    七、sort() -----> 会改变原数组

    在排序时,sort() 方法会调用每个数组项的 toString() 转型方法,然后比较得到的字符串,已确定如何排序,其本质是比较字符串的 ASCII 编码

    即使数组中的每一项都是数值,sort() 方法比较的也是字符串,因此会出现以下情况:

    let arr1 = ['a', 'd', 'e', 'b', 'c']

    console.log(arr1.sort()) // ['a', 'b', 'c', 'd', 'e']



    let arr2 = [12, 26, 3, 99, 52]

    console.log(arr2.sort()) // [12, 26, 3, 52, 99]



    1

    2

    3

    4

    5

    6

    解决办法



    let arr3 = [12, 26, 3, 99, 52]

    arr3.sort((a, b) => {

    return a -b

    })

    console.log(arr3) // [3, 12, 26, 52, 99]

    1

    2

    3

    4

    5

    冒泡排序(优化版)



    function mySort (arr) {

    let count = 0 // 记录循环次数

    // 外层循环  控制循环的次数,每次找到最大值

    for (let i = 0; i < arr.length - 1; i++) {

    count++

    // 判断是否排序好了

    let isSort = true // 初始值默认已经排序好了

    for (let j = 0; j < arr.length - 1 - i; j++) {

    count++

    if (arr[j] > arr[j + 1]) {

    isSort = false

    // 交换位置

    let tmp = arr[j]

    arr[j] = arr[j + 1]

    arr[j + 1] = tmp

    }

    }

    // 某一趟结束,判断一下是否结束

    // 如何判断是否排序好,根据是否发生了位置交换,如果发生了位置交换就说明没有排序好

    if (isSort) {

    break

    }

    }

    console.log(count)

    return arr

    }

    mySort([12, 26, 17, 520, 99])



    // 打印结果:count 9

    // arr [12, 17, 26, 99, 520]



    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    八、reverse() ----->会改变原数组

    反转数组项的顺序

    let arr = [1, 2, 3, 4, 5]

    arr.reverse()

    console.log(arr) // [5, 4, 3, 2, 1]



    1

    2

    3

    4

    九、indexOf() 和 lastIndexOf()

    indexOf() 接受两个参数:要查找的项和查找起点位置的索引(可选项),其中从数组的开头开始向后查找

    lastIndexOf() 接受两个参数:要查找的项和查找起点位置的索引(可选项),其中是从数组的末尾开始向前查找

    返回值:当存在时,返回要查找的项在数组中首次出现的索引值;当不存在时,返回 -1

    可以用来判断一个值是否存在数组中



    let arr = [1, 2, 3, 5, 7, 7, 8, 5, 12, 17]

    console.log(arr.indexOf(5)) // 3

    console.log(arr.lastIndexOf(5)) // 7



    console.log(arr.indexOf(5, 2)) // 3

    console.log(arr.lastIndexOf(5, 4)) // 3



    console.log(arr.indexOf('5')) // -1

    1

    2

    3

    4

    5

    6

    7

    8

    十、includes()

    Array.prototype.includes() 数组实例的方法

    返回一个布尔值,表示某个数组是否包含给定的值

    推荐使用:可以用来判断一个值是否存在数组中



    let arr = [1, 2, 3, 4, 5]

    console.log(arr.includes(3)) // true

    console.log(arr.includes(0)) // false

    1

    2

    3

    十一、forEach()

    对数组进行遍历,对数组中的每一项运行给定函数,没有返回值



    forEarch(function (item, index, array) {})



    参数 item:表示数组中的每一项

    参数 index:表示数组中每一项对应的索引值

    参数 array:表示数组本身

    let arr = [1, 2, 3, 4, 5]

    arr.forEach((item, index, array) => {

    console.log(item + '---' + index + '---' + (arr === array))

    })

    1

    2

    3

    4

    十二、map() -----> 不会改变原数组

    map() 方法是将数组中的每一项调用提供的函数,结果返回一个新数组,并没有改变原来的数组

    映射



    let arr = [1, 2, 3, 4, 5]

    let newArr = arr.map(item => item * item)



    console.log(newArr) // [1, 4, 9, 16, 25]

    console.log(arr) // [1, 2, 3, 4, 5]

    1

    2

    3

    4

    5

    十三、filter() -----> 不会改变原数组

    filter() 方法是将数组中所有的元素进行判断,将满足条件的元素作为一个新数组返回

    过滤



    let arr = [12, 17, 26, 520, 1314]

    let newArr = arr.filter((item, index) => {

    return item > 20

    })

    console.log(newArr) // [26, 520, 1314]

    1

    2

    3

    4

    5

    十四、every()

    every() 判断数组中每一项都是否满足条件,只有所有项都满足条件才返回 true,否则返回 false

    let arr = [1, 2, 3, 4, 5]

    let boolean1 = arr.every(item => item > 0)

    let boolean2 = arr.every(item => item > 3)



    console.log(boolean1) // true

    console.log(boolean2) // false

    1

    2

    3

    4

    5

    6

    十五、some()

    some() 判断数组中是否存在满足条件的项,只要有一项满足条件,就会返回 true,否则返回 false

    let arr = [1, 2, 3, 4, 5]

    let boolean3 = arr.some(item => item > 3)

    let boolean4 = arr.some(item => item < 0)



    console.log(boolean3) // true

    console.log(boolean4) // false

    1

    2

    3

    4

    5

    6

    十六、reduce() 和 reduceRight()

    reduce() 方法是所有元素调用返回函数,返回值为最后结果,传入的值必须是函数类型

    接受两个参数:每一项调用的函数和作为归并基础的初始值(可选项)

    这个函数返回的任何值都会作为第一个参数自动传给下一项。第一次迭代发生在数组的第二项上,因此第一个参数是数组的第一项,第二个参数就是数组的第二项。



    // 利用 reduce() 方法实现数组求和,给数组一开始家里一个初始值 3

    let arr = [1, 2, 3, 4, 5]

    let sum = arr.reduce((prev, cur, index, array) => {

    // 函数接受 4 个参数:

    // 前一个值、当前值、项的索引值、原数组对象

    console.log(prev, '---', cur, '---', index, '---', array)

    return prev + cur

    }, 3)

    console.log(sum) // 18 = 15 + 3

    1

    2

    3

    4

    5

    6

    7

    8

    9

    与之相对应的还有一个 Array.reduceRight() 方法,区别是这个是从右向左操作的



    十七、Array.from() 将类数组转化为数组

    let arrayLike = {

    '0': 'a',

    '1': 'b',

    '2': 'c',

    '3': 'd',

    length: 4

    }

    // ES5 写法

    let arr1 = [].slice.call(arrayLike) // ['a', 'b', 'c', 'd']



    // ES6

    let arr2 = Array.from(arrayLike) // ['a', 'b', 'c', 'd']

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    十八、Array.of() 方法用于将一组值转化为数组

    Array.of总是返回参数值组成的数组。如果没有参数,就返回一个空数组。



    Array.of(1, 2, 3, 4, 5) // [1, 2, 3, 4, 5]

    Array.of('abcd') // ['abcd']

    Array.of('abcd').length // 1

    Array.of() // []



    // Array.of 方法的实现

    function ArrayOf () {

    return [].slice.call(arguments)

    }

    1

    2

    3

    4

    5

    6

    7

    8

    9

    十九、数组实例的 find() 和 findIndex()

    数组实例的 find() 方法,用于找出第一个符合条件的数组成员

    它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为 true 的成员,然后就返回该成员,如果没有符合条件的成员,则返回 undefined

    let arr = [1, 2, 3, 4, 5]

    let value= arr.find((item, index, array) => {

    // item 表示循环遍历数组的每一项

    // index 每一项对应的索引值

    // array 原数组对象

    return item > 3

    })

    console.log(value) // 4

    console.log(arr) // [1, 2, 3, 4, 5]



    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    数组实例的 findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回 -1

    let arr = [1, 2, 3, 4, 5]

    let index = arr.findIndex((item, index, array) => {

    return item > 3

    })



    console.log(index) // 3



    [NaN].indexOf(NaN) // -1

    [NaN].findIndex(value => Object.is(NaN, value)) // 0

    [NaN].includes(NaN) // true

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    由此可见:一般用来判断数组中是否存在某个值,推荐使用 includes



    二十、扁平化数组 flat() 方法 -----> 不会改变原数组

    let arr = [1, [2, 3, [4, 5, [6]]]]

    let arrFlat = arr.flat(Infinity)

    console.log(arrFlat) // [1, 2, 3, 4, 5, 6]

    console.log(arr) // [1, [2, 3, [4, 5, [6]]]]

    1

    2

    3

    4

    利用递归实现数组扁平化



    let arrayFlat = []

    let myFlat = (arr) => {

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

    let item= arr[i]

    // 判断 arr[i] 是否是数组

    if (Array.isArray(item)) {

    // 如果是数组,继续调用函数 myFlat

    myFlat(item)

    } else {

    arrayFlat.push(item)

    }

    }

    return arrayFlat

    }



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

目录页该如何设计?-8个常用的排版方式

涛涛

目录页主要出现在一些篇幅比较长的书籍(画册)中,其位置一般被安排在扉页之后,目录虽然不是正文,却概括了一本书的所有内容,具有便于读者快速了解及查阅书本内容的作用,所以,即使说目录页是一本书中最重要的页面也不为过。

既然如此,那么目录页的设计自然也是十分重要,于是乎,葱爷整理了 8 个很不错的目录设计技巧分享给大家。

直线排版

直线在目录设计中的作用主要有以下三个。

1. 连接

即把每节内容的标题与其对应的页码连起来,这是比较常规的一种做法,可以使目录更加清晰,重复排列的线条会形成统一、规整的美感。采用这种排版方式时,标题与页码一般会设置成两端对齐,这样的效果更加整洁、清晰。

2. 创造形式

对于一些文字内容比较少的目录页,如果像上面的例子一样排列会显得比较单调和小气,所以可以借助直线来增加其趣味性和张力。由于内容不多,所以即使不严格对齐也不会影响阅读。

3. 信息区隔

比如在下图的例子中,直线起到了两个信息区隔的作用,一是区隔页码与大标题;二是使七个大章节的内容独立开来。

加图片

这种形式也适合内容比较少的目录页,当有了图片后,目录页似乎也变成了一个内页版面,更加丰富、饱满。图片在目录设计中主要有两个用法。

1. 概括章节的主要内容

其功能与标题一样,所以如果要使用这种方式,那么就需要为目录中的每个大标题都搭配对应的图片。

2. 装饰

这里的图片不是与标题一一对应的,其目的是为了消除纯文字目录的单调感,使版面更丰富、更好看。

格子排版

即将目录中的元素(页码、标题、图片)用表格的形式来排列,这么做也可以使信息更加清晰,更有秩序。由于这种做法在目录设计中并不常见,所以显得很特别。

大页码

页码或者序号是目录页必不可少的元素,章节细分比较多的目录都会标明页码,而分类比较少的目录一般会采用序列号,用来区分几个大板块。把页码或序号拉大并使用笔画比较粗的字体,除了可以使其更明了、醒目以外,还可以增加版面的大小对比,提升设计感。

把页码裁切一下,会更有设计感。

分栏排版

即把文字信息竖向等分成两份或两份以上,适用于文字比较多的版面,所以如果目录页的内容比较多时也适合分栏排版。由于每一栏的内容都严格对齐,且页码比较大,所以栏与栏之间即使错位排列也不会影响阅读。

除了文字还可以用图片来分栏。

轴排版

即把目录信息沿着某条轴排列,这种形式在目录设计中也比较少见,适用于内容比较少的目录页。轴的形式一般为竖轴和横轴,排列的形式通常为错位排版。

上图并不是以线为轴,而是以图片和色块为轴。

网格排版

我们都知道网格系统是画册设计的常用工具,可以有效组织版面信息,使其更有序、更整洁,所以内容比较多的目录页也可以用网格系统来排版,为了避免单调和无趣,通常会加入图片元素。

留白

如果目录的文字比较少,版面就容易显得很空、很单调,常见的做法是增加图片或者把文字拉大,其实主动保留大量空白也是一种解决办法,比如把内容集中排列在版面的顶部、底部、左下角、右下角等位置,留出其他位置的空白。这么处理的版面虽然有一种不平衡感,但动感和设计感更强,大面积的留白还可以适当缓解眼睛的疲劳。

总结

无论做什么设计我们都要以它的最终目的为设计准则,由于目录是为了方便浏览和查阅书本内容,所以设计时一定要注意视觉的整洁与信息的清晰,所以可以发现对齐和统一是最常被用到的两个技巧。

如何让你的摄影更有张力?

涛涛

如果经常听评片会,许多朋友会听过这样一句话:「这样拍会显得画面更有张力……」就摄影而言,我们认为张力,是让一幅摄影作品在视觉上出效果的重要「内力」。此外「张力」还被广泛应用在点评一段演唱,一幅画,一次表演……我们都似乎能感受「张力」的意境,却又似乎不能参透它的意思。

如何理解「张力」?如何借此来提高我们的摄影感悟?下面我就试着做个粗浅的分析吧。

追根溯源:「张力」到底是什么?

关于「张力」有很多略显深奥的解释。我认为下面这种解释较为通俗,同时与摄影有一些关联:

互补物、相反物和对立物之间的冲突或摩擦。……一般而论,凡是存在着对立而又相互联系的力量、冲动或意义的地方,都存在着张力。(转引自杨果〈隐藏的视点:中西「张力」范畴再辨〉,《江汉学术》,2013年10月)

尽管这段话不是针对摄影,甚至不是针对视觉艺术而写的,但是却很好的解释了张力一词。「张力」(tension)由「内涵」(intension)和「外延」(extension)二词而来。其实它在物理学上的意思便是其在美学上的意义的绝佳比喻。

那么我们便可以粗浅感受一下「张力」在一张照片(或者说任何一种视觉艺术)中表达的是什么了:它通常表示了一幅照片对立而又统一的相互作用,这种作用通常产生紧张感、拉扯感,产生一种繁复的韵味。力的暗示、不平衡、断裂、突发等效果都属于张力范畴。

举个极其通俗的例子,如果我要用图片表达「跨栏」。

这张「没有张力」,因为常规、平衡、稳定:

这张「有张力」,因为夸张,不平衡:

当我们在谈论「张力」的时候,我们在谈论什么?

当我们说一张照片的「张力」的时候,更多表达的是照片给我们带来的主观感受。通常情况下,一张「有张力」的照片背后蕴含着以下的特质。

1. 拉扯感

即我们可以感觉到「力量的存在」,似乎被某种力量拉扯着。哇,这是再直白不过的张力了。

以拍街头行人为例,「奔跑」「转向」或其他肢体较为夸张的动作和表情通常能让我们体会到力量。人的潜意识总是会倾向于,试着让一些看起来没有达到稳态的东西趋向于达到稳态,夸张的动作同时也暗示着那些行人「将要跨出下一步」「将要转过去」「将会拉扯肌肉」等等。

△ 韩松 / 摄 iPhone 7p, 莫斯科。奔跑的人。

△ 韩松 / 摄 iPhone 6, 马尔丁,孩子的表情较为夸张,能感受到肌肉的拉扯,画面感染力较强。

△ 韩松 / 摄 iPhone 6, 马尔丁。同样是人物照,这张就画面张力略显单薄。

而另一种拉扯感来自所拍摄的元素的形态本身。例如夕阳下被拉长的影子,具有纵深感的空间,夸张尖锐的几何形态等。它们都会让我们有被拖拽、被虹吸、被缠绕等感觉。

△ 韩松 / 摄 iPhone 7p, 布达佩斯。影子。

2. 冲突

制造各种对比与冲突。

例如强烈的色相对比,阴影和高光的高调对比等等。这无疑用画面的色彩击中我们的眼球。

再如一切能造成冲击力的题材冲突:如抽象和具象,虚幻和真实,细腻与粗糙,动态与静态等等。

△ 韩松 / 摄 iPhone 6, 香港。红衣人物和绿色墙面的「撞色」。

△ 韩松 / 摄 iPhone 6, 里斯本。行人和影子。

3. 构图

夸张的构图也能产生张力。

斜线的构图通常更有张力,因为它夸张而强烈。但斜线的构图是需要磨练的,有时候「为了斜线而斜线」会显得矫揉造作(之前的文章我建议大家先从摆正,拍平开始)。

△ 谭凌飞 / 摄 iPhone 6, 萨尔茨堡。斜射的影子让不起眼的场景有了张力。

极度不遵从「三分法」「对称」「平衡」等原则,而又在某种意义上很精妙地构图,有时候也能造成张力。这种构图的本质是打破了平衡感,扰动了我们潜意识里的平衡球。元素的极大和极小的对比,大量留白和极度撑满,以及一些「莫名其妙」的夸张形式,都有可能成为视觉张力的发力点。

△ 韩松 / 摄 iPhone 6s, 北京。

△ 韩松 / 摄 iPhone 7p, 日本高松。「极大」的场景和「极小」的人物,拉开了比例。

△ 韩松 / 摄 iPhone 7p, 巴黎。雕塑和观众的比例和颜色对比形成张力,然而他们的动作又有一些联系。

怎样拍有张力?

1. 手机外置广角或鱼眼镜头

手机定焦镜头较为平和,如果加上外置的广角或鱼眼镜头能够拍一些较有冲击力的照片。广角顾名思义是有很宽广的视角,能够近距离将比较宽的场景元素都拉扯在一起,让斜线、曲线都更为夸张。

2. 勇敢面对那些「不舒服」的素材吧

其实本质还是在于不平衡。拥挤、窥视、抖动、不稳定的、转瞬即逝,这些东西都不太舒服,但又常常因此形成视觉上的动感。拥挤人群中的一瞥,从奇特角度的窥探人物的活动、快速运动的骑车的人,匆匆而过的行人汽车等等,让我们感到有「丝毫不安」,却也预示着「这不是稳态」,是矛盾而拉扯着的。

△ 韩松 / 摄 iPhone 7p, 布拉格。拥挤的人群。

△ 韩松 / 摄 iPhone 7p, 日本奈良。透过吃草的鹿看后面的鹿。

△ 谭凌飞/ 摄 iPhone 6s, 巴黎。差点被遮住的铁塔。

3. 不平衡的构图

自不多说。对角线、夸张的引导线,螺旋线,撑满画面的构图。那些找不到几何中心而又精妙的构图。

△ 韩松 / 摄 iPhone 7p, 日本。螺旋线。

4. 拍摄运动物体

跑步的人,快走的人,跳跃的人,快速通过的车。

△ 韩松 / 摄 iPhone 6s, 伊斯坦布尔。撑伞的人走过。

△ 韩松 / 摄 iPhone 7p, 莫斯科。拉手风琴的人与匆匆而过的行人。

5. 后期

通过调高饱和度等参数强化色相的对比等等。

△ 韩松 / 摄 iPhone 7p, 日本。后期调高了些饱和度,强化了人物和背景的颜色对比。

不得不承认,张力还是一个比较抽象的概念,我们从来不会以「张力」为目的去拍一张照片,更多的时候,我们是无意识地被「有张力」的场景所吸引,也具有从一堆原片中甄选出「有张力的照片」的能力。重要的是会在取景框中通过构图的运用来制造张力的可能性。

文章来源:优设

彻底解决小程序无法触发SESSION问题

seo达人

一、首先找到第一次发起网络请求的地址,将服务器返回set-cookie当全局变量存储起来

wx.request({
  ......
  success: function(res) {
    console.log(res.header);
    //set-cookie:PHPSESSID=ic4vj84aaavqgb800k82etisu0; path=/; domain=.fengkui.net

    // 登录成功,获取第一次的sessionid,存储起来
    // 注意:Set-Cookie(开发者工具中调试全部小写)(远程调试和线上首字母大写)
    wx.setStorageSync("sessionid", res.header["Set-Cookie"]);
  }
}) 

二、请求时带上将sessionid放入request的header头中传到服务器,服务器端可直接在cookie中获取

wx.request({
  ......
  header: {
    'content-type': 'application/json', // 默认值
    'cookie': wx.getStorageSync("sessionid")
    //读取sessionid,当作cookie传入后台将PHPSESSID做session_id使用
  },
  success: function(res) {
    console.log(res)
  }
}) 

三、后台获取cookie中的PHPSESSID,将PHPSESSID当作session_id使用

<?php
// 判断$_COOKIE['PHPSESSID']是否存在,存在则作session_id使用
if ($_COOKIE['PHPSESSID']) {
    session_id($_COOKIE['PHPSESSID']);
}

session_start();
echo session_id(); 

jqGrid 表格底部汇总、合计行footerrow处理

seo达人

jqGrid提供了表格底部汇总、合计行功能,我们先看下user-guide关于jqGrid合计行都有哪些说明?然后再看个DEMO,看看jqGrid表格底部汇总、合计行到底如何实现。



1、user-guide关于jqGrid合计行的说明

1)表格配置:footerrow, boolean, 默认false

If set to true this will place a footer table with one row below the gird records and above the pager. The number of columns equal those specified in colModel

表格是否显示底部合计行。



2)表格配置:userDataOnFooter,boolean,默认false

When set to true we directly place the user data array userData in the footer if the footerrow parameter is set to true. The rules are as follows: If the userData array contains a name which matches any name defined in colModel, then the value is placed in that column. If there are no such values nothing is placed. Note that if this option is used we use the current formatter options (if available) for that column. See footerData method.

如果设为true,则userData可以用来填充汇总行。



3)汇总行赋值:footerData([string action], [object data], [boolean format])

This method gets or sets data on the grid footer row. When set data in the footer row, the data is formatted according to the formatter (if defined) in coModel. The method can be used if footerrow option is set to true.

parameters

string action - can be ‘get’ or ‘set’. The default is get. ‘get’ returns an object of type name:value, where the name is a name from colModel. This will return data from the footer. The other two options have no effect in this case. ‘set’ takes a data object and places the values in the footer The value is formatted according to the definition of the formatter in colModel - see next parameter. The object should be in name:value pair, where the name is the name from colModel

object data - data to be set in the footer in name:value pair, where the name should correspond to the name of colModel in order to be set in the appropriate cell.

boolean format - default is true. This instruct the method to use the formatter (if set in colModel) when new values are set. A value of false will disable the using of formatter



2、一个DEMO,如何利用gridComplete事件进行表格数据汇总并赋值给合计行

1)案例截图



2)html代码



<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8" />

<title>jggrid底部汇总行</title>



<link rel="stylesheet" href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />

<link rel="stylesheet" href="https://cdn.bootcss.com/font-awesome/4.5.0/css/font-awesome.min.css" />

<link rel="stylesheet" href="https://cdn.bootcss.com/jqueryui/1.11.0/jquery-ui.min.css" />

<link rel="stylesheet" href="https://js.cybozu.cn/jqgrid/v5.3.1/css/ui.jqgrid.css" />

<script src="https://cdn.bootcss.com/jquery/1.11.1/jquery.min.js"&gt;&lt;/script&gt;

<script src="https://js.cybozu.cn/jqgrid/v5.3.1/js/jquery.jqGrid.min.js"&gt;&lt;/script&gt;

<script src="https://js.cybozu.cn/jqgrid/v5.3.1/js/i18n/grid.locale-en.js"&gt;&lt;/script&gt;

</head>

<body>

<div class="page-content container">

<div class="page-body"> <!-- page-body -->

<div class="panel panel-default" id="panel-orders">

<table id="orders"></table>

</div>

</div>

</div>

<script type="text/javascript">

var data = [];

function getBills() {

var rowCount = 10;

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

data.push({

sid: i,

goods_no: i + 1,

goods_name: '零件名称' + rowCount + i,

car_type_name: '车型' + rowCount + i,

package_name: '包装器具' + rowCount + i,

unit_name: '件',

snp: 0.89,

bill_amount: rowCount + i,

goods_count: rowCount + i,

bill_no: 'BN0000000' + i,

qrcode: '1000000000' + i,

barcode: '1000000000' + i,

})

}

$("#orders").jqGrid("clearGridData").jqGrid('setGridParam',{data: data || []}).trigger('reloadGrid');

}

$(function() {

$("#orders").jqGrid({

colModel: [

{label: "零件号", name: "goods_no", width: 60},

{label: "零件名称", name: "goods_name", search:false, width: 180},

{label: "车型", name: "car_type_name", width: 70},

{label: "包装器具", name: "package_name", width: 70},

{label: "单位", name: "unit_name", width: 40},

{label: "订单号", name: "bill_no", width: 120},

{label: "订单数量", name: "goods_count", width: 80},

],

datatype: 'local',

rownumbers: true,

height: 300,

rowNum: 1000,

footerrow: true,

gridComplete: function() {

var rows = $("#orders").jqGrid("getRowData"), total_count = 0;

        for(var i = 0, l = rows.length; i<l; i++) {

        total_count += (rows[i].goods_count - 0);

        }

        $("#orders").jqGrid("footerData", "set", {goods_name:"--合计--",goods_count:total_count});

        }

});

getBills();

});

</script>

</body>

</html>



3)代码说明:



表格构建时,设置:footerrow: true

gridComplete(jqGridGridComplete)事件处理,进行数据汇总并赋值给合计行

gridComplete fires after all the data is loaded into the grid and all other processes are complete. Also the event fires independent from the datatype parameter and after sorting paging and etc. Does not fire if datatype is a defined as function.



4)获取汇总行数据

var row = $("#orders").jqGrid(“footerData”, “get”);

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

详情页设计不够出彩,该如何提升?

涛涛

从事电商方面的设计师,详情页设计可以说是必修课,好的详情页会给带给用户更流畅的视觉体验、更直观的产品信息、亮点等等,也有助于提升交易的达成率。正是因为如此,所以很多商家不惜重金请设计师为其打造爆款产品的详情页,由此可见详情页在电商设计中的重要程度。本期和大家一起分析总结:如何把详情页做的足够出彩,详情页做不好需要从哪些方面进行提升?





目前被认可的一种详情页设计形式是分屏式,就是按照手机端设计思维以一屏为单位制作,最后整合成一个完整的详情页,这种形式有助于提升视觉流畅度及内容识别度,所以我们可以将每一屏都当作一张海报来制作。而说到海报,就离不开设计构图。


详情页的构图与传统的PC端海报有所不同,因为详情页设计更注重手机端,所以一屏的内容又可以看做是手机端竖向的海报。而一副出彩的海报,必然需要优质的骨架。那么常见竖向海报构图形式有哪些?下面为大家总结了几种在详情页设计中比较实用的构图形式:



如图所示,这三种构图形式看似简单,实则兼顾了手机端的很多必要点,比如:视觉的流畅度、整洁度、辨识度、用户的接受度等等,详情页设计在构图及板式方面并不需要很复杂,反而干净整齐的画面更易于视觉表达,也更利于手机端展示。


这三种构图形式在详情页中使用频率是非常高的,下面我们看几组案例:

看似简单的构图,反而在详情页设计中非常实用,仅靠这三种构图,完全可以做出很优秀的详情页。另外还有一些从这三类衍生的构图形式,也比较常用:



文案在配图下半部分的这类构图相比而言用的少一些、也难把控一些,当然用的好了在版式上会有打破、眼前一亮的视觉感受,只是这类构图不宜多用,完整的详情页中出现1-2次即可。而左右式配图+文案的形式是比较常用的,下面看组案例:

详情页的构图不易太复杂,这六种构图形式完全够日常工作,只需选取其中1-3中构图形式交替使用即可。以上构图示例中标识的装饰元素可以是线条、英文、图标、数字、实物素材等等,也可以选择不使用,具体情况根据配图的留白以及重心灵活使用即可。


所以,详情页中每一屏的构图并不难,完全可以把这六种构图形式当做公式,需要哪种直接套用其结构就可以(结构类似即可,并非要求1:1)。另外:配图形式可以分为三种:全屏、半屏、透明图,具体的构图形式需要结合画面整体的重心、留白、美观度决定。更通俗一些的话,构图就可以理解为填空,内容就往空的地方填,注意好适量的留白。


补充:当透明图作为配图时,不管哪种构图形式都有可能出现空的现象,这时我们可以用一些具有装饰性的数字、英文、线条、形状、文字等等进行填充,举例说明:



案例中的文字、数字与产品相互结合,既解决了空的问题、提升了整体的饱满度,又在形式上做到的新颖、有创意。构图形式与前面所说的皆能吻合。





说到设计素材,浮在脑海中的可能会很多种,而这次要说的主要是三类,即:手势、植物、肌理(在花瓣搜索关键词“手势”“植物”“材质”“肌理”就能找到对应素材),这三类素材在详情页设计中出现的频率也是很高的,如果运用得当会将详情页的出彩度进一步提升一个档次,而且对于视觉表达也会更加生动、形象、富有说服力,下面我们逐一来说:



手势素材

顾名思义,就是各种各样关于手方面的动作,比如:拿、托、指等等,下面举个例子来看:

这些手势在很多详情页中都会出现,接下来我们不妨思考这么一个问题:为什么要用这些手势,只是单纯的好看吗?


其实不然,在视觉上,这些手势使得画面更加生动、有立体感、有层次感,让作品更饱满、更出彩。而对于用户而言,能让其更加深刻的体会到产品是有温度的、可操作的、更真实、更容易理解,所以对于交易的达成以及加深用户对产品的了解也更具说服力。


影响详情页转化率的因素有很多种,视觉表达能否真正抓住用户心理也是很关键的一点!



植物素材

这类素材相信大家都不陌生,在很多页面以及详情页出现的频率都很高,而且装饰性很强,寓意也很宽泛,比:自然、清新、贴合现实、有生机等等,下面举个例子:

如图所示,这里的植物都能很好的与画面主体形成很好的遮挡关系,在视觉层面显得更有层次感、画面也更饱满;而且植物的运用并不是随便使用的,而是与海报氛围、文案都紧密相关,形成了很好的呼应、装饰作用。


我们常用的植物元素可以是清晰的,也可以模糊处理,只要与画面整体气质相符,可以根据实际情况灵活使用。



肌理素材

关于材质、肌理的妙用在前面很多文章中都有提到过,这里简单的说一下:肌理素材对于提升作品细节感、层次感、出彩度以及饱满度都有很大的帮助,如果作品碰到上述问题,不妨用肌理素材试试。





单看标题可能很多人不太明白,什么叫做抽象名词具体化?其实简单理解就是:将一些比较抽象的名词通过设计手法表现出来,比如:风、声音、温度、轻重、锋利等等。这样做的目的不仅可以提升用户体验、加快用户理解,而且在视觉上能生动形象的将抽象化名词表现出来,对于视觉出彩度的提升也很大。给人留下的印象也更加深刻,间接的提升了视觉传达的时效性,下面看个例子:

通过案例我们不难发现:将抽象化的名词通过视觉手法表现出来,对于用户理解的难易程度以及视觉出彩度而言都有提升。如果一款产品详情页中能出现1-2次这样的处理手法,会使得详情页在视觉上更加生动、形象。


补充:在详情页设计中,若文案中出现一些LOGO、数字、英文,注意不要放过它,因为它具有装饰性的特点,对于详情页板式的活跃以及设计感提升都有很大的帮助!形式多为:水印、与产品穿插、作为主体信息使用等等!一款详情页这种用法可以出现2-3次!





详情页设计不可忽视的两点:视觉的流畅度以及文案辨识度。文章所提到的一些构图方式、元素使用、视觉表现形式都是为大家提供一个可供参考的方向,落实到工作中要灵活运用、举一反三。一般情况下,一款详情页大概有2-4屏比较出彩的即可,能形成一定的对比,不至于视觉疲劳、千篇一律!


不妨找一些不错的详情页,按照文章中所写的自己尝试分析分析,看是否与之吻合。切记详情页设计构图及文字排版不易太过复杂,切记、切记、切记,重要的事情说三遍!

文章来源:站酷

好的设计不需要解释

涛涛

IP 形象一直维持着相当高的讨论热度,无论是国外的 Superfiction、linefriends;还是到国内的 qq family、Molly 等等。那些始终让你我耳目一新的品牌 IP,其实都具有自己独特的故事。每一个故事都在日常生活中有迹可循,恰恰是这种紧贴生活的故事切入点,能容易引起用户共鸣。具备性格色彩的角色,交织构建着属于自己的故事,以及故事中贯穿始终的精神信念,共同组成了一个完整饱满的 IP 形象。它可以为品牌带来更具象的感染力,在丰富 IP 的自身形象同时,也为用户的品牌感知提供了更多载体,进一步促使用户对品牌产生价值认同。

在 IP 多元化和传播渠道多面化的时代里,如何塑造出带有「温度」的角色形象?如何构思角色间的创意故事?创意,是否真的是我们刻板印象中的「天马行空」?

本期 SOAP Vol.02,我们将以「品牌IP设计创意」为主题,邀请到京东物流「快递小鸽」的 IP 创意主理人方宇宁MIMI,和大家分享「小鸽」的创意思路及为大厂创作 IP 的心路历程。通过多元的创意视角,深入介绍 IP 创作的要旨和秘方,刷新你对「创意」的认识,带你一同掌握创作 IP 的思路,吸收和萌生创意的创作方法。

完整采访视频链接:https://www.bilibili.com/video/av70731200?zw

以下,是 SOAP 与她的对话。

SOAP:

为什么京东物流的 IP 形象是四只鸽子呢?

MIMI:

大家可能接触到的快递员都是路上送货的小哥,但像我们内部的员工在 618,双十一这样的节日,我们也会去一线支援,会发现在整个车间里面,不管是快递员也好,分拣也好,站长等其实都很忙碌,都在为这份包裹去付出努力,所以我希望在这些维度,去设计一些能代表他们的东西,也正是他们这么一个完整的体系,才能代表整个京东物流所谓的 IP。(心里默默os:其实就是画了很多个不知道怎么挑啦~)

SOAP:

和我们介绍下它们吧。

MIMI:

快递小鸽,我选了一个灰色的赛鸽的形象,是我们日常最常见的一种鸽子,也是数量比较多的一个鸽种。其实这一点很匹配我们快递员群体的一个情况。我们的快递员是一群对生活充满希望、充满干劲的年轻人,所以小鸽这个设定也是一个很年轻、很正能量、积极阳光的角色。

分拣大哥,顾名思义是一个体力活的工种,所以他是一个比较健硕的形象,这种体力型的人格,性格上也会更加分明。

站长大哥是一个管理者的角色,所以也会比较聪明。在我狭隘的认知里面,我觉得高瘦的人都会给人一种聪明的感受,所以我设计了这么一个形象。

司机大哥的形象就比较有梗了,由于长期驾驶的缘故导致半边脸晒黑这么一个形象。

SOAP:

你是怎么塑造它们的性格的?

MIMI:

对于它们整个人物性格的张力,我希望他们是夸张的,能稍微突破常规去展现属于他们的性格,像货运大哥,它虽然晒黑了但也不放弃保养,这张图就是在画它在涂防晒霜。除了保养自己,它也会保养自己的货车。其实在一些细节上面也有去做一些功夫,像货车司机它们成天坐着,屁股有点下垂,所以有了这么一个它在做减臀操的动作。通过这么一系列的表达可以看出来,他们虽然是一群中年人,但它们并不油腻,而是很努力很积极地在生活。这也是我们的品牌希望传递给用户的一种感受和价值观。

SOAP:

你希望这个 IP 带来一个什么样的价值?

MIMI:

我希望能通过一些这样的内容,去让更多的用户除了喜欢他们之外,也能更理解他们,通过这部分的内容输出去改善快递员与用户之间的关系。类似很难避免的一些快递延误的情况,它们是否能通过自己的表达,去缓解这种情景所带来的不良情绪以及尴尬,我觉得这是小鸽这个 IP 对京东物流来说很大一部分的价值。

SOAP:

你在做其他 IP 项目的时候有遇到些什么坎吗?

MIMI:

17年京东的品牌更新算是我初次接触到的形象设计,和好几个同事一起出方案,我那时候入职不久,比较「不懂事」,没有像其他同事一样去考虑太多怎样的方案能通过,符不符合京东想要传达的形象之类的问题。只是凭自己的喜好去做整个方案,最后出来的效果大家都很惊喜,也在知道完全不可能的情况下依然去推动了这个方案,但结果你懂的……

到后面参与的一个品牌联盟的 H5 项目,给每个品牌商品去设计形象,有大概三四十个吧,然后 H5 就没落了……你懂的……

然后是 JOY Avatar 的设计的项目,主要是针对京东内部一些 JOY 形象应用不规范的问题,根据各部门职能做了相应的 Avatar 设计,整个过程中觉得很机械,没什么成就感,业务上的使用和推进也很乏力,当时做到都想离职了。

SOAP:

那后来怎么没走呢?

MIMI:

最后我冷静下来了,去认真审视 IP 这件事情。例如为 joy&doga 去设定它们的角色以及故事背景,背后也花了很大的工作量去创造整个世界观,反复推敲和验证,才得出最后呈现在大家面前的整套设定,包括后面根据它们的设定去创作内容等等。所以在设计小鸽的时候,虽然也是一种探索,但其实已经主动避开很多弯路和大坑了。

SOAP:

你有什么关于创意的心得和大家分享吗?

MIMI:

「创意需要着力点。 」

以往的理解可能觉得创意就是天马行空,所以也有去做过一些科技感、超能力的设定。但是其实我们如果无法在这个世界观里面做到完整的自洽,其实很空,其实就是一群设计师的自嗨,用户感知不到。所以这次的项目里面我一直去寻找现实中的一些着力点,我觉得小鸽这个形象落在物流上面其实是很好的一个着力点,也正是这个巧妙的结合,才能带给用户一个焕然一新的感受,再到形象的设计也是落地到现实生活中真实存在的鸽种上面来,以及后面的性格设定都是一个现实生活中立体人格的映射等等。当用户能够读懂并且感到熟悉的时候,我们的距离就拉近了。

「相信直觉也是一种逻辑。」

我也见过很多人他们去思考一个设计方案的时候都是推导出来的,这一个点那一个点写满了整张纸,如果这样去做设计的话,最后你会发现自己被限制在一个很小的交集里面,就好像如果你说话需要一直思考语法的话,那你根本无法交流。所以我觉得创作的过程更像是一个潜意识输出的过程,需要你用心去探索、去寻找一个更高层次的抽象,寻求那个能够萌生创意的最佳视角。

「好的设计需要做到不需要解释。」

其实日常生活中我不是一个能言善辩的人,嘴可能还比较笨,所以我会尽力做到不用解释就能让对方读懂我的创意,包括每一次开会汇报的时候我都能不说话就不说话,其实这个时候在场的同事或是我总监,其实他们也是一个用户的身份,如果他们没有第一反应去 get 到我这个 idea,或是没能给他们带来惊喜的感觉,那代表这个设计交付到用户手里也会是同样的感受,所以也会去通过这样一种方式去对自己的设计进行判断和优化吧。

SOAP编后记:

在采访 MIMI 之前,我怀抱着能听到一些概念性方法论的心态,毕竟现在的明确化的设计方法论非常受设计师的青睐,然而 MIMI 显然不在我们「以为」的道路上,而是比我们想象的更随性自由。无论是设计思维还是生活方式,她都崇尚真实和真切的体验感,不给自己的思维设限,不让纸张上看似有理有据的条理式「推导」束缚。她总是能从她独特的视角,看到看似普通事物背后的「玩味」,你永远猜不到她的脑袋瓜里到底装着多少宝藏。她看待 IP 设计更像是一次创意实现的过程,为每一个自己亲手捏造的角色人物构思它们的性格故事,并且绘制它们的「番外小故事」,在她看来也是 IP 设计中很有趣的部分。

文章来源:优设

vue-router的router-link详解

seo达人

<router-link>

<router-link> 组件支持用户在具有路由功能的应用中 (点击) 导航。 通过 to 属性指定目标地址,默认渲染成带有正确链接的 <a> 标签,可以通过配置 tag 属性生成别的标签.。另外,当目标路由成功激活时,链接元素自动设置一个表示激活的 CSS 类名。



<router-link> 比起写死的 <a href="..."> 会好一些,理由如下:



无论是 HTML5 history 模式还是 hash 模式,它的表现行为一致,所以,当你要切换路由模式,或者在 IE9 降级使用 hash 模式,无须作任何变动。

在 HTML5 history 模式下,router-link 会守卫点击事件,让浏览器不再重新加载页面。

当你在 HTML5 history 模式下使用 base 选项之后,所有的 to 属性都不需要写 (基路径) 了。

示例代码:



字符串形式,会默认在当前路由下给字符串前面加



<router-link to='propsView'>字符串形式One</router-link><br>

<router-link :to="{path: 'propsView', query: {id: 1}}" replace>字符串形式Two</router-link><br>

路径形式 



<router-link to='/test/propsView'>路径形式One</router-link><br>

<router-link :to="{path: '/test/propsView'}">路径形式Two</router-link><br>

命名的路由 



<router-link :to="{name: 'test', params: {userId: 123}}">跳转至test路由</router-link><br>

想要 <router-link> 渲染成某种标签,例如 <li>。 于是我们使用 tag prop 类指定何种标签, 同样它还是会监听点击,触发导航。默认值: "a"



<router-link :to="{name: 'test'}" tag="li">渲染成li标签</router-link><br>

设置 replace 属性的话,当点击时,会调用 router.replace() 而不是 router.push(),于是导航后不会留下 history 记录。 



<router-link :to="{name: 'test'}" replace>replace导航后不会留下 history 记录</router-link>


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

日历

链接

个人资料

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

存档