扩展uview复选组件库支持自定义图片+自定义内容

简介: 扩展uview复选组件库支持自定义图片+自定义内容

uView 是一套基于UniApp 的前端 UI 框架,它提供了丰富的组件库,用于快速开发移动端和微信小程序等应用。

基本使用

在 uView 中,复选组件通常用于让用户从一组选项中选择多个项目。这些组件可能以 Checkbox Group(复选框组)和 Checkbox(复选框)的形式出现。

把组件拖过来,什么都不需要改,即可生成复选组件。

<template>
  <view class="container container329152">
    <u-form-item class="diygw-col-24" label="复选" prop="checkbox">
      <u-checkbox-group class="flex flex-wrap diygw-col-24 justify-between" wrapClass=" justify-between" v-model="checkbox">
        <u-checkbox v-for="(checkboxitem, checkboxindex) in checkboxDatas" :key="checkboxindex" :name="checkboxitem.value">
          {{ checkboxitem.label }}
        </u-checkbox>
      </u-checkbox-group>
    </u-form-item>
    <view class="clearfix"></view>
  </view>
</template>
 
<script>
  export default {
    data() {
      return {
        //用户全局信息
        userInfo: {},
        //页面传参
        globalOption: {},
        //自定义全局变量
        globalData: {},
        checkboxDatas: [
          { value: '1', label: '选项一' },
          { value: '2', label: '选项二' },
          { value: '3', label: '选项三' }
        ],
        checkbox: ['1', '2']
      };
    },
    onShow() {
      this.setCurrentPage(this);
    },
    onLoad(option) {
      this.setCurrentPage(this);
      if (option) {
        this.setData({
          globalOption: this.getOption(option)
        });
      }
 
      this.init();
    },
    methods: {
      async init() {}
    }
  };
</script>
 
<style lang="scss" scoped>
  .container329152 {
  }
</style>


自定义图片

开启自定义图标,分别设置默认图片及选中图片


自定义内容

可以先外层造 好自己想要的FLEX布局的内容,开启自定义模板,把FLEX内容往里一拖,重新生成源码即可。


扩展源码

<template>
  <view
      class="flex flex-wrap"
      :class="[wrapClass]"
  >
    <slot></slot>
  </view>
</template>
 
