从零到一,我也能写小程序
看了这篇文章,即使让我现在就从头写一个能够正常运行的小程序,也没有原本想象中的那么难了。

如同我们在《开发小程序的正确方式》一文中所介绍的那样,从某种角度来说,开发小程序如同完成前端页面的设计与开发一样,都有似曾相识的感觉。
在本文中,我们将会以一个具体的小程序为例,带领大家从零到一完成一个小程序的开发流程,并将这个小程序上传到 FinClip.com 进行小程序提审与上架操作。
本文为「从认识小程序到研发」系列的第三篇文章,前文为《小程序的昨日与今天》,《开发小程序的正确方式》。
在上篇文章中,我们新建了一个叫做「HelloWorld」的小程序,FIDE 在初始化小程序项目时,会自动在项目目录中补充对应所需要的项目文件。那不妨让我们先从小程序目录下的配置文件开始,逐渐揭开小程序的面纱。
使用 FIDE 编辑小程序
1. 认识 json 文件
在小程序项目目录下,我们首先看到一个 app.json 文件,与其他常见的后缀为 .pptx /.mp4 /.py 文件不同,json 即不是一种可执行文件也不是一种编程语言,而是一种数据格式文件。

json 主要以两侧的 { } (花括号)为代表,花括号也是 json 文件的基本结构,在 json 文件中,我们一般会通过 key - value 的方式来表达数据,而 value 的值一般会被放在双引号中。修改编辑 json 文件时需要严格遵守相关的数据格式(比如不能添加注释,不能使用单引号),否则会编译失败。
在 app.json 文件中,会包括当前小程序的全局配置,也是在这里对小程序的所有页面路径,界面样式等信息进行配置的综合入口。

在上图中我们会看到一共有 4 个字段(即 pages,window,style 和 sitemap),其中 pages 用来描述当前小程序中所有的页面路径,windows 字段用来定义小程序中的页面顶部颜色,所显示的名称等,style 字段用来约束小程序中组件的默认使用样式,而 sitemap 字段则用来控制小程序可被索引的内容。
但如果我们把后面的 3 个字段(即 window,style,sitemap)都删除掉,小程序是否能够被正确编译呢?

事实上,pages 字段是配置文件中唯一必须的字段。所有小程序中的页面都需要在 app.json 中进行注册(即在 pages 这个数组下添加对应的路径)。
但我们也发现,随着 app.json 中其他字段被删除,小程序顶部的导航栏背景变为了黑色。
如果我们需要对不同的页面进行自定义设置,则需要到不同页面目录下的 page.json 进行单独设置(如在 index 页面目录下,则需要修改 index.json 文件)。
如何对某个页面进行单独配置呢?让我们打开对应的页面目录(如 「pages-index」),修改目录中的 index.json 文件:
本段中,我们仅仅以“导航栏背景”与“导航栏文字”进行设置,其实 FinClip 小程序中还有非常多的其他组件,我们可以查看「文档中心 - 开发 - 指南 - 配置小程序」了解更多的可配置内容。
{
"navigationBarBackgroundColor": "#fff",
"navigationBarTextStyle": "black"
}
顾名思义,这里的“navigationBarBackgroundColor”指的就是“导航栏背景颜色”,而“navigationBarTextStyle”指的就是“导航栏字体样式”。

2. 创建页面

在创建页面时,也不需要单独在新增的目录中新增 ftss,fxml,js 和 json 文件,我们仅需要像上图这样,点击顶部的项目名称右侧“第二个加号”创建新目录,右键新目录,并点击「创建 page」输入页面名称,即可自动完成新目录的创建。
通过「创建 page」的形式新建页面,FIDE 会自动将页面文件增加到 app.json 文件中,而如果是通过手动创建页面的形式,则需要开发者自行将页面在 app.json 文件中进行注册。而如果我们需要删除某个页面目录,则也需要在 app.json 文件中清空对应的页面路径。
3. 认识 fxml 文件
如同《开发小程序的正确方式》所说,fxml 是小程序中不同页面的结构文件,通过结合组件和事件系统,就能像玩乐高积木一样,拼搭出页面的整体框架。
为了便于更清晰地熟悉小程序开发过程,我们需要先删除项目中的 index 和 logs 目录,在“pages”目录下新建“introduce”目录,并且修改 app.json 仅保留以下内容:
{
"pages": [
"pages/introduce/introduce"
]
}
在修改保存后重新编译,我们会看到 FIDE 变成了下图这个样子,页面中的“introduce”是 FIDE 自动添加的。

