公用派发组件

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>

效果图

 uniapp 自定义 element 表单验证_数据