首页 > 文章列表 > vue3怎么封装input组件和统一表单数据

vue3怎么封装input组件和统一表单数据

input Vue3
336 2023-05-10

vue3怎么封装input组件和统一表单数据

准备工作

vue create example创建项目,参数大概如下:

用原生 input

原生的 input,主要是 value 和 change,数据在 change 的时候需要同步。

App.tsx如下:

import { ref } from 'vue';



export default {

  setup() {

    // username就是数据

    const username = ref('张三');

    // 输入框变化的时候,同步数据

    const onInput = ;

    return () => (

      <div>

        <input type="text"

            value={username.value}

            onInput={(e: any) => { username.value = e.target.value; }} />

        <div>input的值:{username.value}</div>

      </div>

    );

  },

};

封装 Input

封装 input 的好处,直接传值,减少逻辑,不再需要额外的e.target,为后面的继续封装做准备。

// Input.tsx

import { defineComponent, ref } from 'vue';



// defineComponent定义组件,有props

const Input = defineComponent({

  props: {

    value: {

      required: true,

      type: String,

    },

    onChange: {

      required: true,

      type: Function,

    },

  },

  // 渲染用到props,需要在这里传参

  setup(props) {

    // 值变化 的时候  调用传过来的onChange从而同步父组件的 数据

    const onInput = (e: any) => {

      props.onChange && props.onChange(e.target.value);

    };

    return () => <input type="text" value={props.value} onInput={onInput} />;

  },

});

使用Input组件

import { ref } from 'vue';

import Input from './components/Input';

export default {

  setup() {

    // 数据

    const username: any = ref('张三');

    return () => (

      <div>

        {/* 使用组件,传value和onChange */}

        <Input

          value={username.value}

          onChange={(value: string) => (username.value = value)} // 直接在这同步数据

        />

        <div>input的值:{username.value}</div>

      </div>

    );

  },

};

封装表单数据

表单数据,经常需要赋值、获取值,这边可以用类统一处理,在后面的组件赋值属性的时候极其方便。

useForm的精华,在于proxy,访问属性的时候,返回field数据,这在表单组件里可以简洁使用。

/* eslint-disable @typescript-eslint/explicit-module-boundary-types */

/* eslint-disable @typescript-eslint/no-explicit-any */

import { ref, Ref } from "vue";

export class FormData<T> {

  private data: Ref<any>;

  constructor(data: T) {

    this.data = ref(data || null);

  }



  // 设置某个字段的值

  setValue(name: string, val: any): void {

    const next = { ...this.data.value, [name]: val };

    this.data.value = next;

  }



  // 获取某个字段的值

  getValue(name: string): any {

    return this.data.value[name];

  }



  // 获取整个值

  getValues() {

    return this.data.value;

  }



  // 设置整个值

  setValues(values: T) {

    this.data.value = values;

  }



  // 获取field,字段和字段的修改事件

  getField(name: string) {

    return {

      value: this.data.value[name],

      onChange: (v: any) => {

        this.setValue(name, v);

      },

    };

  }

}



type FormDataProxy<T> = {

  [P in keyof T]: T[P];

};



export function useForm<T extends Record<string, any>>(data: T) {

  const form = new FormData(data);

  const ver = ref(0);



  const proxy = new Proxy(form, {

    // 写proxy的目的是:form.username的时候,直接返回 form.getField(username)

    get(target, name) {

      switch (name) {

        case "getValues":

          return form.getValues.bind(form);

        case "setValues":

          return form.setValues.bind(form);

        default:

          return form.getField(name as string);

      }

    },

    // 写form.username = xx  直接返回 form.setValue('username',xx)

    set(target, name, value) {

      switch (name) {

        case "getValues":

        case "setValues":

          break;

        default:

          form.setValue(name as string, value);

      }

      return true;

    },

  }) as any as FormDataProxy<T> & {

    setValues: (val: T) => void;

    getValues: () => Ref<T>;

  };

  return { form: proxy, ver };

}

使用表单数据

Input组件配合表单,使用效果奇佳。

import Input from './components/Input';

import { useForm } from './hooks/useForm';



// 使用组件

export default {

  setup() {

    // 数据

    const { form, ver } = useForm({ username: '张三', age: 33 });

    console.log(123, form, ver);

    return () => (

      <div>

        {/* 这里的form.username,实际是proxy返回的{value:xxx,onChange:fn} */}

        {/*  多表单组件的时候 这样就非常方便了 */}

        <Input {...form.username} />

        <Input {...form.age} />



        <button

          onClick={() => {

            console.log(form.getValues());

          }}

        >

          提交

        </button>

      </div>

    );

  },

};