公用派发组件
Vue.prototype.$dispatch = function (eventName, data) {
let parent = this.$parent
while (parent) {
parent.$emit(eventName, data)
parent = parent.$parent
}
}
爷级组件 - hFrom.vue
<template>
<form>
<slot></slot>
</form>
</template>
<script>
export default {
name: 'hForm',
provide() {
return {
form: this,
}
},
props: {
model: {
type: Object,
default () {
return {}
}
},
rules: {
type: Object,
default () {
return {}
}
}
},
mounted() { //监听调用了"$emit("validate")"
this.$on('validate', this.validate)
},
methods: {
validate(e) {
const tasks = this.$children
var flag = true
var iVa = tasks.find(item => !item.validate())
if (iVa) {
if(e == "btn"){
uni.showToast({
title: iVa.errortext,
icon: "none",
duration: 2000
});
}
flag = false
}
return flag
}
}
}
</script>
父级组件 - hFromItem.vue
<template>
<view>
<label v-if="label">{{ label }}</label>
<slot></slot>
<p v-if="error" style="color:red">{{ errortext }}</p>
</view>
</template>
<script>
export default {
name: 'hFormItem',
// 注入数据
inject: ['form'],
// 接收参数
props: ['label', 'prop'],
data() {
return {
errortext: '',
error: false,
}
},
mounted() {
this.$on('validate', this.validate)
},
methods: {
validate() {
var model = this.form.model[this.prop]
var rules = this.form.rules[this.prop]
this.errortext = rules.message
var flag = true
if (rules.validator) {
} else {
if(model){
this.error = false
flag = true
}else{
this.error = true
flag = false
}
}
return flag
}
}
}
</script>
子级组件 - hFromInput.vue
<!-- 绑定value属性 使用的是父组件传入的参数 实现input事件 派发事件 固定写法 -->
<template>
<input :type="type" :value="value" @input="onInput" @blur="onBlur" />
</template>
<script>
export default {
name: 'ElInput',
props: {
value: {
type: String,
default: '',
},
type: {
type: String,
default: 'text',
},
},
methods: {
onInput(e) {
this.$emit('input', e.target.value)
this.$nextTick(function(){
this.$dispatch('validate')
})
},
onBlur() {
}
}
}
</script>
<style lang="scss" scoped>
input {
border: 1px solid red;
}
</style>
使用组件
<template>
<view class="exam-search">
<h-from :model="from" :rules="rules" ref="from">
<h-from-item label="label" prop="v1">
<h-from-input v-model="from.v1"></h-from-input>
</h-from-item>
<h-from-item label="label2" prop="v2">
<h-from-input v-model="from.v2"></h-from-input>
</h-from-item>
<h-from-item label="label3" prop="v3">
<h-from-input v-model="from.v3"></h-from-input>
</h-from-item>
</h-from>
<view @click="add" style="border: 1px solid;height: 50px;">
111
</view>
</view>
</template>
<script>
import hFrom from "@/components/common/hFrom.vue"
import hFromItem from "@/components/common/hFromItem.vue"
import hFromInput from "@/components/common/hFromInput.vue"
export default {
components: {
hFrom,
hFromItem,
hFromInput
},
data() {
return {
from: {
v1: "",
v2: "",
v3: ""
},
rules: {
v1: {
message: '请输入姓名',
},
v2: {
message: '请输入姓名111111',
},
v3: {
message: '请输入姓名2222',
},
}
}
},
onLoad(e) {
},
methods: {
add() {
var sss = this.$refs.from.validate("btn")
console.log(sss)
}
},
}
</script>
<style lang="scss" scoped>
.exam-search {
height: 100%;
overflow: hidden;
margin-top: 100px;
background: #fff;
}
</style>
效果图