• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • dedecms
  • ecshop
  • z-blog
  • UcHome
  • UCenter
  • drupal
  • WordPress
  • 帝国cms
  • phpcms
  • 动易cms
  • phpwind
  • discuz
  • 科汛cms
  • 风讯cms
  • 建站教程
  • 运营技巧
您的位置:首页 > CMS教程 >建站教程 > Vue模仿ElementUI的form表单实例代码

Vue模仿ElementUI的form表单实例代码

作者:站长图库 字体:[增加 减小] 来源:互联网 时间:2022-04-29

站长图库向大家介绍了Vue模仿ElementUI,form表单,实例代码等相关知识,希望对您有所帮助

这篇文章主要给大家介绍了关于Vue模仿ElementUI的form表单的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

实现要求

模仿 ElementUI 的表单,分为四层结构:index 组件、Form 表单组件、FormItem 表单项组件、Input 和 CheckBox 组件,具体分工如下:

index 组件:

实现:分别引入 Form 组件、FormItem 组件、Input 组件,实现组装;


Form 表单组件:

实现:预留插槽、管理数据模型 model、自定义校验规则 rules、全局校验方法 validate;


FormItem 表单项组件:

实现:预留插槽、显示 label 标签、执行数据校验、显示校验结果;


Input 和 CheckBox 组件:

实现:绑定数据模型 v-model、通知 FormItem 组件执行校验;

Input 组件

具体实现如下:

1、自定义组件要实现 v-model 必须实现 :value 和 @input。

2、当输入框中的数据发生变化时,通知父组件执行校验。

3、当 Input 组件绑定的 type 类型为 password 时,在组件内部使用 v-bind="$attrs" 获取 props 之外的内容。

4、设置 inheritAttrs 为 false, 从而避免顶层容器继承属性。

Input 组件实现:

<template>    <div>        <input :value="value" @input="onInput" v-bind="$attrs" />    </div></template><script>export default {    inheritAttrs: false, // 避免顶层容器继承属性    props: {        value: {            type: String,            default: ""        }    },    data() {        return {};    },    methods: {        onInput(e) {            // 通知父组件数值发生变化            this.$emit("input", e.target.value);             // 通知 FormItem 执行校验            // 这种写法不健壮,因为 Input 组件和 FormItem 组件之间可能会隔代            this.$parent.$emit("validate");        }    }};</script><style scoped></style>

注意:代码中使用 this.$parent 派发事件,这种写法不健壮,当 Input 组件和 FormItem 组件之间隔代时会出现问题。具体解决方式见文章尾部代码优化部分。

CheckBox 组件

1、自定义实现 checkBox 的双向数据绑定,和 input 大同小异,必须实现 :checked 和 @change。

CheckBox 组件实现:

<template>    <section>        <input type="checkbox" :checked="checked" @change="onChange" />    </section></template><script>export default {    props: {        checked: {            type: Boolean,            default: false        }    },    model: {        prop: "checked",        event: "change"    },    methods: {        onChange(e) {            this.$emit("change", e.target.checked);            this.$parent.$emit("validate");        }    }};</script><style scoped></style>

FormItem 组件

具体实现如下:

1、给 Input 组件或者 CheckBox 组件预留插槽。

2、如果用户在组件上设置 label 属性,要展示 label 标签。

3、监听校验事件,并执行校验(使用 async-validator 插件进行校验)。

4、如果不符合校验规则,需要显示校验结果。

在开发的过程中,我们需要思考几个问题:

1、在组件内部,如何得到需要校验的数据和校验规则?

2、在 Form 表单中会有多个菜单项,如:用户名、密码、邮箱...等等,那么 FormItem 组件是如何得知现在校验的是哪个菜单呢?

FormItem 组件实现:

<template>    <div>        <div>            <label v-if="label" :style="{ width: labelWidth }">{{ label }}:</label>            <slot></slot>        </div>        <p v-if="errorMessage">{{ errorMessage }}</p>    </div></template><script>import Schema from "async-validator";export default {    inject: ["formModel"],    props: {        label: {            type: String,            default: ""        },        prop: String    },    data() {        return {            errorMessage: "",            labelWidth: this.formModel.labelWidth        };    },    mounted() {        // 监听校验事件,并执行校验        this.$on("validate", () => {            this.validate();        });    },    methods: {        validate() {            // 执行组件的校验            // 1、获取数据            const values = this.formModel.model[this.prop];            // 2、获取校验规则            const rules = this.formModel.rules[this.prop];            // 3、执行校验            const schema = new Schema({                [this.prop]: rules            });            // 参数1是值,餐数2是校验错误对象数组            // validate 返回的是 Promise<Boolean>            return schema.validate({ [this.prop]: values }, errors => {                if (errors) {                    this.errorMessage = errors[0].message;                } else {                    this.errorMessage = "";                }            });        }    }};</script><style scoped>@labelWidth: 90px;.formItem-wrapper {    padding-bottom: 10px;}.content {    display: flex;}.errorStyle {    font-size: 12px;    color: red;    margin: 0;    padding-left: @labelWidth;}</style>

我们先回答一下上面提出的两个问题,此处会涉及到组件之间传值,可以《组件传值、通讯》:
首先表单的数据和校验规则是定义在 index 组件内部,并且挂载在 Form 组件上,表单的校验项发生在 FormItem 组件中,先在 Form 组件内部通过 props 接受到传递的数据,然后通过 provide/inject 的方式在 FormItem 组件中传递给后代组件。

我们日常在用 ElementUI 的表单校验是会发现,在每一个需要校验的表单上会设置一个 prop 属性,并且属性值和绑定的数据一致。此处的用途是为了能够在 FormItem 组件中执行校验时获取相对的校验规则和数据对象。

在 FormItem 组件中通过使用 inject 获取注入的 Form 实例,和 prop 属性组合使用,可以获取到表单数据和校验规则。

// 1、获取数据const values = this.formModel.model[this.prop];// 2、获取校验规则const rules = this.formModel.rules[this.prop];

使用 async-validator 插件实例化一个 schema 对象,用来执行校验,schema.validate 需要传递两个参数,参数1是当前需要校验的字段和相对应的 rules 组成的键值对对象,参数2是一个 callback 函数,用来获取错误信息(是一个数组)。validate 方法返回的是一个 Promise<Boolean>。

注意:此组件的 validate 方法中,最后使用 return 的目的是为了在 Form 组件中执行全局校验使用。

Form 组件

具体实现如下:

1、给 FormItem 组件预留插槽。

2、传递 Form 实例给后代,比如 FormItem 用来获取校验的数据和规则。

3、执行全局校验

Form 组件实现:

<template>    <div>        <slot></slot>    </div></template><script>export default {    provide() {        return {            formModel: this // 传递 Form 实例给后代,比如 FormItem 用来获取校验的数据和规则        };    },    props: {        model: {            type: Object,            required: true        },        rules: {            type: Object        },        labelWidth: String    },    data() {        return {};    },    methods: {        validate(cb) {            // 执行全局校验            // map 结果是若干 Promise 数组            const tasks = this.$children.filter(item => item.prop).map(item => item.validate());            // 所有任务必须全部校验成功才算校验通过            Promise.all(tasks)            .then(() => {                cb(true);            })            .catch(() => {                cb(false);            });        }    }};</script><style scoped></style>

我们在 Form 组件中使用 provide 注入当前组件对象,方便后续子孙代获取数据/方法使用。

执行全局校验的时候,先使用 filter 过滤掉不需要校验的组件(我们在 FormItem 组件上设置的 prop 属性,只要有此属性,就是需要校验的),然后分别执行组件中的 validate 方法(如果在 FormItem 组件中不使用 return 数据,最后获取到的全都是 undefined),返回的是一个若干  Promise 数组。

简单介绍一个 Promise.all() 方法:

Promise.all() 方法接收一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,并且只返回一个Promise实例, 那个输入的所有promise的resolve回调的结果是一个数组。这个Promise的resolve回调执行是在所有输入的promise的resolve回调都结束,或者输入的iterable里没有promise了的时候。它的reject回调执行是,只要任何一个输入的promise的reject回调执行或者输入不合法的promise就会立即抛出错误,并且reject的是第一个抛出的错误信息。

index 组件

定义模型数据、校验规则等等,分别引入 Form 组件、FormItem 组件、Input 组件,实现组装。

index 组件实现:

<template>    <div>        <Form :model="formModel" :rules="rules" ref="loginForm" label-width="90px">            <FormItem label="用户名" prop="username">                <Input v-model="formModel.username"></Input>            </FormItem>            <FormItem label="密码" prop="password">                <Input type="password" v-model="formModel.password"></Input>            </FormItem>            <FormItem label="记住密码" prop="remember">                <CheckBox v-model="formModel.remember"></CheckBox>            </FormItem>            <FormItem>                <button @click="onLogin">登录</button>            </FormItem>        </Form>    </div></template><script>import Input from "@/components/form/Input";import CheckBox from '@/components/form/CheckBox'import FormItem from "@/components/form/FormItem";import Form from "@/components/form/Form";export default {    data() {        const validateName = (rule, value, callback) => {            if (!value) {                callback(new Error("用户名不能为空"));            } else if (value !== "admin") {                callback(new Error("用户名错误 - admin"));            } else {                callback();            }        };        const validatePass = (rule, value, callback) => {            if (!value) {                callback(false);            } else {                callback();            }        };        return {            formModel: {                username: "",                password: "",                remember: false            },            rules: {                username: [{ required: true, validator: validateName }],                password: [{ required: true, message: "密码必填" }],                remember: [{ required: true, message: "记住密码必选", validator: validatePass }]            }        };    },    methods: {        onLogin() {            this.$refs.loginForm.validate(isValid => {                if (isValid) {                    alert("登录成功");                } else {                    alert("登录失败");                }            });        }    },    components: {        Input,        CheckBox,        FormItem,        Form    }};</script><style scoped></style>

当我们点击登录按钮时,会执行全局校验方法,我们可以使用 this.$refs.xxx 获取 DOM 元素和组件实例。

在上面我们还留了一个小尾巴~,就是在 Input 组件中通知父组件执行校验,目前使用的是 this.$parent.$emit(),这样写有一个弊端,就是当 Input 组件和 FormItem 组件之后隔代的时候,再使用 this.$parent 获取不到 FormItem 组件。

我们可以封装一个 dispatch 方法,主要实现向上循环查找父元素并且派发事件,代码实现如下:

dispatch(eventName, data) {    let parent = this.$parent;    // 查找父元素    while (parent) {        // 父元素用$emit触发        parent.$emit(eventName, data);        // 递归查找父元素        parent = parent.$parent;    }}

该方法可以借用 mixins 引入使用:mixins/emmiters.js

export default {    methods: {        dispatch(eventName, data) {            let parent = this.$parent;            // 查找父元素            while (parent) {                // 父元素用$emit触发                parent.$emit(eventName, data);                // 递归查找父元素                parent = parent.$parent;            }        }    }};

修改 Input 组件:

<template>    <div>        <input :value="value" @input="onInput" v-bind="$attrs" />    </div></template><script>import emmiter from "@/mixins/emmiter";export default {    inheritAttrs: false, // 避免顶层容器继承属性    mixins: [emmiter],    props: {        value: {            type: String,            default: ""        }    },    data() {        return {};    },    methods: {        onInput(e) {            // 通知父组件数值发生变化            this.$emit("input", e.target.value);             // 通知 FormItem 执行校验            // 这种写法不健壮,因为 Input 组件和 FormItem 组件之间可能会隔代            // this.$parent.$emit("validate");             this.dispatch("validate"); // 使用 mixin 中 emmiter 的 dispatch,解决跨级问题        }    }};</script><style scoped></style>


分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • Vue模仿ElementUI的form表单实例代码

相关文章

  • 2022-04-29dedecms修改摘要、标题、缩略图等字数和大小限制
  • 2022-04-29详解PHP如何高效导出Excel(CSV)
  • 2022-04-29修改织梦cms标签TAG不限制长度
  • 2022-04-29PHP怎么将图片转成base64
  • 2022-04-29Photoshop制作时尚绚丽的3D立体字教程
  • 2022-04-29SEO优化-百度规则解析
  • 2022-04-29FCKeditor安装FLV视频插件,适用所有CMS
  • 2022-04-29css如何实现底部tapbar栏效果
  • 2022-04-29Photoshop制作创意文字标志
  • 2022-04-29YII如何将对象转化为数组或直接输出为json格式

文章分类

  • dedecms
  • ecshop
  • z-blog
  • UcHome
  • UCenter
  • drupal
  • WordPress
  • 帝国cms
  • phpcms
  • 动易cms
  • phpwind
  • discuz
  • 科汛cms
  • 风讯cms
  • 建站教程
  • 运营技巧

最近更新的内容

    • 百度频繁变更算法,我们该怎么办?
    • PHPCMS V9静态化HTML生成设置及URL规则优化
    • PHP重定向如何实现数据不丢失?
    • WordPress常见故障有哪些?怎么处理?
    • 怎样利用Javascript简单实现星空连线的效果
    • 如何用PHP获取referer判断来路防止非法访问
    • Photoshop手工制作精美的格子背景教程
    • Photoshop制作立体效果的像素艺术字
    • Photoshop制作细腻光滑的黄金艺术字教程
    • 如何利用百度外链工具建立有效外链

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有