顶部导航栏的黑色背景太突兀了,让我们打开 introduce.json 文件,定义其中的背景与文字颜色:
{
"navigationBarBackgroundColor": "#fff",
"navigationBarTextStyle": "black"
}
接下来,让我们选中 introduce.fxml 文件,在编辑器中删除 FIDE 自动创建的默认代码(即 <text>introduce</text>),并在其中输入如下代码:
<view>
<text>Hello, World</text>
<image src="https://www.finclip.com/mop/document/images/logo.png" ></image>
<view>
<text>开启 FinClip 小程序之旅</text>
</view>
</view>
保存后点击编译,会看到和下图一模一样的界面,在左侧的模拟器区域成功出现了文字与图片信息。

在这段代码中,我们使用了 3 个 FinClip 小程序的组件,分别是 <view>,<text> 和 <image>。
- <view> 组件通常作为容器来使用,就像是 HTML 中的 <div> 标签一样;
- <text> 组件通常用来显示一段文字,就像是 HTML 中的 <span> 标签一样;
- <image> 组件用来显示图片,就像是 HTML 中的 <img> 标签一样;
我们一般会通过「组件」来描述小程序 fxml 中的相关元素,而通过「标签」描述 HTML 中的相关元素。二者的区别主要是因为,HTML 是一种标记性语言,标签主要用于标记页面中的各种 DOM 元素,而在小程序中,组件不仅仅可以用来标记不同的元素,也可以通过对应的各类属性完成更丰富的拓展。

我们发现,模拟器区域中的图片长宽比失真,而 <image> 组件刚好有一个"mode" 的属性,因此我们可以在 <image> 组件中加上这个属性字段,来优化图片的显示比例。
<view>
<text>Hello, World</text>
<image mode="widthFix" src="https://www.finclip.com/mop/document/images/logo.png"></image>
<view>
<text>开启 FinClip 小程序之旅</text>
</view>
</view>
在上面的 <image> 组件中,我们引用了一张线上的图片,我们也可以将这张图片放在小程序对应的目录中,并且在 src 中替换图片路径。
目前 FIDE 暂时不支持直接复制粘贴对应的文件到指定目录中,所以需要先通过文件管理器或 Finder 进行源文件的处理。在示例中,我们将这个图片放在了 /images 目录中。

<view>
<text>Hello, World</text>
<image src="/images/logo.png" mode="widthFix"></image>
<view>
<text>开启 FinClip 小程序之旅</text>
</view>
</view>
替换图片路径时,我们采用了绝对路径的写法。绝对路径以“/”开头,代表从文件的根目录开始定位文件的位置。
4. 认识 ftss 文件
如同《开发小程序的正确方式》所说,编写小程序样式的语言也是 CSS,所以我们只需要将 CSS 代码写在对应页面的 ftss 文件中即可。
之所以被命名为 ftss,也是代表 fantai stylesheet 的意思(fantai 即凡泰极客,FinClip 的出品公司)。
而与编辑 HTML 中的 CSS 一样,我们在编辑 introduce.ftss 之前,我们需要先在 introduce.fxml 中为每个需要编辑样式的组件定义 class name。
<view class="container">
<text class="chief">Hello, World</text>
<image class="avatar" src="/images/logo.png" mode="widthFix"></image>
<view class="journey-container">
<text class="journey">开启 FinClip 小程序之旅</text>
</view>
</view>
紧接着,我们再回到 introduce.ftss 中,编写对应的 CSS 内容:
.container{
display: flex;
flex-direction:column;
align-items: center;
}
.chief{
margin-top: 20rpx;
font-size: 32rpx;
font-weight: bold;
color: #1E48F5;
}
.avatar{
width: 500rpx;
margin:20rpx;
}
.journey-container{
margin-top: 50rpx;
border: 1rpx solid #1E48F5;
width: 500rpx;
height: 100rpx;
border-radius: 20rpx;
text-align: center;
}
.journey{
font-size: 36rpx;
font-weight: bold;
line-height:100rpx;
color: #1E48F5;
}
保存后编译,我们会发现 FIDE 左侧模拟器中已经出现了一个“样式正常”的页面,文字与图片都能够“正常显示”了。

