一直在摸鱼中赚钱的大家好呀~

先向各位鱼友们汇报一下情况,目前小程序已经有900+的鱼友注册使用过。虽然每天都有新的鱼友注册,但是鱼友增长的还很缓慢。自从国庆前的文字转语音的工具上线到现在已经将近有1个月没有更新小程序了。但是今天终终终终终于又有个小工具上线了,希望这个小工具可以帮助到更多的鱼友们(没错就是你们)

这次更新的工具是一个二维码生成器,虽然很多小程序存在这个工具,但是本人也是想尝试一下实现这个工具。老规矩,先来看下知名UI设计师设计的页面。

用空闲时间做了一个小程序-二维码生成器_UI
用空闲时间做了一个小程序-二维码生成器_UI_02
用空闲时间做了一个小程序-二维码生成器_二维码_03

同样在工具tab页中增加了二维码生成器模块。从UI图中可以看出第一个表单页面不是很难,就是一个文本框、两个颜色选择、一个图片上传。这个页面我在开发中也是很快就完成了,没有什么技术含量。

当我做到颜色选择弹窗的时候是想从网上找一个现成的插件。但是找了半天没有找到合适的,只能自己手动开发一个。既然要做颜色选择器的功能就要先了解一下颜色的两种格式 (我这边的实现就这两种格式)

颜色的HEX格式

颜色的HEX格式是#+六位数字/字母,其中六位数字/字母是一种十六进制的表达方式。这六位分别两个一组,从左到右分别表示绿00表示最小,十进制是0FF表示最大,十进制是255。通俗点讲,某个颜色的数值越大,包含这个颜色就越多。如:#000000-黑色、#FFFFFF-白色、#FF0000-红色、#00FF00-绿色、#0000FF-蓝色。

颜色的RGB格式

颜色的RGB格式是rgb(0-255,0-255,0-255), 其中0-255就是HEX格式的十进制表达方式。这三个数值从左到右分别表示绿0表示最小;255表示最大。通俗点讲,某个颜色的数值越大,包含这个颜色就越多。如:rgb(0,0,0)-黑色、rgb(255,255,255)-白色、rgb(255,0,0)-红色、rgb(0,255,0)-绿色、rgb(0,0,255)-蓝色。

有了上面的概念,我的思路也就出来了。让用户分别选择这三种颜色的数值,然后通过用户选择的三种颜色的数值转成目标颜色,就可以完成颜色选择的功能。思路出来了之后就告知了UI,然后按照我的思路将效果图出了出来 (没错,就是先实现后出图)。实现中主要使用了vant-ui组件库的popupslider两个组件 (聪明人都喜欢用现成的)。贴一下部分实现代码:

<van-popup 
  show="{{ show }}" 
  title="展示弹出层" 
  position="bottom"
  bind:close="cancelHandle"
  custom-style="background-color: #F3F3F9;border-radius: 40rpx 40rpx 0rpx 0rpx;"
  root-portal>
  <view class="color-popup">
    <view class="popup-header flex flex_j_c--space-between flex_a_i--center">
      <view class="flex-item_f-1"></view>
      <view class="title flex-item_f-1">{{ title }}</view>
      <view class="flex-item_f-1 flex flex_j_c--flex-end">
        <van-icon name="cross" size="32rpx" bind:tap="cancelHandle" />
      </view>
    </view>
    <view class="color-picker" wx:for="{{ pickers }}" wx:key="index" wx:if="{{ index !== 3 }}">
      <view class="color-picker-label">{{ item.label }}</view>
      <view class="flex flex_a_i--center">
        <view class="slider-wrap flex-item_f-1 {{ item.field }}">
          <van-slider value="{{ item.value }}" min="{{ 0 }}" max="{{ 255 }}" data-index="{{ index }}" bind:change="changeHandle" bind:drag="changeHandle" custom-class="slider" bar-height="60rpx" active-color="transparent" use-button-slot>
            <view class="slider-button" slot="button"></view>
          </van-slider>
        </view>
        <view class="slider-value">{{ item.value }}</view>
      </view>
    </view>
    <view class="color-preview-box flex flex_a_i--center">
      <view class="preview-box-wrap">
        <view class="preview-box" style="background-color: {{ rgbaStyle }};"></view>
        <view class="preview-label">颜色预览</view>
      </view>
      <view class="presets-box-wrap flex-item_f-1 flex flex_j_c--space-between">
        <view class="presets-box flex flex_j_c--center flex_a_i--center {{ rgbaStyle === item.rgbaStyle ? 'active' : '' }}" wx:for="{{ presets }}" wx:key="index" style="background-color: {{ item.rgbaStyle }};" data-row="{{ item }}" bind:tap="chooseHandle">
          <view class="active-box"></view>
        </view>
      </view>
    </view>
    <view class="confirm-wrap flex">
      <view class="hex-box flex flex_a_i--center flex_j_c--space-between">
        <view>#</view>
        <view>{{ hex }}</view>
      </view>
      <view class="confirm-button-box flex-item_f-1">
        <van-button type="primary" custom-class="confirm-button"  bind:click="confirmHandle" round>确定</van-button>
      </view>
    </view>
  </view>
