Browse Source

feat: radio 开发,配合使用radio-group

yumingming11 5 years ago
parent
commit
ac7c1b52c4

+ 20 - 0
src/config.js

@@ -214,6 +214,26 @@ module.exports = {
           show: true,
           desc: '头像',
           author: 'ailululu'
+        },
+        {
+          version: '3.0.0',
+          name: 'Radio',
+          type: 'component',
+          cName: '单选按钮',
+          desc: '单选按钮',
+          sort: 9,
+          show: true,
+          author: 'Ymm0008'
+        },
+        {
+          version: '3.0.0',
+          name: 'RadioGroup',
+          type: 'component',
+          cName: '单选按钮组',
+          desc: '单选按钮组',
+          sort: 10,
+          show: false,
+          author: 'Ymm0008'
         }
       ]
     },

+ 175 - 0
src/packages/radio/demo.vue

@@ -0,0 +1,175 @@
+<template>
+  <div class="demo-list">
+    <h4>Radio基本用法</h4>
+    <div class="show-demo">
+      <nut-radio v-model="radioVal" :label="2">备选项</nut-radio>
+    </div>
+    <h4>组合使用Radio</h4>
+    <div class="show-demo">
+      <nut-radio v-model="radioVal1" :label="1">备选项1</nut-radio>
+      <nut-radio v-model="radioVal1" :label="2">备选项2</nut-radio>
+      <span>radioVal1: {{ radioVal1 }} </span>
+    </div>
+
+    <p class="p-word">组合使用 Radio 时推荐使用 radiogroup 组件,见下方示例</p>
+
+    <h4>RadioGroup基本用法</h4>
+    <div class="show-demo">
+      <nut-radiogroup v-model="radioGroupVal1">
+        <nut-radio label="a">备选项1</nut-radio>
+        <nut-radio label="b">备选项2</nut-radio>
+      </nut-radiogroup>
+    </div>
+
+    <h4>Radio禁用</h4>
+    <div class="show-demo">
+      <div>
+        <span>未选中时的禁用状态:</span
+        ><nut-radio :disabled="true" v-model="radioVal2" label="禁用"
+          >备选项1</nut-radio
+        >
+      </div>
+      <div>
+        <span>已选中时的禁用状态:</span
+        ><nut-radio :disabled="true" v-model="radioVal2" label="选中且禁用"
+          >备选项2</nut-radio
+        >
+      </div>
+    </div>
+
+    <h4>RadioGroup整体禁用</h4>
+    <div class="show-demo">
+      <nut-radiogroup v-model="radioGroupVal2" :disabled="true">
+        <nut-radio label="1">备选项1</nut-radio>
+        <nut-radio label="2">备选项2</nut-radio>
+        <nut-radio label="3">备选项3</nut-radio>
+      </nut-radiogroup>
+    </div>
+
+    <h4>Radio自定义尺寸</h4>
+    <div class="show-demo show-demo-block">
+      <nut-radio size="small">小号</nut-radio>
+      <nut-radio size="base">默认</nut-radio>
+      <nut-radio size="large">大号</nut-radio>
+      <p>size可选值:'small', 'base', 'large'</p>
+    </div>
+
+    <h4>RadioGroup整体定义尺寸</h4>
+    <div class="show-demo">
+      <nut-radiogroup v-model="radioGroupVal3" size="large">
+        <nut-radio label="1">备选项1</nut-radio>
+        <nut-radio label="2">备选项2</nut-radio>
+        <nut-radio label="3">备选项3</nut-radio>
+      </nut-radiogroup>
+    </div>
+
+    <h4>Radio禁用动效</h4>
+    <div class="show-demo">
+      <nut-radio :animated="false" v-model="radioVal3" label="a"
+        >备选项1</nut-radio
+      >
+      <nut-radio :animated="false" v-model="radioVal3" label="b"
+        >备选项2</nut-radio
+      >
+      <p>animated 属性值为 false 时,禁用自带动效</p>
+    </div>
+
+    <h4>RadioGroup禁用动效</h4>
+    <div class="show-demo">
+      <nut-radiogroup v-model="radioGroupVal4" :animated="false">
+        <nut-radio label="a">备选项1</nut-radio>
+        <nut-radio label="b">备选项2</nut-radio>
+        <nut-radio label="c">备选项3</nut-radio>
+      </nut-radiogroup>
+    </div>
+
+    <h4>自定义Class</h4>
+    <div class="show-demo">
+      <div>
+        <nut-radio class="my-radio" v-model="radioVal5" label="a"
+          >备选项1</nut-radio
+        >
+      </div>
+      <div>
+        <nut-radio class="my-radio" v-model="radioVal5" label="b"
+          >备选项2</nut-radio
+        >
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import { createComponent } from '@/utils/create';
+import { reactive, toRefs } from 'vue';
+const { createDemo } = createComponent('radio');
+export default createDemo({
+  props: {},
+  setup() {
+    const data = reactive({
+      radioVal: 1,
+      radioVal1: 2,
+      radioVal2: '选中且禁用',
+      radioVal3: 'b',
+      radioVal4: 'b',
+      radioVal5: 'a',
+      radioGroupVal1: 'b',
+      radioGroupVal2: '2',
+      radioGroupVal3: '2',
+      radioGroupVal4: 'c'
+    });
+    return {
+      ...toRefs(data)
+    };
+  }
+});
+</script>
+
+<style lang="scss" scoped>
+.demo-list {
+  margin: 60px 0;
+  padding: 17px;
+  h4 {
+    margin-top: 10px;
+    line-height: 20px;
+    color: #909ca4;
+    font-size: 14px;
+  }
+  .show-demo {
+    margin-top: 10px;
+    padding: 15px;
+    background-color: #ffffff;
+    border-radius: 7px;
+    box-shadow: 0px 1px 7px 0px rgba(237, 238, 241, 1);
+    p,
+    span {
+      margin-top: 10px;
+      font-size: 14px;
+      color: #636363;
+    }
+    span {
+      font-size: 12px;
+    }
+  }
+  .p-word {
+    margin: 15px 0;
+    font-size: 14px;
+    color: #636363;
+    padding-left: 5px;
+    border-left: 8px solid #03a9f4;
+  }
+  .show-demo-block {
+    label {
+      display: block;
+      margin-bottom: 10px;
+    }
+  }
+  .my-radio::v-deep {
+    input:checked {
+      background-image: url('https://img13.360buyimg.com/imagetools/jfs/t1/154120/1/10623/372/5fe013e6E4694fbf9/fd38d389b3a3b9c6.png');
+      background-size: 100%;
+      border: none;
+    }
+  }
+}
+</style>

