Zhu xiaohang's blog

组件通信

组件通信

1.为什么要进行组件通信

​ 组件可以说是具有独立功能的整体,但是当我们要将这些组件拼接在一起的时候,这些组件相互之间要建立联系,这个联系我们就称之为通信

2.组件通信的方式有一下几种

​ 1.父子组件通信

​ 使用props来实现

​ 2.子父组件通信

​ 自定义事件

​ 3.非父子组件通信

​ ref链

​ bus事件总线

​ 4.多组件状态共享(多个组件共用同一个数据) 大知识点(vuex) 这边只讲前3个

​ vuex

知识点: app实例的手动挂载

​ new Vue({
​ el:'#app'
​ }).$mount('#app')


父子组件通信

案例:

<body>
    <div id='app'>
        <father></father>
    </div>


    <template id='father'>
        <div>
            <p>这是Father组件</p>
            <hr>
            <son :qwer = "money"></son>   
            <!-- 子组件做数据绑定   绑定父组件里面的数据 -->
        </div>
    </template>

    <template id='son'>
        <div>
            <p>这是son组件</p>
            <p>父亲给了我{{qwer}}元</p>  
            <!-- 子组件可以全局调用这个数据 -->
        </div>
    </template>


    <script>
        // props
        //     1.在父组件的模板中将数据用单项数据绑定的形式,绑定在子组件上
        //     2.在子组件的配置项中可以使用一个props配置项来接收这个数据,接收时,props的取值可以是一个数组
        //     3.在子组件模板中,接收到的属性可以像全局一样使用


        // 这里全局注册Father这个组件
        Vue.component('Father', {
            template: '#father',
            data() {
                return {
                    money: 2000
                }
            }
        })

        // 这里全局注册Son这个组件
        Vue.component('Son', {
            template: '#son',
            props: ['qwer'] //子组件用props来接收这个数据
        })


        new Vue({
            el: '#app'
        })
    </script>
</body>

产生的问题:

问题一:props接收的money和子组件上绑定的自定义属性money是不是同一个?     
      
      不是, 绑定自定义属性名字可以自定义(个人一般会写成一样的)

      注意:自定义命名不能有大写字母 用-a来表示

问题二:为什么data要定义一个函数
        1.组件是一个独立的个体,那么他应该拥有自己的数据,这个数据应该是一个独立的数据
        2.也就是说这个数据应该有独立的作用域(需要一个独立的使用范围,这个范围就是这个组件内)
        3.函数提供了独立的作用域
        
问题三:为什么data要有返回值?返回值还是一个对象

        因为Vue是通过observe来观察data选项的,所以必须要有返回值
        因为Vue要通过es5的Object.defineProperty属性对对象进行getter和setter设置

子父组件通信

<body>
    <div id="app">
        <Father></Father>
    </div>

    <template id='father'>
        <div>
            <h3>这里是father组件</h3>
            <p>儿子给了我{{money}}元钱</p>
            <Son @give='getHongbao'></Son>  
            <!--  这里是第一步! 绑定一个自定义事件在子组件身上 -->
        </div>
    </template>

    <template id='son'>
            <div>
                <button @click = 'giveFather'>give</button>
                <h3>这里是son组件</h3>
            </div>
    </template>


    <script>
        Vue.component('Father', {
            template: '#father',
            data() {
                return {
                    money: 0
                }
            },
            methods: {
                getHongbao(val) {
                    console.log(1)
                    this.money = val
                }
            }
        })

        Vue.component('Son', {
            template: '#son',
            data() {
                return {
                    hongbao: 500 //要把这个数据发给父组件 , 首先要在父组件中定义一个数据用来接收这个数据
                }
            },
            methods: {
                giveFather() {
                    //如何进行父组件给子组件的自定义事件触发?
                    // 这里是第二步骤!!!
                    this.$emit('give', this.hongbao)
                }
            }
        })

        new Vue({
            el: '#app',
        })
    </script>

    <!-- 自定义事件
        1.自定义的 通过 $on 定义  $emit用来触发

        2.通过绑定在组件身上定义   $emit用来触发 -->


    <!-- 总结:   
            1.在父组件的模板中,通过事件绑定的形式,绑定一个自定义事件在子组件身上 
            
            2.在子组件中 (子组件的配置项methods中)写一个事件处理函数,在事件处理函数中触发父组件绑定的自定义事件

            3.将子组件定义的事件处理函数 绑定在子组件的按钮身上(点击触发 实现步骤2) -->
</body>

非父子组件通信(ref链)

