Browse Source

wip(VForm): VForm component development

陈凯龙 3 years ago
parent
commit
d9d64f3931

+ 82 - 8
src/App.vue

@@ -39,6 +39,27 @@ onMounted(() => {
   restaurants.value = loadAll()
 })
 
+const initials = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
+const options = ref<FormOptions[]>(
+  Array.from({ length: 1000 }).map((_, idx) => ({
+    value: `Option ${idx + 1}`,
+    label: `${initials[idx % 10]}${idx}`
+  }))
+)
+const options2 = ref<FormOptions[]>(
+  Array.from({ length: 10 }).map((_, idx) => {
+    const label = idx + 1
+    return {
+      value: `Group ${label}`,
+      label: `Group ${label}`,
+      options: Array.from({ length: 10 }).map((_, idx) => ({
+        value: `Option ${idx + 1 + 10 * label}`,
+        label: `${initials[idx % 10]}${idx + 1 + 10 * label}`
+      }))
+    }
+  })
+)
+
 const schema = reactive<VFormSchema[]>([
   {
     field: 'field1',
@@ -238,6 +259,45 @@ const schema = reactive<VFormSchema[]>([
       }
     ],
     optionsSlot: true
+  },
+  {
+    field: 'field17',
+    label: `${t('formDemo.selectV2')}`,
+    component: 'Divider'
+  },
+  {
+    field: 'field18',
+    label: t('formDemo.default'),
+    component: 'SelectV2',
+    options: options.value
+  },
+  {
+    field: 'field18',
+    label: t('formDemo.slot'),
+    component: 'SelectV2',
+    options: options.value,
+    componentProps: {
+      slots: {
+        default: true
+      }
+    }
+  },
+  {
+    field: 'field19',
+    label: t('formDemo.group'),
+    component: 'SelectV2',
+    options: options2.value
+  },
+  {
+    field: 'field20',
+    label: `${t('formDemo.group')}${t('formDemo.slot')}`,
+    component: 'SelectV2',
+    options: options2.value,
+    componentProps: {
+      slots: {
+        default: true
+      }
+    }
   }
 ])
 </script>
