zoukankan      html  css  js  c++  java
  • Vue学习笔记入门篇——组件的通讯

    本文为转载,原文:Vue学习笔记入门篇——组件的通讯

    组件意味着协同工作,通常父子组件会是这样的关系:组件 A 在它的模版中使用了组件 B。它们之间必然需要相互通信:父组件要给子组件传递数据,子组件需要将它内部发生的事情告知给父组件。然而,在一个良好定义的接口中尽可能将父子组件解耦是很重要的。这保证了每个组件可以在相对隔离的环境中书写和理解,也大幅提高了组件的可维护性和可重用性。
    在 Vue 中,父子组件的关系可以总结为 props down, events up。父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息。看看它们是怎么工作的。

    Prop

    使用Prop传递数据

    组件实例的作用域是孤立的。这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据。要让子组件使用父组件的数据,我们需要通过子组件的 props 选项。
    子组件要显式地用 props 选项声明它期待获得的数据:

    <div id="example">
        <input v-model="parentMsg"><br>
        <child :my-message="parentMsg"></child>
    </div>
        Vue.component('child', {
            props:['myMessage'],
            template:'<span>{{myMessage}}</span>'
        })
        new Vue({
            el:'#example',
            data:{
                parentMsg:''
            }
        })

    注意:
    HTML 特性是不区分大小写的。所以,当使用的不是字符串模版,camelCased (驼峰式) 命名的 prop 需要转换为相对应的 kebab-case (短横线隔开式) 命名

    结果如下:

    这样,每当父组件的数据变化时,该变化也会传导给子组件。

    字面量语法 vs 动态语法

    初学者常犯的一个错误是使用字面量语法传递数值:

    <!-- 传递了一个字符串 "1" -->
    <comp some-prop="1"></comp>

    因为它是一个字面 prop,它的值是字符串 “1” 而不是 number。如果想传递一个实际的 number,需要使用 v-bind,从而让它的值被当作 JavaScript 表达式计算:

    <!-- 传递实际的 number -->
    <comp v-bind:some-prop="1"></comp>

    单向数据流

    prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。这是为了防止子组件无意修改了父组件的状态——这会让应用的数据流难以理解。
    另外,每次父组件更新时,子组件的所有 prop 都会更新为最新值。这意味着你不应该在子组件内部改变 prop。如果你这么做了,Vue 会在控制台给出警告。
    为什么我们会有修改 prop 中数据的冲动呢?通常是这两种原因:
    prop 作为初始值传入后,子组件想把它当作局部数据来用;
    prop 作为初始值传入,由子组件处理成其它数据输出。
    对这两种原因,正确的应对方式是:

    • 定义一个局部变量,并用 prop 的值初始化它:
    props: ['initialCounter'],
    data: function () {
        return { counter: this.initialCounter }
    }
    • 定义一个计算属性,处理 prop 的值并返回:
      props: ['size'],
      computed: {
        normalizedSize: function () {
            return this.size.trim().toLowerCase()
        }
      }

      Prop验证

      我们可以为组件的 props 指定验证规格。如果传入的数据不符合规格,Vue 会发出警告。当组件给其他人使用时,这很有用。
      要指定验证规格,需要用对象的形式,而不能用字符串数组:
    Vue.component('example', {
    props: {
      // 基础类型检测 (`null` 意思是任何类型都可以)
      propA: Number,
      // 多种类型
      propB: [String, Number],
      // 必传且是字符串
      propC: {
        type: String,
        required: true
      },
      // 数字,有默认值
      propD: {
        type: Number,
        default: 100
      },
      // 数组/对象的默认值应当由一个工厂函数返回
      propE: {
        type: Object,
        default: function () {
          return { message: 'hello' }
        }
      },
      // 自定义验证函数
      propF: {
        validator: function (value) {
          return value > 10
        }
      }
    }
    })

    type 可以是下面原生构造器:

    • String
    • Number
    • Boolean
    • Function
    • Object
    • Array
    • Symbol
      type 也可以是一个自定义构造器函数,使用 instanceof 检测。
      当 prop 验证失败,Vue 会在抛出警告 (如果使用的是开发版本)。注意 props 会在组件示例创建之前进行校验,所以在 default 或 validator 函数里,诸如 data、computed 或 methods 的示例属性还无法使用。

    自定义事件

    我们知道,父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,应该怎样做?那就是自定义事件!

    使用v-on绑定自定义事件

    每个 Vue 实例都实现了事件接口 (Events interface),即:

    使用 $on(eventName) 监听事件
    使用 $emit(eventName) 触发事件

    请看下面的例子:

    <div id="counter-event-example">
        <p>{{total}}</p>
        <button-counter v-on:increment="incrementTotal"></button-counter>
        <button-counter v-on:increment="incrementTotal"></button-counter>
    </div>
     Vue.component('button-counter',{
            template:'<button v-on:click="increment">{{counter}}</button>',
            data:function () {
                return {
                    counter : 0
                }
            },
            methods:{
                increment:function () {
                    this.counter += 1
                    this.$emit('increment')
                }
            }
        })
        new Vue({
            el:'#counter-event-example',
            data:{
                total:0
            },
            methods:{
                incrementTotal:function () {
                    this.total += 1
                }
            }
        })

    运行结果如下

    在本例中,子组件已经和它外部完全解耦了。它所做的只是报告自己的内部事件,至于父组件是否关心则与它无关。留意到这一点很重要。

    给组件绑定原生事件

    有时候,你可能想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on。例如:

    <my-component v-on:click.native="doTheThing"></my-component>

    双线绑定的实现

    <div id="app">
        <switchbtn :result="result" @on-result-change="onResultChange"></switchbtn>
        <input type="button" value="change" @click="change">
    </div>
    Vue.component('switchbtn',{
        template:"<div @click='change'>{{myResult?'开':'关'}}</div>",
        props:['result'],
        data:function () {
            return {
                myResult:this.result
            }
        },
        watch:{
            result : function (val) {
                this.myResult = val;
            },
            myResult:function (val) {
                this.$emit("on-result-change", val);
            }
        },
        methods:{
            change:function () {
                this.myResult = !this.myResult;
            }
        }
    })
       var app =  new Vue({
            el:'#app',
            data:{
                result:true
            },
            methods:{
                change:function () {
                    this.result = !this.result;
                },
                onResultChange:function (val) {
                    this.result = val;
                }
            }
        })

    本文为原创,转载请注明出处
    上一节:Vue学习笔记入门篇——组件的使用
    返回目录
    下一节:Vue学习笔记入门篇——组件的内容分发(slot)

     
  • 相关阅读:
    1-27 awk 基本使用
    计算机网络(一)带宽
    CRC检错技术原理
    Wireshark漫谈(一)
    SQL字符串拼接
    MySQL学习笔记(二)
    MySQL学习笔记(一)
    Java 反射机制(二)
    Java 反射机制(一)
    Windows使用MySQL数据库管理系统中文乱码问题
  • 原文地址:https://www.cnblogs.com/ChainZhang/p/7148088.html
Copyright © 2011-2022 走看看