3.4.父子组件传值
3.4.1.子组件 接收信息
父组件 显示子组件模板, 通过 props , $attrs 接值
3.4.1.1.子组件
通过 props 属性接到 父组件 传来值, 在子组件中可以通过 this 来使用这些信息
也可以 通过 $attrs 接收 没有被 props 声明的值
<template>
<div>
<input type="text" :value="value" />{{msg}} <br>
a: {{a}} , other: {{$attrs}} <br>
</div>
</template>
<script>
export default {
name: "BaseComp1",
props: {
msg: {
type: String,
default: "数值"
},
a:{
type: Number,
default: 0
}
},
data() {
return {
value: this.msg + ", 子组件信息"
}
}
}
</script>
3.4.1.2.父组件
通过 msg 属性 向 子组件 传值
也可以通过 v-bind 一次性传递多组信息
<template>
<div>
<BaseComp1 msg="父组件传递的信息" v-bind="{a:100, b:200, c:300}" />
</div>
</template>
<script>
import BaseComp1 from "./BaseComp1.vue"
export default {
name: "index",
components: {
BaseComp1
}
}
</script>
3.4.2.子组件 watch 监听
父组件 传递 动态信息 , 子组件 watch 监听信息
3.4.2.1.子组件
通过 watch 监听 父组件传来 msg 信息, 在回调函数中 修改 子组件中的信息
<template>
<div>
<input type="text" :value="value" />
</div>
</template>
<script>
export default {
name: "BaseComp2",
props: {
msg: {
type: String,
default: "数值"
}
},
data() {
return {
value: this.msg + ", 子组件信息"
}
},
watch: {
msg: {
handler(nv) {
this.value = nv + ", 父信息改变了"
}
}
},
}
</script>
3.4.2.2.父组件
向 子组件 传 msg 信息, 通过 按钮 修改msg, 被子组件watch监听
<template>
<div>
<BaseComp2 :msg="msg" />{{msg}}
<button @click="change">修改信息</button>
</div>
</template>
<script>
import BaseComp2 from "./BaseComp2.vue"
export default {
name: "index",
components: {
BaseComp2
},
data() {
return {
msg: "父组件msg",
}
},
methods: {
change(){
this.msg = "父组件修改信息"
}
}
}
</script>
3.4.3.通过 props 传函数
父组件 传递 函数 , 子组件 调用函数回传值
3.4.3.1.子组件
接收 父组件传来 getData() 函数, 调用此函数 回传信息
<template>
<div>
<input type="text" :value="value" />
<button @click="getData(value)">返回数据</button>
</div>
</template>
<script>
export default {
name: "BaseComp3",
props: {
msg: {
type: String,
default: "数值"
},
getData: {
type: Function,
default: () => {}
}
},
data() {
return {
value: this.msg + ", 子组件信息"
}
}
}
</script>
3.4.3.2.父组件
向 子组件 传getData , 类型为函数, 子组件调用时 触发 监听函数 reData() 接收到值
<template>
<div>
<BaseComp3 :msg="msg" :getData="reData" />{{msg}} -{{reMsg }}
</div>
</template>
<script>
import BaseComp3 from "./BaseComp3.vue"
export default {
name: "index",
components: {
BaseComp3
},
data() {
return {
msg: "父组件msg",
}
},
methods: {
reData(val){
console.log( "返回信息:", val )
this.reMsg = val
}
}
}
</script>
3.4.4.v-model绑定信息
子组件在 props 中使用value 接收信息 v-model的值, 通过 input 接收返回信息
页面 UI 组件最长用的方式
3.4.4.0.v-model的本质
v-model 实现双向绑定的原理 , 是 value 属性 及 input 事件
<input :value="msg" @input="msg=$event.target.value" /> <br>
3.4.4.1.子组件
通过 value 接收到 父组件 v-model 传来的信息
通过 v-model 双向绑定 childMsg, 当在子组件修改这个值时, 会被 watch 监听到
再 通过 this.$emit(‘input’, nv + “返回信息”); 通过 input 返回数据
<template>
<input type="text" v-model="childMsg" />
</template>
<script>
export default {
name: "BaseComp4",
props: {
value: {
type: String,
default: "数值"
}
},
data() {
return {
childMsg: this.value + ", 子组件信息"
}
},
watch: {
childMsg: {
handler(nv) {
console.log(nv)
this.$emit('input', nv + "返回信息");
}
}
}
}
</script>
3.4.4.2.父组件
在 父 组件通过 v-model 双向绑定 msg , 子组件 通过 input 事件返回 子组件返回的信息
<template>
<div>
<h1>组件测试</h1>
<h4> BaseComp4 : 子组件在 props 中使用value 接收信息 v-model的值 </h4>
<h4> 通过 input 接收返回信息 </h4>
<BaseComp4 v-model="msg" /> {{msg}}
</div>
</template>
<script>
import BaseComp4 from "./BaseComp4.vue"
export default {
name: "index",
components: {
BaseComp4
},
data() {
return {
msg: "父组件msg",
}
}
}
</script>
3.4.5.textarea
3.4.5.1.子组件
将 input 换成 textarea 效果是一样
<template>
<textarea v-model="childMsg" ></textarea>
</template>
<script>
export default {
name: "BaseComp5",
props: {
value: {
type: String,
default: "数值"
}
},
data() {
return {
childMsg: this.value + ", 子组件信息"
}
},
watch: {
childMsg: {
handler(nv) {
console.log(nv)
this.$emit('input', nv + "返回信息");
}
}
}
}
</script>
3.4.5.2.父组件
<template>
<div>
<BaseComp5 v-model="msg" /> {{msg}}
</div>
</template>
<script>
import BaseComp5 from "./BaseComp5.vue"
export default {
name: "index",
components: {
BaseComp5
},
data() {
return {
msg: "父组件msg",
}
}
}
</script>
3.4.6.select
3.4.6.1.子组件
接收到 value , options
下拉框 也可以 通过 input 事件, 返回信息
<template>
<div>
<select v-model.number="selVal" >
<option v-for="item in options" :key="item.value" :value="item.value" >{{item.label}}</option>
</select>
</div>
</template>
<script>
export default {
name: "BaseComp6",
props: {
value: {
type: Number,
default: 0
},
options: {
type: Array,
default: () => []
}
},
data() {
return {
selVal: this.value
}
},
watch: {
selVal: {
handler(nv) {
console.log(nv)
this.$emit('input', nv);
}
}
}
}
</script>
3.4.6.2.父组件
<template>
<div>
<BaseComp6 v-model="selVal" :options="checkOptions" /> {{selVal}}
</div>
</template>
<script>
import BaseComp6 from "./BaseComp6.vue"
export default {
name: "index",
components: {
BaseComp6
},
data() {
return {
selVal: 0,
checkOptions: [
{
label: "选项0",
value: "0"
},
{
label: "选项1",
value: "1"
},
{
label: "选项2",
value: "2"
},
{
label: "选项3",
value: "3"
},
{
label: "选项4",
value: "4"
}
]
}
}
}
</script>
3.4.7.radio
3.4.7.1.子组件
单选框 也是通过 input 事件返回信息
<template>
<div>
<label v-for="item in options" :key="item.value" >
<input type="radio" v-model.number="selVal" :value="item.value" > {{item.label}}
</label>
</div>
</template>
<script>
export default {
name: "BaseComp4",
props: {
value: {
type: Number,
default: 0
},
options: {
type: Array,
default: () => []
}
},
data() {
return {
selVal: this.value
}
},
watch: {
selVal: {
handler(nv) {
console.log(nv)
this.$emit('input', nv);
}
}
}
}
</script>
3.4.7.2.父组件
<template>
<div>
<CheckComp1 v-model="selVal" :options="checkOptions" /> {{selVal}}
</div>
</template>
<script>
import CheckComp1 from "./CheckComp1.vue"
export default {
name: "index",
components: {
CheckComp1
},
data() {
return {
selVal: 0,
checkOptions: [
{
label: "选项0",
value: "0"
},
{
label: "选项1",
value: "1"
},
{
label: "选项2",
value: "2"
},
{
label: "选项3",
value: "3"
},
{
label: "选项4",
value: "4"
}
]
}
}
}
</script>
3.4.8.checkbox
3.4.9.1.子组件
用 value 接收到数组
<template>
<div>
<label v-for="item in options" :key="item.value" >
<input type="checkbox" v-model.number="checkVals" :value="item.value" > {{item.label}}
</label>
</div>
</template>
<script>
export default {
name: "BaseComp4",
props: {
value: {
type: Array,
default: () => []
},
options: {
type: Array,
default: () => []
}
},
data() {
return {
checkVals: this.value
}
},
watch: {
checkVals: {
handler(nv) {
console.log(nv)
this.$emit('input', nv);
}
}
}
}
</script>
3.4.8.2.父组件
通过 数组类型 selVals: [0,1], 向子组件 传值
<template>
<div>
<CheckComp2 v-model="selVals" :options="checkOptions" /> {{selVals}}
</div>
</template>
<script>
import CheckComp2 from "./CheckComp2.vue"
export default {
name: "index",
components: {
CheckComp2
},
data() {
return {
selVals: [0,1],
checkOptions: [
{
label: "选项0",
value: "0"
},
{
label: "选项1",
value: "1"
},
{
label: "选项2",
value: "2"
},
{
label: "选项3",
value: "3"
},
{
label: "选项4",
value: "4"
}
]
}
}
}
</script>
3.4.9.model 自定义
通过 model 在子组件中 自定义 接收值 ,及返回事件
3.4.9.1.子组件
通过 model 来 自定义 属性
<template>
<input type="text" v-model="childMsg" />
</template>
<script>
export default {
name: "BaseComp7",
props: {
// value: {
// type: String,
// default: "数值"
// },
customModelValue: {
type: String,
default: "数值"
}
},
model: {
prop: 'customModelValue', // 与父组件 v-model 绑定的 prop 名称
event: 'updateCustomModelValue' // 触发更新父组件数据的事件名
},
data() {
return {
childMsg: this.customModelValue + ", 子组件信息"
}
},
watch: {
childMsg: {
handler(nv) {
console.log(nv)
this.$emit('updateCustomModelValue', nv + "返回信息");
// this.$emit('input', nv + "返回信息");
}
}
}
}
</script>
3.4.9.2.父组件
父组件 使用 v-model:xxx 来指定 向 子组件 传递值
<template>
<div>
<BaseComp7 v-model:customModelValue="msg" /> {{msg}}
</div>
</template>
<script>
import BaseComp7 from "./BaseComp7.vue"
export default {
name: "index",
components: {
BaseComp7
},
data() {
return {
msg: "父组件msg",
}
}
}
</script>
3.4.10..sync
父子同步
3.4.10.1.子组件
使用 update:msg
向 父组件 同步数据
<template>
<input type="text" v-model="childMsg" />
</template>
<script>
export default {
name: "BaseComp4",
props: {
msg: {
type: String,
default: "数值"
}
},
data() {
return {
childMsg: this.msg + ", 子组件信息"
}
},
watch: {
childMsg: {
handler(nv) {
console.log(nv)
this.$emit('update:msg', nv + "返回信息");
}
}
}
}
</script>
3.4.10.2.父组件
不再使用 v-model 来 监听子组件 回传数据, 而是 通过 .sync
来同步子组件返回的数据
<template>
<div>
<SyncComp1 :msg.sync="msg" /> {{msg}}
</div>
</template>
<script>
import SyncComp1 from "./SyncComp1.vue"
export default {
name: "index",
components: {
SyncComp1
},
data() {
return {
msg: "父组件msg"
}
}
}
</script>
3.4.11.Click事件回传数据
3.4.11.1.子组件
使用 按钮 的 click事件 来 返回数据
<template>
<div>
<input type="text" :value="childMsg" />
<button @click="returnData">点击</button>
</div>
</template>
<script>
export default {
name: "ClickComp1",
props: {
value: {
type: String,
default: "数值"
}
},
data() {
return {
childMsg: this.value + ", 子组件信息"
}
},
methods: {
returnData() {
this.$emit("input", this.childMsg + "返回信息")
}
}
}
</script>
3.4.11.2.父组件
<template>
<div>
<ClickComp1 v-model="msg" /> {{msg}}
</div>
</template>
<script>
import ClickComp1 from "./ClickComp1.vue"
export default {
name: "index",
components: {
ClickComp1
},
data() {
return {
msg: "父组件msg",
}
}
}
</script>
3.4.12.computed监听数据
3.4.12.1.子组件
使用 computed 来 返回数据
<template>
<div>
<input type="text" v-model="childMsg1" />
<input type="text" v-model="childMsg2" />
</div>
</template>
<script>
export default {
name: "BaseComp4",
props: {
value: {
type: String,
default: "数值"
}
},
data() {
return {
}
},
computed: {
childMsg1: {
get() {
return this.value+", 有子组件信息";
},
set(val) {
this.$emit('input', val);
}
},
childMsg2: {
get() {
return this.value;
},
set(val) {
this.$emit('input', val);
}
}
}
}
</script>
3.4.12.2.父组件
<template>
<div>
<ComputedComp1 v-model="msg" /> {{msg}}
</div>
</template>
<script>
import ComputedComp1 from "./ComputedComp1.vue"
export default {
name: "index",
components: {
ComputedComp1
},
data() {
return {
msg: "父组件msg",
}
}
}
</script>
3.4.13.数据转汉字
3.4.13.1.子组件
<template>
<div>
<el-input v-model.number="num"></el-input>
<span>{{ numStr }}</span>
</div>
</template>
<script>
export default {
name: "NumToString",
props: {
value: {
type: Number,
default: 0
}
},
data() {
return {
num: this.value,
numStr:''
}
},
watch: {
num: {
handler(nv) {
this.numStr = this.numberToChinese(nv)
this.$emit('input', nv);
}
}
},
methods: {
// 转换函数
numberToChinese(num) {
const digits = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
const units = ['', '十', '百', '千', '万', '十', '百', '千', '亿', '十', '百', '千', '万'];
// 处理负数和0的情况
if (num === 0) return '零';
if (num < 0) return '负' + numberToChinese(-num);
let chineseNum = '';
let currentUnitIndex = 0;
num = num.toString().split('').reverse();
for (let digit of num) {
let digitStr = digits[digit];
if (digit !== '0') {
chineseNum = digitStr + units[currentUnitIndex] + chineseNum;
// 遇到非零数字后,前面的零不再发音
if (currentUnitIndex > 0 && digitStr !== '一' && chineseNum.charAt(chineseNum.length - 1) === '零') {
chineseNum = chineseNum.slice(0, -1);
}
} else {
if (chineseNum.length === 0 || chineseNum.charAt(chineseNum.length - 1) !== '零') {
chineseNum += '零';
}
}
if (digit !== '0' || (digit === '0' && currentUnitIndex % 4 === 0)) {
currentUnitIndex++;
}
}
// 格式化结果,移除不需要的零和单位
chineseNum = chineseNum.replace(/零+([亿|万])/g, '$1').replace(/零+$/, '').replace(/^零+/, '');
return chineseNum;
}
}
}
</script>
3.4.13.2.父组件
<NumToString v-model="num" ></NumToString>
3.4.14.数值范围
3.4.14.1.子组件
<template>
<div>
<el-input-number v-model="range.min" placeholder="请输入最小值" controls-position="right" ></el-input-number>
<span style="margin-left: 10px; margin-right:10px;">~</span>
<el-input-number v-model="range.max" placeholder="请输入最大值" controls-position="right" ></el-input-number>
</div>
</template>
<script>
export default {
name: 'NumberRangeInput',
props: {
value: {
type: Array,
default: () => [null, null]
}
},
data() {
return {
range: {
min: this.value[0],
max: this.value[1]
}
};
},
watch: {
range: {
handler(newValue) {
this.$emit('input', [newValue.min, newValue.max]);
},
deep: true
}
}
};
</script>
3.4.14.2.父组件
<NumberBetween v-model="rangeArray" ></NumberBetween>
...
rangeArray: [null, null],
3.4.15.$refs 找子组件
通过 $refs 找到子组件 调用 子组件函数
3.4.15.1.子组件
子组件 中定义 函数 接收val 参数
<template>
<div>
<input type="text" :value="childMsg" />
</div>
</template>
<script>
export default {
name: "ChildComp1",
data() {
return {
childMsg: '子组件信息'
}
},
methods: {
setData(val) {
this.childMsg = "子组件信息" + val
}
}
}
</script>
3.4.15.2.父组件
在 父组件中 通过 $refs 找到指定的组件
<template>
<div>
<ChildComp1 ref="child1" />
<button @click="$refs.child1.setData('父组件传递的信息')">修改子组件信息</button>
</div>
</template>
<script>
import ChildComp1 from "./ChildComp1.vue"
export default {
name: "index",
components: {
ChildComp1
},
}
</script>