<script>
  import props from './props.js';
  import Emitter from "../../libs/util/emitter.js";
  /**
   * checkboxGroup 复选框组
   * @description 复选框组件一般用于需要多个选择的场景,该组件功能完整,使用方便
   * @tutorial https://www.uviewui.com/components/checkbox.html
   * @property {String}     name      标识符 
   * @property {Array}      value     绑定的值
   * @property {String}     shape     形状,circle-圆形,square-方形 (默认 'square' )
   * @property {Boolean}      disabled    是否禁用全部checkbox (默认 false )
   * @property {String}     activeColor   选中状态下的颜色,如设置此值,将会覆盖parent的activeColor值 (默认 '#2979ff' )
   * @property {String}     inactiveColor 未选中的颜色 (默认 '#c8c9cc' )
   * @property {String | Number}  size      整个组件的尺寸 单位px (默认 18 )
   * @property {String}     placement   布局方式,row-横向,column-纵向 (默认 'row' )
   * @property {String | Number}  labelSize   label的字体大小,px单位  (默认 14 )
   * @property {String}     labelColor    label的字体颜色 (默认 '#303133' )
   * @property {Boolean}      labelDisabled 是否禁止点击文本操作 (默认 false )
   * @property {String}     iconColor   图标颜色 (默认 '#ffffff' )
   * @property {String | Number}  iconSize    图标的大小,单位px (默认 12 )
   * @property {String}     iconPlacement 勾选图标的对齐方式,left-左边,right-右边  (默认 'left' )
   * @property {Boolean}      borderBottom  placement为row时,是否显示下边框 (默认 false )
   * @event {Function}  change  任一个checkbox状态发生变化时触发,回调为一个对象
   * @event {Function}  input 修改通过v-model绑定的值时触发,回调为一个对象
   * @example <u-checkbox-group></u-checkbox-group>
   */
  export default {
    name: 'u-checkbox-group',
    mixins: [Emitter,props],
    computed: {
      // 这里computed的变量,都是子组件u-checkbox需要用到的,由于头条小程序的兼容性差异,子组件无法实时监听父组件参数的变化
      // 所以需要手动通知子组件,这里返回一个parentData变量,供watch监听,在其中去通知每一个子组件重新从父组件(u-checkbox-group)
      // 拉取父组件新的变化后的参数
      parentData() {
        return [this.value, this.modelValue,this.disabled, this.inactiveColor, this.activeColor, this.size, this.labelDisabled, this.shape,
          this.iconSize, this.borderBottom, this.placement
        ]
      },
      bemClass() {
        // this.bem为一个computed变量,在mixin中
        return this.bem('checkbox-group', ['placement'])
      },
    },
    watch: {
      // 当父组件需要子组件需要共享的参数发生了变化,手动通知子组件
      parentData() {
        if (this.children.length) {
          this.children.map(child => {
            // 判断子组件(u-checkbox)如果有init方法的话,就就执行(执行的结果是子组件重新从父组件拉取了最新的值)
            typeof(child.init) === 'function' && child.init()
          })
        }
      },
    },
    data() {
      return {
 
      }
    },
    created() {
      this.children = []
    },
    methods: {
      // 将其他的checkbox设置为未选中的状态
      unCheckedOther(childInstance) {
        const values = []
        this.children.map(child => {
          // 将被选中的checkbox,放到数组中返回
          if (child.isChecked) {
            values.push(child.name)
          }
        })
        this.$nextTick(()=>{
          // 发出事件
          this.$emit('change', values)
        })
        // 修改通过v-model绑定的值
        this.$emit('input', values)
        this.$emit("update:modelValue", values);
        // 由于头条小程序执行迟钝,故需要用几十毫秒的延时
        setTimeout(() => {
          // 将当前的值发送到 u-form-item 进行校验
          this.dispatch("u-form-item", "onFieldChange", values);
        }, 60);
      },
    }
  }
</script>
 
<style lang="scss" scoped>
  @import "../../libs/css/style.components.scss";
  .u-checkbox-group {
 
    &--row {
      @include vue-flex;
      flex-wrap: wrap;
    }
 
    &--column {
      @include vue-flex(column);
      flex-wrap: wrap;
    }
  }
</style>


 let checkbox = {
  name: '',
  shape: '',
  size: '',
  checkbox: false,
  disabled: '',
  activeColor: '',
  inactiveColor: '',
  iconSize: '',
  iconColor: '',
  label: '',
  labelSize: '',
  labelColor: '',
  labelDisabled: ''
 }
 export default {
  props: {
    // checkbox的名称
    name: {
      type: [String, Number, Boolean],
      default: checkbox.name
    },
    // 形状,square为方形,circle为圆型
    shape: {
      type: String,
      default: checkbox.shape
    },
    // 整体的大小
    size: {
      type: [String, Number],
      default: checkbox.size
    },
    // 每个组件都有的父组件传递的样式,可以为字符串或者对象形式
    customStyle: {
      type: [Object, String],
      default: () => ({})
    },
    customClass: {
      type: String,
      default: ''
    },
    // 是否默认选中
    checked: {
      type: Boolean,
      default: checkbox.checked
    },
    // 是否禁用
    disabled: {
      type: [String, Boolean],
      default: checkbox.disabled
    },
    // 选中状态下的颜色,如设置此值,将会覆盖parent的activeColor值
    activeColor: {
      type: String,
      default: checkbox.activeColor
    },
    // 未选中的颜色
    inactiveColor: {
      type: String,
      default: checkbox.inactiveColor
    },
    // 图标的大小,单位px
    iconSize: {
      type: [String, Number],
      default: checkbox.iconSize
    },
    // 图标颜色
    iconColor: {
      type: String,
      default: checkbox.iconColor
    },
    // label提示文字,因为nvue下,直接slot进来的文字,由于特殊的结构,无法修改样式
    label: {
      type: [String, Number],
      default: checkbox.label
    },
    // label的字体大小,px单位
    labelSize: {
      type: [String, Number],
      default: checkbox.labelSize
    },
    // label的颜色
    labelColor: {
      type: String,
      default: checkbox.labelColor
    },
    // 是否禁止点击提示语选中复选框
    labelDisabled: {
      type: [String, Boolean],
      default: checkbox.labelDisabled
    },
    activeImg:{
      type: String,
      default: ''
    },
    img:{
      type: String,
      default: ''
    }
  }
 }
