Vue-组件

一、组件的两种使用方法

二、使用props传递数据

三、单向数据流

四、组件中的命名方式

五、数据验证

六、组件通信

七、slot(插槽)

八、动态组件

Vue中的组件

  • 组件是可复用的Vue实例
  • 命名组件推荐使用小写字母,用-连接
  • 在组件定义中,除了template,其它选项还有:data,methods,computed
  • 组件定义中的data必须是一个方法

一、组件的两种使用方法

全局注册

<my-component></my-component>
Vue.component('my-component',{
   template: '<div>组件内容</div>'
})

局部注册

var app = new Vue({
   el:'#app',
   components:{
       ''my-components:{
            template:'<div>组件内容</div>'
        }
     }  
})

二、使用props传递数据

这边的props采用数组方式

父组件向子组件传递数据

v-bin动态绑定父组件传的内容

<div id="app" style="300px;height:200px;border:2px solid skyblue">
  <child-component msg="我是父组件的内容"></child-component>
  <hr>
 <!--  v-bind进行动态数据动态绑定 将input中的sth传给子组件 -->
  <input type="text" v-model="dadmsg">
  <bind-component :sth="dadmsg"></bind-component>
</div>
var app = new Vue({
  el: '#app',
  data: {
    dadmsg: 'happy'
  },
  components: {
    'child-component': {
      props: ['msg'],
      template: '<div>{{msg}}</div>'
    },
    'bind-component': {
      props: ['sth'],
      template: '<div>{{sth}}</div>'
    }
  }
})

在组件中使用props来从父组件接收参数,在props中的属性,都可以在组件中直接使用。

三、单向数据流

概念理解:通过props传递数据是单向的,父组件变化时数据会传给子组件,但是反过来不行。

目的:是将父子组件解稿,避免子组件修改无意间修改了父组件的状态。

两种改变prop的情况的应用场景

  • 父组件传递初始值,子组件可以将它作为初始值保存起来,在自己的作用域下可以随意进行修改;
  • 将传递进来的数据作为初始值进行保存
  1. 注册组件
  2. 将父组件的数据传递进来,并在子组件中props接收
  3. 将传递进来的数据通过初始值保存起来
<div id='app'>
  <child-component msg='今天也要努力啊'></child-component>
</div>
let app = new Vue({
  el: '#app',
  components: {
    'child-component': {
      props: ['msg'],
      template: '<div>{{count}}</div>',
      data() {
        return {
          count: this.msg
        }
      }
    }
  }
})

prop作为需要被转变的原始值传入,用计算属性对其再次进行计算

  1. 注册组件
  2. 将父组件的数据传递进来,并在子组件中使用props接收
  3. 将传递进来的数据通过计算属性进行重新计算并渲染到页面
<div id="app">
  <input type="text" v-model="width">
  <width-component :width='width'></width-component>
</div>
let app = new Vue({
  el: "#app",
  data: {
     0
  },
  components: {
    'width-component': {
      props: ['width'],
      template: '<div :style="style"></div>',
      computed: {
        style() {
          return {
             this.width + 'px',
            background: 'red',
            height: '30px'
          }
        }
      }
    }
  }
})

四、组件中的命名方式

camelCased (驼峰式)

kebab­case(短横线命名)

  • 组件中的html中、父组件给子组件传递数据,必须使用短横线命名。  (a-bc √    aBc ×)
  • 在props中,短横线命名驼峰命名都可以。
  • 在template中,必须使用驼峰命名,短横线会报错。
  • 在data中,使用this.xxx时,必须使用驼峰命名,短横线会报错。
  • 组件的命名,短横线命名驼峰命名都可以。

五、数据验证

这边的props采用对象方式

可验证的类型:Number  String  Boolean  Array  Object  Function  自定义

<div id="app">
  <style-component :a='a' :b='b' :c='c' :d='d' :e='e' :g='g'></style-component>
</div>
let app = new Vue({
  el: '#app',
  data: {
    a: 1,
    b: '2',
    c: '', //空字符串,就取默认的true
    d: [111, 222, 333],
    e: console.log(),
    g: 3
  },
  components: {
    'styleComponent': {
      props: {
        //数字类型
        a: {
          type: Number,
          required: true //必传
        },
        //字符串类型
        b: {
          type: [String, Number]
        },
        //布尔类型
        c: {
          type: Boolean,
          default: true //默认值
        },
        //数组或对象  默认值是函数形式返回
        d: {
          type: Array,
          default: function() {
            return []
          }
        },
        //函数类型
        e: {
          type: Function
        },
        //自定义一个函数
        g: {
          validator: function(value) {
            return value < 10
          }
        }

      },
      template: '<div>{{a}}--{{b}}--{{c}}--{{d}}--{{g}}</div>'
    }
  }
})

六 、组件通信

子组件向父组件传递数据

——给父组件添加自定义事件

——子组件通过$emit触发事件

  1. 给父组件添加自定义事件
  2. 子组件$emit传出数据
  3. 自定义事件函数接收数据参数并赋值,渲染
<div id="app">
  <p>您的账户余额为{{num}}</p>
  <btn-component @change='change'></btn-component>
</div>
new Vue({
  el: '#app',
  data: {
    num: 3000
  },
  methods: {
    change(value) {
      this.num = value
    }
  },
  components: {
    'btn-component': {
      template: '<div>
                    <button @click="hangle_ad">+1000</button> 
                    <button @click="hangle_re">-1000</button> 
                </div>',
      data() {
        return {
          count: 3000
        }
      },
      methods: {
        hangle_ad() {
          this.count += 1000
          this.$emit('change', this.count)
        },
        hangle_re() {
          this.count -= 1000
          this.$emit('change', this.count)
        }
      }
    }
  }
})

