zoukankan      html  css  js  c++  java
  • Vue——组件通讯

    1.自定义事件

    组件关系可分为父子组件通信、兄弟组件通信、跨级组件通信。
    从父组件像向子组件通信,通过props传递数据就可以了。

    当子组件需要向父组件传递数据时,就要用到自定义事件。
    v-on除了监听DOM事件外,还可以用于组件之间的自定义事件。
    子组件用$emit()来触发事件,父组件用$on()来监听子组件的事件。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="vue.min.js"></script>
    </head>
    <body>
    <div id="app">
        <p>总数: {{ total }}</p>
        <!--定义两个自定义事件-->
        <my-component @increase="handleGetTotal"
                      @reduce="handleGetTotal"></my-component>
        <!--两个自定义事件向一个函数传参,这样能保证counter一致-->
    </div>
    
    <script>
        Vue.component('my-component', {
            template: '' +
            '<div>' +
            '<button @click="handleIncrease">+1</button>' +
            '<button @click="handleReduce">-1</button>' +
            '</div>',
            // 组件绑定两个方法,这两个方法肯定是需要的
            data: function () {
                return {
                    counter: 0
                }
            },
            methods: {
                // 这两个方法都操控的同一个counter,而且现在是在组件里面,还需要向父组件传递数据
                // 当子组件需要向父组件传递数据的时候,就要用到自定义事件,v-on除了可以监听事件之外,还可以用于组件之间的自定义事件
    
                // 触发事件,将消息传递给父组件
                //$emit()第一个参数是自定义事件的名称,第二个参数是向自定义事件传递的参数
                handleIncrease: function () {
                    this.counter++;
                    this.$emit('increase', this.counter)  //儿子向父亲传递数据
                },
                handleReduce: function () {
                    this.counter--;
                    this.$emit('reduce', this.counter)
                }
            }
        });
        var app = new Vue({
            el: "#app",
            data: {
                total: 0  //双向数据绑定
            },
            methods: {
                handleGetTotal: function (total) {
                    this.total = total;
                }
            }
        })
    </script>
    </body>
    </html>

    2.使用v-model

    还有另外一个更加快捷的方法,使用v-model做双向的数据绑定。
    在自定义的标签里面有counter这个属性,使用v-model直接绑定total这个属性。
    不过这里面使用的是input这个特殊事件名。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="vue.min.js"></script>
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    </head>
    <body>
        <div id="app">
            <p>{{ total }}</p>
            <!--我们还可以在自定义组件上使用v-model-->
            <!--这样将total直接与组件绑定到i此绑定在一次-->
            <my-component v-model="total"></my-component>
        </div>
        <script>
            Vue.component('my-component',{
                template: '<button @click="handleIncrease">+1</button>',
                data: function () {
                    return {
                        counter: 0
                    }
                },
                methods: {
                    handleIncrease: function () {
                        this.counter++;
                        //这次使用的是特殊的input
                        this.$emit('input',this.counter)
                    }
                }
            });
            var app = new Vue({
                el: "#app",
                data: {
                    total: 0,
                }
            })
    
        </script>
    </body>
    </html>

    v-model还可以用来创建自定义的表单输入组件,进行数据双向绑定。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="vue.min.js"></script>
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    </head>
    <body>
        <div id="app">
            <p>总数: {{ total }}</p>
            <my-component v-model="total"></my-component>  <!--直接绑定到total上面-->
            <button @click="handleReduce">-1</button>
            <!--这其实是一个三方通信-->
            <!--v-modelp->my-component-->
            <!--my-component->button-->
        </div>
        <script>
            Vue.component('my-component',{
                props:['value'],
                template: '<input :value="value" @input="updateValue">',  //input标签绑定到这个函数,组件中接收value这个值
                methods: {
                    updateValue: function (event) {  //event代表当前操作的这个对象
                        this.$emit('input',event.target.value);  //将值传回去
                    }
            }
            });
            var app = new Vue({
                el: "#app",
                data: {
                    total: 0,
                },
                methods: {
                    handleReduce: function () {
                        this.total--;
                    }
                }
            })
        </script>
    </body>
    </html>

    实现这样一个具有双向绑定的v-model组件要满足下面两个要求:
      接收一个value属性
      在有新的value时触发input事件

    3.非父子组件通信

    在vue1中,$dispatch用于向上级派发事件,只要是它的父级(一级或多级以上),都可以在vue实例的event选项内接收,
    还提供了$broadcast用于上级向下级广播事件。
    这两种方法一旦发出事件之后,任何组件都可以接收,就近原则而且会在第一次接收到后停止冒泡,除非返回true。
    在vue2中这两个事件被废弃,因为基于组件树结构的事件流的方式难以让人理解,并且在扩展的过程中会变得越来越脆弱。
    并且不能解决兄弟组件之间的通信问题。

    在vue2中使用一个空的Vue实例作为中央事件总线,也就是一个中介,专门用来传达消息。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="vue.min.js"></script>
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    </head>
    <body>
        <div id="app">
            {{ message }}
            <my-component></my-component>
        </div>
        <script>
            var bus = new Vue();  //创建一个空的Vue实例,里面并没有任何内容
            Vue.component('my-component',{  //定义组建
                template: '<button @click="handleEvent">传递事件</button>',
                methods: {
                    handleEvent: function () {
                        bus.$emit('on-message','来自组件my-component的内容')  //将事件发送到bus
                    }
                }
            });
            var app = new Vue({
                el: "#app",
                data: {
                    message: '',
                },
                mounted: function () {  //在初始化app的过程中,监听来自bus的消息
                    var _this = this;
                    bus.$on('on-message',function (msg) {  //在初始化的过程中,监听来自bus实例的事件
                        _this.message = msg
                    })
                }
    
            })
        </script>
    </body>
    </html>

    首先创建一个名为bus的空Vue实例,里面没有任何内容。
    然后全局定义组件my-component,最后创建Vue实例app,在app初始化时,
    也就是生命周期钩子函数里面监听来自bus的事件on-message,
    而在组件my-component中点击按钮会通过bus把事件on-message发出去,
    此时app就会就收来自bus的事件,进而在回调里完成自己的业务逻辑。

    这种方法巧妙的轻量的实现了任何组件之间的通讯,包框父子兄弟跨级,
    如果深入使用,可以扩展bus实例,给他添加data、methods、computed等选项,
    在业务中,经常需要共享一下信息,比如用户登录星系、授权token,只需要让bus获取一次机型了。

    4.父链

    在子组件中,使用this.$parent可以直接访问该组件的父实例或组件,
    父组件也可以通过this.$children访问他的所有子组件,而且可以递归向上或向下无限访问。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="vue.min.js"></script>
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    </head>
    <body>
        <div id="app">
            {{ message }}
            <my-component></my-component>
        </div>
        <script>
            Vue.component('my-component',{
                template: "<button @click='handleChange'>通过父链直接修改数据</button>",
                data: function () {
                    return {
                        message: '来自组件的消息'
                    }
                },
                methods: {
                    handleChange: function () {
                        this.$parent.message = this.message
                    }
                }
            });
            var app = new Vue({
                el: "#app",
                data: {
                    message: '老子的老大'
                }
            })
        </script>
    </body>
    </html>

    尽管Vue允许这样做,但是并不建议这样做,
    子组件不应该过多的依赖父组件,更不应该主动去修改它的数据。

    5.子组件索引

    当子组件比较多的时候,通过this.$children来遍历组件比较麻烦。
    vue提供了子组件索引的方法,用特殊的属性ref来为子组件指定一个索引名称。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="vue.min.js"></script>
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    </head>
    <body>
        <div id="app">
            <p>{{ preMessage }}</p>
            <button @click="handleRef">通过ref过去子组件实例</button>
            <my-component ref="comA"></my-component>  <!--指定索引标签-->
        </div>
        <script>
            Vue.component('my-component',{
                template: "<div></div>",
                data: function () {
                    return {
                        message: '子组件的内容'
                    }
                }
            });
            var app = new Vue({
                el: "#app",
                data: {
                    preMessage: '父组件内容'
                },
                methods: {
                    handleRef: function () {
                        this.preMessage = this.$refs.comA.message  //访问指定的子组件
                    }
                }
            })
        </script>
    
    </body>
    </html>

    效果:

  • 相关阅读:
    倍福TwinCAT(贝福Beckhoff)常见问题(FAQ)-如何添加Scope监控
    倍福TwinCAT(贝福Beckhoff)常见问题(FAQ)-如何使用随机数DRAND模块
    倍福TwinCAT(贝福Beckhoff)常见问题(FAQ)-如何使用断点
    倍福TwinCAT(贝福Beckhoff)常见问题(FAQ)-如何实现开平方的Pow函数
    倍福TwinCAT(贝福Beckhoff)常见问题(FAQ)-如何声明定时器,使用定时器TON模块 TC3
    倍福TwinCAT(贝福Beckhoff)常见问题(FAQ)-如何声明定时器,使用定时器TON模块 TC2
    java中配置自定义拦截器中exclude-mapping path是什么意思?
    java web 过滤器跟拦截器的区别和使用
    利用jquery.validate异步验证用户名是否存在
    jquery统计显示或隐藏的元素个数
  • 原文地址:https://www.cnblogs.com/yangmingxianshen/p/12688406.html
Copyright © 2011-2022 走看看