<template>
  <view
      class="u-checkbox"
      :style="[checkboxStyle]"
      @tap.stop="wrapperClickHandler"
      :class="[`u-checkbox-label--${parentData.iconPlacement}`, parentData.borderBottom && parentData.placement === 'column' && 'u-border-bottom']"
  >
    <view
        class="u-checkbox__image-wrap"
        @tap.stop="iconClickHandler"
        :class="iconClasses"
      v-if="activeImg&&img" 
    >
      <image class="u-checkbox__image-wrap_img" :style="{width:$u.addUnit(elIconSize*2),height:$u.addUnit(elIconSize*2)}" :src="isChecked?activeImg:img"></image>
    </view>
    <view
        v-else
        class="u-checkbox__icon-wrap"
        @tap.stop="iconClickHandler"
        :class="iconClasses"
        :style="[iconWrapStyle]"
    >
      <slot name="icon">
        <u-icon
            class="u-checkbox__icon-wrap__icon"
            name="checkbox-mark"
            :size="elIconSize"
            :color="elIconColor"
        />
      </slot>
    </view>
    <view
        @tap.stop="labelClickHandler"
      class="u-checkbox__label"
        :style="{
        color: elDisabled ? elInactiveColor : elLabelColor,
        fontSize: elLabelSize,
        lineHeight: elLabelSize
      }"
    ><slot /></view>
  </view>
</template>
 
