vue3中自定义组件v-model的实现

2021-08-11  本文已影响0人  泡杯感冒灵

主要的两个步骤

  1. 自定义组件创建 props属性 modelValue
  2. 自定义组件触发update:modelValue事件,并把值传出去
<template>
    <div class="validate-input-container pb-3">
        <input
            class="form-control"
            :class="{'is-invalid':inputRef.error}"
            :value="inputRef.val"
            @blur="validateEmail"
            @input="updateValue"
        >
        <div class="invalid-feedback" v-if="inputRef.error">
            {{inputRef.message}}
        </div>
    </div>
</template>

<script lang="ts">
import { defineComponent, reactive, PropType } from 'vue'
const emailReg = /^[A-Za-z\d]+([-_.][A-Za-z\d]+)*@([A-Za-z\d]+[-.])+[A-Za-z\d]{2,4}$/
interface RuleProp {
    type: 'required' | 'email'
    message: string
}
export type RulesProp = RuleProp[]
export default defineComponent({
  name: 'ValidateInput',
  props: {
    rules: Array as PropType<RulesProp>,
    modelValue: String
  },
  setup (props, context) {
    const inputRef = reactive({
      val: props.modelValue || '',
      error: false,
      message: ''
    })
    const updateValue = (e:KeyboardEvent) => {
      const targetValue = (e.target as HTMLInputElement).value
      inputRef.val = targetValue
      context.emit('update:modelValue', targetValue)
    }
    const validateEmail = () => {
      if (props.rules) {
        // 因为需要每个规则都通过才可以,所以用数组的every方法
        const allPassed = props.rules.every(rule => {
          let passed = true
          inputRef.message = rule.message
          switch (rule.type) {
            case 'required':
              passed = (inputRef.val.trim() !== '')
              break
            case 'email':
              passed = emailReg.test(inputRef.val.trim())
              break
            default:
              break
          }
          return passed
        })
        inputRef.error = !allPassed
      }
    }
    return {
      inputRef,
      validateEmail,
      updateValue
    }
  }
})
</script>

然后就是调用组件的地方 v-model就可以使用了
<template>
  <div class="container">
    <global-header :user="currentUser"></global-header>
    <form>
      <div class="mb-3">
        <label for="exampleInputEmail1" class="form-label">邮箱地址</label>
        <validate-input :rules="emailRules" v-model="emailVal"></validate-input>
        {{emailVal}}
      </div>
    </form>
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive, ref } from 'vue'
import 'bootstrap/dist/css/bootstrap.min.css'
import GlobalHeader, { UserProps } from './components/GlobalHeader.vue'
import ValidateInput, { RulesProp } from './components/ValidateInput.vue'
const currentUser:UserProps = {
  isLogin: true,
  name: 'weiyang'
}

export default defineComponent({
  name: 'App',
  components: {
    GlobalHeader,
    ValidateInput
  },
  setup () {
    const emailVal = ref('weiyang')
    const emailRules: RulesProp = [
      { type: 'required', message: '电子邮箱地址不能为空' },
      { type: 'email', message: '请输入正确的电子邮箱格式' }
    ]
    return {
      currentUser,
      emailRules,
      emailVal
    }
  }

})
</script>

<style>
</style>

上一篇下一篇

猜你喜欢

热点阅读