</van-popup>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
import { rgb2Hex } from '../../utils/util'

const presets = [
  [0, 0, 0, 255], [102, 102, 102, 255],
  [0, 95, 244, 255], [100, 196, 102, 255],
  [247, 206, 70, 255], [235, 77, 61, 255],
]

Component({
  options: {
    addGlobalClass: true
  },
  properties: {
    show: {
      type: Boolean,
      value: false
    },
    title: {
      type: String,
      value: ''
    },
    value: {
      type: Array,
      value: [0, 0, 0, 255],
      observer: function(val) {
        const { pickers } = this.data
        if(val.length) {
          this.setData({
            pickers: pickers.map((item, index) => {
              return {...item, value: val[index]}
            }),
          })
          this.setColor(val)
        } else {
          this.setData({
            pickers: pickers.map((item, index) => {
              return {...item, value: index === 3 ? 255 : 0}
            }),
          })
          const rgba = [0, 0, 0, 255]
          this.setColor(rgba)
        }
      }
    }
  },
  data: {
    pickers: [
      { field: 'r', label: '红色', value: 0 },
      { field: 'g', label: '绿色', value: 0 },
      { field: 'b', label: '蓝色', value: 0 },
      { field: 'a', label: '透明度', value: 255 },
    ],
    rgba: [],
    hex: '',
    rgbaStyle: '',
    presets: [
      ...presets.map(rgba => {
        return {
          rgba,
          rgbaStyle: `rgba(${ rgba.join(',') })`
        }
      })
    ]
  },
  methods: {
    changeHandle(e) {
      const { detail, currentTarget: { dataset: { index } } } = e
      const key = `pickers[${ index }].value`
      this.setData({ 
        [key]: typeof detail === 'object' ? detail.value : detail
      })
      const rgba = this.data.pickers.map(item => item.value)
      this.setColor(rgba)
    },
    chooseHandle(e) {
      const { rgba } = e.currentTarget.dataset.row
      this.setData({
        pickers: this.data.pickers.map((item, index) => {
          return {...item, value: rgba[index]}
        }),
      })
      this.setColor(rgba)
    },
    // 设置颜色
    setColor(rgba) {
      const hex = rgb2Hex(...rgba)
      const rgbaStyle = `rgba(${ rgba.join(',') })`
      this.setData({ rgba, hex: hex.replace('#', ''), rgbaStyle })
    },
    confirmHandle(e) {
      this.triggerEvent('confirm', { rgba: this.data.rgba, rgbaStyle: this.data.rgbaStyle })
    },
    cancelHandle() {
      this.triggerEvent('cancel')
    },
  }
})
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.

到此颜色选择器的组件已经实现了,还剩下一个预览下载的页面。我这边的实现并不是直接页面跳转,因为这边预览之后返回是希望还保留预览之前的数据的。如果直接离开当前页面并清除了数据,不符合用户预期的。所以使用了一个假页。微信小程序提供了一个  page-container 的页面容器,效果类似于 popup 弹出层,页面内存在该容器时,当用户进行返回操作,关闭该容器不关闭页面。

如果二维码中含中文的静态码使用微信扫描后是无法正常展示内容的(后期安排上二维码解析的功能)

感谢大家观看我今日的水文,文笔实在是不行,欢迎鱼友们给小程序提提意见,或者有什么有趣的想法也可以与楼主提一提。最后希望大家到我的小程序来多坐坐。

🦀🦀感谢看官看到这里,如果觉得文章不错的话,可以给小生的几个开源项目点个Star⭐!