<script>
  import props from './props.js';
  /**
   * checkbox  复选框
   * @description 复选框组件一般用于需要多个选择的场景,该组件功能完整,使用方便
   * @tutorial https://uviewui.com/components/checkbox.html
   * @property {String | Number | Boolean}  name      checkbox组件的标示符
   * @property {String}           shape     形状,square为方形,circle为圆型
   * @property {String | Number}        size      整体的大小
   * @property {Boolean}            checked     是否默认选中
   * @property {String | Boolean}       disabled    是否禁用
   * @property {String}           activeColor   选中状态下的颜色,如设置此值,将会覆盖parent的activeColor值
   * @property {String}           inactiveColor 未选中的颜色
   * @property {String | Number}        iconSize    图标的大小,单位px
   * @property {String}           iconColor   图标颜色
   * @property {String | Number}        label     label提示文字,因为nvue下,直接slot进来的文字,由于特殊的结构,无法修改样式
   * @property {String}           labelColor    label的颜色
   * @property {String | Number}        labelSize   label的字体大小,px单位
   * @property {String | Boolean}       labelDisabled 是否禁止点击提示语选中复选框
   * @property {Object}           customStyle   定义需要用到的外部样式
   * 
   * @event {Function}  change  任一个checkbox状态发生变化时触发,回调为一个对象
   * @example <u-checkbox v-model="checked" :disabled="false">天涯</u-checkbox>
   */
  export default {
    name: "u-checkbox",
    mixins: [props],
    data() {
      return {
        isChecked: false,
        // 父组件的默认值,因为头条小程序不支持在computed中使用this.parent.shape的形式
        // 故只能使用如此方法
        parentData: {
          iconSize: 12,
          labelDisabled: null,
          disabled: null,
          shape: 'square',
          activeColor: null,
          inactiveColor: null,
          size: 18,
          value: null,
          iconColor: null,
          placement: 'row',
          borderBottom: false,
          iconPlacement: 'left'
        }
      }
    },
    computed: {
      // 是否禁用,如果父组件u-raios-group禁用的话,将会忽略子组件的配置
      elDisabled() {
        return this.disabled !== '' ? this.disabled : this.parentData.disabled !== null ? this.parentData.disabled : false;
      },
      // 是否禁用label点击
      elLabelDisabled() {
        return this.labelDisabled !== '' ? this.labelDisabled : this.parentData.labelDisabled !== null ? this.parentData.labelDisabled :
          false;
      },
      // 组件尺寸,对应size的值,默认值为21px
      elSize() {
        return this.size ? this.size : (this.parentData.size ? this.parentData.size : 21);
      },
      // 组件的勾选图标的尺寸,默认12px
      elIconSize() {
        return this.iconSize ? this.iconSize : (this.parentData.iconSize ? this.parentData.iconSize : 12);
      },
      // 组件选中激活时的颜色
      elActiveColor() {
        return this.activeColor ? this.activeColor : (this.parentData.activeColor ? this.parentData.activeColor : '#2979ff');
      },
      // 组件选未中激活时的颜色
      elInactiveColor() {
        return this.inactiveColor ? this.inactiveColor : (this.parentData.inactiveColor ? this.parentData.inactiveColor :
          '#c8c9cc');
      },
      // label的颜色
      elLabelColor() {
        return this.labelColor ? this.labelColor : (this.parentData.labelColor ? this.parentData.labelColor : '#606266')
      },
      // 组件的形状
      elShape() {
        return this.shape ? this.shape : (this.parentData.shape ? this.parentData.shape : 'circle');
      },
      // label大小
      elLabelSize() {
        let labelSize = this.labelSize ? this.labelSize : this.parentData.labelSize
        if(!labelSize){
          return 'inherit'
        }
        return uni.$u.addUnit(labelSize+'px')
      },
      elIconColor() {
        const iconColor = this.iconColor ? this.iconColor : (this.parentData.iconColor ? this.parentData.iconColor :
          '#ffffff');
        // 图标的颜色
        if (this.elDisabled) {
          // disabled状态下,已勾选的checkbox图标改为elInactiveColor
          return this.isChecked ? this.elInactiveColor : 'transparent'
        } else {
          return this.isChecked ? iconColor : 'transparent'
        }
      },
      iconClasses() {
        let classes = []
        // 组件的形状
        classes.push('u-checkbox__icon-wrap--' + this.elShape)
        if (this.elDisabled) {
          classes.push('u-checkbox__icon-wrap--disabled')
        }
        if (this.isChecked && this.elDisabled) {
          classes.push('u-checkbox__icon-wrap--disabled--checked')
        }
        // 支付宝,头条小程序无法动态绑定一个数组类名,否则解析出来的结果会带有",",而导致失效
        // #ifdef MP-ALIPAY || MP-TOUTIAO
        classes = classes.join(' ')
        // #endif
        return classes
      },
      iconWrapStyle() {
        // checkbox的整体样式
        const style = {}
        style.backgroundColor = this.isChecked && !this.elDisabled ? this.elActiveColor : '#ffffff'
        style.borderColor = this.isChecked && !this.elDisabled ? this.elActiveColor : this.elInactiveColor
        style.width = uni.$u.addUnit(this.elSize+'px')
        style.height = uni.$u.addUnit(this.elSize+'px')
        // 如果是图标在右边的话,移除它的右边距
        if (this.parentData.iconPlacement === 'right') {
          style.marginRight = 0
        }
        return style
      },
      checkboxStyle() {
        const style = {}
        if (this.parentData.borderBottom && this.parentData.placement === 'row') {
          uni.$u.error('检测到您将borderBottom设置为true,需要同时将u-checkbox-group的placement设置为column才有效')
        }
        // 当父组件设置了显示下边框并且排列形式为纵向时,给内容和边框之间加上一定间隔
        if (this.parentData.borderBottom && this.parentData.placement === 'column') {
          style.paddingBottom = '8px'
        }
        return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle))
      }
    },
    mounted() {
      this.init()
    },
    methods: {
      init() {
        // 支付宝小程序不支持provide/inject,所以使用这个方法获取整个父组件,在created定义,避免循环引用
        this.updateParentData()
        if (!this.parent) {
          uni.$u.error('u-checkbox必须搭配u-checkbox-group组件使用')
        }
        // 设置初始化时,是否默认选中的状态,父组件u-checkbox-group的value可能是array,所以额外判断
        if (this.checked) {
          this.isChecked = true
        } else if (uni.$u.test.array(this.parentData.value)) {
          // 查找数组是是否存在this.name元素值
          this.isChecked = this.parentData.value.some(item => {
            return item === this.name
          })
        }
      },
      updateParentData() {
        this.getParentData('u-checkbox-group')
      },
      // 横向两端排列时,点击组件即可触发选中事件
      wrapperClickHandler(e) {
        this.parentData.iconPlacement === 'right' && this.iconClickHandler(e)
      },
      // 点击图标
      iconClickHandler(e) {
        this.preventEvent(e)
        // 如果整体被禁用,不允许被点击
        if (!this.elDisabled) {
          this.setRadioCheckedStatus()
        }
      },
      // 点击label
      labelClickHandler(e) {
        this.preventEvent(e)
        // 如果按钮整体被禁用或者label被禁用,则不允许点击文字修改状态
        if (!this.elLabelDisabled && !this.elDisabled) {
          this.setRadioCheckedStatus()
        }
      },
      emitEvent() {
        this.$emit('change', this.isChecked)
        // 尝试调用u-form的验证方法,进行一定延迟,否则微信小程序更新可能会不及时
        // this.$nextTick(() => {
        //  uni.$u.formValidate(this, 'change')
        // })
      },
      // 改变组件选中状态
      // 这里的改变的依据是,更改本组件的checked值为true,同时通过父组件遍历所有u-checkbox实例
      // 将本组件外的其他u-checkbox的checked都设置为false(都被取消选中状态),因而只剩下一个为选中状态
      setRadioCheckedStatus() {
        // 将本组件标记为与原来相反的状态
        this.isChecked = !this.isChecked
        this.emitEvent()
        typeof this.parent.unCheckedOther === 'function' && this.parent.unCheckedOther(this)
      }
    },
    watch:{
      checked(){
        this.isChecked = this.checked
      }
    }
  }
