Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

form扩展验证 #1747

Open
magnificent007 opened this issue Sep 3, 2024 · 9 comments
Open

form扩展验证 #1747

magnificent007 opened this issue Sep 3, 2024 · 9 comments

Comments

@magnificent007
Copy link

关于form扩展验证问题,文档内只有单个字段,我想扩展多个字段的验证,rules 和 validateData 该以什么样的形式传入进行验证呢?

@chouchouji
Copy link
Member

chouchouji commented Sep 3, 2024

可以参考这里 https://github.com/varletjs/varlet/blob/dev/packages/varlet-ui/src/form/example/index.vue

里面有个 VarCustomFormComponent 组件,拓展多个可以参考这个组件封装

@haoziqaq
Copy link
Member

haoziqaq commented Sep 3, 2024

:rules="[() => model.name.length > 6 || 'Error', () => model.age > 10 || 'Error']"
也是一样的~

@magnificent007
Copy link
Author

:rules="[() => model.name.length > 6 || 'Error', () => model.age > 10 || 'Error']" 也是一样的~

可以确定rules是个数组函数,我就是不清楚验证的数据要用什么格式?对象数组形式还是什么其它的格式?

@magnificent007
Copy link
Author

可以参考这里 https://github.com/varletjs/varlet/blob/dev/packages/varlet-ui/src/form/example/index.vue

里面有个 VarCustomFormComponent 组件,拓展多个可以参考这个组件封装

查看了,但是还是不清楚,验证的数据需要什么格式?可以确定rules是个函数数组,验证的数据是否也要用对象数组?

@haoziqaq
Copy link
Member

haoziqaq commented Sep 4, 2024

不对验证数据格式有要求呀。本质 rules 是一个验证函数数组,组件自动判断验证时机,验证的时候只是执行函数,用户怎么写的就怎么执行。

@magnificent007
Copy link
Author

magnificent007 commented Sep 5, 2024

不对验证数据格式有要求呀。本质 rules 是一个验证函数数组,组件自动判断验证时机,验证的时候只是执行函数,用户怎么写的就怎么执行。

不是的,您可能没理解我的意思。rules是个函数数组,我理解没有问题;我想知道的是要验证的数据 在多字段验证的情况下 需要传入什么格式?是对象数组还是其它形式?

@haoziqaq
Copy link
Member

haoziqaq commented Sep 5, 2024 via email

@magnificent007
Copy link
Author

magnificent007 commented Sep 6, 2024

没有格式要求。input 绑定的是什么值就验证什么值。

没有用input哦,里面是我自定义的多个输入操作,下面我提供下vue3代码片段和效果图

// 接入表单校验组件validate-form.tsx
import { Form } from '@varlet/ui'
import { nextTick, type SetupContext, type PropType } from 'vue'

type FComponentProps = {
  readonly?: Partial<boolean>,
  disabled?: Partial<boolean>,
  validateTrigger?: Partial<Array<string>>,
  rules?: Partial<Array<(v: any) => string | boolean>>,
  validateValues: Array<string>
}

type Events = {
  ['update:validateValues'](validateValues: Objectable): void,
  exposeFormInstance(i: Objectable): void
}

export type ExposeFormInstanceType = {
  reset: () => void, 
  trigger: () => void, 
  validate: () => Promise<boolean>, 
  resetValidation: () => void
}

export const ValidateForm = (props: FComponentProps, context: SetupContext<Events>) => {
  const { slots, emit, attrs } = context
  const { useForm, useValidation } = Form
  const { errorMessage, validateWithTrigger: _validateWithTrigger, validate: _validate, resetValidation } = useValidation()
  const { bindForm, form } = useForm()
  const validate = () => _validate(props.rules, props.validateValues)
  
  function reset() {
    emit('update:validateValues', [])
    resetValidation()
  }
  
  function validateWithTrigger(trigger: any) {
    nextTick(() => {
      const { validateTrigger, rules, validateValues } = props
      _validateWithTrigger(validateTrigger!, trigger, rules, validateValues)
    })
  }
  
  function trigger() {
    if (
      props.readonly ||
      props.disabled ||
      form?.readonly.value || 
      form?.disabled.value
    ) {
      return
    }
    emit('update:validateValues', props.validateValues)
    validateWithTrigger('onToggle')
  }

  emit('exposeFormInstance', { reset, trigger, validate, resetValidation })
  bindForm?.({ reset, validate, resetValidation })

  return (
    <>
      <var-space class="w-full z-99999" direction="column" size={[14, 0]}>
        { slots.main ? slots.main({ readonly: props.readonly, disabled: props.disabled, errorMessage: errorMessage.value }) : (<var-result type='empty' description='三无属性地带..!' />) }
        { slots.footer ? slots.footer({ readonly: props.readonly, disabled: props.disabled }) : (<></>) }
      </var-space>
    </>
  )
}

