直接通过向子组件身上添加方法的方式传递数据:
<uploadCom
:limit="1"
:policy="() => staffGetOssUploadPolicy()"
>uploadCom>
其中,limit
、policy
就是定义好的变量名,子组件用props接收数据时,需要用正确的变量名来接收,如下:
const props = defineProps({
limit: {
type: Number,
default: 100,
},
policy: {
type: Function,
default: async () => {},
}
})
// 使用
let limit = props.limit
const policy = props.policy
需要注意的是,**Vue3 中通过defineProps
方法定义的所有 props,默认为响应式!**这是 Vue3 中新增的一个特性。
因此,我们不再需要像 Vue2 中一样,为这些 props 单独定义watch
方法去监听其变化并实时更新!
Props 响应式的工作原理如下:当父组件的 Props 改变时,相应的子组件会接收到通知并进行更新。这样,当Props 更改后,父组件和子组件的数据就可以保持一致。
注意:
由于vue数据传递是单向数据流,子组件没有权利修改父组件传过来的数据,只能请求父组件对原始数据进行修改,即用 emit 通知父组件去修改。
首先,需要在父组件中的子组件上绑定响应 emit 通知的事件:
<uploadCom
:limit="limit"
@updateLimit="updateLimit"
>uploadCom>
然后定义该事件的处理函数:
// 传入的数据
const limit = ref(1)
// 事件处理函数
const updateLimit = (num) => {
limit.value = num;
}
而在子组件中,首先需要注册一个 emit 方法,然后触发指定的事件即可:
const emit = defineEmits(["updateLimit"])
emit("updateLimit", 2);
这样父组件中就会触发事件调用响应函数,从而实现子组件向父组件传值!
在上面的基础通信方式中,实际上是利用了绑定并触发自定义事件来通知父组件修改原数据。
而当子组件通知父组件更新的值,正好也是父组件通过props传递给子组件的值时,此时可以在父组件中用v-model
在该属性上进行双向绑定。如下:
<uploadCom
v-model:limit="limit"
>uploadCom>
此时,父组件中不再需要绑定自定义事件,也不需要定义响应函数!
而子组件中,直接注册一个 emit 方法,然后通过用emit("update:xxx", param)
即可通知父组件更新指定变量名的数据!
const emit = defineEmits(["update:limit"])
// 个人理解:update:xxx 是一个内置的事件,所以我们不再需要进行手动的绑定、配置处理函数等工作
emit("update:limit", 2);
这样,我们就达成了一种类似于数据双向绑定的效果。
为什么说是类似?因为数据既可以从父组件流向子组件,也可以从子组件流向父组件(但实际上并不是),且也是通过v-model
命令实现的。
当使用父子组件双向绑定时,若我们没有指定变量名:
<TestCom v-model="test1">TestCom> // 未指定变量名
<TestCom v-model:test2="test2">TestCom> // 指定变量名
则此时在子组件中用 props 接收数据时,默认用modelValue
这个属性来接收未命名的数据:
const props = defineProps({
// 父组件 v-model 时test1数据没有指定参数名,所以此时属性modelValue会接收到test1
modelValue:{
type:String,
default: 'test'
},
// 而已命名的数据test2则由对应名称的属性来接收
test2: {
type: String,
default: 'aaa'
}
})
那么要更新这个未命名的数据时该如何操作呢?实际上是同样的方法:
const emit = defineEmits(["update:modelValue"])
emit("update:modelValue", 'update!');
这种情况实际上是很常见的,因为有些公共组件并不能确定父组件中传入的数据的名称,无法通过统一的名称来接收数据,此时就需要用到默认的modelValue
了。