财务小程序账单编辑页面分析

组件通信

Vue组件间的通信方式(多种场景,通俗易懂,建议收藏)_vue实例 与vue实例通信-CSDN博客

通过props和events在父子组件之间进行通信。

Props Props

是父组件传递给子组件的数据。在Vue.js中,父组件可以通过子组件的标签属性传递数据给子组件。 在这段代码中的示例:

<mb-b-type-tabs :items="types" :value="model.type" @selected="onTypeSelected"/>
  1. :items="types" 和 :value="model.type" 是父组件传递给 mb-b-type-tabs 子组件的props。types 是一个包含账单类型的数组,model.type 是当前选中的账单类型。
  2. :items="types" 表示账单类型列表,子组件可以使用这个列表渲染选项。
  3. :value="model.type" 表示当前选中的账单类型,子组件可以根据这个值来设置当前选中的选项。

Events

子组件可以通过触发事件来通知父组件某些操作,父组件可以监听这些事件并做出响应。在这段代码中的实例:

<mb-b-type-tabs :items="types" :value="model.type" @selected="onTypeSelected"/>
  1. @selected="onTypeSelected" 是子组件触发的事件,父组件通过 onTypeSelected 方法来监听这个事件。
  2. 当用户在子组件中选择一个账单类型时,子组件会触发 selected 事件,并传递选中的账单类型数据。
  3. 父组件中的 onTypeSelected 方法会被调用,并接收到这个数据,然后更新父组件的状态。

代码中的事件处理方法:

methods: {
  onTypeSelected(type) {
    this.model.type = type.id;
    // 可以在这里添加更多的逻辑,比如获取分类信息
    this.getCategoryGroups();
  },
}
  1. onTypeSelected 方法是父组件用来处理子组件触发的 selected 事件的方法。
  2. 当事件触发时,这个方法会被调用,并且接收到子组件传递的 type 对象。
  3. 在这个方法中,父组件更新了 model.type 的值,并调用 getCategoryGroups 方法来获取与新选中的账单类型相关的分类信息。

响应式设计

