组件化思想
第三方组件应用
- Element-UI:http://element-cn.eleme.io/
- element集成:vue add element
- 组件使用:创建一个登陆表单并可以校验用户输入
<template>
<div>
<h3>Element表单</h3>
<hr>
<el-form :model="model" :rules="rules" ref="loginForm">
<el-form-item label="用户名" prop="username">
<el-input v-model="model.username" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="password">
<el-input type="password" v-model="model.password" autocomplete="off">
</el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('loginForm')">提交</el-
button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
data() {
return {
model: { username: "tom", password: "" },
rules: {
username: [{ required: true, message: "请输入用户名" }],
password: [{ required: true, message: "请输入密码" }],
}
};
},
methods: {
submitForm(form) {
this.$refs[form].validate(valid=>{
if (valid) {
alert('请求登录!')
} else {
alert('校验失败!')
}
})
}
},
};
</script>
- 使用时我们要先导入Form、FormItem、Input
- import { Button,Form,FormItem,Input } from 'element-ui'
- 然后添加到vue实例上Vue.use(Form)、Vue.use(FormItem)、Vue.use(Input)
组件设计:实现Form、FormItem、Input
核心关注:
- Form怎么跨组件传数据
- FormItem怎么执行校验
- Input怎么实现双向绑定
实现Input
- 任务1:实现input组件双向绑定的功能
v-model是语法糖,实现自定义组件双绑只需要指定:value和@input即可
- 任务2:值发生变化能够通知FormItem组件
<template>
<div>
<input :type="type" :value="value" @input="onInput">
</div>
</template>
<script>
export default {
props: {
value: {
type: String,
default: ''
},
type: {
type: String,
default: 'text'
}
},
methods: { // input事件触发设置模型的值并通知父组件
onInput(e) {
let inputValue = e.target.value;
this.$emit('input', inputValue);
}
},
}
</script>
实现FormItem
- 任务1:给Input预留插槽 - slot
- 任务2:能够展示label和校验信息
- 任务3:能够进行校验
<template>
<div>
<label v-if="label">{{label}}</label>
<slot></slot>
<p v-if="error">{{error}}</p>
</div>
</template>
<script>
export default {
props: {
label: {// 输入项标签
type: String,
default: ''
},
prop: {// 字段名
type: String,
default: ''
},
},
data() {
return {
error: '' // 校验错误
}
},
};
</script>
实现Form
- 给form-item预留槽位
- 将数据传递给后代便于它们访问数据模型和校验规则
provide && inject
<template>
<form>
<slot></slot>
</form>
</template>
<script>
export default {
provide() {
return {
form: this // 将组件实例作为提供者,子代组件可方便获取
};
},
props: {
model: { type: Object, required: true },
rules: { type: Object }
}
};
</script>
数据校验
- 思路:校验发生在FormItem,它需要知道何时校验(让Input通知它),还需要知道怎么校验(注入校验规则)
onInput(e) {
// ...
// $parent指FormItem
this.$parent.$emit('validate');
}
- 任务1:Input通知校验
- 任务2:FormItem监听校验通知,获取规则并执行校验
inject: ['form'], // 注入
mounted(){// 监听校验事件
this.$on('validate', this.validate)
},
methods: {
validate() {
// 获取对应FormItem校验规则
console.log(this.form.rules[this.prop]);
// 获取校验值
console.log(this.form.model[this.prop]);
}
},
- 安装async-validator
npm i async-validator -S
import schema from "async-validator";
validate() {
// 获取对应FormItem校验规则
const rules = this.form.rules[this.prop];
// 获取校验值
const value = this.form.model[this.prop];
// 校验描述对象
const descriptor = { [this.prop]: rules };
// 创建校验器
const schema = new Schema(descriptor);
schema.validate({ [this.prop]: value }, errors => {
if (errors) {
// 将错误信息显示
this.error = errors[0].message;
} else {
// 校验通过
this.error = "";
}
});
}
运行结果
console.log 加 debugger 找到原因
prop="username"
FormItem缺少这个属性,就会导致上面错误出现。
主要是代码实现的不够健壮,没有对校验进行兜底处理。
结语
搬砖的时候有时我会碰到一种状态:着相。陷入自己的模式里无法自拔,进入一种死循环的状态,很明显的错误却发现不了。这种时候寻求队友帮忙换一种思路,或者出去透气把自己解脱出来,可能就会豁然开朗。
使用vue组件化时候,难免也会带有个人色彩,可能与个人经验和思考方式有关系。这种情况我觉得不是减少或者避免,而是需要优化。
只要自己看过足够多的好架构、好设计,自然会不断的借鉴靠近他们,慢慢地自己思想会跟着提升,然后在实践中应用,验证。