</script>
 
<style lang="scss" scoped>
  @import "../../libs/css/style.components.scss";
  $u-checkbox-icon-wrap-margin-right:0px !default;
  $u-checkbox-icon-wrap-font-size:6px !default;
  $u-checkbox-icon-wrap-border-width:1px !default;
  $u-checkbox-icon-wrap-border-color:#c8c9cc !default;
  $u-checkbox-icon-wrap-icon-line-height:0 !default;
  $u-checkbox-icon-wrap-circle-border-radius:100% !default;
  $u-checkbox-icon-wrap-square-border-radius:3px !default;
  $u-checkbox-icon-wrap-checked-color:#fff !default;
  $u-checkbox-icon-wrap-checked-background-color:red !default;
  $u-checkbox-icon-wrap-checked-border-color:#2979ff !default;
  $u-checkbox-icon-wrap-disabled-background-color:#ebedf0 !default;
  $u-checkbox-icon-wrap-disabled-checked-color:#c8c9cc !default;
  $u-checkbox-label-margin-left:5px !default;
  $u-checkbox-label-margin-right:12px !default;
  $u-checkbox-label-color:$u-content-color !default;
  $u-checkbox-label-font-size:15px !default;
  $u-checkbox-label-disabled-color:#c8c9cc !default;
 
  .u-checkbox {
    /* #ifndef APP-NVUE */
    @include vue-flex(row);
    /* #endif */
    overflow: hidden;
    flex-direction: row;
    align-items: center;
    line-height: 1.8;
 
    &-label--left {
      flex-direction: row
    }
 
    &-label--right {
      flex-direction: row-reverse;
      justify-content: space-between
    }
 
      &__image-wrap{
      @include vue-flex;
      flex-shrink: 0;
      align-items: center;
      justify-content: center;
      color: transparent;
      text-align: center;
    }
  
    &__icon-wrap {
      /* #ifndef APP-NVUE */
      box-sizing: border-box;
      // nvue下,border-color过渡有问题
      transition-property: border-color, background-color, color;
      transition-duration: 0.2s;
      /* #endif */
      color: $u-content-color;
      @include vue-flex;
      flex-shrink: 0;
      align-items: center;
      justify-content: center;
      color: transparent;
      text-align: center;
      margin-right: $u-checkbox-icon-wrap-margin-right;
 
      font-size: $u-checkbox-icon-wrap-font-size;
      border-width: $u-checkbox-icon-wrap-border-width;
      border-color: $u-checkbox-icon-wrap-border-color;
      border-style: solid;
 
      /* #ifdef MP-TOUTIAO */
      // 头条小程序兼容性问题,需要设置行高为0,否则图标偏下
      &__icon {
        line-height: $u-checkbox-icon-wrap-icon-line-height;
      }
 
      /* #endif */
 
      &--circle {
        border-radius: $u-checkbox-icon-wrap-circle-border-radius;
      }
 
      &--square {
        border-radius: $u-checkbox-icon-wrap-square-border-radius;
      }
 
      &--checked {
        color: $u-checkbox-icon-wrap-checked-color;
        background-color: $u-checkbox-icon-wrap-checked-background-color;
        border-color: $u-checkbox-icon-wrap-checked-border-color;
      }
 
      &--disabled {
        background-color: $u-checkbox-icon-wrap-disabled-background-color !important;
      }
 
      &--disabled--checked {
        color: $u-checkbox-icon-wrap-disabled-checked-color !important;
      }
    }
 
    &__label {
      flex:1;
      /* #ifndef APP-NVUE */
      word-wrap: break-word;
      /* #endif */
      margin-left: $u-checkbox-label-margin-left;
      margin-right: $u-checkbox-label-margin-right;
      color: $u-checkbox-label-color;
      font-size: $u-checkbox-label-font-size;
 
      &--disabled {
        color: $u-checkbox-label-disabled-color;
      }
    }
  }
