vue3组合式api父子组件传值
如果是子组件中没有任何触发一个方法去触发emit这个方法时,使用ref的方式比较方便,可以拿到子组件传给父组件的值,还可以很方便的调用子组件的方法。引用子组件,在子组件中定义一个属性(这个属性是子组件中defineProps定义的),属性值是自己定义的参数,也就是你要传给子组件的参数值。* 使用到类似这样的监听,当父组件传入的数据发生变化时,根据父组件传入的数据重新渲染值的到新的图表,后面会写一篇
Vue3组合是api父子组件传值
这个是用来记录父子组件传值的一种方式,我这里用的是vite+ts+element plus
在Vue3中props方式,父组件传值给子组件
后面有完整代码,这里是简单的描述过程
父组件引用子组件,在子组件中定义一个属性(这个属性是子组件中defineProps定义的),属性值是自己定义的参数,也就是你要传给子组件的参数值
<template>
<div>
<!-- 这里两种形式都可以,子组件引用,通过props传值, 这里的:sonValue(:son-value 这个是驼峰命名在标签的一种转换形式而已,跟使用:sonValue效果是一样的) 是子组件定义defineProps中定义的sonValue, 具体看子组件代码-->
<Son :son-value="value"></Son> <!-- 这个是引用的子组件 -->
<!-- <Son :sonValue="value"></Son> -->
</div>
</template>
子组件的script中通过defineProps定义属性,用来接收父组件传过来的值,注意在vue3中,不写import { defineProps } from ‘vue’;这一句也是可以的,因为.vue文件中内置了这个,这是一个宏。所以不一定要引用的,可以不写import { defineProps } from ‘vue’;直接用defineProps()
<script setup lang="ts">
import { defineProps } from 'vue';
// props传值,非ts写法,ts写法后面后面的完整代码有,具体看后面的代码
defineProps({
// 这个就是父组件在使用子组件时的属性值,也就是父组件的::son-value或者:sonValue
sonValue: String // 注意这里的String的S是大写的,不是String,也可以用小写的string,看个人需求
})
</script>
完整代码如下
父组件parent.vue
<template>
<div>
<h1>这个是父组件</h1>
<el-input v-model="value" placeholder="请输入内容,父组件输入框"></el-input>
<hr>
<el-row>
<!-- 这里两种形式都可以,子组件引用,通过props传值 -->
<Son :son-value="value"></Son>
<!-- <Son :sonValue="value"></Son> -->
</el-row>
</div>
</template>
<script setup lang="ts">
import Son from '../components/Son.vue';
import { ref } from 'vue'
const value = ref('')
</script>
<style scoped>
</style>
子组件Son.vue
<template>
<div style="width: 500px; height: 400px; background-color: pink;">
<h1>这是子组件</h1>
<hr>
<el-row>
这是父组件传进来的值 {{ sonValue }}
</el-row>
</div>
</template>
<script setup lang="ts">
import { defineProps } from 'vue';
// props传值,非ts写法,ts写法后面后面的完整代码有,具体看后面的代码
defineProps({
sonValue: String // 注意这里的String的S是大写的,不是String
})
</script>
<style scoped>
</style>
结果就是,在父组件的输入框输入数据,子组件接受到数据并展示
通过上面的方式就可以将父组件的内容传给子组件了,但是这里就有一个问题。Vue中如果在子组件中修改props的值,会发出警告的。并不是很支持直接修改props传的值,所以我们这里可以通过一个变量接受props传入的值,然后在template中展示。而且这里会有一个现象就是,在template标签中,传入的props的值是可以跟父组件实时改变的。但是在script setup lange="ts"中的数据这个不是实时改变的,总结一句话就是,如果是直接使用props的值,可以实时改变,如图过是想在js或者ts赋值给变量后使用,就不会实时改变。具体如下。
父组件Parent.vue
<template>
<div>
<h1>这个是父组件</h1>
<el-input v-model="value" placeholder="请输入内容,父组件输入框"></el-input>
<hr>
<el-row>
<!-- 这里两种形式都可以,子组件引用,通过props传值,也可以传一个user对象 -->
<Son :son-value="value" :user="user"></Son>
</el-row>
</div>
</template>
<script setup lang="ts">
import Son from '../components/Son.vue';
import { ref } from 'vue'
const value = ref('这是父组件的初始value值')
const user = ref({
username: '张三',
age: 23
})
</script>
<style scoped>
</style>
子组件Son.vue
<template>
<div style="width: 500px; height: 400px; background-color: pink;">
<h1>这是子组件</h1>
<hr>
<el-row>
这是父组件传进来的值 {{ sonValue }}
</el-row>
<hr>
<el-row>
这是子组件中的Script中的值scriptValue1: {{ scriptValue1 }} <br>不会实时改变的
</el-row>
<hr>
<el-row>
user对象数据:用户名:{{ user.username }}, 年龄:{{ user.age }}
</el-row>
</div>
</template>
<script setup lang="ts">
import { defineProps } from 'vue';
// 下面这里是ts的写法
const props = defineProps<{
sonValue: String, // 注意这里的String的S是大写的,不是String
user: {
username: String,
age: Number
}
}>()
const scriptValue1 = props.sonValue
// js的写法,非ts的写法
// const props = defineProps(
// {
// sonValue: String, // 注意这里的String的S是大写的,不是String
// user: {
// username: String,
// age: Number
// }
// }
// )
</script>
<style scoped></style>
要想Script中的值也实时改变,我们可以通过watch监听的props的方式进行实时改变script中的值
父组件parent.vue
<template>
<div>
<h1>这个是父组件</h1>
<el-input v-model="value" placeholder="请输入内容,父组件输入框"></el-input>
<hr>
<el-row>
<!-- 这里两种形式都可以,子组件引用,通过props传值,也可以传一个user对象 -->
<Son :son-value="value" :user="user"></Son>
</el-row>
</div>
</template>
<script setup lang="ts">
import Son from '../components/Son.vue';
import { ref } from 'vue'
const value = ref('这是父组件的初始value值')
const user = ref({
username: '张三',
age: 23
})
</script>
<style scoped>
</style>
子组件Son.vue
<template>
<div style="width: 500px; height: 400px; background-color: pink;">
<h1>这是子组件</h1>
<hr>
<el-row>
这是父组件传进来的值 {{ sonValue }}
</el-row>
<hr>
<el-row>
这是子组件中的Script中的值scriptValue1: {{ scriptValue1 }} <br><b>通过监听之后这时就会实时改变</b>
</el-row>
<hr>
<el-row>
user对象数据:用户名:{{ user.username }}, 年龄:{{ user.age }}
</el-row>
</div>
</template>
<script setup lang="ts">
import { ref, defineProps, watch } from 'vue';
// 面这里是ts的写法
const props = defineProps<{
sonValue: string, // 这里的String是小写的s
user: {
username?: String, // 有?说明非必须的,这里也可以是string
// default: '----', 这个可以为username设置默认值
age: Number
}
}>()
const scriptValue1 = ref('')
scriptValue1.value = props.sonValue
/**
* 监听props,当props变化时改变scriptValue1的值
* 我们也可以通过监听做一些事情,如封装echarts组件组件通过props传值的时候,或许可以
* 使用到类似这样的监听,当父组件传入的数据发生变化时,根据父组件传入的数据重新渲染值的到新的图表,后面会写一篇文章的
*/
watch(props, (newValue) => {
console.log(newValue) // console.log(newValue)可以知道这里是vue3中reactive类型的数据
console.log(`这是变化的新值:`, newValue.sonValue)
// 统监听props的值变化,动态修改scriptValue1的值
scriptValue1.value = newValue.sonValue
})
// const result = ref('0')
// watch(result, (newValue) => {
// console.log(newValue)
// })
// js的写法,非ts的写法
// const props = defineProps(
// {
// sonValue: String, // 注意这里的String的S是大写的,不是String
// user: {
// username: String,
// age: Number
// }
// }
// )
</script>
<style scoped>
</style>
通过defineEmits子组件传值给父组件
在子组件中声明定义一个常量,用户实现方法传参,方法名可以自定义
const emit = defineEmits(['sonChange', 'sonChangParams'])
这个需要在子组件中定义一个方法去触发emit这个方法,具体如下代码所示
emit("sonChangParams", value) // 其中value是参数
在父组件中
<template>
<div>
<!-- 只调用一个事件 -->
<!-- <Son @son-change="sonChange"></Son> -->
<!-- <Son @sonChange="sonChange"></Son> -->
<!-- 自定义事件中,可以值传一个时间,也可以传两个参数,前提是名称要跟子组件定义的const emit = defineEmits(['sonChange', 'sonChangParams'])参数个数
和名称一样,这里的可以用@son-change 、 @son-chang-params 或者 @sonChange 、sonChangParams都可以 -->
<!-- 调用两个事件 -->
<Son @son-change="sonChange" @son-chang-params="sonChangeParams"></Son>
</div>
</template>
完整代码如下:
父组件parent.vue
<template>
<div>
<h1>这个是父组件</h1>
<hr>
<el-row>
子组件修改调用父组件:
</el-row>
<el-row>
{{ parentValue }}
</el-row>
<hr>
<el-row>
<!-- 只调用一个事件 -->
<!-- <Son @son-change="sonChange"></Son> -->
<!-- <Son @sonChange="sonChange"></Son> -->
<!-- 自定义事件中,可以值传一个时间,也可以传两个参数,前提是名称要跟子组件定义的const emit = defineEmits(['sonChange', 'sonChangParams'])参数个数
和名称一样,这里的可以用@son-change 、 @son-chang-params 或者 @sonChange 、sonChangParams都可以 -->
<!-- 调用两个事件 -->
<Son @son-change="sonChange" @son-chang-params="sonChangeParams"></Son>
</el-row>
</div>
</template>
<script setup lang="ts">
import Son from '../components/Son.vue';
import { ref } from 'vue'
const parentValue = ref('')
const getList = () => {
parentValue.value = '子组件按钮调用父组件的函数getList()'
}
// 子组件按钮事件
const sonChange = () => {
// 子组件按钮时间
getList()
}
/**
* 获取子组件传给父组件的参数
* @param val 这个是子组件传的参数,这里调用的是带参数的子组件触发方法
*/
const sonChangeParams = (val: any) => {
// 子组件修改父组件的parentValue值
parentValue.value = val
// 返回子组件传给父组件的参数
return val;
}
</script>
<style scoped>
</style>
子组件son.vue
<template>
<div style="width: 500px; height: 400px; background-color: pink;">
<h1>这是子组件</h1>
<hr>
<el-row>
<el-button type="primary" @click="usedParentMethods">子组件通过点击事件调用父组件的方法(无参)</el-button>
</el-row>
<el-row>
<el-button type="success" @click="usedParentMethodsParams">子组件通过点击事件调用父组件的方法(通过携带参数将子组件的某些数据传给父组件)</el-button>
</el-row>
</div>
</template>
<script setup lang="ts">
import { ref, defineEmits, reactive } from 'vue';
const childrenValue = ref('这个是子组件传给父组件的参数的值,这是子组件传给父组件的参数值')
// const user = reactive({
// userName: '子组件张三'
// })
// 名字自定义,如这里有两个sonChange、sonChangParams
const emit = defineEmits(['sonChange', 'sonChangParams'])
// 调用父组件的函数
const usedParentMethods = () => {
// 这里的名字要跟const emit = defineEmits(['sonChange', 'sonChangParams'])定义的一样
emit("sonChange") // 无参传值
}
// 传入参数
const usedParentMethodsParams = () => {
// emit既可以传复杂数据,也可以传简单数据
// emit("sonChangParams", user)
// 这里的名字要跟const emit = defineEmits(['sonChange', 'sonChangParams'])定义的一样
emit("sonChangParams", childrenValue.value)
}
</script>
<style scoped>
</style>
其结果如下所示
通过ref的方式给子组件传值给父组件
另外一种方式就是通过ref的方式子组件给父组件传值,这种方法在子组件中导入使用defineExpose方法,把你想要传的参数或者方法(函数)抛出去
<script setup lang="ts">
import { ref, defineExpose } from 'vue';
const childrenValue = ref('这是子组件的childrenValue值')
const childrenValue2 = ref('这是子组件的childrenValue值')
const sum = ref(0)
const play1 = () => {
sum.value = 3 + 7
console.log("调用了子组件的play()函数")
}
const play2 = () => {
return '这个是子组件的play2()函数'
}
defineExpose({
// 只有暴露出去的参数和函数在ref中才可以访问到,如这里childrenValue2没有暴露出去,所以
// 不能在父组件中使用ref访问到childrenValue2的值
childrenValue,
play1, // 这个是函数,但是不加括号(),否则报错,在父组件中使用是需要加括号,具体看父组件的代码
play2, // 这个是函数,但是不加括号(),否则报错,在父组件中使用是需要加括号,具体看父组件的代码
})
</script>
在父组件中引用的子组件上接收ref,名字自定义
<tepmlate>
<div>
<Son ref="childrenRef"></Son>
</div>
</tepmlate>
通过ref就可以直接获取到子组件的值了
// 这里ref中什么都不写
const childrenRef = ref()
console.log(childrenRef.value.childrenValue)
childrenRef.value.play1()
const play2ReturnValue = childrenRef.value.play2()
console.log(play2ReturnValue)
完整代码如下:
父组件parent.vue
<template>
<div>
<h1>这个是父组件</h1>
<el-input v-model="value" placeholder="请输入内容,父组件输入框"></el-input>
<el-button type="primary" @click="getChildrenRef">运行或者获取子组件的参数和函数</el-button>
<hr>
<el-row>
<Son ref="childrenRef"></Son>
</el-row>
</div>
</template>
<script setup lang="ts">
import Son from '../components/Son.vue';
import { ref } from 'vue'
const value = ref('这是父组件的初始value值')
// 这里ref中什么都不写
const childrenRef = ref()
// 这几个不能直接这样写,应该放到一个函数中,直接在这里写会报错的,代码都运行不起来
// console.log('子组件的childrenValue值')
// console.log(childrenRef.value.childrenValue)
// console.log('子组件的play方法')
// childrenRef.value.paly()
// childrenRef.value.play2()
const getChildrenRef = () => {
// 这里的childrenValue和play1()、play2()要跟子组件中defineExpose暴露的一一对应,
// 如果是函数,记得加括号(),在子组件的defineExpose中不需要加括号(),具体看子组件的代码
// console.log('子组件的childrenValue值=====》')
console.log(childrenRef.value.childrenValue)
// console.log('子组件的play1()方法')
childrenRef.value.play1()
// console.log('调用了play2()的方法')
const play2ReturnValue = childrenRef.value.play2()
console.log(play2ReturnValue)
}
</script>
<style scoped>
</style>
子组件son.vue
<template>
<div style="width: 500px; height: 400px; background-color: pink;">
<h1>这是子组件</h1>
<hr>
<el-row>
{{ childrenValue }}
</el-row>
<el-row>
{{ childrenValue2 }}
</el-row>
<el-row>
3 + 7 = {{ sum }}
</el-row>
</div>
</template>
<script setup lang="ts">
import { ref, defineExpose } from 'vue';
const childrenValue = ref('这是子组件的childrenValue值')
const childrenValue2 = ref('这是子组件的childrenValue值')
const sum = ref(0)
const play1 = () => {
sum.value = 3 + 7
console.log("调用了子组件的play()函数")
}
const play2 = () => {
return '这个是子组件的play2()函数'
}
defineExpose({
// 只有暴露出去的参数和函数在ref中才可以访问到,如这里childrenValue2没有暴露出去,所以
// 不能在父组件中使用ref访问到childrenValue2的值
childrenValue,
play1, // 这个是函数,但是不加括号(),否则报错,在父组件中使用是需要加括号,具体看父组件的代码
play2, // 这个是函数,但是不加括号(),否则报错,在父组件中使用是需要加括号,具体看父组件的代码
})
</script>
<style scoped>
</style>
具体结果如下所示,浏览器中可以f12可以看到看到这个结果
既然我们在父组件中能达到子组件的值了,这里我们就可以尝试在父组件中修改子组件的值了,还不需要使用监听就可以修改子组件的值了,前提是子组件暴露出来的值或者函数对应的值是响应式的,如果不是响应式的值,改了也没用。调用子组件的函数,
父组件parent.vue
<template>
<div>
<h1>这个是父组件</h1>
<el-input v-model="parentValue" placeholder="请输入内容,父组件输入框" @input="changChildValue"></el-input>
<el-row>
调用子组件的求和函数得到的结果为:12 + 13 = {{ sum }}
</el-row>
<hr>
<el-row>
<Son ref="childrenRef"></Son>
</el-row>
</div>
</template>
<script setup lang="ts">
import Son from '../components/Son.vue';
import { ref } from 'vue'
const parentValue = ref('这是父组件的初始value值')
// 这里ref中什么都不写
const childrenRef = ref()
const sum = ref(0)
// element plus中el-input封装的change事件
const changChildValue = () => {
// console.log(childrenRef.value.childrenValue) 获取子组件暴露的childrenValue值,具体看子组件代码
childrenRef.value.childrenValue = parentValue.value
sum.value = childrenRef.value.sum(12, 13) // 函数记得添加括号(),还要看函数需不需要传参
}
</script>
<style scoped>
</style>
子组件son.vue
<template>
<div style="width: 500px; height: 400px; background-color: pink;">
<h1>这是子组件</h1>
<hr>
<el-row>
这是暴露给父组件的值: {{ childrenValue }}
</el-row>
<el-row>
父组件调用求和函数之后的值:{{ sumValue }}
</el-row>
<el-row>
3 + 7 = {{ sumValue }}
</el-row>
</div>
</template>
<script setup lang="ts">
import { ref, defineExpose } from 'vue';
const childrenValue = ref('这是子组件的childrenValue值')
const sumValue = ref(0)
const sum = (value1: number, value2: number) => {
sumValue.value = value1 + value2
return value1 + value2
}
defineExpose({
// 只有暴露出去的参数和函数在ref中才可以访问到,如这里sumValue没有暴露出去,所以
// 不能在父组件中使用ref访问到sumValue的值
childrenValue,
sum, // 这个是函数,但是不加括号(),否则报错,在父组件中使用是需要加括号,具体看父组件的代码
})
</script>
<style scoped>
</style>
运行结果如下所示
总结,在子组件给父组件传值的过程中,如果子组件有点击事件,然后传值给父组件,使用defineEmits方式比较方便。如果是子组件中没有任何触发一个方法去触发emit这个方法时,使用ref的方式比较方便,可以拿到子组件传给父组件的值,还可以很方便的调用子组件的方法。使用ref父组件还可以很方便修改子组件的响应式的值,这个就相当于props的监听那里一样,可以在父组件修改script中的值。如果结合echarts的话,还可以调用对应的子组件方法设置echarts的配置项,从而修改echarts的图表配置。这个后面会写一篇使用vue封装echarts的学习文章的。
更多推荐
所有评论(0)