ValidateForm.props = {
  readonly: {
    type: Boolean as PropType<Partial<boolean>>,
    default: false
  },
  disabled: {
    type: Boolean as PropType<Partial<boolean>>,
    default: false
  },
  validateTrigger: {
    type: Array as PropType<Partial<Array<string>>>,
    default: () => ['onToggle']
  },
  rules: {
    type: Array as PropType<Partial<Array<(v: any) => string | boolean>>>,
    default: () => []
  },
  validateValues: {
    type: Array as PropType<Array<string>>,
    default: () => []
  }
}

export default ValidateForm
// 使用
<script lang='ts' setup>
import { ref } from 'vue'
import { ValidateForm, type ExposeFormInstanceType } from '@/components/basic/validate-form/validate-form'
import { pull } from 'lodash-es'


// ------------------ 验证从这里开始 ------------------

const { getFormInstance, validate } = useForm()
const { characteristic, checkedCharacter } = useSelectCharacter()

function useSelectCharacter() {
  const characteristic = ref<Array<string>>([])
  
  const checkedCharacter = (e: any, additional: { readonly: boolean, disabled: boolean }) => {
    if (additional.readonly || additional.disabled) return 
    const { id } = e.target.dataset
    if (characteristic.value.includes(id)) {
      pull(characteristic.value, id)
      return 
    }
    characteristic.value.push(id)
  }

  return {
    characteristic,
    checkedCharacter
  }
}

function useForm() {
  const formInstance = ref<ExposeFormInstanceType>()

  function getFormInstance(instance: ExposeFormInstanceType) {
    formInstance.value = instance
  }

  function validate() {
    formInstance.value?.validate()
  }

  return {
    formInstance,
    getFormInstance,
    validate
  }
}


const questions = [
  {
    title: '标题1',
    subtitle: '副标题1',
    list: ['积极', '好学', '勇敢', '阳光']
  },
  {
    title: '标题2',
    subtitle: '副标题2',
    list: ['消极', '懒惰', '胆小', '阴暗']
  }
]
</script>
<template>
  <ValidateForm 
    :readonly="false" 
    :disabled="false" 
    :rules="[v => v.length >= 1 || '至少选择1个', v => v.length >= 1 || '至少选择1个']" 
    v-model:validateValues="characteristic" 
    @exposeFormInstance="getFormInstance"
  >
    <template #main="{ readonly, disabled, errorMessage }">

      <div class="character-wrapper box-border" v-for="q in questions" :key="q.title">
        <span class="title block">{{ q.title }}</span>
        <span class="subtitle">{{ q.subtitle }}</span>
        <var-form-details :error-message="errorMessage" />
        <div class="flex flex-wrap justify-between gap-row-6 mt-4" @click="checkedCharacter($event, { readonly, disabled })">
          <var-paper 
            :class="['relative text-center', readonly || disabled ? 'disabled': '', characteristic.includes(i) ? 'active' : '']"
            :ripple="!(readonly || disabled)"
            width="30%" 
            height="4rem" 
            :elevation="2"
            v-for="i in q.list"
            :key="i"
            :data-id="i"
          >
            <span class="leading-16 text-coolGray font-bold" :data-id="i">{{ i }}</span>
          </var-paper>
        </div>
      </div>
      
    </template>
    <template #footer="{ readonly, disabled }">
      <slot name="footer" :readonly="readonly" :disabled="disabled"></slot>
    </template>
  </ValidateForm>
  <var-button 
    block 
    type="success" 
    loading-size="small" 
    loading-type="wave" 
    @click="validate"
  >
    验证
  </var-button>
</template>
<style lang='scss' scoped>
.character-wrapper {
  padding: 12px;

  .title {
    font-size: 18px;
    font-weight: bold;
    color: black;
  }

  .subtitle {
    font-size: 14px;
    color: gray;
  }
}

.disabled::before {
  content: '';
  box-sizing: border-box;
  background-color: rgba(0, 0, 0, 0.1);
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 101;
}

.active::after {
  content: '';
  box-sizing: border-box;
  background-color: green;
  color: white;
  font-size: 12px;
  line-height: 1rem;
  width: 1rem;
  height: 1rem;
  position: absolute;
  top: 0;
  right: 0;
  z-index: 100;
}
</style>

想实现的效果图

@haoziqaq
Copy link
Member

haoziqaq commented Sep 8, 2024

image
image
我这边没问题,你这边提供的 tsx 代码可能存在问题,可以尝试按照图2修复。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants