code实践之如何制作一个简单的全栈原型

受到设计师 Marc Krenn的启发和鼓舞,我开始走出自己的舒服区,拿自己接手的项目开刀实践如何制作一个全栈原型。本文的某些操作和观点部分摘取他的一篇名为Supercharge your Framer prototype with Firebase 的文章,有兴趣的可以去拜读一下他的原帖。

 

 

一、认识全栈原型

1.什么是全栈原型

和我们平时做的普通原型不同的是,全栈原型是通过实时请求数据库去动态填充界面,甚至通过前端触发与数据库进行数据交互去完成某些操作指令。

 

2.全栈原型的应用场景

全栈原型的概念,会帮助我们在设计工作中以下几个方面中有所突破:

  • 全方位还原界面的各种态(初始、常规、边界、报错);
  • 跟踪用户交互行为并采集数据(比如统计用户找到一个按钮并触发所用的时间);
  • 项目资源的复用(比如将品牌色、缓动参数、通用组件保存在云端使得能在多个原型中复用);
  • 远程控制(同理因为多个原型使用同一套数据库,便可以通过操作某个原型修改数据库进而去远程控制另一个原型)

 

二、全栈原型实践

因为编程能力以及篇幅限制,我主要结合自己在搭建后台界面过程中,如何写一个下拉选择器的组件为实例,聊一聊怎样制作一个可以从firebase抓取数据填充内容的动态原型。

1.准备工作

首先对于制作原型的工具选择,Framer是一款为数不多可以编程的设计工具,对于前端工程师上手相当容易,同时对于那些在学习JS编程的设计师,可以用它来验证和提高自己的编程能力。Framer官网的标语就是Design everything,确实,只要是你能想得到的效果,它都能实现。

其次如果想要制作一个动态原型,那首先你需要构思好,那些内容是需要从后端抓取,可以提前以JSON的格式将他们以不同类型组织好,它可以是标量、序列、映射等等不同类型http://www.w3school.com.cn/json/index.asp

所有原型里将会填充的数据在本地先用JSON格式模拟好

 

 

比如我要整理一个平台切换的下拉选项可能会有的内容,我将它分成平台类别和业务线名称,以映射集合的形式写成

client data =
[
{cgy:"APP", name:"appitem01"},
{cgy:"APP", name:"appitem02"},
{cgy:"APP", name:"appitem03"},
{cgy:"WEB", name:"webitem01"},
{cgy:"WEB", name:"webitem02"},
{cgy:"APP", name:"appitem04"},
{cgy:"H5", name:"h5item01"}
]

一级选项有APP,WEB…

二级选项有分别对应的是appitem01,appitem02,appitem03…webitem04…

 

2.界面布局

和静态界面布局不一样的是,页面的结构和内容是由JSON决定的,那么我们只能通过JSON数据,运算获取我们想要布局元素的数量、内容以及其它信息。

接着我们一步一步推导如何在前端编辑JSON进而提取信息去进行页面布局,方法如下:

1)新建clientCgyArry数组,用来存放JSON中所抽取的所有平台类别字段

for i in [0..clientdata.length-1]
#挑出数组字段
clientCgyArry.push(clientdata[i].cgy)

»   [“APP”, “APP”, “APP”, “WEB”, “WEB”, “APP”, “APP”, “APP”, “WEB”, “WEB”]

 

2)显然平台类别数组里重复的字段不可取,需要去重

#为了方便复用,为数组添加一个去重的方法属性
Array.prototype.unique = ->
#新建一个数组存放结果
res = [];
#新建一个空对象
json = {};
#遍历当前数组并从原数组中取出一个元素与对象进行对比
for i in [0..this.length-1]
#如果这个元素不重复,则把它存放到结果数组中,同时把这个元素的内容作为对象的一个属性,并赋值为1
if!json[this[i]] then res.push(this[i]) and json[this[i]]=1;
res;
print clientCgyArry.unique()
» ["APP", "WEB”]

3)接着为了获取每个平台类别下对应的业务线名称,我们可以先定义一个数组将JSON里的键值对按类别分组,具体如下:

