工作中记录 - Vue3.x 和 Vue2常用组件通信

222 阅读1分钟

Vue2.x组件通信


1、父子组件通信

  • props - 子组件接收到数据后,不能直接修改父组件的数据。(父组件重新渲染时,数据会被覆盖);推荐使用 computed。
//父组件
    <template>
        <child :msg="msg"></child>
    </temolate>
    
//子组件
    export default{
        // 写法一:数组接收
        props:['msg']
        // 写法二:用对象接收,可以限定接收的数据类型,设置默认值、验证等
        props:{
            msg:{
                type:String,
                default:'这是默认数据'
            }
        },
        mounted(){
            console.log(this.msg)
        }
    }
  • $emit / v-on - 子组件通过派发事件的方式给父组件数据,或者触发父组件更新等操作。
// 子组件 派发
    export default {
      data(){
          return { msg: "这是发给父组件的信息" }
      },
      methods: {
          handleClick(){
              this.$emit("sendMsg",this.msg)
          }
      },
    }
    
// 父组件 响应
    <template>
        <child v-on:sendMsg="getChildMsg"></child>
        // 或 简写
        <child @sendMsg="getChildMsg"></child>
    </template>

    export default {
        methods:{
            getChildMsg(msg){
                console.log(msg) // 这是父组件接收到的消息
            }
        }
    }
  • ref - ref 如果在普通的DOM元素上,引用指向的就是该DOM元素;如果在子组件上,引用的指向就是子组件实例,然后父组件就可以通过 ref 主动获取子组件的属性或者调用子组件的方法。
//子组件
    export default {
        data(){
            return {
                name:"沐华"
            }
        },
        methods:{
            someMethod(msg){
                console.log(msg)
            }
        }
    }

//父组件
    <template>
        <child ref="child"></child>
    </template>
    <script>
    export default {
        mounted(){
            const child = this.$refs.child
            console.log(child.name) // 沐华
            child.someMethod("调用了子组件的方法")
        }
    }
    </script>
  • .syns - 可以实现父组件向子组件传递的数据的双向绑定,所以子组件接收到数据后,可直接修改,并且会同时修改父组件的数据。
//父组件
    <template> 
        <child :page.sync="page"></child> 
    </temolate>
    export default{
        data(){
            return {
                page:1
            }
        }
    }
    
//子组件
    export default{
        props:["page"],
        computed(){
            // 在子组件里修改 currentPage 时,父组件的 page 也会随之改变
            currentPage{
                get(){ 
                    return this.page 
                },
                set(newVal){
                    this.$emit("update:page", newVal)
                }
            }
        }
    }
  • v-model - 和 .sync 类似,可以实现将父组件传给子组件的数据为双向绑定,子组件通过 $emit 修改父组件的数据
// 父组件
    <template>
        <child v-model="value"></child>
    </template>
    <script>
    export default {
        data(){
            return {
                value:1
            }
        }
    }

// 子组件
    <template>
        <input :value="value" @input="handlerChange">
    </template>
    export default {
        props:["value"],
        // 可以修改事件名,默认为 input
        model:{
            event:"updateValue"
        },
        methods:{
            handlerChange(e){
                this.$emit("input", e.target.value)
                // 如果有上面的重命名就是这样
                this.$emit("updateValue", e.target.value)
            }
        }
    }
</script>
  • $$children / $parent

2、兄弟组件通信

  • EventBus - EventBus 是中央事件总线,不管是父子组件,兄弟组件,跨层级组件等都可以使用它完成通信操作。
// 方法一
// 抽离成一个单独的 js 文件 Bus.js ,然后在需要的地方引入
// Bus.js
    import Vue from "vue"
    export default new Vue()

// 方法二 直接挂载到全局
// main.js
    import Vue from "vue"
    Vue.prototype.$bus = new Vue()

// 方法三 注入到 Vue 根对象上
// main.js
    import Vue from "vue"
    new Vue({
        el:"#app",
        data:{
            Bus: new Vue()
        }
    })
  • Vuex - Vuex 是状态管理器,集中式存储管理所有组件的状态。