</style>
目录
相关文章
|
6月前
|
前端开发 JavaScript
使用JavaScript实现复杂功能:构建一个自定义的拖拽功能
使用JavaScript实现复杂功能:构建一个自定义的拖拽功能
|
4月前
|
前端开发 JavaScript 索引
uniapp的u-album组件自定义删除功能
这样,你就可以在u-album组件中实现自定义的删除功能了。需要注意的是,这个删除操作只是在前端删除了图片项,并没有在后端删除对应的图片文件,如果你需要在后端也删除对应的图片文件,你还需要在删除操作后发送一个请求到后端,让后端删除对应的图片文件。
114 0
|
4月前
|
小程序 JavaScript 前端开发
【微信小程序-原生开发】实用教程06-轮播图、分类页签 tab 、成员列表(含Tdesign升级,切换调试基础库,设置全局样式,配置组件按需注入,添加图片素材,wx:for,生命周期 onLoad)
【微信小程序-原生开发】实用教程06-轮播图、分类页签 tab 、成员列表(含Tdesign升级,切换调试基础库,设置全局样式,配置组件按需注入,添加图片素材,wx:for,生命周期 onLoad)
140 0
|
6月前
|
JavaScript 前端开发 API
【每周一个小技巧】如何自定义客服、生活号组件的样式
【每周一个小技巧】如何自定义客服、生活号组件的样式
67 8
|
6月前
Qt表格中的自定义编辑组件---------------自定义代理QStyledItemDelegate
Qt表格中的自定义编辑组件---------------自定义代理QStyledItemDelegate
75 5
|
前端开发 程序员
前端反卷计划-组件库-03-组件样式
前端反卷计划-组件库-03-组件样式
|
JavaScript
vue项目实现预览pdf功能(解决动态文字无法显示的问题)
最近,因为公司项目需要预览pdf的功能,开始的时候找了市面上的一些pdf插件,都能用,但是,后面因为pdf变成了需要根据内容进行变化的,然后,就出现了需要动态生成的文字不显示了。换了好多好多的插件,都无法显示,直接无语了。 (pdf-vue3,pdf.js,vue3-pdfjs,vue-pdf-embed等插件无法显示动态文字)
749 0
|
JavaScript
fastadmin 自定义 按钮 动态切换数据 TAB切换
fastadmin 自定义 按钮 动态切换数据 TAB切换
278 0
|
JavaScript
vue 里使用 antv g6 实现脑图左右布局、文本超出隐藏处理、自定义边、自定义节点、自定义事件功能
vue 里使用 antv g6 实现脑图左右布局、文本超出隐藏处理、自定义边、自定义节点、自定义事件功能
2237 0
vue 里使用 antv g6 实现脑图左右布局、文本超出隐藏处理、自定义边、自定义节点、自定义事件功能