<body>
    <div id="app">
        <Father></Father>
    </div>

    <template id="father">
        <div>
            <h3>这里是father</h3>
            <button @click = 'look'>点击查看father的this</button>
            <p>father的n: {{ n }}</p>
            <hr>
            <Son ref = 'son'></Son>
            <hr>
            <Girl ref = 'girl' :n = 'n'></Girl>   

            <!-- 通过ref绑定组件后,我们发现在他们共同父组件的$refs里面可以找到子组件 -->

        </div>
    </template>

    <template id="son">
        <div>
            <h3>这里是son组件</h3>
        </div>
    </template>


    <template id="girl">
        <div>
            <h3>这里是girl组件</h3>
            <button @click = 'out'> 输出girl的this </button>
        </div>
    </template>

    <script>
        Vue.component('Father', {
            template: '#father',
            data() {
                return {
                    n: 0
                }
            },
            methods: {
                look() {
                    this.n = this.$refs.son.money
                }
            }
        })

        Vue.component('Son', {
            template: '#son',
            data() {
                return {
                    money: 1000
                }
            }
        })

        Vue.component('Girl', {
            template: '#girl',
            data() {
                return {
                    num: 0
                }
            },
            methods: {
                out() {
                    console.log(this)
                    console.log(this.$attrs.n)
                }
            }
        })


        new Vue({
            el: '#app'
        })
    </script>

    <!-- 总结:ref链可以实现非父子组件的通信,但是如果层级太多就比较繁琐了 -->
</body>

非父子组件通信(bus事件总线)

    <div id='app'>
        <Bro></Bro>
        <Sma></Sma>
    </div>

    <template id="big">
        <div>
            <h3>这里是哥哥组件</h3>
            <button @click = 'hick'>揍</button>
        </div>
    </template>

    <template id="sma">
        <div>
            <h3>这里是弟弟组件</h3>
            <p v-show = 'flag'>呜呜呜呜呜呜wuwuwuu</p>
        </div>
    </template>

    <script>
        var bus = new Vue()

        Vue.component('Bro', {
            template: '#big',
            methods: {
                hick() {
                    bus.$emit('aa');
                }
            }
        })

        Vue.component('Sma', {
            template: '#sma',
            data() {
                return {
                    flag: false
                }
            },
            mounted() {
                var _this = this

                //当前组件挂载结束,也就是我们在页面当中看到真实的dom
                //mounted这个钩子函数的触发条件是组件创建时会自动触发
                bus.$on('aa', function() {

                    _this.flag = true

                })
            }
        })

        new Vue({
            el: '#app'
        })
    </script>
    
    <!-- 总结:
        1.在其中一个组件的挂载钩子函数上做事件的声明

        2.在另一个组件中,通过 bus.$emit('事件名称')来触发自定义事件 -->

非常规手段(不推荐使用)

子父通信

<body>
    <div id='app'>
        <Father></Father>
    </div>

    <template id='father'>
        <div>
            <h3>这里是father组件</h3>
            <p>这里是父组件的n:{{n}}</p>
            <Son :add = 'add'></Son>
        </div>
    </template>

    <template id='son'>
            <div>
                <h3>这里是son组件</h3>
                <button @click = 'add(2000)'>give</button>
            </div>
    </template>

    <script>
        //我们要进行子父组件通信
        //理解:使用自定义事件实现

        Vue.component('Father', {
            template: '#father',
            data() {
                return {
                    n: 0
                }
            },
            methods: {
                add(val) {
                    this.n = val
                }
            }
        })

        Vue.component('Son', {
            template: '#son',
            data() {
                return {
                    money: 1000
                }
            },
            props: ['add']
        })

        new Vue({
            el: '#app'
        })
    </script>
</body>

动态组件

1.什么是动态组件

​ 可以改变的组件

2.使用

​ 通过Vue提供了一个component+is属性使用

3.动态组件指定就是component这个组件

  <div id="app">
    <button @click = "change"> 切换 </button>
    <!-- <keep-alive include="">
      <component :is = "type"></component>
    </keep-alive> -->
    
    
    <component :is = "type"></component>

  </div>
</body>
<script>
/* 
  业务: 点击一个按钮进行两个组件的切换

 */
  Vue.component('Aa',{
    template: '<div> Aa </div>'
  })

  Vue.component('Bb',{
    template: '<div> Bb </div>'
  })

  new Vue({
    data: {
      type: 'Aa'
    },
    methods: {
      change () {
        this.type = (this.type === 'Aa'?'Bb':'Aa')
      }
    }
  }).$mount('#app')
</script>
posted @ 2019-06-25 22:59  mckk  阅读(293)  评论(0编辑  收藏  举报