Input.vue
<template>
<div>
<input :value="value" @input="onInput" v-bind="$attrs">
</div>
</template>
<script>
export default {
inheritAttrs: false,
props: {
value: {
type: String,
default: ""
}
},
methods: {
onInput(e) {
this.$emit("input", e.target.value);
this.$parent.$emit('validate');
}
}
};
</script>
<style lang="scss" scoped>
</style>
FormItem.vue
<template>
<div>
<label v-if="label">{{label}}</label>
<slot></slot>
<p v-if="errorMessage">{{errorMessage}}</p>
</div>
</template>
<script>
import Schema from 'async-validator'
export default {
inject: ["form"],
props: {
label: {
type: String,
default: ""
},
prop: {
type: String
}
},
data() {
return {
errorMessage: ""
};
},
mounted() {
this.$on('validate', this.validate)
},
methods: {
validate() {
// 做校验
const value = this.form.model[this.prop]
const rules = this.form.rules[this.prop]
// npm i async-validator -S
const desc = {[this.prop]: rules};
const schema = new Schema(desc);
// return的是校验结果的Promise
return schema.validate({[this.prop]: value}, errors => {
if (errors) {
this.errorMessage = errors[0].message;
}else {
this.errorMessage = ''
}
})
}
},
};
</script>
<style lang="scss" scoped>
</style>
Form.vue
<template>
<div>
<slot></slot>
</div>
</template>
<script>
export default {
provide() {
return {
form: this
};
},
props: {
model: {
type: Object,
required: true
},
rules: {
type: Object
}
},
methods: {
validate(cb) {
const tasks = this.$children
.filter(item => item.prop)
.map(item => item.validate());
// 所有任务都通过才算校验通过
Promise.all(tasks)
.then(() => cb(true))
.catch(() => cb(false));
}
}
};
</script>
<style lang="scss" scoped>
</style>
Index.vue
<template>
<div>
<h3>Element表单</h3>
<hr>
<k-form :model="model" :rules="rules" ref="loginForm">
<k-form-item label="用户名" prop="username">
<k-input v-model="model.username" autocomplete="off" placeholder="输入用户名"></k-input>
</k-form-item>
<k-form-item label="确认密码" prop="password">
<k-input type="password" v-model="model.password" autocomplete="off"></k-input>
</k-form-item>
<k-form-item>
<button @click="submitForm('loginForm')">提交</button>
</k-form-item>
</k-form>
{{model}}
</div>
</template>
<script>
import KForm from "./Form";
import KFormItem from "./FormItem";
import KInput from "./Input";
import Notice from "@/components/notice/KNotice";
export default {
components: {
KForm,
KFormItem,
KInput
},
data() {
return {
model: { username: "tom", password: "" },
rules: {
username: [{ required: true, message: "请输入用户名" }],
password: [{ required: true, message: "请输入密码" }]
}
};
},
methods: {
submitForm(form) {
this.$refs[form].validate(valid => {
const notice = this.$create(Notice, {
title: "Hello World",
message: valid ? "请求登录!" : "校验失败!",
duration: 1000
});
notice.show();
});
}
}
};
</script>
KNotice.vue
<template>
<div class="box" v-if="isShow">
<h3>{{title}}</h3>
<p class="box-content">{{message}}</p>
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
default: ""
},
message: {
type: String,
default: ""
},
duration: {
type: Number,
default: 1000
}
},
data() {
return {
isShow: false
};
},
methods: {
show() {
this.isShow = true;
setTimeout(this.hide, this.duration);
},
hide() {
this.isShow = false;
this.remove();
}
}
};
</script>
<style scoped>
.box {
position: fixed;
width: 100%;
top: 16px;
left: 0;
text-align: center;
pointer-events: none;
}
.box-content {
width: 200px;
margin: 10px auto;
font-size: 14px;
border: blue 3px solid;
padding: 8px 16px;
background: #fff;
border-radius: 3px;
margin-bottom: 8px;
}
</style>