在这里,我们也简单讲解一下这些 CSS 样式的作用:
- .container 是所有组件的容器样式,我们使用了 Flex 布局控制子元素的排布样式;
- .chief 是顶部“Hello, World”这段文本的样式;
- .avatar 是图中 FinClip Logo 的图片样式;
- .journey-container 是“开启 FinClip 小程序之旅”的外边框;
- .journey 是“开启 FinClip 小程序之旅”的文字样式;
假设我们的小程序中包括数十个页面,而在不同的页面目录内单独修改 page.ftss 就显得比较笨拙了。
与 page.json 与 app.json 一样,ftss 也有默认的全局配置文件,就是我们在小程序根目录中看到的 app.ftss 文件。当小程序目录中 app.ftss 与 page.ftss 中的内容重复时,则会优先读取页面中的样式文件。
5. 认识 js 文件
在一个小程序中,如果只有界面展示是完全不够的,还需要增加一些用户交互的响应内容,而这些与用户交互相关的脚本(如响应用户的点击、获取用户的位置等等)则需要通过 JS 脚本文件来进行处理。
让我们尝试给小程序中的 FinClip Logo 增加一个交互吧!
首先,我们在 introduce.fxml 中增加一个组件<view>,并且定义为“hey” :
<view class="container">
<text class="chief">Hello, World</text>
<image bindtap="clickMe" class="avatar" src="/images/logo.png" mode="widthFix"></image>
<view class="journey-container">
<text class="journey">开启 FinClip 小程序之旅</text>
</view>
<view class="hey">{{ msg }}</view>
</view>
然后,在 introduce.ftss 中为这个组件写明对应的样式:
.container{
display: flex;
flex-direction:column;
align-items: center;
}
.chief{
margin-top: 20rpx;
font-size: 32rpx;
font-weight: bold;
color: #1E48F5;
}
.avatar{
width: 500rpx;
margin:20rpx;
}
.journey-container{
margin-top: 50rpx;
border: 1rpx solid #1E48F5;
width: 500rpx;
height: 100rpx;
border-radius: 20rpx;
text-align: center;
}
.journey{
font-size: 36rpx;
font-weight: bold;
line-height:100rpx;
color: #1E48F5;
}
.hey{
margin-top: 40rpx;
font-size: 28rpx;
color: #333;
}
最后,再回到 introduce.js 中补充对应的交互效果:
Page({
clickMe: function() {
this.setData({ msg: "你点击了 FinClip 的 Logo!" })
}
})
保存后编译,点击 Logo 后会发生什么变化呢?

既然可以给 Logo 上绑定脚本事件,那理所当然我们可以在 introduce 页面中的「开启 FinClip 小程序之旅」上也绑定一个跳转事件,不如就在点击按钮之后,跳转到我们的 FinClip 博客中吧!
考虑到本文的主要目标是带领各位读者完成一个完整小程序的制作过程。 Fxml 的代码逻辑与 HTML 的代码逻辑几乎一致,js 文件也有其相对应的编写方法,Ftss 的代码逻辑与 CSS 样式代码逻辑几乎一致,因此在本文中则不再赘述。如果想了解其中的各种延伸内容,可以点击下方的扩展链接,或者加入 FinClip 的开发者社群进行沟通:
- FinClip 小程序代码样式结构(官方文档)
- FinClip ftss 样式特性介绍 (官方文档,包括 rpx 单位,样式导入与选择器)
- Html 基本语法指南(MDN 官方文档)
- Js 基本语法指南(廖雪峰老师的博客)
- CSS 基本语法指南(MDN 官网文档)
- Flex 布局语法指南(阮一峰老师的博客)
6. 说干就干
既然我们想通过点击「开启 FinClip 小程序之旅」打开博客页面,那理所当然需要先做一个装载博客的页面。FinClip 提供了 web-view 的组件来承载网页,因此我们仅仅需要在页面中加入这个组件。
第一步,创建 blog 页面
还是按照前文所提到的「创建 page」的方法,创建对应的页面(如 blog 页面),并在 blog.fxml 中引入 web-view 组件,此时 blog.fxml 中的内容为:
<web-view src="https://finclip.com/blog/"></web-view>
第二步,为按钮增加属性
回到 introduce.fxml 中,为之前写好的 <view class="journey-container"> 增加按钮属性 bindtap="goBlog" ,此时 introduce.fxml 中的内容为:
<view class="container">
<text class="chief">Hello, World</text>
<image bindtap="clickMe" class="avatar" src="/images/logo.png" mode="widthFix"></image>
<view bindtap="goBlog" class="journey-container">
<text class="journey">开启 FinClip 小程序之旅</text>
</view>
<view class="hey">{{ msg }}</view>
</view>
第三步,修改 js 脚本,补充跳转动作
再让我们切换到 introduce.js 中,为 goBlog 增加后续的交互动作,通过 ft.navigateTo 来增加跳转逻辑,此时 introduce.js 中的内容为:
Page({
clickMe: function() {
this.setData({ msg: "你点击了 FinClip 的 Logo!" })
},
goBlog: function(){
ft.navigateTo({
url:'../blog/blog'
})
},
})
二者之间的关系是这样的:

