我喜欢极简风格,所以我搭建了这款微信记账本小程序。在开发微信记账本小程序过程中,有一些值得关注的技术要点,我则简而记之。
1、空态界面
在没有数据时,我设计了空状态时的占位提示。
在框架中,我使用了 wx:if="{{ isShow }}" 来判断是否需要渲染该代码块。而isShow的赋值逻辑是通过判断数组的长度,如果为0则为false,否则为true。

2、新增记账
这里我基于表单元素封装了一个业务表单组件,通过遮罩层弹出。使用到的表单项有form、input、radio、textarea、picker、button,通过自定义样式实现定制化界面。
其实,我有考虑过使用Skyline进行渲染的。但是由于还不太掌握,所以还是使用自定义组件的方式,实现弹层效果。
况且,这个模块后面还会在其他地方用到,所以为了提高可复用性才做了封装。

那么,在微信小程序中,如何封装自定义组件和引用呢?
1) 创建自定义组件:
首先,在项目根目录下创建一个文件夹 `components`,用于存放自定义组件。
在 `components` 文件夹下创建一个子文件夹`my-component`,用于存放自定义组件的相关文件。
在 `my-component` 文件夹下创建以下四个文件:
`my-component.wxml`:组件的模板结构。
`my-component.wxss`:组件的样式表。
`my-component.js`:组件的逻辑代码。
`my-component.json`:组件的配置信息。
编写组件的代码,然后在需要使用该组件的页面中进行引用。
2)引用自定义组件:
在需要使用自定义组件的页面的 `json` 文件中,添加 `usingComponents` 字段,用于声明要使用的自定义组件。
// json{"usingComponents": {"my-component": "/components/my-component/my-component"}}
在页面的 `wxml` 文件中,使用自定义组件的标签来引用它。
// wxml<my-component></my-component>
注意,自定义组件的名称必须遵循一定的命名规范,即以字母开头,可以包含数字、下划线、横杠等字符。
这样,就大致上在微信小程序中使用自定义组件了。接下来,就是写页面结构布局与样式,还有业务逻辑代码了。
这里的拖拽效果,我是基于框架提供的draggable-sheet 组件实现的,封装了这一能力,包括:
隐藏滚动条
滚动回弹效果
滚动到指定位置(snap 到关键点)
滚动帧回调(实现滚动驱动动画)
<draggable-sheetclass="sheet"initial-child-size="0.5"min-child-size="0.2"max-child-size="0.8"snap="{{true}}"snap-sizes="{{[0.4, 0.6]}}"worklet:onsizeupdate="onSizeUpdate"><scroll-viewscroll-y="{{true}}"type="list"associative-container="draggable-sheet"bounces="{{true}}"/></draggable-sheet>
3、选择类型和分类管理
这里的长按拖动分类排序,我认为也是一个技术难点。
实现长按拖拽某个选项进行排序,我采用了以下技术方案来实现。
首先,在页面的 `wxml` 文件中,为每个选项添加一个 `touchstart` 和 `touchmove` 事件监听器。
// wxml<view class="item" bindtouchstart="startDrag" bindtouchmove="drag" data-index="{{index}}">{{item}}</view>
在对应的 `js` 文件中,定义 `startDrag` 和 `drag` 方法。`startDrag` 方法用于记录触摸开始时的位置和索引,`drag` 方法用于处理拖拽过程中的逻辑。
// javascriptPage({data: {items: ['餐饮', '交通', '服饰']},startDrag: function (e) {// 记录触摸开始时的位置和索引this.setData({startX: e.touches[0].clientX,startY: e.touches[0].clientY,startIndex: e.currentTarget.dataset.index});},drag: function (e) {// 获取触摸移动时的位置const moveX = e.touches[0].clientX;const moveY = e.touches[0].clientY;const startX = this.data.startX;const startY = this.data.startY;const startIndex = this.data.startIndex;// 计算拖拽的距离const distanceX = moveX - startX;const distanceY = moveY - startY;// 如果拖拽距离大于一定阈值,则认为是拖拽操作if (Math.abs(distanceX) > 10 || Math.abs(distanceY) > 10) {// 获取当前拖拽的元素const currentItem = this.data.items[startIndex];// 从数组中移除当前元素const newItems = this.data.items.filter((item, index) => index !== startIndex);// 计算新的插入位置const newIndex = startIndex + Math.round(distanceX / 100);// 将当前元素插入到新的位置newItems.splice(newIndex, 0, currentItem);// 更新数据this.setData({items: newItems});}}});
这样,当用户长按并拖动某个选项时,选项会根据拖动的距离进行重新排序。

4、智能分类和报表分析
为了实现日、月的收支报表,以及分类统计图表,我采用了echarts可视化图表库。这也是一项大工程,后面再单独展开写一下。

5、账目管理
看,这里修改数据的模块,就是引用了前面封装的组件。这开发效率,杠杠滴。
而删除前询问用户以避免误删数据,我是使用了框架的wx.showModal方法显示模态对话框。

当然,还有更多开发过程中的技术要点和开发技巧。但是如果都要一一细写,恐怕就要等后面出教程了。