@@ -260,18 +320,32 @@ const schema = reactive<VFormSchema[]>([
         <span class="link">{{ item.link }}</span>
       </template>
 
-      <template #field14-option="item">
+      <template #field14-option="{ item }">
+        <span style="float: left">{{ item.label }}</span>
+        <span style="float: right; font-size: 13px; color: var(--el-text-color-secondary)">
+          {{ item.value }}
+        </span>
+      </template>
+
+      <template #field16-option="{ item }">
+        <span style="float: left">{{ item.label }}</span>
+        <span style="float: right; font-size: 13px; color: var(--el-text-color-secondary)">
+          {{ item.value }}
+        </span>
+      </template>
+
+      <template #field18-default="{ item }">
         <span style="float: left">{{ item.label }}</span>
-        <span style="float: right; font-size: 13px; color: var(--el-text-color-secondary)">{{
-          item.value
-        }}</span>
+        <span style="float: right; font-size: 13px; color: var(--el-text-color-secondary)">
+          {{ item.value }}
+        </span>
       </template>
 
-      <template #field16-option="item">
+      <template #field20-default="{ item }">
         <span style="float: left">{{ item.label }}</span>
-        <span style="float: right; font-size: 13px; color: var(--el-text-color-secondary)">{{
-          item.value
-        }}</span>
+        <span style="float: right; font-size: 13px; color: var(--el-text-color-secondary)">
+          {{ item.value }}
+        </span>
       </template>
     </VFrom>
   </ElConfigProvider>

+ 7 - 42
src/components/Form/src/VForm.vue

@@ -1,10 +1,11 @@
 <script lang="tsx">
 import { PropType, defineComponent, ref, computed, unref } from 'vue'
-import { ElForm, ElFormItem, ElRow, ElCol, ElOption, ElOptionGroup } from 'element-plus'
+import { ElForm, ElFormItem, ElRow, ElCol } from 'element-plus'
 import { componentMap } from './componentMap'
 import { propTypes } from '@/utils/propTypes'
 import { getSlot } from '@/utils/tsxHelper'
 import { setTextPlaceholder, setGridProp, setComponentProps, setItemComponentSlots } from './helper'
+import { useRenderSelect } from './components/useRenderSelect'
 
 export default defineComponent({
   name: 'VForm',
@@ -74,9 +75,12 @@ export default defineComponent({
               <Com
                 {...(autoSetPlaceholder && setTextPlaceholder(item))}
                 {...setComponentProps(item.componentProps)}
+                // 单独给SelectV2做判断
+                options={item.component === 'SelectV2' ? item.options || [] : undefined}
               >
                 {{
-                  default: () => (item.options ? renderOptions(item) : null),
+                  default: () =>
+                    item.options && item.component !== 'SelectV2' ? renderOptions(item) : undefined,
                   ...setItemComponentSlots(slots, item?.componentProps?.slots, item.field)
                 }}
               </Com>
@@ -90,52 +94,13 @@ export default defineComponent({
     function renderOptions(item: VFormSchema) {
       switch (item.component) {
         case 'Select':
+          const { renderSelectOptions } = useRenderSelect(slots)
           return renderSelectOptions(item)
         default:
           break
       }
     }
 
-    // 渲染 select options
-    function renderSelectOptions(item: VFormSchema) {
-      // 如果有别名,就取别名
-      const labelAlias = item.optionsField?.labelField
-      return item.options?.map((option) => {
-        if (option?.options?.length) {
-          return (
-            <ElOptionGroup label={labelAlias ? option[labelAlias] : option['label']}>
-              {() => {
-                return option?.options?.map((v) => {
-                  return renderSelectOptionItem(item, v)
-                })
-              }}
-            </ElOptionGroup>
-          )
-        } else {
-          return renderSelectOptionItem(item, option)
-        }
-      })
-    }
-
-    // 渲染 select option item
-    function renderSelectOptionItem(item: VFormSchema, option: FormOptions) {
-      // 如果有别名,就取别名
-      const labelAlias = item.optionsField?.labelField
-      const valueAlias = item.optionsField?.valueField
-      return (
-        <ElOption
-          label={labelAlias ? option[labelAlias] : option['label']}
-          value={valueAlias ? option[valueAlias] : option['value']}
-        >
-          {{
-            default: () =>
-              // option 插槽名规则,{field}-option
-              item.optionsSlot ? getSlot(slots, `${item.field}-option`, option) : null
-          }}
-        </ElOption>
-      )
-    }
-
     // 过滤传入Form组件的属性
     function getFormBindValue() {
       // 避免在标签上出现多余的属性

+ 49 - 0
src/components/Form/src/components/useRenderSelect.tsx

@@ -0,0 +1,49 @@
+import { ElOption, ElOptionGroup } from 'element-plus'
+import { getSlot } from '@/utils/tsxHelper'
+import { Slots } from 'vue'
+
+export function useRenderSelect(slots: Slots) {
+  // 渲染 select options
+  function renderSelectOptions(item: VFormSchema) {
+    // 如果有别名,就取别名
+    const labelAlias = item.optionsField?.labelField
+    return item.options?.map((option) => {
+      if (option?.options?.length) {
+        return (
+          <ElOptionGroup label={labelAlias ? option[labelAlias] : option['label']}>
+            {() => {
+              return option?.options?.map((v) => {
+                return renderSelectOptionItem(item, v)
+              })
+            }}
+          </ElOptionGroup>
+        )
+      } else {
+        return renderSelectOptionItem(item, option)
+      }
+    })
+  }
+
+  // 渲染 select option item
+  function renderSelectOptionItem(item: VFormSchema, option: FormOptions) {
+    // 如果有别名,就取别名
+    const labelAlias = item.optionsField?.labelField
+    const valueAlias = item.optionsField?.valueField
+    return (
+      <ElOption
+        label={labelAlias ? option[labelAlias] : option['label']}
+        value={valueAlias ? option[valueAlias] : option['value']}
+      >
+        {{
+          default: () =>
+            // option 插槽名规则,{field}-option
+            item.optionsSlot ? getSlot(slots, `${item.field}-option`, { item: option }) : undefined
+        }}
+      </ElOption>
+    )
+  }
+
+  return {
+    renderSelectOptions
+  }
+}

+ 2 - 0
src/components/Form/src/helper.ts

@@ -117,3 +117,5 @@ export function setItemComponentSlots(
   }
   return slotObj
 }
+
+export function setModel() {}

+ 2 - 1
src/locales/en.ts

@@ -16,6 +16,7 @@ export default {
     position: 'Position',
     autocomplete: 'Autocomplete',
     select: 'Select',
-    group: 'Select Group'
+    group: 'Select Group',
+    selectV2: 'SelectV2'
   }
 }

+ 2 - 1
src/locales/zh-CN.ts

@@ -16,6 +16,7 @@ export default {
     position: '位置',
     autocomplete: '自动补全',
     select: '选择器',
-    group: '选项分组'
+    group: '选项分组',
+    selectV2: '虚拟列表选择器'
   }
 }