表单组件实现
Input
1.双向绑定:@input、:value
2.派发校验事件
<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>
FormItem
1.给Input预留插槽 - slot
2.能够展示label和校验信息
3.能够进行校验
<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>
Form
1.给FormItem留插槽
2.设置数据和校验规则
3.全局校验
<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>
Notice组件实现
1.组件实例创建函数:create函数
import Vue from 'vue';
export default function create(Component, props) {
// 先创建实例
const vm = new Vue({
render(h) {
// h就是createElement,它返回VNode
return h(Component, {props})
}
}).$mount();
// 手动挂载
document.body.appendChild(vm.$el);
// 销毁方法
const comp = vm.$children[0];
comp.remove = function() {
document.body.removeChild(vm.$el);
vm.$destroy();
}
return comp;
}
2.Notice组件
(1)插槽预留
(2)标题、内容等属性
(3)自动关闭
<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>
3.使用
<script>
import Notice from "@/components/notice/KNotice";
export default {
methods: {
submitForm(form) {
this.$refs[form].validate(valid => {
const notice = this.$create(Notice, {
title: "喊你来搬砖",
message: valid ? "请求登录!" : "校验失败!",
duration: 1000
});
notice.show();
});
}
}
};
</script>
Tree组件实现
1.递归组件Item创建
<template>
<li>
<div @click="toggle">
{{model.title}}
<span v-if="isFolder">[{{open ? '-' : '+'}}]</span>
</div>
<ul v-show="open" v-if="isFolder">
<item class="item" v-for="model in model.children" :model="model" :key="model.title"></item>
</ul>
</li>
</template>
<script>
export default {
name: "Item",
props: {
model: {
type: Object,
required: true
}
},
data() {
return {
open: false
};
},
computed: {
isFolder() {
return this.model.children && this.model.children.length;
}
},
methods: {
toggle() {
if (this.isFolder) {
this.open = !this.open;
}
}
}
};
</script>
2.数据和使用
<template>
<div>
<ul>
<item class="item" :model="treeData"></item>
</ul>
</div>
</template>
<script>
import Item from "./Item";
export default {
name: "app",
data() {
return {
treeData: {
title: "Web全栈架构师",
children: [
{title: "Java架构师"},
{ title: "JS高级", children: [ { title: "ES6" }, { title: "动效" }] },
{ title: "Web全栈", children: [
{ title: "Vue训练营", expand: true, children: [ { title: "组件化" }, {title: "源码" }, { title: "docker部署" } ]},
{ title: "React", children: [ { title: "JSX" }, { title: "虚拟DOM" } ] },
{title: "Node" }
] }
]
}
};
},
components: { Item }
};
</script>