vue3中简单封装input组件和统一表单数据

简介: vue3中简单封装input组件和统一表单数据

vue3中简单封装input组件和统一表单数据


vue3 支持用 jsx 实现组件,摆脱了 vue 文件式的组件,不再需要额外的指令,写法非常接近 React,减少记忆负担。

本文简单的练习,用 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>
    );
  },
};

网络异常,图片无法展示
|


目录
相关文章
|
10天前
|
资源调度 JavaScript API
vue3封装城市联动组件
vue3封装城市联动组件
|
10天前
|
存储 JavaScript
vue组件的五种传值方法(父子\兄弟\跨组件)
vue组件的五种传值方法(父子\兄弟\跨组件)
|
12天前
|
Android开发 iOS开发 C#
Xamarin:用C#打造跨平台移动应用的终极利器——从零开始构建你的第一个iOS与Android通用App,体验前所未有的高效与便捷开发之旅
【8月更文挑战第31天】Xamarin 是一个强大的框架,允许开发者使用单一的 C# 代码库构建高性能的原生移动应用,支持 iOS、Android 和 Windows 平台。作为微软的一部分,Xamarin 充分利用了 .NET 框架的强大功能,提供了丰富的 API 和工具集,简化了跨平台移动应用开发。本文通过一个简单的示例应用介绍了如何使用 Xamarin.Forms 快速创建跨平台应用,包括设置开发环境、定义用户界面和实现按钮点击事件处理逻辑。这个示例展示了 Xamarin.Forms 的基本功能,帮助开发者提高开发效率并实现一致的用户体验。
25 0
|
JavaScript 前端开发
模拟Vue数据的双向绑定
Vue的数据双向绑定功能一直为人称道, Vue数据的双向数据绑定主要依赖了Object.defineProperty,这里尝试用最简单的代码, 实现数据的双向绑定Demo MVVM ViewModel基本实现原理 Gi...
919 0
|
7天前
|
JavaScript
vue中使用@scroll不生效的问题
vue中使用@scroll不生效的问题
|
2天前
|
JavaScript 算法 前端开发
vue学习(1)
vue学习(1)
189 62
|
2天前
|
JavaScript
vue学习(3)模板语法
vue学习(3)模板语法
25 10
|
2天前
|
存储 JavaScript 前端开发
vue学习(2)
vue学习(2)
185 65
|
2天前
|
JavaScript
vue键盘事件
vue学习(11)键盘事件
|
6天前
|
数据采集 JavaScript 搜索推荐
我们一起聊聊如何对Vue项目进行搜索引擎优化
【9月更文挑战第4天】Vue 项目的搜索引擎优化(SEO)较为复杂,因其内容默认由 JavaScript 渲染,部分搜索引擎难以索引。为提升 SEO 效果,可采用服务器端渲染(SSR)或预渲染,使用 Nuxt.js 或 Vue Server Renderer 实现 SSR,或利用 Prerender SPA Plugin 预渲染静态 HTML。此外,动态管理 Meta 标签、优化静态内容与 Sitemap、懒加载、图片优化、提升页面速度、设置正确的路由模式、使用结构化数据及构建良好外链均有益于 SEO。
40 11