Browse Source

upd: checkbox-group 开发

yumingming11 5 years ago
parent
commit
dcfff52b79

+ 10 - 0
src/config.js

@@ -234,6 +234,16 @@ module.exports = {
           sort: 10,
           show: false,
           author: 'Ymm0008'
+        },
+        {
+          version: '3.0.0',
+          name: 'CheckboxGroup',
+          type: 'component',
+          cName: '多选按钮组',
+          desc: '多选按钮组',
+          sort: 11,
+          show: false,
+          author: 'Ymm0008'
         }
       ]
     },

+ 114 - 25
src/packages/checkbox/demo.vue

@@ -7,11 +7,30 @@
       >
       <span>{{ checkbox1 }}</span>
     </div>
+    <p class="p-word"
+      >组合使用 checkbox 时推荐使用 checkboxgroup 组件,见下方示例</p
+    >
+    <h4>CheckboxGroup基本用法</h4>
+    <div class="show-demo">
+      <nut-checkboxgroup v-model="checkboxGroup1">
+        <nut-checkbox label="选项一"></nut-checkbox>
+        <nut-checkbox label="选项二"></nut-checkbox>
+      </nut-checkboxgroup>
+      <p>选择状态:{{ checkboxGroup1 }}</p>
+    </div>
     <h4>禁用状态</h4>
     <div class="show-demo show-demo-block">
       <nut-checkbox v-model="checkbox2" disabled>未选时禁用状态</nut-checkbox>
       <nut-checkbox v-model="checkbox3" disabled>已选时禁用状态</nut-checkbox>
     </div>
+    <h4>CheckboxGroup整体禁用</h4>
+    <div class="show-demo">
+      <nut-checkboxgroup v-model="checkboxGroup2" disabled>
+        <nut-checkbox label="选项一"></nut-checkbox>
+        <nut-checkbox label="选项二"></nut-checkbox>
+      </nut-checkboxgroup>
+      <p>选择状态:{{ checkboxGroup2 }}</p>
+    </div>
     <h4>自定义尺寸</h4>
     <div class="show-demo show-demo-block">
       <nut-checkbox v-model="checkbox4" size="small">小号1</nut-checkbox>
@@ -19,6 +38,13 @@
       <nut-checkbox v-model="checkbox6" size="large">大号</nut-checkbox>
       <p>size可选值:'small', 'base', 'large'</p>
     </div>
+    <h4>CheckboxGroup整体尺寸</h4>
+    <div class="show-demo">
+      <nut-checkboxgroup v-model="checkboxGroup3" size="small">
+        <nut-checkbox label="选项一"></nut-checkbox>
+        <nut-checkbox label="选项二"></nut-checkbox>
+      </nut-checkboxgroup>
+    </div>
     <h4>禁用动效</h4>
     <div class="show-demo">
       <nut-checkbox v-model="checkbox7" :animation="false"
@@ -26,6 +52,13 @@
       >
       <p>animation属性值为false时,禁用自带动效</p>
     </div>
+    <h4>CheckboxGroup整体禁用动效</h4>
+    <div class="show-demo">
+      <nut-checkboxgroup v-model="checkboxGroup4" :animation="false">
+        <nut-checkbox label="没有动效1"></nut-checkbox>
+        <nut-checkbox label="没有动效2"></nut-checkbox>
+      </nut-checkboxgroup>
+    </div>
     <h4>事件</h4>
     <div class="show-demo">
       <div class="demo-box">
@@ -36,29 +69,17 @@
           >备选项</nut-checkbox
         >
         <span>{{ result1 }}</span>
-        <p>值发生变化时,将触发change事件</p>
       </div>
     </div>
+    <h4>CheckboxGroup整体事件</h4>
     <div class="show-demo">
-      <div class="demo-box">
-        <nut-checkbox
-          v-model="checkbox10"
-          :label="'选项值1'"
-          @change="getChange"
-          >change事件</nut-checkbox
-        >
-        <span>{{ result2 }}</span>
+      <div>
+        <nut-checkboxgroup v-model="checkboxGroup4" @change="getChange">
+          <nut-checkbox label="选项一"></nut-checkbox>
+          <nut-checkbox label="选项二"></nut-checkbox>
+        </nut-checkboxgroup>
       </div>