for a in [0..clientCgyArry.unique().length-1]
#按去重后的类别新建空数组
clientdataCgy[a] = []
#在平台JSON源里查找
for i in [0..clientdata.length-1]
#如果JSON数据源里有这个平台类别,则把它丢到对应的clientdataCgy子数组里
if clientdata[i].cgy == clientCgyArry.unique()[a] then clientdataCgy[a].push(clientdata[i])
print clientdataCgy
» [
[
{cgy:"APP", name:"appitem01"},
{cgy:"APP", name:"appitem02"},
{cgy:"APP", name:"appitem03"},
{cgy:"APP", name:"appitem04"},
{cgy:"APP", name:"appitem05"},
{cgy:"APP", name:"appitem06”}
]
,
[
{cgy:"WEB", name:"webitem01"},
{cgy:"WEB", name:"webitem02"},
{cgy:"WEB", name:"webitem03"},
{cgy:"WEB", name:"webitem04”}
]
]
#分别在每个子数组里遍历,查找得到业务线字段并打印
for i in [0..clientdataCgy[0].length-1]
print clientdataCgy[0][i].name
» "appitem01"
» "appitem02"
» "appitem03"
» "appitem04"
» "appitem05"
» "appitem06"
for i in [0..clientdataCgy[1].length-1]
print clientdataCgy[0][i].name
» "webitem01"
» "webitem02"
» "webitem03"
» "webitem04"

这样得到这几个关键数组我们就能通过数组里遍历渲染出选择器控件样式:

#渲染下拉选择器样式
#下拉选择器
client = new Layer
parent: sideBar
x: 0
y: logo.y+40
backgroundColor: "transparent"
width: 224
height: 70
z: 0
for c in [0..clientCgyArry.unique().length-1]
#下拉一级选项
client_item = new Layer
parent: list_bg
x: 80
y: 80+32*c
backgroundColor: "rgba(255,255,255,0.9)"
backgroundBlur: 60
width: 158
height: 32
z: 99
name: "client_item"+(c+1)
visible: false
client_item_txt = new TextLayer
parent: client_item
x: 16
y: 8
text: clientCgyArry.unique()[c]
fontSize: 12
fontFamily: "PingFang SC"
width: 158
height: 32
fontWeight: 400
lineHeight: 1.5
textAlign: "left"
color: textColor
#下拉二级选项
for d in [0..clientdataCgy[c].length-1]
secondary_client_item = new Layer
parent: client_item
id: clientdataCgy[c]+d
name: "secondary_client_item"+d
x: client_item.width
y: 32*d
backgroundColor: "rgba(255,255,255,0.9)"
backgroundBlur: 60
width: 158
height: 32
visible: false
secondary_client_item_txt = new TextLayer
parent: secondary_client_item
x: 16
y: 8
text: clientdataCgy[c][d].name
fontSize: 12
fontFamily: "PingFang SC"
fontWeight: 400
lineHeight: 1.5
textAlign: "left"
color: textColor

结构写出来了,那么添加事件就方便了,在一级平台选择悬停时添加事件,展示它下面的业务线选择面板。

#一级选择
for c in [0..clientCgyArry.unique().length-1]
#为一级选择添加鼠标移入移除态
client_item.states =
mouseOver:
backgroundColor:primaryColor01
mouseOut:
backgroundColor:"rgba(255,255,255,0.9)"
#为一级选择添加鼠标移入移除事件
client_item.onMouseOver (event, layer) ->
@stateSwitch("mouseOver")
for i in [0..@children.length-1-1]
@children[i].visible = true
client_item.onMouseOut (event, layer) ->
@stateSwitch("mouseOut")
for i in [0..@children.length-1-1]
@children[i].visible = false

当然一个完整的下拉操作交互应该是 :

点开选择器展示平台类别 » 悬停平台类别选项展示其子业务线 » 选择业务线并且将其字段传给选择器选择框。

具体可以下载我在本地测试的Framer原型查看完整代码演示:https://framer.cloud/ppGVY.

完整的选择器交互效果

为了操作的反馈更明显,我引入了facebook的音效素材包。使得不同的操作有不同的音效提示http://facebook.design/soundkit。

这时候你可以尝试在本地修改clientdata里面的内容,比如多添加一个新的平台类别和对应的业务线{cgy:”H5″,name:”h5item01”},如果界面成功渲染,说明代码运转正常。

 

 

3.搭建数据库

到这里,前面提到的Firebase终于可以压轴出场了,Firebase是一家实时后端数据库创业公司,它能帮助开发者很快的写出Web端和移动端的应用。简而言之就是一家提供BaaS(后端及服务)的公司。当然我们不需要像全栈工程师那样了解它所有的功能,这里主要介绍一下它实时同步JSON数据库的功能。

数据库的搭建流程大致分为一下几个步骤:

1.去Firebase官网https: //firebase.google.com→ 登录 → 控制台 → 创建新项目(国内访问需要翻墙)

2.选择数据库,创建数据表。你可以在firebase上直接添加,也可以载入本地的JSON文件。

3.修改权限,获取访问路径

创建好数据表后,可以观察到生成了一串数据库的网址:通过 这串网址前缀+XXX.json就是这段json文件在firebase上面的访问路径。

比如浏览器里键入https://userbehavior-dashboard.firebaseio.com/clientdata.json就可以访问数据库里的clientdata数据。

由于数据库为避免他人窜改,默认是非公开的,需要秘钥才能访问,这时只要点击Firebase数据界面的规则tab,把读和写的布尔值改为true,就可以让任何人通过网址直接访问(这里仅用于公开原型测试)。

4.在Framer里引入

打开Framer,选择侧边栏里的 snippet » Other » JSON API Call,得到如下代码

Utils.domLoadJSON "https://api.github.com/repos/koenbok/Framer", (error, response) ->
print response.name
print response.url
print response.des cription  

把示例链接替换成你要访问的json链接,response可以自己命名,方便后面引用(注意缩进规则)。比如:

Utils.domLoadJSON "https://userbehavior-dashboard.firebaseio.com/clientdata.json", (error, clientdata) ->
print clientdata
» [
{cgy:"APP", name:"appitem01"},
{cgy:"APP", name:"appitem02"},
{cgy:"APP", name:"appitem03"},
{cgy:"WEB", name:"webitem01"},
{cgy:"WEB", name:"webitem02"},
{cgy:"APP", name:"appitem04"},
{cgy:"H5", name:"h5item01"}
]

打印测试显示数据库访问正常。

到此为止,我们一个动态的组件原型就制作完成了,我们可以把这套下拉选项的内容复用在别的原型里,或者可以通过在firebase上直接操作数据库,去实时同步我们所有复用到数据库的组件原型。

比如在这个原型里,我使用这个组件通过所选择的业务线,判断它的平台类别,进而抓取该平台下的导航数据并将其结构和样式渲染出来。https://framer.cloud/oVmLd (访问需要打开翻墙工具)

5.数据库进阶操作

Firebase和Framer的珠联璧合不仅仅局限在数据的载入上。阅读以下教程,试一试用Marc Krenn写的firebase module去体验其它进阶的数据库操作https://github.com/marckrenn/framer-Firebase#getting-started-in-under-5-minutes 。

三、总结&感悟

全栈原型的制作,让你的设计不仅仅停留在界面,你可能要试着设计信息架构,试着设计数据接口,试着通过代码去还原交互动效…总之,在锻炼编程能力之余,让你能从更广阔的维度去审视你的设计项目,最重要的是对互联网底层运作了解的越深,越能帮助我们在还原设计及创意上有的放矢,利用既有的知识储备去挖掘出更多前所未有的交互体验。

code实践下来,首先我被迫养成了良好的代码标注习惯,由于自己逻辑思维能力较差,加上如果代码修改量过多的话,不做备注隔天就忘记了自己写的什么;其次很高兴自己能坚持下来,因为大部分时间与其说是在写交互,不如说是修复bug,或者说是沉迷于解决一些细节的交互冲突,感谢自己的固执,让我总能找到解决问题的方法,过程虽然痛苦,你若坦荡面对,最终会回报于你的是莫大满足感。

最后,2018年预祝各位工作学习,节节攀高!

刷牙君

View posts by 刷牙君
处女座设计师一枚,涉及的专业领域视觉,交互,前端。

Leave a Reply

Your email address will not be published. Required fields are marked *