通过媒体查询和视窗单位(如rpx)来实现不同屏幕尺寸的适配。详细分析一下这段代码的这部分。

 视窗单位(rpx

rpx(responsive pixel)是一种在小程序中使用的视窗单位,它可以根据屏幕宽度进行自适应。在小程序中,屏幕宽度默认为750rpx。这意味着,如果屏幕宽度发生变化,rpx单位的值也会相应地进行缩放,从而实现响应式布局。

代码示例:

.header {
  padding: 35rpx 20rpx;
  ...
}

在这个例子中,.header 的 padding 使用了 rpx 单位,这意味着内边距会随着屏幕宽度的变化而缩放。

动态计算元素高度

在这段代码中,通过动态计算元素的高度来适应不同设备的屏幕尺寸。这是通过在组件的 onReady 生命周期钩子中使用 uni.getSystemInfouni.createSelectorQuery 来实现的。

代码示例:

dynamicHeight() {
  let that = this;
  uni.getSystemInfo({
    success(res) {
      let pH = res.windowHeight;
      let query = uni.createSelectorQuery().in(that);
      query.select("#edit-header").fields({ size: true });
      query.select("#edit-amount").fields({ size: true });
      query.select("#edit-key-board-container").fields({ size: true });
      try{
        query.exec((data) => {
          data.map((i) => {
            that.scrollHeight += i.height;
          });
          that.scrollHeight = pH - that.scrollHeight;
        });
      }
      catch(err){
        that.scrollHeight = pH - 210;
      }
    },
  });
}
  1. uni.getSystemInfo 获取设备的系统信息,包括屏幕的高度(windowHeight)。
  2. uni.createSelectorQuery 用于获取页面中元素的尺寸信息。
  3. 通过选择特定的元素(如 #edit-header#edit-amount 和 #edit-key-board-container),并获取它们的高度,然后计算出剩余的屏幕空间,从而动态设置 scrollHeight 的值。
  4. 这种方法确保了即使在不同尺寸的屏幕上,内容区域的高度也能适应屏幕的变化。

通过使用视窗单位(如 rpx)、动态计算元素高度以及媒体查询(如果需要),这段代码实现了响应式设计,确保了在不同设备上的兼容性和用户体验。这些技术使得布局能够自适应不同的屏幕尺寸,从而提供一致的界面和交互体验。

优化拓展:媒体查询

虽然这段代码中没有直接使用CSS媒体查询,但在Vue或小程序中,媒体查询仍然是一种常用的响应式设计技术。媒体查询允许开发者根据不同的屏幕尺寸、分辨率或其他特性来应用不同的CSS样式。示例:

@media screen and (max-width: 600px) {
  .header {
    padding: 20rpx;
  }
}

这个媒体查询规则表示,当屏幕宽度小于或等于600px时,.header 的内边距将变为 20rpx

媒体查询入门指南 - 学习 Web 开发 | MDN (mozilla.org)

API交互

如何通过API请求获取数据(如获取账单分类、账户信息等),以及如何处理API响应。

 获取账单分类 (getCategoryGroups 方法)

getCategoryGroups() {
  if(this.model.type == undefined) return;
  this.$api.getCategoryGroups({ type: this.model.type }).then((res) => {
    if (res.data.code === 0) {
      // this.categoryGroups = res.data.result.list;
      this.categoryGroups = regroups(res.data.result);
    }
  });
},
  • API请求getCategoryGroups 方法通过this.$api发送一个请求到后端API,请求账单分类数据。请求中包含一个参数{ type: this.model.type },这是用于区分不同类型账单的分类。
  • 处理响应: 使用.then()方法来处理Promise对象,它在API请求成功返回后被调用。检查响应中的code字段是否为0(通常表示成功),然后使用regroups函数处理分类数据,并将其赋值给this.categoryGroups

获取账单账户 (getAssetGroups 方法)

getAssetGroups() {
  this.$api.getAssetGroups().then((res) => {
    if (res.data.code === 0) {
      // this.assetGroups = res.data.result.list;
      this.assetGroups = regroups(res.data.result);
    }
  });
},
  • API请求getAssetGroups 方法发送一个请求到后端API,获取账单账户信息。这个方法没有额外的参数,因为它获取所有账户信息。
  • 处理响应: 同样使用.then()方法来处理成功的响应。检查code字段,然后使用regroups函数处理账户数据,并将其赋值给this.assetGroups

 获取预购分组详情 (getPreOrderGroup 方法)

getPreOrderGroup(id) {
  this.$api.getPreOrderGroupWithAmount({ id: id }).then((res) => {
    if (res.data.code === 0) {
      let result = res.data.result;
      this.model.type = 0;
      this.model.description = result.description;
      this.model.amount = result.realAmount;
      this.initAmount = result.realAmount;
      this.group = result;
      this.getLocation(); // 更新地址信息
    } else {
      this.$tip.toast(res.data.message);
      this.isOrder = false;
    }
  });
},
  • API请求getPreOrderGroup 方法通过this.$api发送一个请求,获取与特定ID关联的预购分组的详情。
  • 处理响应: 检查响应中的code字段。如果请求成功,更新模型(this.model)的多个属性,如类型、描述和金额。如果请求失败,显示错误消息并更新isOrder状态。

获取账单详情 (getBillDetail 方法)

getBillDetail(id, isCopy = false) {
  this.$api.billDetail({ id: id }).then((res) => {
    if (res.data.code === 0) {
      let result = res.data.result;
      this.model = result;
      this.initAmount = result.amount;
      if (isCopy) {
        this.model.id = 0;
        this.getLocation(); // 更新地址信息
      } else {
        let dateTime = new Date(result.time);
        this.date = datetime.getCurDate(dateTime);
        this.model.time = this.model.time.substring(11,16);
      }
    }
  });
},
  • API请求getBillDetail 方法发送一个请求,根据账单ID获取账单的详细信息。
  • 处理响应: 检查code字段。如果请求成功,更新this.model的状态,包括账单的ID、描述、金额等。如果请求是复制操作(isCopytrue),则重置ID并更新地址信息。
总结

在这些API交互中,我们可以看到以下模式:

  • 请求发送: 使用this.$api对象发送请求,通常包含一些参数。
  • 响应处理: 使用.then()方法来处理成功的响应,检查code字段来确定请求是否成功,并更新组件的状态。
  • 错误处理: 如果响应中的code字段表示错误,通常会显示一个提示消息,并可能更新一些状态来反映错误。

这种模式确保了组件能够与后端服务进行有效的数据交换,并根据响应更新用户界面。

代码分析示例

账单类型选择

在代码中,账单类型选择是通过一个名为 mb-b-type-tabs 的自定义组件实现的。这个组件允许用户从预定义的账单类型中选择一个。以下是对这部分代码的详细分析:

组件定义
在 <template> 部分,mb-b-type-tabs 组件被用来显示和选择账单类型:
组件定义

<template> 部分,mb-b-type-tabs 组件被用来显示和选择账单类型:

<view class="type-content">
  <mb-b-type-tabs :items="types" :value="model.type" @selected="onTypeSelected"/>
</view>
  • :items="types": 这是通过 v-bind 传递给组件的 props,types 是一个数组,包含了所有可供选择的账单类型。每个类型可能包含一个 id 和一个 text 属性,以及一个 selcolor 属性用于定义选中时的颜色。
  • :value="model.type": 这也是一个 props,表示当前选中的账单类型。它绑定到组件的 value prop 上,用于显示哪个类型当前被选中。
  • @selected="onTypeSelected": 这是一个事件监听器,用于监听组件发出的 selected 事件。当用户选择一个类型时,组件会触发这个事件,并传递选中的类型数据。
数据模型

data 函数中,typesmodel.type 被定义如下:

data() {
  return {
    types: [
      { id: 0, text: "支出", selcolor: "#47A271" },
      { id: 1, text: "收入", selcolor: "#C24F50" },
    ],
    model: {
      type: 0,
      // 其他属性...
    },
    // 其他数据...
  };
}
  • types: 这是一个数组,定义了两种账单类型:支出和收入。每个类型有一个唯一的 id,一个用于显示的 text,以及一个 selcolor 属性,后者在UI中用于显示选中状态的颜色。
  • model.type: 这个属性用于存储当前选中的账单类型。初始值设置为 0,表示默认选中“支出”。
事件处理

methods 部分,定义了 onTypeSelected 方法来处理类型选择事件:

methods: {
  onTypeSelected(type) {
    this.model.type = type.id;
    // 可能还需要在这里调用其他方法来处理类型变更后的逻辑
  },
  // 其他方法...
}

onTypeSelected(type): 这个方法在用户选择一个账单类型时被调用。它接收一个参数 type,这是被选中的类型的数据对象。方法内部,它更新 this.model.type 为选中类型的 id。这会触发视图的更新,因为 model.type 被用作组件的 value prop。

日期和时间选择

在代码中,日期和时间选择是通过两个 picker 组件实现的,允许用户分别为账单选择日期和时间。以下是对这部分代码的详细分析:

日期选择器
<picker
  class="date-picker"
  mode="date"
  @change="onDatePicker"
  fields="day"
  :value="date"
  :end="pickerEnd"
>
  <view class="x-ac date">
    <text> {{ selectedDateText }}</text>
  </view>
</picker>
  • 组件picker 是一个内置的小程序组件,用于选择日期和时间。
  • mode="date": 这个属性设置选择器的模式为日期选择。
  • @change="onDatePicker": 这是一个事件监听器,当用户选择一个日期时触发 onDatePicker 方法。
  • fields="day": 这个属性限制日期选择器只能选择到天。
  • :value="date": 这是一个绑定属性,表示当前选择的日期,它绑定到组件的 value prop 上。
  • :end="pickerEnd": 这个属性设置日期选择器的最大日期,通常设置为当前日期以防止用户选择未来的日期。
时间选择器
<picker
  class="time-picker"
  mode="time"
  @change="onTimePicker"
  :value="model.time"
>
  <view class="x-ac time">
    <text> {{ model.time }}</text>
    <i class="iconfont icon-bottom icon-down" />
  </view>
</picker>
  • mode="time": 这个属性设置选择器的模式为时间选择。
  • @change="onTimePicker": 这是一个事件监听器,当用户选择一个时间时触发 onTimePicker 方法。
  • :value="model.time": 这是一个绑定属性,表示当前选择的时间,它绑定到组件的 value prop 上。
数据模型

data 函数中,datemodel.time 被定义如下:

data() {
  return {
    date: datetime.getCurDate(),
    model: {
      type: 0,
      time: `${now.getHours()<10 ? '0'+now.getHours():now.getHours()}:${now.getMinutes()<10 ? '0'+now.getMinutes():now.getMinutes()}`,
      // 其他属性...
    },
    // 其他数据...
  };
}
  • date: 这个属性用于存储当前选择的日期,初始值通过 datetime.getCurDate() 获取当前日期。
  • model.time: 这个属性用于存储当前选择的时间,初始值通过格式化当前时间获取。
事件处理

methods 部分,定义了 onDatePickeronTimePicker 方法来处理日期和时间选择事件:

methods: {
  onDatePicker({ detail }) {
    this.date = detail.value;
    this.model.date = detail.value;
  },
  onTimePicker({ detail }) {
    this.model.time = detail.value;
  },
  // 其他方法...
}
  • onDatePicker({ detail }): 这个方法在用户选择一个日期时被调用。它接收一个事件对象,其中 detail.value 包含用户选择的日期值。方法内部,它更新 this.date 和 this.model.date 为用户选择的日期。
  • onTimePicker({ detail }): 这个方法在用户选择一个时间时被调用。它同样接收一个事件对象,其中 detail.value 包含用户选择的时间值。方法内部,它更新 this.model.time 为用户选择的时间。
总结

这部分代码展示了如何在Vue组件中实现日期和时间的选择功能,包括组件的定义、数据模型的设置、以及事件处理逻辑。通过这种方式,用户可以轻松选择日期和时间,并且选择的结果会实时反映在UI上,同时更新应用的状态。这种模式是处理日期和时间选择的标准做法,可以很容易地扩展或修改以适应不同的需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值