vue - 子级向父级传递参数
就和 html 一样,不到万不得已你不会使用 id,因此也不考虑 ref 的使用。
业务场景
设计一个表单组件,需要用户填写年龄,因此有个输入框,我们使用 v-model 绑定年龄字段,
显然,年龄不能超过 200,因此组件还必须给出校验位,当年龄超过 200,校验位就置成false,
因为校验位是在组件内部凭空产生的,父组件如何获取校验位就成了一个难题。
解决思路
总得来说,就是改变参数类型,原先我们只想传递单个数值,如果传递一整个对象,或者一个回调函数,即可解决问题。
方案1:v-model
简单的实现方案,就是实现自定义组件的 v-model 功能,缺点就是 v-model 只能绑定一个值。
(虽说只能绑定一个值,但是这个值可以是一个对象,因此列为一种解决方案,最好的案例就是 el-form)
<el-form :model="numberValidateForm" ref="numberValidateForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="年龄" prop="age">
<el-input v-model.number="numberValidateForm.age" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<script>
export default {
data() {
return {
numberValidateForm: {
age: ''
}
};
}
}
</script>
方案2:props
props 使用 Object 类型,万物皆对象,Object 意味着可以传递一切,绕过了所有限制。
以下面代码为例,参数是一个很复杂的对象,父子组件只要约定好参数中的内容即可。
<template xmlns="http://www.w3.org/1999/html">
<data-table :table="table"></data-table>
</template>
<script>
import DataTable from '@/components/widget/DataTable.vue'
export default {
components: {
DataTable
},
data() {
return {
table: {
//分页配置
url: undefined
, page: 1
, limit: 10
, enabledSelection: true
, resultParser: undefined
, data: [{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄',
isDisabled: false,
select: 1,
image: 'http://www.baidu.com'
}]
}
}
}
}
</script>
方案3:provide
本质上与方案 2 完全一致,不过不用 props,而是使用 provide,也是将一整个对象传递给子控件。
两种做法,应用场景有些不同。
案例:
可以查看 element-ui 的 table 设计,table 和 column 一般会同时使用,
我们只把数据传递给了 table 组件,但是 column 明显也获取了我们的数据,
我们并没有看到 table 将数据传递给 column。
(el-form 与 el-form-item 的关系亦是如此)
其他人看不到父子组件之间传递参数,但是子组件确确实实获得了父组件的参数,
如果也希望设计这样的组件,这时候就要用到 provide,provide 能起到暗度陈仓的效果,悄悄地就把参数传给了子组件。
父级控件
通过 provide,将自己的参数传递到子级控件。
<script>
import FormInput from './FormInput.vue'
export default {
name: "fast-form"
, provide() {
return {
formGroup: this.formGroup
};
}
}
<script>
子级控件
通过 inject 接收父级传递的参数。
<script>
export default {
name: "form-input"
, inject: ['formGroup']
, created: function () {
//给formGroup增加一个事件回调,此处不符合VUE数据单向数据流的设计要求,但是满足普通JS语法
let currentWidget = this;
for (let i = 0; i < currentWidget.formGroup.length; i++) {
if (currentWidget.formGroup[i].name === this.name) {
currentWidget.formGroup[i].isValid = function () {
return currentWidget.checkFormInputValidity();
}
}
}
}, methods: {
/**
* 比较当前值是否有效
*/
checkFormInputValidity: function (value) {
}
}
}
<script>