单选复选状态控制类

场景

不同的平台写基础组件,写累了,对于单选复选这种逻辑闭合的组件,javascript 控制脚本是可以完全独立出来的,仅对外暴露状态即可根据不同的平台和环境进行视图的渲染

效果

请添加图片描述

使用

初始化

 let selector = new Selector({
    
    
     key: 'value',
     multiple: true,
     limit: 2,
     changeHandle: (selection, selectionMap) => {
    
    
       this.status = selectionMap
     },
     invalidHandle: (msg) => {
    
    
       console.log(msg)
     }
 })

invalidHandle 为触发但是没有实际变更内容的动作的回调
changeHandle 为选项发生变化时触发
selectionMap 为选中状态字典,将值赋给status后在视图中按照如下方式渲染

 <template v-for="(item,index) in ops">
    <span class="item" :class="{'active':status[item.value]}"
          @click="toggle(item.value)">
      {
    
    {
    
    item.label}}
    </span>
 </template>

常用的方法

toggle(key,status) 单选或者复选模式下切换指定key的状态
toggleMulti(data:[{key:Any,status:Boolean}]) 复选模式下批量修改key的状态
getSelection 获取选中项
setData(Array) 动态设置可选项的时候会用到,如果需要保留变化前的状态,只需要再
toggle或者 toggleMulti 一下就行了

代码

/*
* 选择器
* 限制必须使用 key 指明选项的唯一索引,常理下各项一定是互相不同的,即使原始数据存在相同项也要尝试给添加一个唯一标识
* */
const TIP_NO_CHANGE = '未变化的值',
  TIP_TOGGLE_MULTI_NO_MATCH = '非多选模式不可调用',
  TIP_OVER_LIMIT = '超出上限';

export class Selector {
    
    
  data = []
  multiple = false
  limit = Infinity
  nodeMap = null
  key = null
  changeHandle = null
  invalidHandle = null

  constructor(option = {
     
     }) {
    
    
    this.multiple = option.multiple || false
    this.key = option.key || 'value'
    this.limit = +(option.limit) || Infinity

    this.changeHandle = option.changeHandle
    this.invalidHandle = option.invalidHandle
    this.setData(option.data)
  }

  /**
   * 设置选项值,根据key生成节点索引
   */
  setData(data = []) {
    
    
    const vm = this, {
    
     key } = vm
    vm.data = data
    let nodeMapTemp = {
    
    }
    for (let i = 0, item; (item = data[i]) != null; i++) {
    
    
      nodeMapTemp[item[key]] = {
    
     index: i, status: false }
    }
    vm.nodeMap = nodeMapTemp
  }

  /**
   * 单选|复选  通过指定key 变更选项状态
   *
   * 单选模式下对于触发的选项无论如何只会有 false => true 一种行为
   * @param key
   * @param status
   */
  toggle(key, status) {
    
    
    const vm = this, {
    
     multiple } = vm
    let keyNode = vm.nodeMap[key]
    if (keyNode) {
    
    
      if (multiple) {
    
    
        vm.toggleMulti({
    
     key, status })
      } else {
    
    
        let active = vm.getSelection()[0]
        if (active && active[vm.key] != key) {
    
    
          vm.nodeMap[active[vm.key]].status = false
        }
        if (keyNode.status != true) {
    
    
          keyNode.status = true
          vm.change()
        } else {
    
    
          vm.invalid(TIP_NO_CHANGE)
        }
      }
    }
  }

  /**
   * 批量变更指定状态,必须使用key指明选项
   * @param data:[{key:Any,status:Boolean}]
   */
  toggleMulti(data) {
    
    
    const vm = this, {
    
     limit, multiple } = vm
    if (!multiple) {
    
    
      vm.invalid(TIP_TOGGLE_MULTI_NO_MATCH)
      return
    }
    if (!(data instanceof Array)) {
    
    
      data = [data]
    }
    let hasChange = false
    let nextSelection = []
    for (let i = 0, item; (item = data[i]) != null; i++) {
    
    
      let keyData = this.nodeMap[item.key]

      if (keyData) {
    
    
        if (item.status == null) {
    
    
          item.status = !(keyData.status)
        }
        //1) 若选项为不可编辑,跳过
        if (keyData.disable === true) {
    
    
          continue
        }
        //2) 若选项新状态为true且不在超过已选上限,跳过
        if (item.status) {
    
    
          nextSelection.push(item)
        } else {
    
    
          if (vm.nodeMap[item.key].status) {
    
    
            hasChange = true
          }
          vm.nodeMap[item.key].status = false
        }
      }
    }
    let selectionLen = vm.getSelection().length
    for (let i = 0, item; (item = nextSelection[i]) != null; i++) {
    
    
      if (selectionLen >= limit) {
    
    
        vm.invalid(TIP_OVER_LIMIT)
        break
      } else {
    
    
        if (!vm.nodeMap[item.key].status) {
    
    
          hasChange = true
        }
        vm.nodeMap[item.key].status = true
        selectionLen++
      }
    }
    if (hasChange) {
    
    
      vm.change()
    }
  }

  getSelection() {
    
    
    const vm = this, {
    
     key } = vm;
    return vm.data.filter(d => vm.nodeMap[d[key]].status)
  }

  invalid(msg) {
    
    
    if (this.invalidHandle) {
    
    
      this.invalidHandle(msg)
    }
  }

  change() {
    
    
    const vm = this
    let selection = vm.getSelection()
    let statusMap = {
    
    }
    selection.forEach(d => statusMap[d[vm.key]] = true)
    vm.changeHandle(selection, statusMap)
  }
}

猜你喜欢

转载自blog.csdn.net/weixin_43954962/article/details/126936205