+ 124 - 0
src/packages/radio/doc.md

@@ -0,0 +1,124 @@
+# Radio 单选按钮
+
+## 基本用法
+
+通过 **v-model** 绑定值当前选中项的 **label** ,二者一致时 **Radio** 选中。
+```html
+<nut-radio 
+  v-model="radioVal"
+  :label="b"
+>备选项1
+</nut-radio>
+```
+```javascript
+export default {
+  data() {
+    return {
+      radioVal:"a",
+    }
+  }
+};
+```
+
+## 组合使用
+
+```html
+<nut-radio 
+  v-model="radioVal1"
+  :label="1"
+>备选项1
+</nut-radio>
+
+<nut-radio 
+  v-model="radioVal1"
+  :label="2"
+>备选项2
+</nut-radio>
+```
+
+
+## 禁用状态
+
+通过给 **disabled** 传布尔值 **false** ,可将组件禁用
+
+```html
+<nut-radio 
+  :disabled="true" 
+  v-model="radioVal2" 
+  label="禁用"
+>备选项1
+</nut-radio>
+```
+
+
+## 自定义尺寸
+
+内置 **small**,**base**,**large** 三种规格供使用。
+
+```html
+<nut-radio 
+  size="small"
+>小号
+</nut-radio>
+
+<nut-radio 
+  size="base"
+>默认
+</nut-radio>
+
+<nut-radio 
+  size="large"
+>大号
+</nut-radio>
+```
+
+## 禁用动效
+
+通过给 **animated** 传布尔值 **false** ,禁用自带动效
+
+```html
+<nut-radio 
+   :animated="false" 
+   v-model="radioVal3" 
+   label="a"
+>备选项1
+</nut-radio>
+
+<nut-radio 
+   :animated="false" 
+   v-model="radioVal3" 
+   label="b"
+>备选项2</nut-radio>
+```
+
+禁用 **RadioGroup** 动效
+
+```html
+<nut-radiogroup v-model="radioGroupVal4" :animated="false">
+  <nut-radio label="a">备选项1</nut-radio>
+  <nut-radio label="b">备选项2</nut-radio>
+  <nut-radio label="c">备选项3</nut-radio>
+</nut-radiogroup>
+```
+
+
+## 新增自定义class
+```html
+<nut-radio 
+   class="my-radio"
+>备选项</nut-radio>
+```
+**RadioGroup** 也支持新增自定义class
+
+## Prop
+
+### Radio
+
+| 字段 | 说明 | 类型 | 默认值
+|----- | ----- | ----- | ----- 
+| v-model | 当前选中项的标识符,与label值一致时呈选中状态 | 任意类型 | -
+| label | 标识符,与v-model值一致时呈选中状态 | 任意类型 | -
+| size | 尺寸,可选值small/base/large | String | base
+| disabled | 是否禁用 | Boolean | false
+| animated | 是否需要动效 | Boolean | true
+

