zoukankan      html  css  js  c++  java
  • vue组件之属性Props

    组件的属性和事件

    父子组件之间的通信

    父子组件之间的通信就是 props down,events up,父组件通过 属性props向下传递数据给子组件,子组件通过 事件events 给父组件发送消息。
    比如,子组件需要某个数据,就在内部定义一个prop属性,然后父组件就像给html元素指定特性值一样,把自己的data属性传递给子组件的这个属性。
    而当子组件内部发生了什么事情的时候,就通过自定义事件来把这个事情涉及到的数据暴露出来,供父组件处理。

    <my-component v-bind:foo="baz" v-on:event-a="doThis(arg1,...arg2)"></my-component>
    

    如上代码,

    • foo是组件内部定义的一个prop属性,baz是父组件的一个data属性,
    • event-a是子组件定义的一个事件,doThis是父组件的一个方法

    过程就是这样:

    • 父组件把baz数据通过prop传递给子组件的foo;
    • 子组件内部得到foo的值,就可以进行相应的操作;
    • 当子组件内部发生了一些变化,希望父组件能知道时,就利用代码触发event-a事件,把一些数据发送出去
    • 父组件把这个事件处理器绑定为doThis方法,子组件发送的数据,就作为doThis方法的参数被传进来
    • 然后父组件就可以根据这些数据,进行相应的操作
    属性Props

    Vue组件通过props属性来声明一个自己的属性,然后父组件就可以往里面传递数据。

    Vue.component('mycomponent',{
        template: '<div>这是一个自定义组件,父组件传给我的内容是:{{myMessage}}</div>',
        props: ['myMessage'],
        data () {
          return {
            message: 'hello world'
          }
        }
      })
    

    然后调用该组件

    注意,由于HTML特性是不区分大小写的,所以传递属性值时,myMessage应该转换成 kebab-case (短横线隔开式)my-message="hello"。

    <div id="app">
        <mycomponent my-message="hello"></mycomponent>
    </div>
    
    v-bind绑定属性值

    v-bind绑定属性值的一个特性:一般情况下,使用v-bind给元素特性(attribute)传递值时,Vue会将""中的内容当做一个表达式。

    //比如
    <div attr="message">hello</div>
    

    上面这样,div元素的attr特性值就是message。

    <div v-bind:attr="message">hello</div>
    

    这里的message应该是Vue实例的data的一个属性,这样div元素的attr特性值就是message这个属性的值。

    之所以说是一般情况,是因为class和style特性并不是这样。用v-bind:class和class传入正常的类名,效果是一样的,因为对于这两个特性,Vue采用了合并而不是替换的原则。

    动态绑定特性值

    根据上面,想要把父组件的属性绑定到子组件,应该使用v-bind,这样,父组件中数据改变时能反映到子组件。
    注意,根据父组件传递给子组件的属性类型的不同,当在子组件中更改这个属性时,会有以下两种情况:

    • 当父组件传递的属性是引用类型时,在子组件中更改相应的属性会导致父组件相应属性的更改。
    <div id="app">
         <div>这是父组件的parentArray:{{parentArray}}</div>
         <my-component :child-array="parentArray"></my-component>
       </div>
       <script>
         Vue.component('my-component', {
           template: `
           <div>这是接收了父组件传递值的子组件的childArray: {{childArray}} <br>
               <button type="button" @click="changeArray">
               点击我改变父元素的parentArray</button>
             </div>`,
           props: ['childArray'],
           data () {
             return {
               counter: 1
             }
           },
           methods: {
             changeArray () {
               this.childArray.push(this.counter++)
             }
           }
         })
         new Vue({
           el: '#app',
           data: {
             parentArray: []
           }
         })
       </script>
    

    点击结果

    当父组件传递值为基本类型时,在子组件中更改这个属性会报错。正确的做法是,在父组件中绑定属性值时,加上.sync修饰符。

      <div id="app2">
            <div>这是父组件的parentArray:{{parent}}</div>
            <my-component-sync :child.sync="parent"></my-component-sync>
    
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
        <script>
            Vue.component('myComponentSync', {
                template: `<div>这是接收了父组件传递值的子组件的child: {{child}} <br>
                  <button type="button" @click="change">
                  点击我改变父元素的parent</button>
                </div>`,
                props: ['child'],
                data() {
                    return {
                        counter: this.child
                    }
                },
                methods: {
                    change() {
                        this.counter++
                        this.$emit('update:child', this.counter)
                    }
                }
            })
            new Vue({
                el: '#app2',
                data: {
                    parent: 0
                }
            })
        </script>
         
    

    点击结果如下图,去掉无法改变

    子组件希望对传入的prop进行操作

    一般来说,是不建议在子组件中对父组件中传递来的属性进行操作的。如果真的有这种需求,可以这样:

    1. 父组件传递了一个基本类型值,那么可以在子组件中创建一个新的属性,并以传递进来的值进行初始化,之后就可以操作这个新的属性了
    props: ['initialCounter'],
    data: function () {
      return { counter: this.initialCounter }
    }
    
    1. 父组件传递了一个引用类型值,为了避免更改父组件中相应的数据,最好是对引用类型进行复制。复杂的情况,肯定应该是深复制。
    给子组件传递正确类型的值

    同样是上面的原因,静态的给子组件的特性传递值,它都会把他当做一个字符串。

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

    子组件中,特性的值是字符串 "1" 而不是 number 1。如果想传递正确的数值,应该使用v-bind传递,这样就能把传递的值当做一个表达式来处理,而不是字符串。

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

    我们可以给组件的props属性添加验证,当传入的数据不符合要求时,Vue会发出警告。

    Vue.component('myComponent', {
      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 检测。
    // 自定义Person构造器
     function Person(name, age) {
        this.name = name
        this.age = age
      }
      Vue.component('my-component', {
        template: `<div>名字: {{ person-prop.name }}, 年龄: {{ person-prop.age }} </div>`,
        props: {
          person-prop: {
            type: Person     // 指定类型
          }
        }
      })
      new Vue({
        el: '#app2',
        data: {
          person: 2        // 传入Number类型会报错
        }
      })
    
    非Prop类型的属性

    也可以像在html标签中添加data-开头的自定义属性一样,给自定义组件添加任意的属性。而不仅限于data-*形式,这样做的话,Vue会把这个属性放在自定义组件的根元素上。一个自定义组件的模板只能有一个根元素。

    覆盖非Prop属性

    如果父组件向子组件的非prop属性传递了值,那么这个值会覆盖子组件模板中的特性。

    <div id="app3">
        <my-component2 att="helloParent"></my-component2>
    </div>
    <script>
      Vue.component('my-component2', {
        template: `<div att="helloChild">子组件原有的特性被覆盖了</div>`
      })
      new Vue({
        el: '#app3'
      })
    </script>
    

    上面渲染的结果是,div的att属性是helloParent。
    注意:前面已经提到过,覆盖原则对于class和style不适用,而是采用了合并(merge)的原则。

    <div id="app3">
        <my-component2 att="helloParent" class="class2" style="color: red;"></my-component2>
    </div>
    <script>
      Vue.component('my-component2', {
        template: `<div att="helloChild" class="class1" style="background: yellow;">子组件原有的特性被覆盖了</div>`
      })
      new Vue({
        el: '#app3'
      })
    </script>
    

    上面的渲染结果是,div的类名是class1 class2,行内样式是color:red; background:yellow;。

  • 相关阅读:
    Git 基础
    SharePoint 2013 对象模型操作"网站设置"菜单
    SharePoint 2013 隐藏部分Ribbon菜单
    SharePoint 2013 Designer系列之数据视图筛选
    SharePoint 2013 Designer系列之数据视图
    SharePoint 2013 Designer系列之自定义列表表单
    SharePoint 2013 设置自定义布局页
    SharePoint 2013 "通知我"功能简介
    SharePoint 2013 创建web应用程序报错"This page can’t be displayed"
    SharePoint 禁用本地回环的两个方法
  • 原文地址:https://www.cnblogs.com/wentutu/p/10930399.html
Copyright © 2011-2022 走看看