微信小程序 - 自定义计数器

微信小程序通过自定义组件,实现计数器值的增加、减少、清零、最大最小值限定、禁用等操作。通过按钮事件触发方式,更新计数器的值,并修改相关联的其它变量。通过提升用户体验,对计数器进行优化设计,使用户操作更加便捷和直观。

计数器的实现主要涉及到几个关键部分:

  1. 计数值的增加:通过按钮事件触发方式,实现计数器值的增加,当触增加操作时,更新相应的计数值、按钮状态等。
  2. 计数值的减少:通过按钮事件触发方式,实现计数器值的减少。当触减少操作时,更新相应的计数值、按钮状态等。
  3. 计数值的清零:通过按钮事件等触发方式,相关业务变量变更、逻辑调整等,实现计数值的清零。
  4. 大小值限定:通过按钮事件等触发方式,根据组件定义时指定的最大值、最小值限定增、减数值的范围。
  5. 计数器按钮的禁用:通过按钮事件等触发方式,相关业务变量变更、逻辑调整等,实现计数器按钮的禁用。

一、计数器组件定义

首先在项目中创建计数器组件(Counter),如下图:

index.wxml代码如下:

html 复制代码
<!--components/Counter/index.wxml-->
<view class="counter-wrap">
  <button class="btn mul" disabled="{{isDisabledMul}}" bind:tap="mulEvent">-</button>
  <input type="number" value="{{value}}" class="number" />
  <button class="btn add" disabled="{{isDisabledAdd}}" bind:tap="addEvent">+</button>
</view>

index.wxss代码如下:

css 复制代码
/* components/Counter/index.wxss */
.counter-wrap{ white-space: nowrap; }
.counter-wrap .btn, .counter-wrap .number{ 
    height: 60rpx; 
    line-height: 60rpx; 
    padding: 0; 
    display: inline-block; 
    vertical-align: middle; 
    text-align: center; 
}
.counter-wrap .btn{ 
    width: 60rpx; 
    line-height: 50rpx; 
    font-size: 50rpx; 
    color: #000000; 
    border: 1px solid #cccccc; 
    border-radius: 8rpx; 
    background-color: transparent; 
    padding: 0; 
}
.counter-wrap .btn:disabled{ opacity: .6; }
.counter-wrap .number{ width: 80rpx; }
javascript 复制代码
// components/Counter/index.js
Component({

  /**
   * 组件的属性列表
   */
  properties: {
    // 值
    value: {
      type: Number,
      value: 0
    },
    // 最小值
    min: {
      type: Number,
      value: null
    },
    // 最大值
    max: {
      type: Number,
      value: null
    }
  },
  /**
   * 组件的初始数据
   */
  data: {
    isDisabledAdd: false,     // 是否禁用 加 按钮
    isDisabledMul: false      // 是否禁用 减 按钮
  },
  /**
   * 组件的方法列表
   */
  methods: {
    // 通知父组件值改变
    triggerMsg(value){
      this.triggerEvent('valueChange', {value});
    },
    // 递增事件
    addEvent(){
      const value = this.data.value + 1;
      // 通知父组件 更新数据
      this.triggerMsg(value);
    },
    // 递减事件
    mulEvent(){
      const value = this.data.value - 1;
      // 通知父组件 更新数据
      this.triggerMsg(value);
    }
  }
})

自定义组件触发事件时,需要使用 triggerEvent 方法,指定事件名、detail对象和事件选项,通知父组件并将相关数据发送给父组件。

二、全局组件定义

在 app.json 中声明的自定义组件视为全局自定义组件,在小程序内的页面或自定义组件中可以直接使用而无需再声明。则在app.json中,增加计数器组件,将其定义为全局组件。代码如下:

javascript 复制代码
{
  "pages": [
    "pages/index/index",
    "pages/logs/logs",
    "pages/mine/index"
  ],
  "window": {
    "navigationBarTextStyle": "black",
    "navigationBarTitleText": "Weixin",
    "navigationBarBackgroundColor": "#ffffff",
    "navigationStyle": "custom"
  },
  "usingComponents": {
    "custom-header": "./components/Header/index",
    "custom-counter": "./components/Counter/index"
  }
}

三、计数器组件的引用

由于计数器组件已定义为全局组件,所以在小程序首页中,直接使用即可。代码如下:

index.wxml代码如下:

