微信小程序开发连载:3个核心步骤教你从零搭建首个上线项目
从零开始的微信小程序开发,我把它拆解成一系列可以跟着操作的连载。今天这篇,我们直奔主题:怎么创建第一个能跑起来的小程序,并且解决那些文档里不会明说的坑。
照着官方文档走,第一步就卡住了——注册账号时选“个人”还是“企业”?选错了,后面想用支付功能、云开发、甚至某些API,都得推倒重来。个人账号能发布,但限制多:不支持微信支付、不能做社交类目、虚拟商品购买也不行。企业账号审核严,但功能全开。如果你只是练手,个人号就够了;如果想上线赚钱,哪怕先去淘宝花几十块办个个体户执照,也要走企业流程。
注册完拿到AppID,打开微信开发者工具。新建项目时,有个选项叫“不使用云服务”。很多教程建议新手直接勾上,我反而建议你这次先选“使用云服务”。为什么?云开发能让你绕过服务器配置,直接用数据库和存储,前两周的进度能快一倍。等后面你熟悉了,再切回传统模式也不迟。好比学开车,先开自动挡熟悉路况,再换手动挡理解原理。
项目建好,你会看到四个核心文件:app.js、app.json、app.wxss,以及一个pages文件夹。app.json是全局配置,大多数人第一次踩坑就在这里——他们改了页面路径,忘记同步注册。比如你在pages里新建了一个“about”文件夹,里面放了about.wxml和about.js,但app.json的pages数组里没写"pages/about/about",页面就死活不显示。这个数组的顺序决定了页面加载顺序,第一项就是首页。
现在打开index.wxml,删掉默认代码,写一行:
<view>Hello 小程序</view>
保存,模拟器里能看到文字。但这样太枯燥,我们来点交互。在index.js的data里加一个变量:
data: { message: "你点了我一下" }
然后在wxml里加个按钮:
<button bindtap="handleTap">点我</button>
回到index.js,写方法:
handleTap: function() { this.setData({ message: "被点了!" }) }
运行,点击按钮,文字变了。这里有个关键:直接写this.data.message = "新值" 不会更新界面,必须用setData。setData是同步的?不,它是异步的,但视图更新是异步批量处理的。新手容易犯的错是setData之后立刻读取data里的值,发现没变——因为视图还没渲染完。如果要拿到更新后的值,用setData的回调函数。
说到样式,小程序用的是wxss,和css几乎一样,但有个大坑:不支持通配符*。你没法用* { margin: 0 } 来重置样式。替代方案是在app.wxss里逐个标签重置,或者用官方推荐的rpx单位。rpx是自适应单位,设计稿宽度默认750rpx。比如你量出一个按钮宽度300px,在iPhone 6上,直接写300rpx,它会在不同屏幕自动缩放。但注意:rpx不能用在font-size上,文字用rpx会导致不同机型字号忽大忽小,最好用px或者用计算后的数值。
接下来是跳转页面。假设你想从首页跳到about页。在wxml里加个navigator组件:
<navigator url="/pages/about/about">去关于页</navigator>
路径写绝对路径,前面加斜杠。如果写相对路径,比如"../about/about",在分包或复杂目录下容易出错。跳转后,about页怎么接收参数?在url后面加问号:
url="/pages/about/about?id=123"
然后在about.js的onLoad生命周期里取:
onLoad: function(options) { console.log(options.id) }
这里有个容易被忽略的细节:onLoad只触发一次,如果用户从A页跳到B页,再返回A页再跳B页,onLoad不会再次执行。这时候参数怎么更新?用onShow。onShow每次页面显示都会触发,适合做数据刷新。但onShow拿不到options参数,你需要把参数存到全局变量或者页面栈里。
说到数据存储,小程序有同步和异步两种缓存API。图省事全用同步,但同步会阻塞后续代码执行。比如:
wx.setStorageSync('key', 'value')
这个操作如果数据量大,用户会感觉卡顿。正确的做法是:少量关键数据用同步(比如登录态),大量数据用异步:
wx.setStorage({ key: 'key', data: 'value' })
异步的另一个好处是能监听成功或失败,做错误处理。小程序里很多API都有同步和异步两个版本,比如getStorageSync和getStorage,removeStorageSync和removeStorage。记住一条原则:所有带Sync的都是同步,会阻塞;不带的是异步,不阻塞。
再往下走,你会碰到组件的概念。小程序里组件分两种:内置组件和自定义组件。内置组件比如swiper轮播图,直接复制文档代码,发现图片不显示。检查一下图片地址是不是网络图,还是本地图。小程序里,本地图片必须放在项目文件夹内,用相对路径引用;网络图片必须在微信公众平台后台配置“downloadFile合法域名”,否则开发工具里能看,真机就裂了。而且这个配置要审核通过才生效,不是配完立刻能用。
自定义组件是进阶必备。比如你做一个商品卡片,在多个页面复用。创建components文件夹,右键新建Component。组件的js文件里有个properties,用来接收外部传入的数据。写组件时注意:组件的样式默认隔离,父组件的样式不会影响子组件。如果你希望子组件能继承父组件的某些样式,可以在组件的options里加:
options: { styleIsolation: 'apply-shared' }
但这样又会污染子组件内部的样式,需要谨慎使用。更推荐的做法是:用CSS变量或者直接在子组件里定义好自己的样式,父组件通过传class名来控制。
最后聊一个问的问题:小程序里怎么用npm包?官方支持npm,但步骤繁琐。你需要在项目根目录初始化npm,安装包,然后点击开发者工具里的“工具” -> “构建npm”。构建成功后,在js里直接用require引入。但注意:不是所有npm包都能用,依赖浏览器API的包(比如操作DOM的)在小程序里会报错。选包之前,先看它是不是“纯JS”或者有“小程序版本”。比如lodash可以用,但jQuery不行。如果你需要一个时间格式化库,推荐dayjs而不是moment,因为moment包体积太大,小程序对代码包有2MB限制。
说到包体积,小程序包超过2MB就无法上传。解决办法是分包加载。在app.json里配置subPackages,把不常用的页面(比如帮助中心、关于我们)放到子包。主包只保留首页和核心页面。子包在用户访问时才下载,不影响首屏速度。配置方式很简单:
"subPackages": [ { "root": "pages/sub", "pages": ["help/help"] } ]
然后跳转时路径写成"/pages/sub/help/help"。注意:子包之间不能互相跳转,除非通过主包中转。而且子包里的页面不能作为tabBar页面。这些限制在设计之初就要想好,否则后期重构很痛苦。
这一篇先到这里。你跟着操作一遍,应该能跑通一个带页面跳转、数据绑定、样式调整的小程序。下期连载,我们专门讲云开发:怎么用数据库存用户信息、怎么上传图片、怎么在不需要服务器的情况下实现用户登录。这些都是实战里高频出现的问题,我会把我在项目中踩过的坑和解决方案都铺开来讲。