-      <div class="demo-box">
-        <nut-checkbox
-          v-model="checkbox11"
-          :label="'选项值2'"
-          @change="getChange2"
-          >change事件</nut-checkbox
-        >
-        <span>{{ result3 }}</span>
-      </div>
-      <p>设置label时,可获取选项label值</p>
+      <span>{{ result2 }}</span>
     </div>
     <h4>自定义Class</h4>
     <div class="show-demo">
@@ -66,6 +87,47 @@
         >自定义Class:"my-checkbox"</nut-checkbox
       >
     </div>
+    <h4>全选与反选</h4>
+    <div class="show-demo">
+      <div>
+        <nut-checkboxgroup
+          ref="checkboxGroupDemo"
+          v-model="checkboxGroup5"
+          @change="getChange2"
+        >
+          <nut-checkbox label="选项一"></nut-checkbox>
+          <nut-checkbox label="选项二"></nut-checkbox>
+          <nut-checkbox label="选项三"></nut-checkbox>
+        </nut-checkboxgroup>
+      </div>
+      <div>
+        <span>{{ result3 }}</span>
+      </div>
+      <nut-button size="small" type="primary" @click="chooseAll(true)"
+        >全选</nut-button
+      >
+      <nut-button size="small" type="primary" @click="chooseAll()"
+        >反选</nut-button
+      >
+      <nut-button size="small" type="primary" @click="chooseAll(false)"
+        >取消</nut-button
+      >
+    </div>
+    <h4>CheckboxGroup排列方向</h4>
+    <div class="show-demo">
+      <div>
+        <nut-checkboxgroup
+          v-model="checkboxGroup6"
+          direction="vertical"
+          @change="getChange3"
+        >
+          <nut-checkbox label="选项一"></nut-checkbox>
+          <nut-checkbox label="选项二"></nut-checkbox>
+          <nut-checkbox label="选项三"></nut-checkbox>
+        </nut-checkboxgroup>
+      </div>
+      <span>{{ result2 }}</span>
+    </div>
   </div>
 </template>
 <script lang="ts">