html 复制代码
<!--pages/index/index.wxml-->
<Header title="首页"></Header>
<view style="padding: 30rpx;">
  <view class="table">
    <view class="row">
      <view class="cell">
        <custom-counter value="{{value1}}" bind:valueChange="valueChangeEvent"></custom-counter>
      </view>
      <view class="cell">
        <custom-counter value="{{value2}}" max="8" bind:valueChange="valueChangeEvent"></custom-counter>
      </view>
    </view>
    <view class="row">
      <view class="cell">
        <custom-counter value="{{value3}}" min="2" bind:valueChange="valueChangeEvent"></custom-counter>
      </view>
      <view class="cell">
        <custom-counter value="{{value4}}" min="0" max="10" bind:valueChange="valueChangeEvent"></custom-counter>
      </view>
    </view>
  </view>
</view>

index.js代码如下:

javascript 复制代码
// pages/index/index.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    value1: 0,
    value2: 0,
    value3: 0,
    value4: 0
  },
  valueChangeEvent(e){
    console.log(e);
  }
})

页面效果如下图:

四、双向绑定数值

如上图可见,此时计数器已可正常通信了,但是首页中定义了四个计数器,对应变量分别为value1、value2、value3、value4;但是小程序中没有双向绑定功能,所以这里需要在定义计数器组件时,告诉子组件将变化的值,绑定给谁。

在首页定义组件时,增加target属性,告知子组件,首页index.wxml代码如下:

html 复制代码
<!--pages/index/index.wxml-->
<Header title="首页"></Header>
<view style="padding: 30rpx;">
  <view class="table">
    <view class="row">
      <view class="cell">
        <custom-counter value="{{value1}}" target="value1" bind:valueChange="valueChangeEvent"></custom-counter>
      </view>
      <view class="cell">
        <custom-counter value="{{value2}}" target="value2" max="8" bind:valueChange="valueChangeEvent"></custom-counter>
      </view>
    </view>
    <view class="row">
      <view class="cell">
        <custom-counter value="{{value3}}" target="value3" min="2" bind:valueChange="valueChangeEvent"></custom-counter>
      </view>
      <view class="cell">
        <custom-counter value="{{value4}}" target="value4" min="0" max="10" bind:valueChange="valueChangeEvent"></custom-counter>
      </view>
    </view>
  </view>
</view>

然后再将Counter计数器组件中,将index.js中的函数triggerMsg()稍作修改,代码如下:

javascript 复制代码
// components/Counter/index.js
Component({

  /**
   * 组件的属性列表
   */
  properties: {
    // 值
    value: {
      type: Number,
      value: 0
    },
    // 目标key
    target: {
      type: String,
      value: ''
    },
    // 最小值
    min: {
      type: Number,
      value: null
    },
    // 最大值
    max: {
      type: Number,
      value: null
    }
  },
  /**
   * 组件的初始数据
   */
  data: {
    isDisabledAdd: false,     // 是否禁用 加 按钮
    isDisabledMul: false      // 是否禁用 减 按钮
  },
  /**
   * 组件的方法列表
   */
  methods: {
    // 通知父组件值改变
    triggerMsg(value){
      const data = {};
      if(!this.data.target) data['value'] = value;
      else data[this.data.target] = value;
      this.triggerEvent('valueChange', data);
    },
    // 递增事件
    addEvent(){
      const value = this.data.value + 1;
      // 通知父组件 更新数据
      this.triggerMsg(value);
    },
    // 递减事件
    mulEvent(){
      const value = this.data.value - 1;
      // 通知父组件 更新数据
      this.triggerMsg(value);
    }
  }
})

此时触发首页计数器增、减按钮,返回的数据如下:

由此可见,当首页中valueChangeEvent()函数触发后,直接将e.detail塞给this.setData()函数即可。代码如下:

javascript 复制代码
// pages/index/index.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    value1: 0,
    value2: 0,
    value3: 0,
    value4: 0
  },
  valueChangeEvent(e){
    this.setData(e.detail);
  }
})

现在不同计数器触发增、减按钮事件后,只会修改当前计数器的值了,如下图:

五、限定大小值

判断最大值和最小值限定前,先判断当前计数器组件是否设置了最大值和最小值。当max或min变量值不为null时,表明当前组件已设置了最大值和最小值,代码如下:

Counter组件index.js代码如下:

javascript 复制代码
// components/Counter/index.js
Component({

  /**
   * 组件的属性列表
   */
  properties: {
    // 值
    value: {
      type: Number,
      value: 0
    },
    // 目标key
    target: {
      type: String,
      value: ''
    },
    // 最小值
    min: {
      type: Number,
      value: null
    },
    // 最大值
    max: {
      type: Number,
      value: null
    }
  },
  /**
   * 组件的初始数据
   */
  data: {
    isDisabledAdd: false,     // 是否禁用 加 按钮
    isDisabledMul: false      // 是否禁用 减 按钮
  },
  /**
   * 组件的方法列表
   */
  methods: {
    // 通知父组件值改变
    triggerMsg(value){
      const data = {};
      if(!this.data.target) data['value'] = value;
      else data[this.data.target] = value;
      this.triggerEvent('valueChange', data);
    },
    // 递增事件
    addEvent(){
      const value = this.data.value + 1;
      // 最大值不为空时,判断最大值
      if(this.data.max != null && this.data.max < value)  {
        return;
      } 
      // 通知父组件 更新数据
      this.triggerMsg(value);
    },
    // 递减事件
    mulEvent(){
      const value = this.data.value - 1;
      // 最小值不为空时,判断最小值
      if(this.data.min != null && this.data.min > value) {
        return;
      } 
      // 通知父组件 更新数据
      this.triggerMsg(value);
    }
  }
})

