美文网首页
vue父子组件通信踩坑,数据变化未监听到

vue父子组件通信踩坑,数据变化未监听到

作者: smaVivian | 来源:发表于2019-01-24 10:54 被阅读0次

    遇到这样一种需求场景:点赞为子组件,页面为父组件
    \color{#FF0000}{问题1:} vue子组件变化父组件未监测到,点赞时父组件的点赞人数未自动更新。

    image.png

    \color{#FF0000}{问题2:} vue父组件变化子组件未监测到,发表动态后列表数据变化,子组件还保持原来的顺序。
    发表前:

    image.png

    发表后:


    image.png
    父组件page.vue:
    <!--父组件-->
    <div v-for="(item, index) in dataList" :key="index">
        <my-cmp-like :isLike="item.isGood==='1'?true:false" :likeId="item.id" :index="index"></my-cmp-like>
    </div>
    
    子组件MyLike.vue(点赞):
    <!--子组件-->
    props: {
        isLike: {
            type: Boolean,
            default: false
        },
        likeId: {
            type: String,
            default: ''
        },
        index: {
            type: Number,
            default: 0
        }
    }
    

    \color{#FF0000}{解决问题1:} vue为单向数据流,数据从父级组件传递给子组件,只能单向绑定,子组件内部不能直接修改从父级传递过来的数据。

    • 方法一:在子组件中利用$parent直接修改父组件数据。(不推荐该方式,原因见下文末)
      MyLike.js:
    <!--子组件-->
    this.$parent.dataList[this.index].praiseNameList = res.data.data.praiseNameList;
    
    • 方法二:通过$emit向父组件传递方法
    <!--父组件-->
    <template>
        <my-cmp-like @praiseChange="updatePraise" :isLike="item.isGood==='1'?true:false" :likeId="item.id" :index="index"></my-cmp-like>
    </template>
    <script>
      import myCmpLike from './ChildCount';
    
      export default{
        components: {
            myCmpLike,
        },
        methods: {
            updatePraise(index, data) {
                this.dataList[index].praiseNameList = data;
            },
        },
      };
    </script>
    
    <!--子组件-->
    this.$emit('praiseChange', this.index, res.data.data);
    

    \color{#FF0000}{解决问题2:} 父组件中:key="index"未发生变化,故监测不到,改为:key="item.id"

    <!--父组件-->
    <div v-for="(item, index) in dataList" :key="item.id">
        <my-cmp-like :isLike="item.isGood==='1'?true:false" :likeId="item.id" :index="index"></my-cmp-like>
    </div>
    

    vue父子组件通信总结:

    父组件向子组件通信

    1. 通过props传递数据
    <template>
      <div>
        <h2>父组件</h2>
        <child-count :msg="message"></child-count>
      </div>
    </template>
    <script>
      import childCount from './ChildCount';
    
      export default{
        components: {
            childCount,
        },
        data: {
            message: '信息'
        },
      };
    </script>
    
    <!--子组件-->
    <template>
      <div>
        <h3>我是子组件</h3>
        <span>{{parentMessage}}</span>
      </div>
    </template>
    <script>
      export default{
        props: {
            msg: {
              type: String,
              default: ''
            },
            isLike: {
              type: Boolean,
              default: false
            },
            index: {
              type: Number,
              default: 0
            },
            // 其他入参
            type: {
              type: String,
              default: ''
            },
            // 回调
            func: Function  
          },
      };
    </script>
    
    1. 通过ref属性名称获取到子组件的实例
    <!--父组件-->
    <template>
      <div v-for="(item, index) in dataList" :key="index">
        <h2>父组件</h2>
        <div @click="someFun(index)">调用子组件方法</div>
        <my-cmp-like ref="myLike"></my-cmp-like>
      </div>
    </template>
    <script>
      import myCmpLike from '@/components/MyLike'
    
      export default{
        components: {
            myCmpLike,
        },
        data() {
            return {
                dataList: []
            }
        },
        methods(){
            someFun(i) {
                this.$refs.myLike[i].showMsg()
            },
        },
      };
    </script>
    
    <!--子组件-->
    <template>
      <div>
        <h3>我是子组件</h3>
        <span>{{msg}}</span>
      </div>
    </template>
    <script>
      export default{
        props: {...},
        data() {
            return {
              msg: '子组件'
            }
        },
        methods: {
            showMsg() {
            alert(this.msg)
            },
        }
      };
    </script>
    

    子组件向父组件通信

    1. 通过$emit向父组件传递方法
    <!--子组件-->
    <template>
      <div>
        <h3>我是子组件一</h3>
      </div>
    </template>
    <script>
      export default{
        data() {
          return {
            item: {
                name: 'Tony'
            },
          };
        },
        mounted() {
          this.$emit('childEvent', this.item);
        },
      };
    </script>
    
    <!--父组件-->
    <template>
      <div>
        <h2>父组件</h2>
        <Child-one @childEvent="parentMethod"></Child-one>
      </div>
    </template>
    <script>
      import ChildOne from './ChildOne';
    
      export default{
        components: {
          ChildOne,
        },
        data() {
          return {
            parentMessage: '我是来自父组件的消息',
          };
        },
        methods: {
          parentMethod(item) {
            console.log(item)
            alert(this.parentMessage)
          },
        },
      };
    </script>
    
    1. 通过props回调参数调用父组件方法
    <!--父组件-->
    <template>
      <div>
        <h2>父组件</h2>
        <Child-one :func="showMsg"></Child-one>
      </div>
    </template>
    <script>
      import ChildOne from './ChildOne';
    
      export default{
        components: {
          ChildOne,
        },
        data() {
          return {
            parentMessage: '我是来自父组件的消息',
          };
        },
        methods: {
          showMsg(item) {
            console.log(item)
            alert(this.parentMessage)
          },
        },
      };
    </script>
    
    <!--子组件-->
    <template>
      <div>
        <h3>我是子组件</h3>
        <span>{{parentMessage}}</span>
      </div>
    </template>
    <script>
      export default{
        data() {
            return {
                msg: '子组件的信息'
            }
        },
        props: {
            // 回调
            func: Function  
        },
        mounted() {
            this.func && this.func(this.msg)
        },
      };
    </script>
    
    1. 通过$parent获取父组件中的数据(不推荐该方式,因为vue提倡单向数据流,只有父组件交给子组件的数据子组件才有使用的权限,不允许子组件私自获取父组件的数据进行使用。)
    <!--子组件-->
    this.$parent.dataList[this.index].praiseNameList = res.data.data.praiseNameList;
    

    vue兄弟组件、页面之间通信

    1. 复杂情况用vuex
    2. 简单情况用事件总线

    新建eventBus.js

    // 事件总线
    import Vue from 'Vue'
    
    export default new Vue()
    

    a页面

    import eventBus from '@/utils/eventBus' 
    beforeDestroy() {
        eventBus.$emit('eventPerson', { a: 111 })
      }
    

    b页面

    import eventBus from '@/utils/eventBus' 
    created() {
        // 处理事件
        eventBus.$on('eventPerson', data => {
          console.log('事件总线数据呀', data)
        })
      },
      beforeDestroy() {
        // 组件销毁前清除事件监听
        eventBus.$off('eventPerson')
        // eventBus.$off('eventPerson', this.handleEventPerson)
      }
    

    相关文章

      网友评论

          本文标题:vue父子组件通信踩坑,数据变化未监听到

          本文链接:https://www.haomeiwen.com/subject/mskjjqtx.html