大家在使用vue库的时候,有没有想过他们是怎么实现的,有没有想过如何实现一个!
先看效果
这篇文章我们会介绍一下内容
- 父子组件
- 插槽的用法-slot
- 跨组件传值-provide
- 跨组件通信--mmit
- 自定义props
- 自定义事件
贴代码
<template>
<div class="container">
{{ formState }}
<yue-ma-edu-form :rules="rules" @finish="finish" :model="formState">
<yue-ma-edu-form-item label="用户名" name="username">
<yue-ma-edu-input
v-model:value="formState.username"
placeholder="跃码教育"
/>
</yue-ma-edu-form-item>
<yue-ma-edu-form-item label="描述" name="description">
<yue-ma-edu-input
type="textarea"
v-model:value="formState.description"
placeholder="跃码教育"
/>
</yue-ma-edu-form-item>
<yue-ma-edu-form-item>
<yue-ma-edu-button> 保存 </yue-ma-edu-button>
</yue-ma-edu-form-item>
</yue-ma-edu-form>
</div>
</template>
戳这里,观看视频教程
首先我们定义一个父级容器存放我们所有的组件
<template>
<form :class="{ 'was-validated': validated }" @submit.prevent="submit">
<slot />
</form>
</template>
定义父级容器的props
···
props: { model: { type: Object, }, rules: { type: Object, }, }
···
定义父级容器的方法
emits: ["finish"],
定义父级容器的校验方法
setup(props, ctx) {
const formMapKey = {};
for (let k of Object.keys(props.rules)) {
formMapKey[k] = true;
}
const formState = reactive(formMapKey);
// formState.username = false;
const validated = computed(() => {
let res = true;
for (let k in formMapKey) {
res = res && formMapKey[k];
}
return res;
});
const validate = (k) => {
let rules = null;
let model = null;
if (k === "") {
rules = props.rules;
model = props.model;
} else {
rules = { [k]: props.rules[k] };
model = { [k]: props.model[k] };
}
const validator = new Schema(rules);
const handleErrors = (errors, fields) => {
VueEvent.emit("validate", fields);
const keySet = new Set(Object.keys(fields));
for (let k in formState) {
if (keySet.has(k)) {
formState[k] = false;
} else {
formState[k] = true;
}
}
};
validator
.validate(model)
.then(() => {
// 课堂作业,找出我的bug修改
// validation passed or without error message
VueEvent.emit("validate", { [k]: [] });
})
.catch(({ errors, fields }) => {
return handleErrors(errors, fields);
});
};
const submit = (e) => {
validate("");
ctx.emit("finish");
};
onMounted(() => {
VueEvent.on("check", (k) => {
validate(k);
});
});
return {
submit,
validated,
};
},
定义yue-ma-edu-form-item用于承载输入组件
<template>
<div class="mb-3">
<label :for="name" class="form-label">{{ label }}</label>
<slot />
</div>
</template>
<script lang="ts">
import { defineComponent, provide } from "vue";
export default defineComponent({
props: {
label: {
type: String,
},
name: {
type: String,
},
},
setup(props) {
provide("name", props.name);
},
});
</script>
通过provider跨组件传输数据
provide("name", props.name);
自定义输入组件 yue-ma-edu-input
<template>
<template v-if="type === 'textarea'">
<textarea
:class="{ 'form-control': true, 'is-invalid': invalid }"
:id="name"
:name="name"
:value="value"
:placeholder="placeholder"
@input="inputHandler"
></textarea>
</template>
<template v-if="type === 'text' || type === 'password'">
<input
:class="{ 'form-control': true, 'is-invalid': invalid }"
:type="type"
:id="name"
:name="name"
:value="value"
:placeholder="placeholder"
@input="inputHandler"
/>
</template>
<div class="invalid-feedback">{{ msg }}</div>
</template>
<script lang="ts">
import { computed, defineComponent, inject, onMounted, ref } from "vue";
import VueEvent from "./VueEvent";
export default defineComponent({
props: {
placeholder: {
type: String,
default: "跃码教育提示您:请输入内容",
},
value: {
type: String,
},
type: {
type: String,
default: "text",
},
},
setup(props, ctx) {
// inject 第二个参数是默认值
const name = inject("name");
const msg = ref("");
// 计算出来一个变量
const invalid = computed(() => msg.value.length > 0);
onMounted(() => {
VueEvent.on("validate", (res) => {
if (res[name] !== undefined) {
if (res[name].length > 0) {
const error = res[name].pop();
msg.value = error.message;
} else {
msg.value = "";
}
}
});
});
// TODO 拿到了数据,我就可以在这里进行校验我的数据
const inputHandler = (e: Event) => {
ctx.emit("update:value", e.target.value);
VueEvent.emit("check", name);
};
return {
name,
inputHandler,
msg,
invalid,
};
},
});
</script>
通过 const name = inject("name");获取父级组件传输的数据
监听跨组件事件
VueEvent.on("validate", (res) => {
if (res[name] !== undefined) {
if (res[name].length > 0) {
const error = res[name].pop();
msg.value = error.message;
} else {
msg.value = "";
}
}
});