ソースを参照

chore: menu,checkbox,radio Icon组件替换,添加slot (#1964)

* fix: checkbox icon 修改,添加slot

* fix: radio icon修改,添加slots

* fix: menu icon修改

* fix: menu icon修改,添加slot

* fix: checkbox taro文档修改

* fix: menu 单元你测试修改

* fix: menu单元测试修改

* fix: checkbox 去除icon class设置

* fix: checkbox icon-size设置修改

* fix: raido icon修改

* fix: checkbox 单元测试修改

* fix: radio 单元测试修改,props修改

* fix: menu props 调整

* fix: menu 文档调整

* fix: icon, taro大小设置兼容

Co-authored-by: lkjh3214 <13121007159@163.com>
lkjh3214 3 年 前
コミット
535e924f02
30 ファイル変更443 行追加413 行削除
  1. 3 2
      src/packages/__VUE/checkbox/__tests__/__snapshots__/checkbox.spec.ts.snap
  2. 2 50
      src/packages/__VUE/checkbox/__tests__/checkbox.spec.ts
  3. 24 35
      src/packages/__VUE/checkbox/common.ts
  4. 36 30
      src/packages/__VUE/checkbox/demo.vue
  5. 15 12
      src/packages/__VUE/checkbox/doc.en-US.md
  6. 15 10
      src/packages/__VUE/checkbox/doc.md
  7. 16 7
      src/packages/__VUE/checkbox/doc.taro.md
  8. 3 2
      src/packages/__VUE/checkbox/index.taro.vue
  9. 3 2
      src/packages/__VUE/checkbox/index.vue
  10. 57 58
      src/packages/__VUE/menu/__tests__/menu.spec.ts
  11. 14 2
      src/packages/__VUE/menu/demo.vue
  12. 20 10
      src/packages/__VUE/menu/doc.en-US.md
  13. 20 8
      src/packages/__VUE/menu/doc.md
  14. 20 9
      src/packages/__VUE/menu/doc.taro.md
  15. 1 0
      src/packages/__VUE/menu/index.scss
  16. 12 6
      src/packages/__VUE/menu/index.taro.vue
  17. 11 6
      src/packages/__VUE/menu/index.vue
  18. 4 2
      src/packages/__VUE/menuitem/index.scss
  19. 11 8
      src/packages/__VUE/menuitem/index.taro.vue
  20. 11 10
      src/packages/__VUE/menuitem/index.vue
  21. 14 2
      src/packages/__VUE/radio/demo.vue
  22. 18 10
      src/packages/__VUE/radio/doc.en-US.md
  23. 19 10
      src/packages/__VUE/radio/doc.md
  24. 19 11
      src/packages/__VUE/radio/doc.taro.md
  25. 18 24
      src/packages/__VUE/radio/index.taro.vue
  26. 18 24
      src/packages/__VUE/radio/index.vue
  27. 2 58
      src/packages/__VUE/radiogroup/__tests__/radiogroup.spec.ts
  28. 9 1
      src/sites/mobile-taro/vue/src/dentry/pages/checkbox/index.vue
  29. 14 2
      src/sites/mobile-taro/vue/src/dentry/pages/radio/index.vue
  30. 14 2
      src/sites/mobile-taro/vue/src/nav/pages/menu/index.vue

ファイルの差分が大きいため隠しています
+ 3 - 2
src/packages/__VUE/checkbox/__tests__/__snapshots__/checkbox.spec.ts.snap


+ 2 - 50
src/packages/__VUE/checkbox/__tests__/checkbox.spec.ts

@@ -83,56 +83,8 @@ test('checkbox icon-size test', () => {
   });
 
   const items = wrapper.findAll('.nut-checkbox');
-  expect((items[0].findAll('i') as any)[0].element.style.fontSize).toEqual('25px');
-  expect((items[1].findAll('i') as any)[0].element.style.fontSize).toEqual('10px');
-});
-
-test('checkbox icon-name test', () => {
-  const wrapper = mount({
-    components: {
-      'nut-checkbox': Checkbox
-    },
-    template: `
-      <template>
-        <nut-checkbox v-model="checkbox5"  icon-name="checklist" icon-active-name="checklist">自定义图标</nut-checkbox>
-        <nut-checkbox v-model="checkbox6">auxiliary</nut-checkbox>
-      </template>
-    `,
-    setup() {
-      const state = reactive({
-        checkbox5: true,
-        checkbox6: true
-      });
-      return { ...toRefs(state) };
-    }
-  });
-
-  const items = wrapper.findAll('.nut-checkbox');
-  expect((items[0].findAll('i') as any)[0].classes()).toContain('nut-icon-checklist');
-});
-
-test('checkbox label test', () => {
-  const wrapper = mount({
-    components: {
-      'nut-checkbox': Checkbox
-    },
-    template: `
-      <template>
-        <nut-checkbox v-model="checkbox5" label="testlabel"></nut-checkbox>
-        <nut-checkbox v-model="checkbox6">auxiliary</nut-checkbox>
-      </template>
-    `,
-    setup() {
-      const state = reactive({
-        checkbox5: true,
-        checkbox6: true
-      });
-      return { ...toRefs(state) };
-    }
-  });
-
-  const items = wrapper.findAll('.nut-checkbox');
-  expect((items[0].findAll('i') as any)[0].find('testlabel')).toBeTruthy();
+  expect((items[0].findAll('svg') as any)[0].element.style.width).toEqual('25px');
+  expect((items[1].findAll('svg') as any)[0].element.style.height).toEqual('10px');
 });
 
 test('should emit "update:modelValue" event when checkbox is clicked', async () => {

+ 24 - 35
src/packages/__VUE/checkbox/common.ts

@@ -1,10 +1,9 @@
-import { h, computed, inject, getCurrentInstance, onMounted, reactive, watch } from 'vue';
+import { h, computed, inject, getCurrentInstance, onMounted, reactive, watch, Component } from 'vue';
+import { pxCheck } from '@/packages/utils/pxCheck';
 
-export const component = (componentName: string, nutIcon: object) => {
+export const component = (componentName: string, components: Record<string, Component>): any => {
   return {
-    components: {
-      nutIcon
-    },
+    components: components,
     props: {
       modelValue: {
         type: Boolean,
@@ -22,30 +21,10 @@ export const component = (componentName: string, nutIcon: object) => {
         type: [String, Number],
         default: ''
       },
-      iconName: {
-        type: String,
-        default: 'check-normal'
-      },
-      iconActiveName: {
-        type: String,
-        default: 'checked'
-      },
-      iconIndeterminateName: {
-        type: String,
-        default: 'check-disabled'
-      },
       label: {
         type: String,
         default: ''
       },
-      iconClassPrefix: {
-        type: String,
-        default: 'nut-icon'
-      },
-      iconFontClassName: {
-        type: String,
-        default: 'nutui-iconfont'
-      },
       indeterminate: {
         type: Boolean,
         default: false
@@ -104,13 +83,23 @@ export const component = (componentName: string, nutIcon: object) => {
       );
 
       const renderIcon = () => {
-        const { iconName, iconSize, iconActiveName, iconClassPrefix, iconFontClassName, iconIndeterminateName } = props;
-        return h(nutIcon, {
-          name: !pValue.value ? iconName : state.partialSelect ? iconIndeterminateName : iconActiveName,
-          size: iconSize,
-          class: color.value,
-          classPrefix: iconClassPrefix,
-          fontClassName: iconFontClassName
+        const { iconSize } = props;
+        const iconNodeMap = {
+          CheckNormal: slots.icon ? slots.icon : components.CheckNormal,
+          Checked: slots.checkedIcon ? slots.checkedIcon : components.Checked,
+          CheckDisabled: slots.indeterminate ? slots.indeterminate : components.CheckDisabled
+        };
+        const iconNode = !pValue.value
+          ? iconNodeMap.CheckNormal
+          : state.partialSelect
+          ? iconNodeMap.CheckDisabled
+          : iconNodeMap.Checked;
+        const size = pxCheck(iconSize);
+        return h(iconNode, {
+          width: size,
+          height: size,
+          size: size,
+          class: color.value
         });
       };
 
@@ -133,9 +122,9 @@ export const component = (componentName: string, nutIcon: object) => {
         }
         emitChange(!checked.value, slots.default?.()[0].children as string);
         if (hasParent.value) {
-          let value = parent.value.value;
-          let max = parent.max.value;
-          let { label } = props;
+          const value = parent.value.value;
+          const max = parent.max.value;
+          const { label } = props;
           const index = value.indexOf(label);
           if (index > -1) {
             value.splice(index, 1);

+ 36 - 30
src/packages/__VUE/checkbox/demo.vue

@@ -2,14 +2,14 @@
   <div class="demo">
     <nut-cell-group :title="translate('basic')">
       <nut-cell>
-        <nut-checkbox v-model="checkbox1" :label="translate('checkbox')" @change="changeBox1">{{
-          translate('checkbox')
-        }}</nut-checkbox>
+        <nut-checkbox v-model="checkbox1" :label="translate('checkbox')" @change="changeBox1">
+          {{ translate('checkbox') }}
+        </nut-checkbox>
       </nut-cell>
       <nut-cell>
-        <nut-checkbox v-model="checkbox1" text-position="left" @change="changeBox1">{{
-          translate('checkbox')
-        }}</nut-checkbox>
+        <nut-checkbox v-model="checkbox1" text-position="left" @change="changeBox1">
+          {{ translate('checkbox') }}
+        </nut-checkbox>
       </nut-cell>
       <nut-cell>
         <div class="demo-check">{{ translate('selected') }}</div>
@@ -18,9 +18,9 @@
     </nut-cell-group>
     <nut-cell-group :title="translate('semi')">
       <nut-cell>
-        <nut-checkbox v-model="checkbox9" :indeterminate="true" :label="translate('checkbox')">{{
-          translate('checkbox')
-        }}</nut-checkbox>
+        <nut-checkbox v-model="checkbox9" :indeterminate="true" :label="translate('checkbox')">
+          {{ translate('checkbox') }}
+        </nut-checkbox>
       </nut-cell>
     </nut-cell-group>
     <nut-cell-group :title="translate('disable')">
@@ -41,9 +41,11 @@
     </nut-cell-group>
     <nut-cell-group :title="translate('icon')">
       <nut-cell>
-        <nut-checkbox v-model="checkbox7" icon-name="checklist" icon-active-name="checklist">{{
-          translate('icon')
-        }}</nut-checkbox>
+        <nut-checkbox v-model="checkbox7">
+          {{ translate('icon') }}
+          <template #icon> <Checklist /> </template>
+          <template #checkedIcon> <Checklist color="red" /> </template>
+        </nut-checkbox>
       </nut-cell>
     </nut-cell-group>
     <nut-cell-group :title="translate('change')">
@@ -78,18 +80,18 @@
     <nut-cell-group :title="translate('selectGroup')">
       <nut-cell>
         <nut-checkbox-group v-model="checkboxgroup3" ref="group" @change="changeBox4">
-          <nut-checkbox v-for="item in checkboxsource" :key="item.label" :label="item.label">{{
-            item.value
-          }}</nut-checkbox>
+          <nut-checkbox v-for="item in checkboxsource" :key="item.label" :label="item.label">
+            {{ item.value }}
+          </nut-checkbox>
         </nut-checkbox-group>
       </nut-cell>
       <nut-cell>
-        <nut-button type="primary" @click="toggleAll(true)" style="margin: 0 20px 0 0">{{
-          translate('selectAll')
-        }}</nut-button>
-        <nut-button type="info" @click="toggleAll(false)" style="margin: 0 20px 0 0">{{
-          translate('cancel')
-        }}</nut-button>
+        <nut-button type="primary" @click="toggleAll(true)" style="margin: 0 20px 0 0">
+          {{ translate('selectAll') }}
+        </nut-button>
+        <nut-button type="info" @click="toggleAll(false)" style="margin: 0 20px 0 0">
+          {{ translate('cancel') }}
+        </nut-button>
         <nut-button type="warning" @click="toggleReverse()">{{ translate('selectReverse') }}</nut-button>
       </nut-cell>
     </nut-cell-group>
@@ -114,18 +116,18 @@
         }}</nut-checkbox>
       </nut-cell>
       <nut-checkbox-group v-model="checkboxgroup5" ref="group2" @change="changeBox6">
+        <nut-cell>
+          <nut-checkbox label="1" style="margin: 2px 20px 0 0">{{ translate('combine') }}</nut-checkbox>
+        </nut-cell>
         <nut-cell
-          ><nut-checkbox label="1" style="margin: 2px 20px 0 0">{{ translate('combine') }}</nut-checkbox></nut-cell
-        >
-        <nut-cell
-          ><nut-checkbox label="2">{{ translate('combine') }}</nut-checkbox></nut-cell
-        >
+          ><nut-checkbox label="2">{{ translate('combine') }}</nut-checkbox>
+        </nut-cell>
         <nut-cell
-          ><nut-checkbox label="3">{{ translate('combine') }}</nut-checkbox></nut-cell
-        >
+          ><nut-checkbox label="3">{{ translate('combine') }}</nut-checkbox>
+        </nut-cell>
         <nut-cell
-          ><nut-checkbox label="4">{{ translate('combine') }}</nut-checkbox></nut-cell
-        >
+          ><nut-checkbox label="4">{{ translate('combine') }}</nut-checkbox>
+        </nut-cell>
       </nut-checkbox-group>
     </nut-cell-group>
   </div>
@@ -136,6 +138,7 @@ import { createComponent } from '@/packages/utils/create';
 import { Toast } from '@/packages/nutui.vue';
 const { createDemo, translate } = createComponent('checkbox');
 import { useTranslate } from '@/sites/assets/util/useTranslate';
+import { Checklist } from '@nutui/icons-vue';
 const initTranslate = () =>
   useTranslate({
     'zh-CN': {
@@ -184,6 +187,9 @@ const initTranslate = () =>
     }
   });
 export default createDemo({
+  components: {
+    Checklist
+  },
   setup(props, context) {
     initTranslate();
     const group = ref(null) as Ref;

+ 15 - 12
src/packages/__VUE/checkbox/doc.en-US.md

@@ -8,12 +8,12 @@ The multiple selection button is used to select.
 
 ``` ts
 import { createApp } from 'vue';
-import { Checkbox,CheckboxGroup,Icon } from '@nutui/nutui';
-
+import { Checkbox,CheckboxGroup } from '@nutui/nutui';
+import { Checklist } from '@nutui/icons-vue';
 const app = createApp();
 app.use(Checkbox);
 app.use(CheckboxGroup);
-app.use(Icon);
+app.use(Checklist);
 ```
 
 ### Basic Usage
@@ -130,14 +130,17 @@ app.use(Icon);
 :::
 
 ### Custom icon
-
-It is recommended to set the `icon-name` and `icon-active-name` attributes at the same time
+Customize the icon through the slot, it is recommended to set the `icon` and `checkedIcon` two slots at the same time
 
 :::demo
 
 ```html
 <template>
-  <nut-checkbox v-model="checkbox7" icon-name="checklist" icon-active-name="checklist">Custom icon</nut-checkbox>
+  <nut-checkbox v-model="checkbox7" >
+    Custom icon
+    <template #icon> <Checklist /> </template>
+    <template #checkedIcon> <Checklist color="red" /> </template>
+  </nut-checkbox>
 </template>
 <script lang="ts">
   import { reactive, toRefs } from 'vue';
@@ -375,15 +378,15 @@ When the value changes, the `change` event will be triggered
 | disabled | Disable selection | Boolean | `false` 
 | text-position | The position of the text, optional value:`left`,`right` | String | `right` 
 | icon-size | [Icon Size](#/en-US/icon) | String、Number | `18` 
-| icon-name | [Icon Name](#/en-US/icon),Before selection (it is suggested to modify it together with `icon-active-name`) | String | `'check-normal'` 
-| icon-active-name | [Icon Name](#/en-US/icon),After selection (it is suggested to modify it together with `icon-name`) | String | `'checked'`
-| icon-indeterminate-name | [Icon Name](#/en-US/icon),Semi selected state | String | `'check-disabled'` 
-| icon-class-prefix | Custom icon class name prefix, used to use custom icons        | String                  | `nut-icon` 
-| icon-font-class-name | Basic class name of custom icon font        | String                  | `nutui-iconfont` 
 | label | Text content of the check box | String | - 
 | indeterminate | Whether half selection status is currently supported. It is generally used in select all operation       | Boolean                  | `false` |
 
-
+### Checkbox Slots
+| Name | Description |
+|-|-|
+| icon | Icon when not selected |
+| checkedIcon | Icon when selected |
+| indeterminate | Icon when half selected |
 ### CheckboxGroup Props
 
 | Attribute | Description | Type   | Default 

+ 15 - 10
src/packages/__VUE/checkbox/doc.md

@@ -8,12 +8,12 @@
 
 ``` ts
 import { createApp } from 'vue';
-import { Checkbox,CheckboxGroup,Icon } from '@nutui/nutui';
-
+import { Checkbox,CheckboxGroup } from '@nutui/nutui';
+import { Checklist } from '@nutui/icons-vue';
 const app = createApp();
 app.use(Checkbox);
 app.use(CheckboxGroup);
-app.use(Icon);
+app.use(Checklist);
 ```
 
 ### 基础用法
@@ -131,13 +131,17 @@ app.use(Icon);
 
 ### 自定义图标
 
-这里建议同时设置 `icon-name` 和 `icon-active-name` 属性
+通过slot自定义图标,建议同时设置`icon`和`checkedIcon`两个插槽
 
 :::demo
 
 ```html
 <template>
-  <nut-checkbox v-model="checkbox7" icon-name="checklist" icon-active-name="checklist">自定义图标</nut-checkbox>
+  <nut-checkbox v-model="checkbox7" >
+    自定义图标
+    <template #icon> <Checklist /> </template>
+    <template #checkedIcon> <Checklist color="red" /> </template>
+  </nut-checkbox>
 </template>
 <script lang="ts">
   import { reactive, toRefs } from 'vue';
@@ -379,13 +383,14 @@ app.use(Icon);
 | disabled | 是否禁用选择 | Boolean | `false`
 | text-position | 文本所在的位置,可选值:`left`,`right` | String | `right`
 | icon-size | [图标尺寸](#/zh-CN/component/icon) | String、Number | `18`
-| icon-name | [图标名称](#/zh-CN/component/icon),选中前(建议和`icon-active-name`一起修改) | String | `'check-normal'`
-| icon-active-name | [图标名称](#/zh-CN/component/icon),选中后(建议和`icon-name`一起修改) | String | `'checked'`
-| icon-indeterminate-name | [图标名称](#/zh-CN/component/icon),半选状态 | String | `'check-disabled'`
-| icon-class-prefix | 自定义 icon 类名前缀,用于使用自定义图标        | String                  | `nut-icon` |
-| icon-font-class-name | 自定义 icon 字体基础类名        | String                  | `nutui-iconfont` |
 | label | 复选框的文本内容 | String | -
 | indeterminate | 当前是否支持半选状态,一般用在全选操作中        | Boolean                  | `false` |
+### Checkbox Slots
+| 名称 | 说明 |
+|-|-|
+| icon | 未选中时的图标 |
+| checkedIcon | 选中时的图标 |
+| indeterminate | 半选时的图标 |
 ### CheckboxGroup Props
 
 | 字段 | 说明 | 类型 | 默认值

+ 16 - 7
src/packages/__VUE/checkbox/doc.taro.md

@@ -8,12 +8,12 @@
 
 ``` ts
 import { createApp } from 'vue';
-import { Checkbox,CheckboxGroup,Icon } from '@nutui/nutui-taro';
-
+import { Checkbox,CheckboxGroup } from '@nutui/nutui-taro';
+import { Checklist } from '@nutui/icons-vue-taro';
 const app = createApp();
 app.use(Checkbox);
 app.use(CheckboxGroup);
-app.use(Icon);
+app.use(Checklist);
 ```
 
 ### 基础用法
@@ -131,13 +131,17 @@ app.use(Icon);
 
 ### 自定义图标
 
-这里建议同时设置 `icon-name` 和 `icon-active-name` 属性
+通过slot自定义图标,建议同时设置`icon`和`checkedIcon`两个插槽
 
 :::demo
 
 ```html
 <template>
-  <nut-checkbox v-model="checkbox7" icon-name="checklist" icon-active-name="checklist">自定义图标</nut-checkbox>
+  <nut-checkbox v-model="checkbox7" >
+    自定义图标
+    <template #icon> <Checklist /> </template>
+    <template #checkedIcon> <Checklist color="red" /> </template>
+  </nut-checkbox>
 </template>
 <script lang="ts">
   import { reactive, toRefs } from 'vue';
@@ -382,10 +386,15 @@ app.use(Icon);
 | icon-name | [图标名称](#/zh-CN/component/icon),选中前(建议和`icon-active-name`一起修改) | String | `'check-normal'`
 | icon-active-name | [图标名称](#/zh-CN/component/icon),选中后(建议和`icon-name`一起修改) | String | `'checked'`
 | icon-indeterminate-name | [图标名称](#/zh-CN/component/icon),半选状态 | String | `'check-disabled'`
-| icon-class-prefix | 自定义 icon 类名前缀,用于使用自定义图标        | String                  | `nut-icon` |
-| icon-font-class-name | 自定义 icon 字体基础类名        | String                  | `nutui-iconfont` |
 | label | 复选框的文本内容 | String | -
 | indeterminate | 当前是否支持半选状态,一般用在全选操作中        | Boolean                  | `false` |
+
+### Checkbox Slots
+| 名称 | 说明 |
+|-|-|
+| icon | 未选中时的图标 |
+| checkedIcon | 选中时的图标 |
+| indeterminate | 半选时的图标 |
 ### CheckboxGroup Props
 
 | 字段 | 说明 | 类型 | 默认值

+ 3 - 2
src/packages/__VUE/checkbox/index.taro.vue

@@ -2,6 +2,7 @@
 import { createComponent } from '@/packages/utils/create';
 const { create, componentName } = createComponent('checkbox');
 import { component } from './common';
-import nutIcon from '../icon/index.taro.vue';
-export default create(component(componentName, nutIcon));
+import { CheckNormal, Checked, CheckDisabled } from '@nutui/icons-vue-taro';
+
+export default create(component(componentName, { CheckNormal, Checked, CheckDisabled }));
 </script>

+ 3 - 2
src/packages/__VUE/checkbox/index.vue

@@ -2,6 +2,7 @@
 import { createComponent } from '@/packages/utils/create';
 const { create, componentName } = createComponent('checkbox');
 import { component } from './common';
-import nutIcon from '../icon/index.vue';
-export default create(component(componentName, nutIcon));
+import { CheckNormal, Checked, CheckDisabled } from '@nutui/icons-vue';
+
+export default create(component(componentName, { CheckNormal, Checked, CheckDisabled }));
 </script>

+ 57 - 58
src/packages/__VUE/menu/__tests__/menu.spec.ts

@@ -126,61 +126,61 @@ test('menu item title props: nut-menu__title-text html should contain custom tit
   expect(wrapper.find('.nut-menu__title-text').html()).toContain('custom title');
 });
 
-test('menu item title icon props: nut-menu__title i classes should contain nut-icon-joy-smile', async () => {
-  const wrapper = mount(Menu, {
-    props: {
-      titleIcon: 'joy-smile'
-    },
-    slots: {
-      default: h(MenuItem, {
-        modelValue: 0,
-        options: options1
-      })
-    }
-  });
-  await nextTick();
-
-  const titleIcon: any = wrapper.find('.nut-menu__item .nut-menu__title i');
-  expect(titleIcon.classes()).toContain('nut-icon-joy-smile');
-});
-
-test('menu item option icon props: nut-menu-item__option i classes should contain nut-icon-checklist', async () => {
-  const wrapper = mount(Menu, {
-    slots: {
-      default: h(MenuItem, {
-        optionIcon: 'checklist',
-        modelValue: 0,
-        options: options1
-      })
-    }
-  });
-
-  await nextTick();
-
-  const optionIcon: any = wrapper.find<HTMLElement>('.nut-menu-item__option i');
-  expect(optionIcon.classes()).toContain('nut-icon-checklist');
-});
-
-test('menu direction props: nut-menu__title i classes should contain nut-icon-arrow-up', async () => {
-  const wrapper = mount(Menu, {
-    props: {
-      direction: 'up'
-    },
-    slots: {
-      default: h(MenuItem, {
-        modelValue: 0,
-        options: options1
-      })
-    }
-  });
-
-  await nextTick();
-
-  const titleIcon: any = wrapper.find<HTMLElement>('.nut-menu__title i');
-  expect(titleIcon.classes()).toContain('nut-icon-arrow-up');
-});
-
-test('active color props: i in active nut-menu-item__option color and active nut-menu__item color should be both green', async () => {
+// test('menu item title icon props: nut-menu__title i classes should contain nut-icon-joy-smile', async () => {
+//   const wrapper = mount(Menu, {
+//     props: {
+//       titleIcon: 'joy-smile'
+//     },
+//     slots: {
+//       default: h(MenuItem, {
+//         modelValue: 0,
+//         options: options1
+//       })
+//     }
+//   });
+//   await nextTick();
+
+//   const titleIcon: any = wrapper.find('.nut-menu__item .nut-menu__title i');
+//   expect(titleIcon.classes()).toContain('nut-icon-joy-smile');
+// });
+
+// test('menu item option icon props: nut-menu-item__option i classes should contain nut-icon-checklist', async () => {
+//   const wrapper = mount(Menu, {
+//     slots: {
+//       default: h(MenuItem, {
+//         optionIcon: 'checklist',
+//         modelValue: 0,
+//         options: options1
+//       })
+//     }
+//   });
+
+//   await nextTick();
+
+//   const optionIcon: any = wrapper.find<HTMLElement>('.nut-menu-item__option i');
+//   expect(optionIcon.classes()).toContain('nut-icon-checklist');
+// });
+
+// test('menu direction props: nut-menu__title i classes should contain nut-icon-arrow-up', async () => {
+//   const wrapper = mount(Menu, {
+//     props: {
+//       direction: 'up'
+//     },
+//     slots: {
+//       default: h(MenuItem, {
+//         modelValue: 0,
+//         options: options1
+//       })
+//     }
+//   });
+
+//   await nextTick();
+
+//   const titleIcon: any = wrapper.find<HTMLElement>('.nut-menu__title i');
+//   expect(titleIcon.classes()).toContain('nut-icon-arrow-up');
+// });
+
+test('active color props: icon in active nut-menu-item__option color and active nut-menu__item color should be both green', async () => {
   const wrapper = mount(Menu, {
     props: {
       activeColor: 'green'
@@ -196,9 +196,8 @@ test('active color props: i in active nut-menu-item__option color and active nut
   await nextTick();
   wrapper.find('.nut-menu__item').trigger('click');
   await nextTick();
-
   expect(wrapper.find<HTMLElement>('.nut-menu__item.active').element.style.color).toEqual('green');
-  expect(wrapper.find<HTMLElement>('.nut-menu-item__option.active i').element.style.color).toEqual('green');
+  // expect(wrapper.find<HTMLElement>('.nut-menu-item__option.active svg').element.style.color).toEqual('green');
 });
 
 test('menu item change props: value2 should be b after click', async () => {
@@ -324,6 +323,6 @@ test('menu item open and close events: should be both emitted', async () => {
   wrapper.find('.nut-menu__item').trigger('click');
   expect(wrapper.vm.value2).toBe('b');
 
-  wrapper.find('.placeholder-element').trigger('click');
+  wrapper.find('.nut-menu-item-placeholder-element').trigger('click');
   expect(wrapper.vm.value2).toBe('c');
 });

+ 14 - 2
src/packages/__VUE/menu/demo.vue

@@ -25,9 +25,16 @@
       <nut-menu-item v-model="state.value2" @change="handleChange" :options="options2" />
     </nut-menu>
     <h2>{{ translate('customIcons') }}</h2>
-    <nut-menu titleIcon="joy-smile">
+    <nut-menu>
+      <template #icon>
+        <TriangleDown />
+      </template>
       <nut-menu-item v-model="state.value1" :options="options1" />
-      <nut-menu-item v-model="state.value2" @change="handleChange" :options="options2" optionIcon="checklist" />
+      <nut-menu-item v-model="state.value2" @change="handleChange" :options="options2">
+        <template #icon>
+          <Checked></Checked>
+        </template>
+      </nut-menu-item>
     </nut-menu>
     <h2>{{ translate('expandDirection') }}</h2>
     <nut-menu direction="up">
@@ -47,6 +54,7 @@ import { reactive, ref, computed } from 'vue';
 import { createComponent } from '@/packages/utils/create';
 const { createDemo, translate } = createComponent('menu');
 import { useTranslate } from '@/sites/assets/util/useTranslate';
+import { TriangleDown, Checked } from '@nutui/icons-vue';
 const initTranslate = () =>
   useTranslate({
     'zh-CN': {
@@ -121,6 +129,10 @@ const initTranslate = () =>
     }
   });
 export default createDemo({
+  components: {
+    TriangleDown,
+    Checked
+  },
   props: {},
   setup() {
     initTranslate();

+ 20 - 10
src/packages/__VUE/menu/doc.en-US.md

@@ -9,13 +9,14 @@ The menu list that pops down downwards.
 ``` javascript
 import { createApp } from 'vue';
 import { Menu, MenuItem,Overlay, Popup } from '@nutui/nutui';
-
+import { TriangleDown, Checked } from '@nutui/icons-vue';
 const app = createApp();
 app.use(Menu);
 app.use(MenuItem);
 app.use(Overlay);
 app.use(Popup);
-
+app.use(TriangleDown);
+app.use(Checked);
 ```
 
 ### Basic Usage
@@ -219,8 +220,15 @@ export default {
 ```html
 <template>
   <nut-menu>
-    <nut-menu-item v-model="state.value1" :options="state.options1" titleIcon="joy-smile" />
-    <nut-menu-item v-model="state.value2" @change="handleChange" :options="state.options2" optionIcon="checklist" />
+    <template #icon>
+      <TriangleDown />
+    </template>
+    <nut-menu-item v-model="state.value1" :options="options1" />
+    <nut-menu-item v-model="state.value2" @change="handleChange" :options="options2">
+      <template #icon>
+        <Checked></Checked>
+      </template>
+    </nut-menu-item>
   </nut-menu>
 </template>
 
@@ -387,8 +395,10 @@ export default {
 | scroll-fixed           | Whether to fixed when window is scrolled, fixed position can be set | Boolean、String、Number | false   |
 | title-class            | Custome title class                                                 | String                  | -       |
 | lock-scroll            | Whether the background is locked                                    | Boolean                 | true    |
-| title-icon               | Custome title icon                                                  | String                  | -       |
-
+### Menu Slots
+| Name | Description |
+|-|-|
+| icon | Custom title icon |
 ### MenuItem Props
 
 | Attribute | Description                          | Type    | Default        |
@@ -398,15 +408,15 @@ export default {
 | disabled  | Whether to disable dropdown item     | Boolean | false          |
 | cols      | Display how many options in one line | Number  | 1              |
 
-| option-icon         | Custome option icon                  | String  | 'Check'        |
 | direction           | Expand direction, can be set to up   | String  | 'down'         |
 | active-title-class   | Active custome title class           | String  | -              |
 | inactive-title-class | Inactive custome title class         | String  | -              |
-| font-class-name | Custom icon font base class name                                                                         | String           | `nutui-iconfont` |
-| class-prefix    | Custom icon class name prefix for using custom icons                                                     | String           | `nut-icon`       |
-
 
 
+### MenuItem Slots
+| Name | Description |
+|-|-|
+| icon | Custom option icon |
 ### MenuItem Events
 
 | Event  | Description                   | Arguments      |

+ 20 - 8
src/packages/__VUE/menu/doc.md

@@ -9,12 +9,14 @@
 ``` javascript
 import { createApp } from 'vue';
 import { Menu, MenuItem,Overlay, Popup } from '@nutui/nutui';
+import { TriangleDown, Checked } from '@nutui/icons-vue';
 const app = createApp();
 app.use(Menu);
 app.use(MenuItem);
 app.use(Overlay);
 app.use(Popup);
-
+app.use(TriangleDown);
+app.use(Checked);
 ```
 
 
@@ -219,8 +221,15 @@ export default {
 ```html
 <template>
   <nut-menu>
-    <nut-menu-item v-model="state.value1" :options="state.options1" titleIcon="joy-smile" />
-    <nut-menu-item v-model="state.value2" @change="handleChange" :options="state.options2" optionIcon="checklist" />
+    <template #icon>
+      <TriangleDown />
+    </template>
+    <nut-menu-item v-model="state.value1" :options="options1" />
+    <nut-menu-item v-model="state.value2" @change="handleChange" :options="options2">
+      <template #icon>
+        <Checked></Checked>
+      </template>
+    </nut-menu-item>
   </nut-menu>
 </template>
 
@@ -387,8 +396,11 @@ export default {
 | scroll-fixed           | 滚动后是否固定,可设置固定位置 | Boolean、String、Number | false   |
 | title-class            | 自定义标题样式类               | String                  | -       |
 | lock-scroll            | 背景是否锁定                   | Boolean                 | true    |
-| title-icon              | 自定义标题图标                 | String                  | -       |
 
+### Menu Slots
+| 名称 | 说明 |
+|-|-|
+| icon | 自定义标题图标 |
 
 ### MenuItem Props
 
@@ -398,13 +410,13 @@ export default {
 | options                       | 选项数组                                | Array   | -                |
 | disabled                      | 是否禁用菜单                            | Boolean | false            |
 | cols                          | 可以设置一行展示多少列 options          | Number  | 1                |
-| option-icon         | 自定义选项图标                          | String  | 'Check'          |
 | direction          | 菜单展开方向,可选值为up                | String  | 'down'           |
 | active-title-class   | 选项选中时自定义标题样式类              | String  | -                |
 | inactive-title-class | 选项非选中时自定义标题样式类            | String  | -                |
-| font-class-name       | 自定义icon 字体基础类名                 | string  | `nutui-iconfont` |
-| class-prefix          | 自定义icon 类名前缀,用于使用自定义图标 | string  | `nut-icon`       |
-
+### MenuItem Slots
+| 名称 | 说明 |
+|-|-|
+| icon | 自定义选项图标 |
 ### MenuItem Events
 
 | 事件名 | 说明                 | 回调参数     |

+ 20 - 9
src/packages/__VUE/menu/doc.taro.md

@@ -9,12 +9,14 @@
 ``` javascript
 import { createApp } from 'vue';
 import { Menu, MenuItem,Overlay, Popup } from '@nutui/nutui-taro';
+import { TriangleDown, Checked } from '@nutui/icons-vue-taro';
 const app = createApp();
 app.use(Menu);
 app.use(MenuItem);
 app.use(Overlay);
 app.use(Popup);
-
+app.use(TriangleDown);
+app.use(Checked);
 ```
 
 
@@ -219,8 +221,15 @@ export default {
 ```html
 <template>
   <nut-menu>
-    <nut-menu-item v-model="state.value1" :options="state.options1" titleIcon="joy-smile" />
-    <nut-menu-item v-model="state.value2" @change="handleChange" :options="state.options2" optionIcon="checklist" />
+    <template #icon>
+      <TriangleDown />
+    </template>
+    <nut-menu-item v-model="state.value1" :options="options1" />
+    <nut-menu-item v-model="state.value2" @change="handleChange" :options="options2">
+      <template #icon>
+        <Checked></Checked>
+      </template>
+    </nut-menu-item>
   </nut-menu>
 </template>
 
@@ -387,9 +396,11 @@ export default {
 | scroll-fixed           | 滚动后是否固定,可设置固定位置 | Boolean、String、Number | false   |
 | title-class           | 自定义标题样式类               | String                  | -       |
 | lock-scroll           | 背景是否锁定                   | Boolean                 | true    |
-| title-icon              | 自定义标题图标                 | String                  | -       |
-
 
+### Menu Slots
+| 名称 | 说明 |
+|-|-|
+| icon | 自定义标题图标 |
 ### MenuItem Props
 
 | 参数                          | 说明                                    | 类型    | 默认值           |
@@ -398,13 +409,13 @@ export default {
 | options                       | 选项数组                                | Array   | -                |
 | disabled                      | 是否禁用菜单                            | Boolean | false            |
 | cols                          | 可以设置一行展示多少列 options          | Number  | 1                |
-| option-icon         | 自定义选项图标                          | String  | 'Check'          |
 | direction          | 菜单展开方向,可选值为up                | String  | 'down'           |
 | active-title-class   | 选项选中时自定义标题样式类              | String  | -                |
 | inactive-title-class | 选项非选中时自定义标题样式类            | String  | -                |
-| font-class-name       | 自定义icon 字体基础类名                 | string  | `nutui-iconfont` |
-| class-prefix          | 自定义icon 类名前缀,用于使用自定义图标 | string  | `nut-icon`       |
-
+### MenuItem Slots
+| 名称 | 说明 |
+|-|-|
+| icon | 自定义选项图标 |
 ### MenuItem Events
 
 | 事件名 | 说明                 | 回调参数     |

+ 1 - 0
src/packages/__VUE/menu/index.scss

@@ -46,6 +46,7 @@
 
       .nut-menu__title-icon {
         transition: all 0.2s linear;
+        display: flex;
       }
 
       .nut-menu__title {

+ 12 - 6
src/packages/__VUE/menu/index.taro.vue

@@ -10,12 +10,12 @@
         >
           <view class="nut-menu__title" :class="getClasses(item.state.showPopup)">
             <view class="nut-menu__title-text">{{ item.renderTitle() }}</view>
-            <nut-icon
-              v-bind="$attrs"
-              :name="titleIcon || (direction === 'up' ? 'arrow-up' : 'down-arrow')"
-              size="10"
-              class="nut-menu__title-icon"
-            ></nut-icon>
+            <span class="nut-menu__title-icon">
+              <slot name="icon">
+                <ArrowUp2 v-if="direction === 'up'" />
+                <ArrowDown2 v-else />
+              </slot>
+            </span>
           </view>
         </view>
       </template>
@@ -29,7 +29,13 @@ import { createComponent } from '@/packages/utils/create';
 import Taro, { usePageScroll } from '@tarojs/taro';
 import { useTaroRect } from '@/packages/utils/useTaroRect';
 const { componentName, create } = createComponent('menu');
+import { ArrowUp2, ArrowDown2 } from '@nutui/icons-vue-taro';
+
 export default create({
+  components: {
+    ArrowUp2,
+    ArrowDown2
+  },
   props: {
     activeColor: {
       type: String,

+ 11 - 6
src/packages/__VUE/menu/index.vue

@@ -10,12 +10,12 @@
         >
           <view class="nut-menu__title" :class="getClasses(item.state.showPopup)">
             <view class="nut-menu__title-text">{{ item.renderTitle() }}</view>
-            <nut-icon
-              v-bind="$attrs"
-              :name="titleIcon || (direction === 'up' ? 'arrow-up' : 'down-arrow')"
-              size="10"
-              class="nut-menu__title-icon"
-            ></nut-icon>
+            <span class="nut-menu__title-icon">
+              <slot name="icon">
+                <ArrowUp2 v-if="direction === 'up'" />
+                <ArrowDown2 v-else />
+              </slot>
+            </span>
           </view>
         </view>
       </template>
@@ -28,7 +28,12 @@ import { reactive, provide, computed, ref, onMounted, onUnmounted } from 'vue';
 import { createComponent } from '@/packages/utils/create';
 import { useRect } from '@/packages/utils/useRect';
 const { componentName, create } = createComponent('menu');
+import { ArrowUp2, ArrowDown2 } from '@nutui/icons-vue';
 export default create({
+  components: {
+    ArrowUp2,
+    ArrowDown2
+  },
   props: {
     activeColor: {
       type: String,

+ 4 - 2
src/packages/__VUE/menuitem/index.scss

@@ -7,7 +7,7 @@
 }
 
 .nut-menu-item {
-  &.active {
+  .active {
     font-weight: $menu-active-item-font-weight;
     color: $menu-item-active-text-color !important;
   }
@@ -30,7 +30,9 @@
     display: flex;
     align-items: center;
 
-    i {
+    .nut-menu-item__span {
+      display: flex;
+      align-items: center;
       margin-right: $menu-item-option-i-margin-right;
     }
   }

+ 11 - 8
src/packages/__VUE/menuitem/index.taro.vue

@@ -39,16 +39,18 @@
             :style="{ 'flex-basis': 100 / cols + '%' }"
             @click="onClick(option)"
           >
-            <nut-icon
+            <span
+              class="nut-menu-item__span"
+              v-if="option.value === modelValue"
               :class="{
                 activeTitleClass: option.value === modelValue,
                 inactiveTitleClass: option.value !== modelValue
               }"
-              v-if="option.value === modelValue"
-              :name="optionIcon"
-              v-bind="$attrs"
-              :color="parent.props.activeColor"
-            ></nut-icon>
+            >
+              <slot name="icon">
+                <Check v-bind="$attrs" :color="parent.props.activeColor"></Check>
+              </slot>
+            </span>
             <view
               :class="{
                 activeTitleClass: option.value === modelValue,
@@ -68,9 +70,10 @@
 import { reactive, PropType, inject, getCurrentInstance, computed, onUnmounted } from 'vue';
 import { createComponent } from '@/packages/utils/create';
 const { componentName, create } = createComponent('menu-item');
-import Icon from '../icon/index.taro.vue';
 import Popup from '../popup/index.taro.vue';
 import NutScrollView from '../scrollView/index.taro.vue';
+import { Check } from '@nutui/icons-vue-taro';
+
 let _zIndex = 2000;
 
 export default create({
@@ -97,7 +100,7 @@ export default create({
     }
   },
   components: {
-    [Icon.name]: Icon,
+    Check,
     [Popup.name]: Popup,
     NutScrollView
   },

+ 11 - 10
src/packages/__VUE/menuitem/index.vue

@@ -38,13 +38,15 @@
           :style="{ 'flex-basis': 100 / cols + '%' }"
           @click="onClick(option)"
         >
-          <nut-icon
-            v-bind="$attrs"
-            :class="{ activeTitleClass: option.value === modelValue, inactiveTitleClass: option.value !== modelValue }"
+          <span
+            class="nut-menu-item__span"
             v-if="option.value === modelValue"
-            :name="optionIcon"
-            :color="parent.props.activeColor"
-          ></nut-icon>
+            :class="{ activeTitleClass: option.value === modelValue, inactiveTitleClass: option.value !== modelValue }"
+          >
+            <slot name="icon">
+              <Check v-bind="$attrs" :color="parent.props.activeColor"></Check>
+            </slot>
+          </span>
           <view
             :class="{ activeTitleClass: option.value === modelValue, inactiveTitleClass: option.value !== modelValue }"
             :style="{ color: option.value === modelValue ? parent.props.activeColor : '' }"
@@ -60,9 +62,8 @@
 import { reactive, PropType, inject, getCurrentInstance, computed, onUnmounted } from 'vue';
 import { createComponent } from '@/packages/utils/create';
 const { componentName, create } = createComponent('menu-item');
-import Icon from '../icon/index.vue';
 import Popup from '../popup/index.vue';
-
+import { Check } from '@nutui/icons-vue';
 export default create({
   props: {
     title: String,
@@ -87,8 +88,8 @@ export default create({
     }
   },
   components: {
-    [Icon.name]: Icon,
-    [Popup.name]: Popup
+    [Popup.name]: Popup,
+    Check
   },
   emits: ['update:modelValue', 'change', 'open', 'close'],
   setup(props, { emit, slots }) {

+ 14 - 2
src/packages/__VUE/radio/demo.vue

@@ -57,8 +57,16 @@
     <nut-cell-group :title="translate('icon')">
       <nut-cell>
         <nut-radio-group v-model="radioVal5">
-          <nut-radio label="1" icon-name="checklist" icon-active-name="checklist">{{ translate('icon') }}</nut-radio>
-          <nut-radio label="2" icon-name="checklist" icon-active-name="checklist">{{ translate('icon') }}</nut-radio>
+          <nut-radio label="1">
+            {{ translate('icon') }}
+            <template #icon> <Checklist /> </template>
+            <template #checkedIcon> <Checklist color="red" /> </template>
+          </nut-radio>
+          <nut-radio label="2">
+            {{ translate('icon') }}
+            <template #icon> <Checklist /> </template>
+            <template #checkedIcon> <Checklist color="red" /> </template>
+          </nut-radio>
         </nut-radio-group>
       </nut-cell>
     </nut-cell-group>
@@ -79,6 +87,7 @@ import { createComponent } from '@/packages/utils/create';
 import { reactive, toRefs } from 'vue';
 const { createDemo, translate } = createComponent('radio');
 import { useTranslate } from '@/sites/assets/util/useTranslate';
+import { Checklist } from '@nutui/icons-vue';
 const initTranslate = () =>
   useTranslate({
     'zh-CN': {
@@ -106,6 +115,9 @@ const initTranslate = () =>
   });
 export default createDemo({
   props: {},
+  components: {
+    Checklist
+  },
   setup() {
     initTranslate();
     const data = reactive({

+ 18 - 10
src/packages/__VUE/radio/doc.en-US.md

@@ -9,11 +9,11 @@ Used to make a single selection in a set of alternatives
 ``` ts
 import { createApp } from 'vue';
 import { Radio,RadioGroup,Icon } from '@nutui/nutui';
-
+import { Checklist } from '@nutui/icons-vue'
 const app = createApp();
 app.use(Radio);
 app.use(RadioGroup);
-app.use(Icon);
+app.use(Checklist);
 ```
 ### Basic Usage
 
@@ -135,7 +135,7 @@ Bind the **label** of the current option through **v-model**. And it must be use
 
 ### Custom icon
 
-It is suggested to modify `icon-name` and `icon-active-name`
+Customize the icon through the slot, it is recommended to set the `icon` and `checkedIcon` two slots at the same time
 
 :::demo
 
@@ -144,8 +144,16 @@ It is suggested to modify `icon-name` and `icon-active-name`
   <nut-cell-group title="Radio Custom icon">
     <nut-cell>
       <nut-radio-group v-model="radioVal">
-        <nut-radio label="1" icon-name="checklist" icon-active-name="checklist">Custom icon</nut-radio>
-        <nut-radio label="2" icon-name="checklist" icon-active-name="checklist">Custom icon</nut-radio>
+        <nut-radio label="1">
+          Custom icon
+          <template #icon> <Checklist /> </template>
+          <template #checkedIcon> <Checklist color="red" /> </template>
+        </nut-radio>
+        <nut-radio label="2">
+          Custom icon
+          <template #icon> <Checklist /> </template>
+          <template #checkedIcon> <Checklist color="red" /> </template>
+        </nut-radio>
       </nut-radio-group>
     </nut-cell>
   </nut-cell-group>
@@ -204,13 +212,13 @@ It is suggested to modify `icon-name` and `icon-active-name`
 |------------------|--------------------------------------------------------------|-------------------------|-------------------|
 | disabled         | Disable selection                                           | Boolean                 | `false`           |
 | icon-size        | [Icon Size](#/en-US/icon)                                           | String、Number          | `18`              |
-| icon-name        | [Icon Name](#en-US//icon),Before selection (it is suggested to modify it together with `icon-active-name`) | String                  | `'check-normal'`  |
-| icon-active-name | [Icon Name](#en-US//icon),After selection (it is suggested to modify it together with `icon-name`)       | String                  | `'check-checked'` |
-| icon-class-prefix | Custom icon class name prefix, used to use custom icons        | String                  | `nut-icon` |
-| icon-font-class-name | Basic class name of custom icon font        | String                  | `nutui-iconfont` |
 | label            | Radio box ID                                                  | String、Number、Boolean | -                 |
 | shape            | Shape, optional values are `button`、`round`                                | String                  | round             |
-
+### Radio Slots
+| Name | Description |
+|-|-|
+| icon | Icon when not selected |
+| checkedIcon | Icon when selected |
 ### RadioGroup Props
 
 | Attribute          | Description                                          | Type                    | Default     |

+ 19 - 10
src/packages/__VUE/radio/doc.md

@@ -8,12 +8,12 @@
 
 ``` ts
 import { createApp } from 'vue';
-import { Radio,RadioGroup,Icon } from '@nutui/nutui';
-
+import { Radio,RadioGroup } from '@nutui/nutui';
+import { Checklist } from '@nutui/icons-vue';
 const app = createApp();
 app.use(Radio);
 app.use(RadioGroup);
-app.use(Icon);
+app.use(Checklist);
 ```
 ### 基础用法
 
@@ -135,7 +135,7 @@ app.use(Icon);
 
 ### 自定义图标
 
-建议 `icon-name` `icon-active-name` 一起修改
+通过slot自定义图标,建议同时设置`icon`和`checkedIcon`两个插槽
 
 :::demo
 
@@ -144,8 +144,16 @@ app.use(Icon);
   <nut-cell-group title="Radio自定义图标">
     <nut-cell>
       <nut-radio-group v-model="radioVal">
-        <nut-radio label="1" icon-name="checklist" icon-active-name="checklist">自定义图标</nut-radio>
-        <nut-radio label="2" icon-name="checklist" icon-active-name="checklist">自定义图标</nut-radio>
+        <nut-radio label="1">
+          自定义图标
+          <template #icon> <Checklist /> </template>
+          <template #checkedIcon> <Checklist color="red" /> </template>
+        </nut-radio>
+        <nut-radio label="2">
+          自定义图标
+          <template #icon> <Checklist /> </template>
+          <template #checkedIcon> <Checklist color="red" /> </template>
+        </nut-radio>
       </nut-radio-group>
     </nut-cell>
   </nut-cell-group>
@@ -204,13 +212,14 @@ app.use(Icon);
 |------------------|--------------------------------------------------------------|-------------------------|-------------------|
 | disabled         | 是否禁用选择                                                 | Boolean                 | `false`           |
 | icon-size        | [图标尺寸](#/zh-CN/component/icon)                                           | String、Number          | `18`              |
-| icon-name        | [图标名称](#/zh-CN/component/icon),选中前(建议和`icon-active-name`一起修改) | String                  | `'check-normal'`  |
-| icon-active-name | [图标名称](#/zh-CN/component/icon),选中后(建议和`icon-name`一起修改)        | String                  | `'check-checked'` |
-| icon-class-prefix | 自定义 icon 类名前缀,用于使用自定义图标        | String                  | `nut-icon` |
-| icon-font-class-name | 自定义 icon 字体基础类名        | String                  | `nutui-iconfont` |
 | label            | 单选框标识                                                   | String、Number、Boolean | -                 |
 | shape            | 形状,可选值为 button、round                                 | String                  | round             |
 
+### Radio Slots
+| 名称 | 说明 |
+|-|-|
+| icon | 未选中时的图标 |
+| checkedIcon | 选中时的图标 |
 ### RadioGroup Props
 
 | 字段          | 说明                                          | 类型                    | 默认值     |

+ 19 - 11
src/packages/__VUE/radio/doc.taro.md

@@ -8,12 +8,12 @@
 
 ``` ts
 import { createApp } from 'vue';
-import { Radio,RadioGroup,Icon } from '@nutui/nutui-taro';
-
+import { Radio,RadioGroup } from '@nutui/nutui-taro';
+import { Checklist } from '@nutui/icons-vue-taro';
 const app = createApp();
 app.use(Radio);
 app.use(RadioGroup);
-app.use(Icon);
+app.use(Checklist);
 ```
 ### 基础用法
 
@@ -135,7 +135,7 @@ app.use(Icon);
 
 ### 自定义图标
 
-建议 `icon-name` `icon-active-name` 一起修改
+通过slot自定义图标,建议同时设置`icon`和`checkedIcon`两个插槽
 
 :::demo
 
@@ -144,8 +144,16 @@ app.use(Icon);
   <nut-cell-group title="Radio自定义图标">
     <nut-cell>
       <nut-radio-group v-model="radioVal">
-        <nut-radio label="1" icon-name="checklist" icon-active-name="checklist">自定义图标</nut-radio>
-        <nut-radio label="2" icon-name="checklist" icon-active-name="checklist">自定义图标</nut-radio>
+        <nut-radio label="1">
+          自定义图标
+          <template #icon> <Checklist /> </template>
+          <template #checkedIcon> <Checklist color="red" /> </template>
+        </nut-radio>
+        <nut-radio label="2">
+          自定义图标
+          <template #icon> <Checklist /> </template>
+          <template #checkedIcon> <Checklist color="red" /> </template>
+        </nut-radio>
       </nut-radio-group>
     </nut-cell>
   </nut-cell-group>
@@ -204,13 +212,13 @@ app.use(Icon);
 |------------------|--------------------------------------------------------------|-------------------------|-------------------|
 | disabled         | 是否禁用选择                                                 | Boolean                 | `false`           |
 | icon-size        | [图标尺寸](#/zh-CN/component/icon)                                           | String、Number          | `18`              |
-| icon-name        | [图标名称](#/zh-CN/component/icon),选中前(建议和`icon-active-name`一起修改) | String                  | `'check-normal'`  |
-| icon-active-name | [图标名称](#/zh-CN/component/icon),选中后(建议和`icon-name`一起修改)        | String                  | `'check-checked'` |
-| icon-class-prefix | 自定义 icon 类名前缀,用于使用自定义图标        | String                  | `nut-icon` |
-| icon-font-class-name | 自定义 icon 字体基础类名        | String                  | `nutui-iconfont` |
 | label            | 单选框标识                                                   | String、Number、Boolean | -                 |
 | shape            | 形状,可选值为 button、round                                 | String                  | round             |
-
+### Radio Slots
+| 名称 | 说明 |
+|-|-|
+| icon | 未选中时的图标 |
+| checkedIcon | 选中时的图标 |
 ### RadioGroup Props
 
 | 字段          | 说明                                          | 类型                    | 默认值     |

+ 18 - 24
src/packages/__VUE/radio/index.taro.vue

@@ -1,10 +1,15 @@
 <script lang="ts">
 import { computed, h, inject } from 'vue';
-import nutIcon from '../icon/index.taro.vue';
 import { createComponent } from '@/packages/utils/create';
 const { componentName, create } = createComponent('radio');
+import { CheckNormal, CheckChecked } from '@nutui/icons-vue-taro';
+import { pxCheck } from '@/packages/utils/pxCheck';
 
 export default create({
+  components: {
+    CheckNormal,
+    CheckChecked
+  },
   props: {
     disabled: {
       type: Boolean,
@@ -18,25 +23,9 @@ export default create({
       type: [String, Number, Boolean],
       default: ''
     },
-    iconName: {
-      type: String,
-      default: 'check-normal'
-    },
-    iconActiveName: {
-      type: String,
-      default: 'check-checked'
-    },
     iconSize: {
       type: [String, Number],
       default: ''
-    },
-    iconClassPrefix: {
-      type: String,
-      default: 'nut-icon'
-    },
-    iconFontClassName: {
-      type: String,
-      default: 'nutui-iconfont'
     }
   },
   setup(props, { emit, slots }) {
@@ -59,13 +48,18 @@ export default create({
     });
 
     const renderIcon = () => {
-      const { iconName, iconSize, iconActiveName, iconClassPrefix, iconFontClassName } = props;
-      return h(nutIcon, {
-        name: isCurValue.value ? iconActiveName : iconName,
-        size: iconSize,
-        class: color.value,
-        classPrefix: iconClassPrefix,
-        fontClassName: iconFontClassName
+      const { iconSize } = props;
+      const iconNodeMap = {
+        CheckNormal: slots.icon ? slots.icon : CheckNormal,
+        Checked: slots.checkedIcon ? slots.checkedIcon : CheckChecked
+      };
+      const iconNode = !isCurValue.value ? iconNodeMap.CheckNormal : iconNodeMap.Checked;
+      const size = pxCheck(iconSize);
+      return h(iconNode, {
+        width: size,
+        height: size,
+        size: size,
+        class: color.value
       });
     };
 

+ 18 - 24
src/packages/__VUE/radio/index.vue

@@ -1,10 +1,15 @@
 <script lang="ts">
 import { computed, h, inject } from 'vue';
 import { createComponent } from '@/packages/utils/create';
-import nutIcon from '../icon/index.vue';
 const { componentName, create } = createComponent('radio');
+import { CheckNormal, CheckChecked } from '@nutui/icons-vue';
+import { pxCheck } from '@/packages/utils/pxCheck';
 
 export default create({
+  components: {
+    CheckNormal,
+    CheckChecked
+  },
   props: {
     disabled: {
       type: Boolean,
@@ -18,25 +23,9 @@ export default create({
       type: [String, Number, Boolean],
       default: ''
     },
-    iconName: {
-      type: String,
-      default: 'check-normal'
-    },
-    iconActiveName: {
-      type: String,
-      default: 'check-checked'
-    },
     iconSize: {
       type: [String, Number],
       default: ''
-    },
-    iconClassPrefix: {
-      type: String,
-      default: 'nut-icon'
-    },
-    iconFontClassName: {
-      type: String,
-      default: 'nutui-iconfont'
     }
   },
   setup(props, { emit, slots }) {
@@ -59,13 +48,18 @@ export default create({
     });
 
     const renderIcon = () => {
-      const { iconName, iconSize, iconActiveName, iconClassPrefix, iconFontClassName } = props;
-      return h(nutIcon, {
-        name: isCurValue.value ? iconActiveName : iconName,
-        size: iconSize,
-        class: color.value,
-        classPrefix: iconClassPrefix,
-        fontClassName: iconFontClassName
+      const { iconSize } = props;
+      const iconNodeMap = {
+        CheckNormal: slots.icon ? slots.icon : CheckNormal,
+        Checked: slots.checkedIcon ? slots.checkedIcon : CheckChecked
+      };
+      const iconNode = !isCurValue.value ? iconNodeMap.CheckNormal : iconNodeMap.Checked;
+      const size = pxCheck(iconSize);
+      return h(iconNode, {
+        width: size,
+        height: size,
+        size: size,
+        class: color.value
       });
     };
 

+ 2 - 58
src/packages/__VUE/radiogroup/__tests__/radiogroup.spec.ts

@@ -150,64 +150,8 @@ test('radio icon-size test', async () => {
   });
 
   const items: any = wrapper.findAll('.nut-radio');
-  expect((items[0].findAll('i') as any)[0].element.style.fontSize).toEqual('25px');
-  expect((items[1].findAll('i') as any)[0].element.style.fontSize).toEqual('12px');
-});
-
-test('radio icon-name test', async () => {
-  const wrapper = mount({
-    components: {
-      'nut-radio-group': RadioGroup,
-      'nut-radio': Radio
-    },
-    template: `
-      <template>
-        <nut-radio-group v-model="radioVal" direction="horizontal">
-          <nut-radio label="1" icon-size="25" icon-name="checklist" icon-active-name="checklist"></nut-radio>
-          <nut-radio label="2" icon-size="12"></nut-radio>
-        </nut-radio-group>
-      </template>
-    `,
-    setup() {
-      const state = reactive({
-        radioVal: ''
-      });
-      return {
-        ...toRefs(state)
-      };
-    }
-  });
-
-  const items = wrapper.findAll('.nut-radio');
-  expect((items[0].findAll('i') as any)[0].classes()).toContain('nut-icon-checklist');
-});
-
-test('radio label test', async () => {
-  const wrapper = mount({
-    components: {
-      'nut-radio-group': RadioGroup,
-      'nut-radio': Radio
-    },
-    template: `
-      <template>
-        <nut-radio-group v-model="radioVal" direction="horizontal">
-          <nut-radio icon-size="25" label="testlabel"></nut-radio>
-          <nut-radio label="2" icon-size="12"></nut-radio>
-        </nut-radio-group>
-      </template>
-    `,
-    setup() {
-      const state = reactive({
-        radioVal: ''
-      });
-      return {
-        ...toRefs(state)
-      };
-    }
-  });
-
-  const items = wrapper.findAll('.nut-radio');
-  expect((items[0].findAll('i') as any)[0].find('testlabel')).toBeTruthy();
+  expect((items[0].findAll('svg') as any)[0].element.style.width).toEqual('25px');
+  expect((items[1].findAll('svg') as any)[0].element.style.height).toEqual('12px');
 });
 
 test('radio shape test', async () => {

+ 9 - 1
src/sites/mobile-taro/vue/src/dentry/pages/checkbox/index.vue

@@ -35,7 +35,11 @@
     </nut-cell-group>
     <nut-cell-group title="自定义图标">
       <nut-cell>
-        <nut-checkbox v-model="checkbox7" icon-name="checklist" icon-active-name="checklist">自定义图标</nut-checkbox>
+        <nut-checkbox v-model="checkbox7"
+          >自定义图标
+          <template #icon> <Checklist /> </template>
+          <template #checkedIcon> <Checklist color="red" /> </template>
+        </nut-checkbox>
       </nut-cell>
     </nut-cell-group>
     <nut-cell-group title="点击触发change事件">
@@ -110,7 +114,11 @@
 </template>
 <script lang="ts">
 import { reactive, ref, toRefs, Ref } from 'vue';
+import { Checklist } from '@nutui/icons-vue-taro';
 export default {
+  components: {
+    Checklist
+  },
   setup(props, context) {
     const group = ref(null) as Ref;
     const group2 = ref(null) as Ref;

+ 14 - 2
src/sites/mobile-taro/vue/src/dentry/pages/radio/index.vue

@@ -57,8 +57,16 @@
     <nut-cell-group title="Radio自定义图标">
       <nut-cell>
         <nut-radio-group v-model="radioVal5">
-          <nut-radio label="1" icon-name="checklist" icon-active-name="checklist">自定义图标</nut-radio>
-          <nut-radio label="2" icon-name="checklist" icon-active-name="checklist">自定义图标</nut-radio>
+          <nut-radio label="1">
+            自定义图标
+            <template #icon> <Checklist /> </template>
+            <template #checkedIcon> <Checklist color="red" /> </template>
+          </nut-radio>
+          <nut-radio label="2">
+            自定义图标
+            <template #icon> <Checklist /> </template>
+            <template #checkedIcon> <Checklist color="red" /> </template>
+          </nut-radio>
         </nut-radio-group>
       </nut-cell>
     </nut-cell-group>
@@ -76,8 +84,12 @@
 
 <script lang="ts">
 import { reactive, toRefs } from 'vue';
+import { Checklist } from '@nutui/icons-vue-taro';
 export default {
   props: {},
+  components: {
+    Checklist
+  },
   setup() {
     const data = reactive({
       radioVal: 1,

+ 14 - 2
src/sites/mobile-taro/vue/src/nav/pages/menu/index.vue

@@ -26,8 +26,15 @@
     </nut-menu>
     <h2>自定义图标</h2>
     <nut-menu>
-      <nut-menu-item v-model="state.value1" :options="state.options1" titleIcon="joy-smile" />
-      <nut-menu-item v-model="state.value2" @change="handleChange" :options="state.options2" optionIcon="checklist" />
+      <template #icon>
+        <TriangleDown />
+      </template>
+      <nut-menu-item v-model="state.value1" :options="state.options1" />
+      <nut-menu-item v-model="state.value2" @change="handleChange" :options="state.options2">
+        <template #icon>
+          <Checked></Checked>
+        </template>
+      </nut-menu-item>
     </nut-menu>
     <h2>向上展开</h2>
     <nut-menu direction="up">
@@ -44,7 +51,12 @@
 
 <script>
 import { ref, reactive, toRefs } from 'vue';
+import { TriangleDown, Checked } from '@nutui/icons-vue-taro';
 export default {
+  components: {
+    TriangleDown,
+    Checked
+  },
   props: {},
   setup() {
     const state = reactive({