简而言之,我们在 fxml 中为按钮绑定了对应的按钮属性,随后又在 js 脚本中为这个按钮增加了对应的跳转操作。
第四步,修改 page.json
再保存编译后,我们发现已经可以通过点击「开启 FinClip 小程序之旅」跳转到我们的 FinClip 博客中了,但好像两个页面顶部的背景还颜色还不太统一,因此我们还需要做一点点小的修改:
(1)首先修改 app.json
通过全局定义的方式,修改顶部的导航栏背景与文字颜色为白底黑字
{
"pages": [
"pages/introduce/introduce",
"pages/blog/blog"
],
"window":{
"navigationBarBackgroundColor": "#fff",
"navigationBarTextStyle": "black"
}
}
(2)分别修改 page.json
修改不同页面中的导航栏标题内容,来区分不同的页面
{
"navigationBarTitleText": "我的第一个 FinClip 小程序"
}
{
"navigationBarTitleText": "FinClip Blog"
}
(3)保存并编译小程序
既然一切就绪,编译时也没有提示对应的报错信息,那我们一起编写的小程序应该能够正常顺利的运行了,一起来试试吧!

🤔 感觉还行,不仅点击 FinClip 的 Logo 能显示我们提前配置好的文字,点击对应的按钮也会跳转到我们的博客之中。
我们也可以点击 FIDE 顶部工具栏的「预览」,通过 FinClip APP 扫码,在真机上进行预览。
将小程序上传到 FinClip
如果你阅读了我们的前一篇文章《开发小程序的正确方式》,其中第一步就是介绍如何在 FinClip.com 中创建账号并新建小程序,第四步则是使用同样的账号登录 FIDE ,为了节省篇幅我们就不再重复这一过程了。
我们需要在 FIDE 中登录账号,并点击顶部工具栏右侧的「上传」按钮,并选择我们提前新建的小程序。

然后,我们需要登录 FinClip.com,点击首页或左侧的「小程序管理」,进入到已经新建好的小程序详情中,进行小程序的提审与上架操作。

选中版本并点击「下一步」后,就到了补充审核信息的步骤了。如果我们的小程序比较简单,也不包括登录逻辑,则可以直接点击下一步对所有信息进行二次确认。


其实也可以直接勾选底部的「审核通过后自动上架」。如果在预览小程序时有任何觉得需要修改的地方,都可以关闭窗口,更新对应的内容。
在审核通过后,点击「审核版本」卡片右侧的「版本上架」,就可以将小程序上架在 FinClip.com 中了。
点击「审核版本」左侧的「线上版」按钮,即可获得一个可以公开的二维码,任何人均可通过 FinClip APP 扫码体验。

你可以参照上文中的步骤尝试编写代码使用,祝你成功!
后记
我是 FinClip 的产品经理 Wannz,也是 FinClip 的首席打杂官,目前的主要工作是负责 FinClip 各项产品与功能的「无摩擦使用优化」,即让更多用户快速、轻松的了解,上手 FinClip。
在日常响应 FinClip 的开发者与用户声音的时候,我们的产品经理经常会听到用户提这样问题“到底小程序能干嘛?”,“写小程序到底难不难?”,刚回答这个问题的时候心里还觉得比较激动,但回答多了就会觉得这种问题就和“学 python 有啥用?”,“python 难不难?”差不多,问题确实有答案,但并不能解决什么问题。
小程序并不能替代传统的编程语言(它和前端的语言也有很多共通之处),我觉得相比关注“写小程序难不难”,倒不如想想哪些场景和领域更加适合通过小程序去实现。在 FinClip 的立项之初,我们就认为小程序的重点优势应该放在「平衡 Native 与 H5」之间,它既不像原生应用那么复杂,学习成本那么高,也不像 H5 应用那样体验不一致,需要在过多的复杂框架中进行选择与学习。
🐶 当然,我没有说 Native 和 H5 不好的意思。
在创作文章《小程序的昨日与今天》,《开发小程序的正确方式》和本文前,我还主导了 FinClip 开发文档的统一梳理与优化,但即使增加补充了对应的引导之后,对于小程序的初学者而言,好像还是「差点儿意思」。
可从从本质上来说,开发文档应该被用于查询对应的 API 与组件属性,就像《新华字典》一样简洁高效。而本文与前两篇文章则主要是用来分享与小程序相关的背景知识,进行入门的,就像开始识字的小朋友们尽可以通过阅读《新华字典》认识不同的汉字,但如果想要具体明白汉字怎么写,当然需要教科书的背景知识与引导,本文扮演的就是引导的角色。
如果有的字不会怎么办?查字典呀!开发文档的作用也应该是查询 API 与组件说明的工具,而非入门教程。
在参考,学习互联网上各类的文章之后,我也尝试撰写了 FinClip 小程序的系列文章,希望能够对你在了解,认识,使用产品的过程中提供些许帮助。受限于时间有限,本文中依然有些许不完善的地方,如果有其他建议与问题,欢迎与我联系。