+ 94 - 0
src/packages/radio/index.scss

@@ -0,0 +1,94 @@
+.nut-radio {
+  margin-right: 10px;
+  .nut-radio-label {
+    pointer-events: none;
+    vertical-align: middle;
+  }
+  input {
+    position: relative;
+    -webkit-appearance: none;
+    border: 1px solid #dadada;
+    border-radius: 50%;
+    background-size: cover;
+    outline: 0;
+    opacity: 1;
+    vertical-align: middle;
+    margin-top: 0px;
+    &::after {
+      position: absolute;
+      left: 50%;
+      top: 50%;
+      content: '';
+      width: 0;
+      height: 0;
+      transform: translate(-50%, -50%);
+      background: $primary-color;
+      border-radius: 50%;
+      opacity: 0;
+      pointer-events: none;
+    }
+    &:checked {
+      //   @include nut-radio-bg('FFFFFF');
+      background-image: url('https://img12.360buyimg.com/imagetools/jfs/t1/146940/23/19455/4738/5fe06883Eb79934cc/d8d983ba5fb8d126.png');
+      background-repeat: no-repeat;
+      background-position: center;
+      background-size: 100%;
+      // box-shadow: 0 4px 6px 0 rgba($primary-color, 0.15);
+      &:not(:disabled).nut-radio-ani::after {
+        animation: nutPulse 0.25s;
+      }
+    }
+    &:disabled {
+      background-image: url('https://img14.360buyimg.com/imagetools/jfs/t1/155506/4/9365/704/5fd3103cE779ad491/1939699720df7770.png');
+      &:checked {
+        // @include nut-radio-bg('999999');
+        background-image: url('https://img13.360buyimg.com/imagetools/jfs/t1/156222/17/1338/2270/5fe06886E776430e1/b15beeb3b31553b4.png');
+      }
+      & + .nut-radio-label {
+        color: #999999;
+      }
+    }
+  }
+  &.nut-radio-size-base {
+    input {
+      width: 18px;
+      height: 18px;
+    }
+    .nut-radio-label {
+      font-size: $font-size-2;
+    }
+  }
+  &.nut-radio-size-small {
+    input {
+      width: 16px;
+      height: 16px;
+    }
+    .nut-radio-label {
+      font-size: $font-size-1;
+      margin-left: 2px;
+    }
+  }
+  &.nut-radio-size-large {
+    input {
+      width: 22px;
+      height: 22px;
+    }
+    .nut-radio-label {
+      font-size: $font-size-3;
+      margin-left: 2px;
+    }
+  }
+}
+
+@keyframes nutPulse {
+  0% {
+    width: 100%;
+    height: 100%;
+    opacity: 0.5;
+  }
+  100% {
+    width: 150%;
+    height: 150%;
+    opacity: 0;
+  }
+}

+ 127 - 0
src/packages/radio/index.vue