//目录层级
    store
        |-state.js
        |-actions.js
        |-getter.js
        |-muations.js
        |-moeules
// index.js封装
    import Vue from 'vue'
    import Vuex from 'vuex'
    import getters from './getters'
    import actions from './actions'
    import mutations from './mutations'
    import state from './state'
    import user from './modules/user'

    Vue.use(Vuex)
    
    const store = new Vuex.Store({
      modules: {
        user
      },
      getters,
      actions,
      mutations,
      state
    })
    export default store

// 在需要的组件里面使用
    import {mapGetters,mapMutations} from "vuex",
    export default{
        computed:{
            //方式一:通过this.属性名就可以用
            ...mapGetters({"引入getters.js里属性1""属性2"})
            //方式二:
            ...mapGetters("user",["user模块里的属性1","属性2"])
        },
        methods:{
            //方式一:通过this.属性名就可以用
            ...mapMustaions(["引入mutations.js里的方法1","方法2"])
            //方式二:
            ...mapMuations("user",["引入user模块里的方法1""方法2"])
        }
    }

Vue3.x组件通信


defineProps ----> [用来接收父组件传来的 props]:

  • 父组件代码:
    <template>
        <Child @getChili="getChili" :title="msg" />
    </template>
    
    <script setup>
        import {ref} from 'vue'
        import Child from './child.vue'
        
        //把值传递给子组件 --> :title="msg"
        cosnt msg = ref('父组件的值')
    </script>
    
  • 子组件代码:
    <template>
       <div style="color: red">{{props.title}}</div>
    </template>
    
    <script setup>
        import {defineProps} from 'vue'
         //接收父组件 传过来的值!
         const  props = defineProps({
           title: {
             type: String
           }
         });
         //打印一下 接收父组件的值
         console.log(props.title) //父的值
     </script>
    

defineEmit ----> [子组件向父组件事件传递] :

  • 子组件代码:
    <temolate>
        <button @click="toEmits">点击传值到父组件</button>
    </temolate>
    
    <script setup>
        import {defineEmits,ref} from 'vue'
        //先定义一下,在发送值
        const emits = defineEmits(['getChili'])
        
        const toEmits = () => {
            emits('getChili','子组件的值')
        }
    </script>
    
  • 父组件代码:
    <template>
        <div>{{data}}</div>
        <Child @getChili="getChili" :title="msg" />
    </template>
    
    <script setup>
        import {ref} from 'vue'
        import Child from './child.vue'
        
        //空值接收 子组件的传值
        const data = ref(null)
        const getChili = (e) => {
            console.log(e) //子组件的值
            data.value = e
        }
    </script>
    

在标准组件写法里,子组件的数据都是默认隐式暴露给父组件的,但在script-setup模式下,所有数据只是默认return给template 使用,不会暴露到组件外,所以父组件是无法直接通过挂载ref 变量获取子组件的数据。如果要调用子组件的数据,需要先在子组件显示的暴露出来,才能够正确的拿到,这个操作,就是由defineExpose来完成。

defineExpose ----> [组件暴露出自己的属性] :

  • 子组件代码:
    <template>
        <div>{{user.name}}</div>
    </template>
    
    <script setup>
        import {ref, defineExpose, reactive} from 'vue'
        const user = reactive({
            name:'张三',
            age:20
        })
        
        const userNew = ref('小张三')
        console.log(userNew)
        
        defineExpose({
            user,
            userNew
        })
    </script>
    
  • 父组件代码:
    <template>
        <button @click="shiEmots">获取暴露</button>
        <Child ref="shield"/>
    </template>
    
    <script setup>
        import Child from './child.vue'
        import {defineEmits,defineProps,ref} from 'vue'
    
        const shield = ref()
    
        const  shiEmots = () =>{
          //子组件接收暴露出来得值
          console.log('接收reactive暴漏出来的值',shield.value.xiaoZhi)
          console.log('接收ref暴漏出来的值',shield.value.xiaoXiaoZhi)
        }
    </script>