限定大小值范围条件判断:

  1. 当最大值不为null时,并且当前数值大于最大值时,返回return禁止通知父组件修改值。
  2. 当最小值不为null时,并且当前数值小于最小值时,返回return禁止通知父组件修改值。

六、禁用按钮

如上图,最大值和最小值限定后,当当前计数器值为最大值或最小值时,将增加按钮或减少按钮,置灰为不可用状态。代码如下:

javascript 复制代码
// components/Counter/index.js
Component({

  /**
   * 组件的属性列表
   */
  properties: {
    // 值
    value: {
      type: Number,
      value: 0
    },
    // 目标key
    target: {
      type: String,
      value: ''
    },
    // 最小值
    min: {
      type: Number,
      value: null
    },
    // 最大值
    max: {
      type: Number,
      value: null
    }
  },
  /**
   * 组件的初始数据
   */
  data: {
    isDisabledAdd: false,     // 是否禁用 加 按钮
    isDisabledMul: false      // 是否禁用 减 按钮
  },
  /**
   * 组件的方法列表
   */
  methods: {
    // 通知父组件值改变
    triggerMsg(value){
      const data = {};
      if(!this.data.target) data['value'] = value;
      else data[this.data.target] = value;
      this.triggerEvent('valueChange', data);
    },
    // 递增事件
    addEvent(){
      const value = this.data.value + 1;
      // 最大值不为空时,判断最大值
      if(this.data.max != null && this.data.max < value)  {
        this.setData({ isDisabledAdd: true });            // 当超过最大值时,禁用 加 按钮 
        return;
      } 
      // 未超最大值时,如果 加 按钮为true, 置为false可用状态
      else if(this.data.isDisabledAdd) {
        this.setData({ isDisabledAdd: false })  
      }
      // 当 加 按钮可用时,如 减 按钮为禁用状态,解除禁用
      if(this.data.isDisabledMul) this.setData({isDisabledMul: false});
      // 通知父组件 更新数据
      this.triggerMsg(value);
    },
    // 递减事件
    mulEvent(){
      const value = this.data.value - 1;
      // 最小值不为空时,判断最小值
      if(this.data.min != null && this.data.min > value) {
        this.setData({ isDisabledMul: true });            // 当底于最小值时,禁用 减 按钮
        return;
      } 
      // 未低于小最值时,如果 减 按钮为true,置为false可用状态
      else if(this.data.isDisabledMul) {
        this.setData({ isDisabledMul: false })
      }
      // 当 减 按钮可用时,如 加按钮为禁用状态,解除禁用
      if(this.data.isDisabledAdd) this.setData({isDisabledAdd: false});
      // 通知父组件 更新数据
      this.triggerMsg(value);
    }
  }
})

具体逻辑代码中已具体说明,这里就不再细说了。

相关推荐
Myli_ing18 分钟前
考研倒计时-配色+1
前端·javascript·考研
余道各努力,千里自同风21 分钟前
前端 vue 如何区分开发环境
前端·javascript·vue.js
PandaCave28 分钟前
vue工程运行、构建、引用环境参数学习记录
javascript·vue.js·学习
软件小伟30 分钟前
Vue3+element-plus 实现中英文切换(Vue-i18n组件的使用)
前端·javascript·vue.js
醉の虾1 小时前
Vue3 使用v-for 渲染列表数据后更新
前端·javascript·vue.js
张小小大智慧1 小时前
TypeScript 的发展与基本语法
前端·javascript·typescript
疯狂的沙粒2 小时前
对 TypeScript 中高级类型的理解?应该在哪些方面可以更好的使用!
前端·javascript·typescript
旭日猎鹰3 小时前
Flutter踩坑记录(二)-- GestureDetector+Expanded点击无效果
前端·javascript·flutter
一条晒干的咸魚3 小时前
【Web前端】创建我的第一个 Web 表单
服务器·前端·javascript·json·对象·表单
花海少爷4 小时前
第十章 JavaScript的应用课后习题
开发语言·javascript·ecmascript