——v-model代替自定义事件

v-model实质背后做了两个操作

  1. v-bind绑定一个value属性  (父组件要接收一个value值)
  2. v-on指令给当前元素绑定input事件  (子组件在有新的value值得时候要触发一个input事件)

所以上面那个银行存款的demo可以改为

<div id="app">
  <p>您的账户余额为{{num}}</p>
  <btn-component v-model='num'></btn-component>  这边改啦!!
</div>
new Vue({
  el: '#app',
  data: {
    num: 3000
  },                               //父组件没有自定义函数啦!!
  components: {
    'btn-component': {
      template: '<div>
                    <button @click="hangle_ad">+1000</button> 
                    <button @click="hangle_re">-1000</button> 
                </div>',
      data() {
        return {
          count: 3000
        }
      },
      methods: {
        hangle_ad() {
          this.count += 1000
          this.$emit('input', this.count)  //这边改啦!!
        },
        hangle_re() {
          this.count -= 1000
          this.$emit('input', this.count)   //这边改啦!!
        }
      }
    }
  }
})        

非父组件之间的通信

两个非父子关系的组件进行通信,可以使用一个空的Vue实例作为中央事件总线(中介)

<div id="app">
  <ahandle></ahandle>
  <bhandle></bhandle>
</div>
var app = new Vue({
  el: '#app',
  data: {
    bus: new Vue() //bus中介
  },
  components: {
    'ahandle': {
      template: '<div><button @click="aclick">点击向b组件传递数据</button></div>',
      data() {
        return {
          aaa: '我是来自a组件的内容'
        }
      },
      methods: {
        aclick() { //a组件创建事件,供b组件监听   由bus中介$emit提交
          this.$root.bus.$emit('givetob', this.aaa)
        }
      }
    },
    'bhandle': {
      template: '<div>我是b组件</div>',
      created() { //b组件监听a组件创建的事件   由bus中介$on监听
        this.$root.bus.$on('givetob', function(value) { //这里的value就是a组件传进来的this.aaa
          alert(value)
        })
      }
    }
  }
})

父链  $.parent

<div id="app">
<btn-component></btn-component>--{{msg}}
</div>
let app = new Vue({
  el: '#app',
  data: {
    msg: '我是父组件,我现在没有内容'
  },
  components: {
    'btn-component': {
      template: '<button @click="changeFather">点击修改父组件中的内容</button>',
      methods: {
        changeFather() {
          this.$parent.msg = '我现在有内容啦'
        }
      }
    }
  }
})

子链 $children

vue提供索引:$ref

<div id="app">
  <button @click='getchild'>点击父组件按钮获取a组件内容</button>
  <a-component ref='a'></a-component>   添加索引ref
  <b-component ref='b'></b-component>
  {{msg}}
</div>
let app = new Vue({
  el: '#app',
  data: {
    msg: '子组件数据未获得'
  },
  methods: {
    getchild() {
      this.msg = this.$refs.a.msg  //获取a组件的内容 ---refs
    }
  },
  components: {
    'a-component': {
      template: '<span></span>',
      data() {
        return {
          msg: '我是a组件中的内容'
        }
      }
    },
    'b-component': {
      template: '<span></span>',
      data() {
        return {
          msg: '我是b组件中的内容'
        }
      }
    }
  }
})

七、slot(插槽)

使用slot进行分发内容

编译的作用域

父组件模板的内容在父组件作用域中编译;

子组件模板的内容在子组件作用域内编译。

插槽的用法

混合父组件的内容与子组件自己的模板

  • 单个插槽
<div id="app">
  <slotcomponent>
    <p>父组件插入到子组件的内容——我把子组件的slot替换掉啦</p>
  </slotcomponent>
</div>
new Vue({
  el: '#app',
  components: {
    'slotcomponent': {
      template: '<slot>父组件没有插入内容没有内容就显示这个</slot>'
    }
  }
})
  • 具名插槽
    <div id="app">
        <name-component>
            <h2 slot="header">标题</h2>
            <p>内容1</p>
            <p>内容2</p>
            <p slot="footer">底部</p>
        </name-component>
    </div>
 let app = new Vue({
            el: '#app',
            components: {
                'name-component': {
                    template: '<div> 
                        <div class="header"> 
                            <slot name="header"></slot> 
                        </div> 
                        <div class="container"> 
                            <slot></slot> 
                        </div> 
                        <div class="footer"> 
                            <slot name="footer"></slot> 
                        </div> 
                    </div>'
                }
            }
        })
  • 作用域插槽
<div id="app">
  <mycomponent>
    <p slot='aaa' slot-scope='child'>
      {{child.text}} name拿不到
    </p>
  </mycomponent>
</div>
let app = new Vue({
  el: '#app',
  components: {
    'mycomponent': {
      template: '<div>
      <slot text="我是子组件插槽的内容" name="aaa"></slot>
      </div>'
    }
  }
})

*2.5.0之前都是用template中写,渲染的是template中的内容

<div id="app">
  <mycomponent>
    <template slot='aaa' slot-scope='child'>
      {{child.text}} name拿不到
    </template>
  </mycomponent>
</div>

访问slot

this.$slot.插槽名称

在具名插槽的例子前提下添加代码

......
components:{
......
mounted(){
     var header = this.$slots.header
     console.log(header) //此处拿到的是虚拟节点
     var headerin = this.$slots.header[0].elm.innerText
     console.log(headerin)
     }
}

八、动态组件

使用Vue提供的component元素,动态挂载不同的组件

使用is特性来实现

代码

待补充待补充待补充......

原文地址:https://www.cnblogs.com/BUBU-Sourire/p/11429016.html