vue2
props
父组件向子组件传递数据
自定义事件
子组件向父组件传递数据
v-model
1.实现父子组件双向通信
父组件:
<template>
<div>
<CustomInput v-model="sysUserName"></CustomInput>
{{sysUserName}}
</div>
</template>
export default {
data() {
return {
sysUserName: "张三"
};
},
}
子组件:
<template>
<div>
<input name="sysUserName" :value="value" @input="$emit('input',$event.target.value)"></input>
</div>
</template>
export default {
props: ['value'],
}
原理:
绑定数据+自定义事件
父组件:父组件自定义input事件
<template>
<div>
<CustomInput :sysUserName="sysUserName" @input="sysUserName = $event "></CustomInput>
{{sysUserName}}
</div>
</template>
数据:
data() {
return {
sysUserName: "张三"
};
},
子组件:@input是原生DOM事件
<template>
<div>
<input name="sysUserName" :value="sysUserName" @input="$emit('input',$event.target.value)"></input>
</div>
</template>
export default {
props: ['sysUserName'],
}
2.实现表单数据双向绑定
<template>
<div>
<input name="sysUserName" v-model="formData.sysUserName"></input>
{{formData.sysUserName}}
</div>
</template>
data() {
return {
formData: {
sysUserName: "张三"
},
};
},
原理:
数据绑定 + input事件赋值
<template>
<div>
<input name="sysUserName" :value="formData.sysUserName" @input="formData.sysUserName = $event.target.value"></input>
{{formData.sysUserName}}
</div>
</template>
data() {
return {
formData: {
sysUserName: "张三"
},
};
},
sync修饰符
父组件:
<template>
<div>
小明的爸爸现在有{{money}}元
<h2>使用sync修改符</h2>
<Child :money.sync="money"></Child>
<hr>
</div>
</template>
<script type="text/ecmascript-6">
import Child from './Child.vue'
export default {
name: 'SyncTest',
components: {
Child
},
data() {
return {
money:10000
}
},
methods:{}
}
</script>
子组件:
<template>
<div style="background: #ccc; height: 50px;">
<span>小明每次花100元</span>
<button @click="$emit('update:money',money-100)">花钱</button>
爸爸还剩{{money}}元
</div>
</template>
<script type="text/ecmascript-6">
export default {
name: 'Child',
props:['money']
}
</script>
原理:
父组件可以不使用sync修饰符:
自定义事件@update:money
<Child :money="money" @update:money="money = $event"></Child>
注意带有
.sync修饰符的v-bind不能和表达式一起使用 (例如v-bind:title.sync=”money + 100”是无效的)。取而代之的是,你只能提供你想要绑定的 property 名,类似v-model。
parent
this.$refs可以操作子组件的数据和方法
this.$refs.button.size = 'max'
this.$children可以获取所有的子组件,并操作子组件数据
this.$parent可以获取父组件,并操作父组件数据
父组件:
<template>
<div>
<h2>BABA有存款: {{ money }}</h2>
<button @click="borrowFromXM">找小明借钱100</button><br />
<button @click="borrowFromXH">找小红借钱150</button><br />
<button @click="borrowFromAll">找所有孩子借钱200</button><br />
<br />
<!-- ref:可以获取到真实DOM节点,可以获取相应组件的实例VC -->
<!-- ref也算在一种通信手段:在父组件中可以获取子组件(属性|方法) -->
<Son ref="son" />
<br />
<Daughter ref="dau" />
</div>
</template>
<script>
import Son from "./Son";
import Daughter from "./Daughter";
export default {
name: "ChildrenParentTest",
data() {
return {
money: 1000,
};
},
methods: {
//小明借用100元
borrowFromXM() {
//父亲的钱加上100元
this.money += 100;
this.$refs.son.money -= 100;
},
borrowFromXH() {
this.money += 150;
this.$refs.dau.money -= 150;
},
borrowFromAll() {
//VC:$children属性,可以获取当前组件的全部子组件[这个属性在用的时候很少用索引值获取子组件,因为没有办法确定数组里面的元素到底是哪一个子组件]
this.money += 400;
this.$children.forEach((item) => {
item.money -= 200;
});
},
},
components: {
Son,
Daughter,
},
};
</script>
<style>
</style>
子组件son:
<template>
<div style="background: #ccc; height: 50px;">
<h3>儿子小明: 有存款: {{money}}</h3>
<button @click="giveMoney">给BABA钱: 50</button>
</div>
</template>
<script>
export default {
name: 'Son',
data () {
return {
money: 30000
}
},
methods: {
giveMoney(){
this.money-=50;
//$parent,VC一个属性,可以获取当前组件(属性|方法)
this.$parent.money+=50;
}
}
}
</script>
子组件:
<template>
<div style="background: #ccc; height: 50px;">
<h3>女儿小红: 有存款: {{money}}</h3>
<button @click="giveMoney">给BABA钱: 100</button>
</div>
</template>
<script>
export default {
name: 'Daughter',
data () {
return {
money: 20000
}
},
methods: {
giveMoney(){
this.money-=100;
this.$parent.money+=100;
}
}
}
</script>
listeners
父组件:
<template>
<div>
<h1>对于el-button进行二次封装</h1>
<hintButton type="warning" icon="el-icon-s-help" size="mini" tip="豪哥提示信息" @click="handler"></hintButton>
</div>
</template>
<script type="text/ecmascript-6">
export default {
name: 'AttrsListenersTest',
methods: {
handler(){
console.log("自定义事件");
}
},
}
</script>
子组件:
<template>
<div :tip="$attrs.tip">
<el-button :type="$attrs.type" :icon="$attrs.icon" :size="$attrs.size" v-on="$listeners">警告按钮</el-button>
</div>
</template>
<script>
export default {
name: "hintButton",
};
</script>
也可以简写:
<template>
<div :tip="$attrs.tip">
<el-button v-bind="$attrs" v-on="$listeners">警告按钮</el-button>
</div>
</template>
<script>
export default {
name: "hintButton",
};
</script>
attrs中就接收不到数据了
vue3
props
子组件接收:
对象式
const props = defineProps({
modelValue: {
type: String,
},
type: {
type: String,
default: 'text',
},
width: {
type: [Number, String],
default: '300px',
},
})
数组形式:
const props = defineProps(['modelValue','type','width']);
自定义事件
子组件向父组件传递数据
父组件
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
子组件:
//定义事件
const emit = defineEmits(['sizeChange', 'currentChange']);
//触发事件
const sizeChangeHandle = (val: number) => {
emit('sizeChange', val);
};
// 分页改变
const currentChangeHandle = (val: number) => {
emit('currentChange', val);
};
v-model
父组件
<right-toolbar v-model:showSearch="showSearch"></right-toolbar>
const showSearch = ref(true);
子组件:
<el-tooltip :content="showSearch ? '隐藏搜索' : '显示搜索'">
<el-button circle icon="Search" @click="toggleSearch()" />
const props = defineProps({
/**
* 是否显示搜索框
*/
showSearch: {
type: Boolean,
default: true,
}
})
const emits = defineEmits(['update:showSearch']);
const toggleSearch = () => {
emits('update:showSearch', !props.showSearch);
};
多个 v-model 绑定
父组件:
<UserName
v-model:first-name="first"
v-model:last-name="last"
/>
子组件:
<script>
export default {
props: {
firstName: String,
lastName: String
},
emits: ['update:firstName', 'update:lastName']
}
</script>
<template>
<input
type="text"
:value="firstName"
@input="$emit('update:firstName', $event.target.value)"
/>
<input
type="text"
:value="lastName"
@input="$emit('update:lastName', $event.target.value)"
/>
</template>
$attrs
父向子传递数据
父组件:
<child type="primary" size="large"></child>
子组件:
<template>
<div>
<el-button :type="$attrs.type" :size="$attrs.size">开关</el-button>
<el-button v-bind="$attrs">开关</el-button>
<el-button :="$attrs">开关</el-button>
</div>
</template>
或者
<el-button :type="attrs.type" :size="attrs.size">开关</el-button>
<el-button v-bind="attrs">开关</el-button>
<el-button :="attrs">开关</el-button>
<script>
import {useAttrs} from "vue";
const attrs = useAttrs();
</script>
attrs中就接收不到数据了
ref和$parents
子向父传递数据
父组件:
<script setup lang="ts">
import Child from '/@/views/test/child/index.vue'
const money = ref(1000)
const child = ref()
const withdraw = () => {
money.value += 100
child.value.money -= 100
child.value.withdraw();
}
</script>
<template>
<div>
<h1>父组件余额:{{money}}</h1>
<Child ref="child"></Child>
<br>
<br>
<button @click="withdraw">向子组件借100</button>
</div>
</template>
子组件:
<script setup lang="ts" >
const money = ref(500)
const withdraw = () => {
console.log("子组件向父组件借了100元")
}
defineExpose({money,withdraw})
</script>
<template>
<div>
<h1>子组件余额: {{ money }}</h1>
</div>
</template>
provide和inject
provide可以为后代组件传递数据
组件:
<script setup lang="ts">
import {provide} from 'vue'
provide('money', money)
</script>
在app组件上提供的数据在该应用内的所有组件中都可以注入。
const app = createApp({})
app.provide( 'message', 'hello!')
inject获取数据:
<script setup lang="ts">
import {inject} from 'vue'
const money = inject('money')
</script>