@@ -0,0 +1,127 @@
+<template>
+  <label :class="['nut-radio', 'nut-radio-size-' + currentSize]">
+    <input
+      type="radio"
+      :value="currentValue"
+      :class="{ 'nut-radio-ani': isAnimated }"
+      :checked="currentValue === label"
+      :disabled="isDisabled"
+      :label="label"
+      @click="clickEvt"
+    />
+    <span class="nut-radio-label">
+      <slot></slot>
+    </span>
+  </label>
+</template>
+<script lang="ts">
+import {
+  compile,
+  computed,
+  reactive,
+  ref,
+  toRefs,
+  getCurrentInstance,
+  inject
+} from 'vue';
+import { createComponent } from '@/utils/create';
+const { componentName, create } = createComponent('radio');
+
+type Iparent = {
+  parentNode: boolean;
+  changeVal: Function;
+};
+export default create({
+  props: {
+    modelValue: {
+      type: [String, Number, Boolean],
+      default: false
+    },
+    label: [String, Number, Boolean],
+    size: {
+      type: String,
+      default: 'base'
+    },
+    disabled: {
+      type: Boolean,
+      default: false
+    },
+    animated: {
+      type: Boolean,
+      default: true
+    }
+  },
+  components: {},
+  emits: ['input', 'update:modelValue'],
+  setup(props, { emit }) {
+    const parentGroup = <Iparent>inject('radiogroup', {
+      parentNode: false
+    });
+    const internalInstance = getCurrentInstance()?.parent;
+    const parentProps = internalInstance?.props;
+    // const parentEl = internalInstance?.type;
+
+    const currentValue = computed({
+      get: () => {
+        if (parentGroup && parentGroup.parentNode) {
+          return parentProps?.modelValue;
+        } else {
+          return props.modelValue;
+        }
+      },
+      set: val => {
+        if (parentGroup && parentGroup.parentNode) {
+          parentGroup?.changeVal(<string | number | boolean>val);
+        } else {
+          emit('input', val);
+        }
+      }
+    });
+
+    const currentSize = computed(() => {
+      if (parentGroup && parentGroup.parentNode) {
+        return parentProps?.size;
+      } else {
+        return props.size;
+      }
+    });
+
+    const isDisabled = computed(() => {
+      if (parentGroup && parentGroup.parentNode) {
+        return parentProps?.disabled;
+      } else {
+        return props.disabled;
+      }
+    });
+
+    const isAnimated = computed(() => {
+      if (parentGroup && parentGroup.parentNode) {
+        return parentProps?.animated;
+      } else {
+        return props.animated;
+      }
+    });
+
+    const clickEvt = (event: any) => {
+      event?.stopPropagation();
+      if (isDisabled.value) {
+        return false;
+      }
+      currentValue.value = props.label ?? '';
+      emit('update:modelValue', props.label);
+    };
+
+    return {
+      currentValue,
+      currentSize,
+      isDisabled,
+      isAnimated,
+      clickEvt
+    };
+  }
+});
+</script>
+
+<style lang="scss">
+@import 'index.scss';
+</style>

+ 25 - 0
src/packages/radiogroup/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('radiogroup');
+export default createDemo({
+  props: {},
+  setup() {
+    return {};
+  }
+});
+</script>
+
+<style lang="scss" scoped>
+.nut-temp {
+}
+</style>

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

@@ -0,0 +1,34 @@
+#  radiogroup组件
+
+    ### 介绍
+    
+    基于 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 |
+    

+ 2 - 0
src/packages/radiogroup/index.scss

@@ -0,0 +1,2 @@
+.nut-radiogroup {
+}

+ 39 - 0
src/packages/radiogroup/index.vue

@@ -0,0 +1,39 @@
+<template>
+  <view class="nut-radiogroup">
+    <slot></slot>
+  </view>
+</template>
+<script lang="ts">
+import { toRefs, provide } from 'vue';
+import { createComponent } from '@/utils/create';
+const { componentName, create } = createComponent('radiogroup');
+
+export default create({
+  props: {
+    modelValue: {
+      type: [String, Number, Boolean],
+      default: false
+    },
+    disabled: {
+      type: Boolean,
+      default: false
+    },
+    size: {
+      type: String,
+      default: 'base'
+    },
+    animated: {
+      type: Boolean,
+      default: true
+    }
+  },
+  setup(props, { emit }) {
+    provide('radiogroup', {
+      parentNode: true,
+      changeVal: (val: string | number) => {
+        emit('update:modelValue', val);
+      }
+    });
+  }
+});
+</script>