vue3 父子组件间的数据传递

一、简介

二、实际代码

三、问题

 

一、简介

  vue 父子组件的传递原则是单向的, 子组件是无法修改父组件的参数, 但是可以通过另一种渠道可以实现通信。            

二、实际代码

  1 父传子

  1.1 props 

  父组件内容

<template>
    <div>这里是父组件</div>
    <input type="text" v-model="inputMsg"/>
    
    <div>
        inputMsg:{{inputMsg}}
    </div>
    <div>
        msg:{{msg}}
    </div>
    
    <div>
        <button @click="changeMsg">点击修改</button>
    </div>
    <div style="margin: 10px;">分割线-------------------------</div>

<childView
    :toMsg="msg"
    :toFunc="func"
></childView>

</template>

<script setup>
import { reactive, ref } from 'vue';
import  childView  from './edit.vue'

const inputMsg = ref('这里是父组件的消息')
const msg = ref('')

const func = () =>{
    changeMsg()
}

const changeMsg = () => {
    msg.value = inputMsg.value
}

</script>

    这里父组件传入msg  和一个方法

   子组件内容

<template>
    <div>
        <div>这里是子组件</div>
        <div>收到父组件消息toMsg:{{toMsg}}</div>
    </div>
    <div>
        <button @click="toFunc">点击执行收到的父组件方法</button>
    </div>
    <div>
        <button @click="changeMsg">点击修改toMsg</button>
    </div>
    
</template>

<script setup>
    // 需要定义defineProps
const props = defineProps({
    toMsg: {
        type: String,
        default: 100,
    },
    toFunc: {
        type: Function,
        default: async () => {},
    }
})

const changeMsg = () => {
    props.toMsg = "子组件修改"
}
</script>

<style>
</style>

    这样了就得到了这样一个界面

   点击父组件的修改,就会修改msg 参数的值,并且会实时渲染到子组件

    点击子组件里的 执行收到的父组件方法也可以达到同样的效果, 但是点击 子组件里的修改toMsg 就会报错

    这就是vue的特性,父组件能修改值,但是子组件不能修改父组件的子,只能通过调用父组件的方法修改值。

    顺带提一句,可以直接使用 inputMsg 传入子组件的toMsg,可以立即渲染。

<childView
    :toMsg="inputMsg"
    :toFunc="func"
></childView>

  按照上面的逻辑,是不是可以回调方法传参呢,我将父组件稍微调整了下

<template>
    <div>这里是父组件</div>
    <input type="text" v-model="inputMsg"/>
    
    <div>
        inputMsg:{{inputMsg}}
    </div>
    <div>
        msg:{{msg}}
    </div>
    
    <div>
        <button @click="tapChangeMsg">点击修改</button>
    </div>
    <div style="margin: 10px;">分割线-------------------------</div>

<childView
    :toMsg="msg"
    :toFunc="func"
></childView>

</template>

<script setup>
import { reactive, ref } from 'vue';
import  childView  from './edit.vue'

const inputMsg = ref('这里是父组件的消息')
const msg = ref('')

// 增加参数 const func = (val) =>{ changeMsg(val) } const tapChangeMsg = () =>{ changeMsg() } const changeMsg = (val) => { if (!!val){ msg.value = val }else{ msg.value = inputMsg.value } }
</script>

  子组件传参

<template>
    <div>
        <div>这里是子组件</div>
        <div>收到父组件消息toMsg:{{toMsg}}</div>
    </div>
    <div>
        <button @click="toFunc('1')">点击执行收到的父组件方法</button>
    </div>
    <div>
        <button @click="changeMsg">点击修改toMsg</button>
    </div>
    
</template>

  实验结果,是可行的

 

  2 子传父

    除了上面的回调传参,还有一种其他方式,

    emit: 组件封装了一系列 emit 事件,并返回数据、回调函数等,或单纯执行某个操作后,触发父组件的事件响应。 外部要用时,使用 @xxxx 来接收使用、响应。

  2.1 实际内容

  父组件

<template>
    <div>这里是父组件</div>

    <div>
        msg:{{msg}}
    </div>

    <div style="margin: 10px;">分割线-------------------------</div>

<childView
    @backTo="func"
></childView>

</template>

<script setup>
import { ref } from 'vue';
import  childView  from './edit.vue'

const msg = ref('')
const func = (val) =>{
    msg.value = val
}

</script>

   子组件

<template>

    <div>
        <button @click="changeMsg">点击修改父组件</button>
    </div>
    
</template>

<script setup>
    // 需要定义defineProps
const emit = defineEmits(["backTo"])

const changeMsg = () => {
    emit("backTo", "子组件修改") 
}
</script>

  执行效果

    这里就是使用 defineEmits 自定义了一个事件列表,使用@的方式。

 

  3 父子组件双向绑定

    这个的实现,需要使用到computed, 对于这个网上没有看到一个通俗详细的说法,只知道性能比调用方法好,会缓存。

    可以参考这里去看看

  3.1  实际代码

  父组件

<template>
    <div>这里是父组件</div>
    <div>
        msg:{{msg}}
    </div>
    <button @click="change">父组件改</button>
    <div style="margin: 10px;">分割线-------------------------</div>

<childView
   v-model:msg="msg"
></childView>

</template>

<script setup>
import { reactive, ref } from 'vue';
import  childView  from './edit.vue'


const msg = ref('')

const change = () => {
    msg.value = "从父组件改"
}

</script>

  子组件

<template>

    <div>
        {{value}}
    </div>
    <button @click="change">改变值</button>
</template>

<script setup>
    // 需要定义defineProps

// 接受父组件传递过来的参数msg
const props = defineProps(['msg'])
// 定义子传父事件, update可默认执行父组件数据更新,父组件不需要调用此方法
const emit = defineEmits(['update:msg'])
// 计算属性接受父组件传递过来的msg, 设置get、set方法实现数据双向绑定
const value = computed({
    get: () => props.msg,
    set: (val) => emit('update:msg', val)
})

const change = () => {
    value.value = "从子组件改"
}
</script>

<style>
</style>

  这样相当于,父组件msg 变化会影响到 子组件value, 而子组件value变换会通过 emit 修改父组件的值。

  注意:不管使用props 或者emits 在vue3 里面都需要使用 defineProps 和 defineEmits 声明。

  4 注入传值。

  vue3 还有一种传值方式 provide 和 inject

  按照上面父子组件传值只能传一层,也就是当父子组件大于2以上层数时, 最上面一层往底层传参,按传统得一层一层传,使用这个,就可以直接传下去。

  详细可参考这

  4.1 实际代码

  父组件

<template>
    <div>这里是父组件</div>
    <div>
        msg:{{msg}}
    </div>
    <button @click="change">父组件改</button>
    <div style="margin: 10px;">分割线-------------------------</div>

<childView
></childView>

</template>

<script setup>
import { reactive, ref } from 'vue';
import  childView  from './edit.vue'

const msg = ref('')

const change = () => {
    msg.value = "从父组件改"
}

provide('proMsg',msg)

</script>

  子组件

<template>

    <div>
        {{ofMsg}}
    </div>
    <button @click="change">改变值</button>
</template>

<script setup>

const change = () => {
    ofMsg.value = "从子组件改"
}

const ofMsg = inject('proMsg',ref('none'))

</script>

<style>
</style>

  实测,数据可以双向绑定,子组件修改,父组件可以改变,子组件修改,父组件会更改。

  上面代码操作跟3.1的操作结果一致。

三、问题

posted @ 2024-01-25 14:20  PKGAME  阅读(3868)  评论(0编辑  收藏  举报