@@ -87,12 +149,19 @@ export default createDemo({
       checkbox10: true,
       checkbox11: false,
       checkbox12: true,
-      checkbox13: false
+      checkbox13: false,
+      checkboxGroup1: ['选项一'],
+      checkboxGroup2: ['选项一'],
+      checkboxGroup3: [],
+      checkboxGroup4: ['选项一'],
+      checkboxGroup5: [],
+      checkboxGroup6: []
     });
     const result = reactive({
       result1: '',
       result2: '',
-      result3: ''
+      result3: '',
+      result4: ''
     });
     const changeBox1 = (state: boolean) => {
       data.checkbox1 = state;
@@ -100,17 +169,27 @@ export default createDemo({
     const checkboxChange = (state: string, val: string) => {
       result.result1 = state;
     };
-    const getChange = (state: boolean, val: string) => {
-      result.result2 = '选中状态:' + state + ',选项:' + val;
+    const getChange = (val: string) => {
+      result.result2 = '选中状态选项:' + val;
+    };
+    const getChange2 = (val: string) => {
+      result.result3 = '选中状态选项:' + val;
     };
-    const getChange2 = (state: boolean, val: string) => {
-      result.result3 = '选中状态:' + state + ',选项:' + val;
+    const getChange3 = (val: string) => {
+      result.result4 = '选中状态选项:' + val;
+    };
+    const checkboxGroupDemo = ref(null);
+    const chooseAll = (val: boolean | string) => {
+      (checkboxGroupDemo.value as any).toggleAll(val);
     };
     return {
       changeBox1,
       checkboxChange,
+      checkboxGroupDemo,
       getChange,
       getChange2,
+      getChange3,
+      chooseAll,
       ...toRefs(data),
       ...toRefs(result)
     };
@@ -148,6 +227,16 @@ export default createDemo({
     span {
       font-size: 12px;
     }
+    .nut-button {
+      margin: 10px 10px 0 0;
+    }
+  }
+  .p-word {
+    margin: 15px 0;
+    font-size: 14px;
+    color: #636363;
+    padding-left: 5px;
+    border-left: 8px solid #03a9f4;
   }
   .show-demo-block {
     view {

+ 4 - 0
src/packages/checkbox/index.scss

@@ -1,3 +1,7 @@
+.nut-checkboxgroup-vertical .nut-checkbox {
+  display: block;
+  margin-top: 8px;
+}
 .nut-checkbox {
   margin-right: 10px;
   .nut-checkbox-label {

+ 95 - 22
src/packages/checkbox/index.vue

@@ -1,11 +1,11 @@
 <template>
   <view>
-    <label :class="['nut-checkbox', 'nut-checkbox-size-' + size]">
+    <label :class="['nut-checkbox', 'nut-checkbox-size-' + currentSize]">
       <input
         type="checkbox"
         :name="name"
-        :class="{ 'nut-checkbox-ani': animation }"
-        :disabled="disabled"
+        :class="{ 'nut-checkbox-ani': isAnimated }"
+        :disabled="isDisabled"
         :checked.prop="isChecked"
         :value="submittedValue"
         @change="changeEvt"
@@ -20,7 +20,16 @@
   </view>
 </template>
 <script lang="ts">
-import { reactive, ref, toRefs, watch, watchEffect } from 'vue';
+import {
+  reactive,
+  ref,
+  toRefs,
+  watch,
+  watchEffect,
+  computed,
+  getCurrentInstance,
+  inject
+} from 'vue';
 import { createComponent } from '@/utils/create';
 const { componentName, create } = createComponent('checkbox');
 
@@ -65,32 +74,96 @@ export default create({
   },
   components: {},
   setup(props, { emit }) {
-    const isCheckedVal = props.modelValue == props.trueValue || props.checked;
-    const isChecked = ref(isCheckedVal);
+    const parentGroup = inject('checkboxgroup', {
+      parentNode: false,
+      changeVal: val => {
+        console.log();
+      }
+    });
+    const parentProps = getCurrentInstance()?.parent?.props;
+
+    const isChecked = computed(() => {
+      if (parentGroup && parentGroup.parentNode) {
+        const choosedVal = parentProps?.modelValue;
+        const chooseFlag =
+          (choosedVal as any).indexOf(props.label) == -1 ? false : true;
+        return chooseFlag;
+      } else {
+        const isCheckedVal =
+          props.modelValue == props.trueValue || props.checked;
+        return isCheckedVal;
+      }
+    });
+    // const isCheckedVal = props.modelValue == props.trueValue || props.checked;
+    // const isChecked = ref(isCheckedVal);
     const isObject = obj => {
       return obj !== null && typeof obj === 'object';
     };
 
-    const looseEqual = (a, b) => {
-      return (
-        a == b ||
-        (isObject(a) && isObject(b)
-          ? JSON.stringify(a) === JSON.stringify(b)
-          : false)
-      );
-    };
+    // const looseEqual = (a, b) => {
+    //   return (
+    //     a == b ||
+    //     (isObject(a) && isObject(b)
+    //       ? JSON.stringify(a) === JSON.stringify(b)
+    //       : false)
+    //   );
+    // };
 
-    watchEffect(() => {
-      isChecked.value = looseEqual(props.modelValue, props.trueValue);
+    const isDisabled = computed(() => {
+      if (parentGroup && parentGroup.parentNode) {
+        return parentProps?.disabled;
+      } else {
+        return props.disabled;
+      }
     });
 
-    const { size, label, name, disabled, submittedValue, animation } = reactive(
-      props
-    );
+    const currentSize = computed(() => {
+      if (parentGroup && parentGroup.parentNode) {
+        return parentProps?.size;
+      } else {
+        return props.size;
+      }
+    });
+
+    const isAnimated = computed(() => {
+      if (parentGroup && parentGroup.parentNode) {
+        return parentProps?.animated;
+      } else {
+        return props.animation;
+      }
+    });
+
+    const { label, name, submittedValue } = reactive(props);
+
+    const setParentValue = checked => {
+      // const { label } = props;
+      // const { max, modelValue } = parentProps?.modelValue;
+      const modelValue = parentProps?.modelValue;
+      const value = (modelValue as any).slice();
+      if (checked) {
+        if (value.indexOf(label) === -1) {
+          value.push(label);
+          parentGroup?.changeVal(value);
+        }
+      } else {
+        const index = value.indexOf(label);
+        if (index !== -1) {
+          value.splice(index, 1);
+          parentGroup?.changeVal(value);
+        }
+      }
+    };
 
     const changeEvt = (event: any) => {
       event?.stopPropagation();
       const isCheck: boolean = event.target.checked;
+      if (isDisabled.value) {
+        return false;
+      }
+      if (parentGroup.parentNode) {
+        setParentValue(isCheck);
+        return false;
+      }
       emit('update:modelValue', isCheck);
       emit(
         'input',
@@ -109,12 +182,12 @@ export default create({
     };
 
     return {
-      size,
+      currentSize,
       label,
       name,
-      disabled,
+      isDisabled,
       submittedValue,
-      animation,
+      isAnimated,
       isChecked,
       changeEvt
     };

+ 25 - 0
src/packages/checkboxgroup/demo.vue

@@ -0,0 +1,25 @@
+<template>
+  <div class="demo">
+    <h2>基础用法</h2>
+    <nut-cell>
+      <nut-temp name="wifi"></nut-temp>
+      <nut-temp name="mail" txt="test txt"></nut-temp>
+    </nut-cell>
+  </div>
+</template>
+
+<script lang="ts">
+import { createComponent } from '@/utils/create';
+const { createDemo } = createComponent('checkboxgroup');
+export default createDemo({
+  props: {},
+  setup() {
+    return {};
+  }
+});
+</script>
+
+<style lang="scss" scoped>
+.nut-temp {
+}
+</style>

+ 34 - 0
src/packages/checkboxgroup/doc.md

@@ -0,0 +1,34 @@
+#  checkboxgroup组件
+
+    ### 介绍
+    
+    基于 xxxxxxx
+    
+    ### 安装
+    
+    
+    
+    ## 代码演示
+    
+    ### 基础用法1
+    
+
+    
+    ## API
+    
+    ### Props
+    
+    | 参数         | 说明                             | 类型   | 默认值           |
+    |--------------|----------------------------------|--------|------------------|
+    | name         | 图标名称或图片链接               | String | -                |
+    | color        | 图标颜色                         | String | -                |
+    | size         | 图标大小,如 '20px' '2em' '2rem' | String | -                |
+    | class-prefix | 类名前缀,用于使用自定义图标     | String | 'nutui-iconfont' |
+    | tag          | HTML 标签                        | String | 'i'              |
+    
+    ### Events
+    
+    | 事件名 | 说明           | 回调参数     |
+    |--------|----------------|--------------|
+    | click  | 点击图标时触发 | event: Event |
+    

+ 0 - 0
src/packages/checkboxgroup/index.scss


+ 83 - 0
src/packages/checkboxgroup/index.vue

@@ -0,0 +1,83 @@
+<template>
+  <view :class="['nut-checkboxgroup', 'nut-checkboxgroup-' + direction]">
+    <slot></slot>
+  </view>
+</template>
+<script lang="ts">
+import { toRefs, watch, reactive, provide, getCurrentInstance } from 'vue';
+import { createComponent } from '@/utils/create';
+const { componentName, create } = createComponent('checkboxgroup');
+
+export default create({
+  props: {
+    modelValue: {
+      type: Array,
+      default: () => []
+    },
+    disabled: {
+      type: Boolean,
+      default: false
+    },
+    size: {
+      type: String,
+      default: 'base'
+    },
+    animated: {
+      type: Boolean,
+      default: true
+    },
+    direction: {
+      type: String,
+      default: 'horizontal'
+    }
+  },
+  emits: ['change', 'update:modelValue'],
+  setup(props, { slots, emit }) {
+    watch(
+      () => props.modelValue,
+      value => {
+        emit('change', value);
+      }
+    );
+
+    function useExtend(apis: any) {
+      const instance = getCurrentInstance();
+      if (instance) {
+        Object.assign(instance.proxy, apis);
+      }
+    }
+
+    const toggleAll = checked => {
+      const children = (slots as any)?.default();
+      if (checked === false) {
+        emit('update:modelValue', []);
+      } else if (checked === true) {
+        const labels = children.map(item => item.props?.label);
+        emit('update:modelValue', labels);
+      } else {
+        const names = children
+          .filter(item => {
+            const label = item.props?.label;
+            const idx = props.modelValue.indexOf(label);
+            if (idx == -1) {
+              return label;
+            }
+          })
+          .map(item => item.props?.label);
+        emit('update:modelValue', names);
+      }
+    };
+    useExtend({ toggleAll });
+
+    provide('checkboxgroup', {
+      parentNode: true,
+      changeVal: val => {
+        if (props.disabled) {
+          return false;
+        }
+        emit('update:modelValue', val);
+      }
+    });
+  }
+});
+</script>