props
经典的属性绑定传参,学过vue就会。
// 核心代码,接收父组件的值
let { item } = defineProps<{ item: any }>()
具体代码
下面是父组件
<script setup lang="ts">
import { reactive } from 'vue'
import Son from './components/Son.vue'
let obj = reactive({
name: '张三',
age: 18,
sex: 'male'
})
</script>
<template>
<div class="main">
<Son :item="obj"></Son>
</div>
</template>
<style lang="less">
body {
margin: 0;
}
.main {
height: 300px;
background-color: skyblue;
padding: 12px 32px;
}
</style>
下面是子组件
<template>
<div class="son">
子元素
<div class="inner">
父组件传来的
<div>姓名: {{ item.name }}</div>
<div>年龄: {{ item.age }}</div>
<div>性别: {{ item.sex }}</div>
</div>
</div>
</template>
<script setup lang="ts">
let { item } = defineProps<{ item: any }>()
console.log('父传子: ', item)
</script>
<style scoped lang="less">
.son {
background-color: red;
}
</style>
props子传父
基本一致,子组件使用父组件定义的回调函数传参。
回调传参的思路都是一致的,父组件定义回调函数,用于接收和更新自身的数据;子组件调用该函数并把值作为参数传过去。
核心代码
let item = ref<Item>({} as Item)
let setValue = (obj: Item) => {
console.log('父组件获取到obj', obj)
item.value = obj
}
具体代码
下面是父组件
<script setup lang="ts">
import { reactive, ref } from 'vue'
import Son from './components/Son.vue'
interface Item {
name: string
age: number
sex: string
}
let item = ref<Item>({} as Item)
let setValue = (obj: any) => {
console.log('父组件获取到obj', obj)
item.value = obj
}
</script>
<template>
<div class="main">
<Son :setValue="setValue"></Son>
子组件传来的:
<div>姓名: {{ item.name }}</div>
<div>年龄: {{ item.age }}</div>
<div>性别: {{ item.sex }}</div>
</div>
</template>
<style lang="less">
body {
margin: 0;
}
.main {
height: 300px;
background-color: skyblue;
padding: 12px 32px;
}
</style>
下面是子组件
<template>
<div class="son">子元素</div>
</template>
<script setup lang="ts">
let { setValue } = defineProps<{ setValue: (obj: any) => any }>()
setValue({
name: '李四',
age: 20,
sex: 'female'
})
</script>
<style scoped lang="less">
.son {
background-color: red;
}
</style>
v-model双向绑定
原理解释。
<Son v-model="item"></Son>
v-model其实被解释为一个v-bind属性值和一个事件绑定
<Son :modelValue="item" @update:modelValue="item = $event" />
父组件中值发生变化时,v-bind可以使得子组件的值同步更新;而子组件中的值发生变化时,我们只需要触发update:modelValue这个事件,并把对应的值作为参数即可,父组件触发回调item = $event完成值的更新。
具体代码
父组件
<script setup lang="ts">
import { reactive, ref } from 'vue'
import Son from './components/Son.vue'
let item = ref<{ name: string; age: number; sex: string }>({
name: '张三',
age: 18,
sex: '男'
})
</script>
<template>
<div class="main">
父组件的add事件
<button @click="item.age += 1">年龄+1</button>
<Son v-model="item"></Son>
父组件区域的值:
<div>姓名: {{ item.name }}</div>
<div>年龄: {{ item.age }}</div>
<div>性别: {{ item.sex }}</div>
</div>
</template>
<style lang="less">
body {
margin: 0;
}
.main {
height: 300px;
background-color: skyblue;
padding: 12px 32px;
}
</style>
子组件
<template>
<div class="son">
子元素区域
<button @click="addAge">年龄+1</button>
<div>姓名: {{ modelValue.name }}</div>
<div>年龄: {{ modelValue.age }}</div>
<div>性别: {{ modelValue.sex }}</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
let item = ref({})
let { modelValue } = defineProps<{ modelValue: any }>()
const emit = defineEmits(['update:modelValue'])
const addAge = () => {
modelValue.age += 1
emit('update:modelValue', modelValue)
}
console.log(item)
</script>
<style scoped lang="less">
.son {
background-color: red;
}
</style>
$parent和$refs(双向绑定)
这两种方式用得很少,但是这个更接近于真正意义上的双向绑定,这里只介绍refs 注意:
- parent都是只能在template内使用,因此如果要在ts代码中获取,可以使用方法传值过去。
- 不像其他的方式,refs这种方式在组件初始化时获取不到值,因此一般使用单击事件等可以触发。
核心:子组件使用defineExpose来暴露自身内部的值给外部,外部使用ref()接收,这是一个宏函数,不需要使用import来导入。
具体代码
<script setup lang="ts">
import { reactive, ref } from 'vue'
import Son from './components/Son.vue'
const item = ref()
const handleBtn = (refs: any) => {
console.log('传来的item对象', item.value.item)
console.log('age++:', refs.item.item.age++)
}
</script>
<template>
<div class="main">
父组件的add事件
<button @click="handleBtn($refs)">age+1</button>
<Son ref="item"></Son>
初始化获取refs:
{{ $refs }}
</div>
</template>
<style lang="less">
body {
margin: 0;
}
.main {
height: 300px;
background-color: skyblue;
padding: 12px 32px;
}
</style>
子组件
<template>
<div class="son">
子元素区域
<!-- <button @click="addAge">年龄+1</button> -->
<div>姓名: {{ item.name }}</div>
<div>年龄: {{ item.age }}</div>
<div>性别: {{ item.sex }}</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
let item = ref<{ name: string; age: number; sex: string }>({
name: '张三',
age: 18,
sex: '男'
})
defineExpose({ item })
console.log(item)
</script>
<style scoped lang="less">
.son {
background-color: red;
}
</style>