vue组件化

1. 注册组件的基本步骤

1.创建组件构造器

const myComponent = Vue.extend({
  template:`
    

组件标题

我是子组件

`
})

调用 Vue.extend 创建的是一个组件构造器,在创建组件构造器时,传入template 代表自定义组件模板。

2.注册组件

Vue.component('cpn',myComponent)

调用Vue.component 将刚才的组件构造器注册为一个组件,并起一个组件标签名称。

3.使用组件

<div id="app">
  <cpn><cpn/>
div>

2. 全局组件和局部组件

全局组件

当通过 Vue.component 注册组件时,组件的注册是全局的,也就是这个组件可以在任意的Vue 实例下使用。

局部组件

当在某一具体的 vue 实例中设置 注册组件 这一步骤时,此时,该组件为局部组件

const vm = new Vue({
  el:"#app",
  data:{
  },
  components:{
    'cpn':myComponent
}

3. 注册组件的简写

注册组件的简写省去了调用 Vue.extend 的步骤,而是直接可以使用一个对象来代替。

注册全局组件的简写:

<script>
  Vue.component('cpn',{
    template:`
      

组件标题

我是子组件

`
})
script>

注册局部组件的简写:

const vm = new Vue({
  el:"#app",
  data:{
  },
  components:{
    'cpn':{
      template:`
          

组件标题

我是子组件

`
}

抽离模板:

<template id="cpn">
    <div>
        <h2>组件标题h2>
        <p>我是子组件p>
      div>
template>
<script>
const vm = new Vue({
  el:"#app",
  data:{
  },
  components:{
    'cpn':{
      template:'#cpn'
    }

4. 组件数据的存放

组件是不可以访问vue 实例中的数据的,Vue 组件应该有保存自己数据的地方。

组件对象也有一个 data 属性,也可以有 methods 属性。这个data必须是一个函数,而且返回一个对象,对象内部保存着数据。

components:{
    'cpn':{
      template:'#cpn',
      data(){
        return {
          message: '我是子组件中的message'
        }

为什么 data 是一个函数

如果不是一个函数,那么 Vue 会直接报错。

其次,Vue 可以让每个组件对象都返回一个新的对象,因为如果是同一个对象的话,多个组件使用时会互相影响。比如该组件为加减操作,使用多个组件时,假如 data 不是函数,那么所有组件共用同一个data,其中一个加减后,其余的组件都会被影响。

5. 父子组件及通信

父组件和子组件的注册方式如下:

<script>
  const vm = new Vue({
    el:"#app",
    components:{
      'parent-cpn':{
        template: '#parent-cpn',
        components:{
          'child-cpn':{
            template:'#child-cpn'
          }
script>   

子组件是不能引用父组件或者 Vue 实例中的数据的。在一个页面中,通常由大组件获取数据,直接让大组件将数据传递给小组件,并不会让小组件去发送网络请求。

Vue 实例和子组件的通通信 和 父组件和子组件的通信 过程是一样的。

5.1 父级向子级传递

在组件中,使用 props 来声明需要从父组件接收到的数据。

props 的值有两种方式:

方式一:字符串数组,数组中的字符串就是传递时的名称。

方式二:对象,对象可以设置传递时的类型,也可以设置默认值等。

数组方式

1.在子组件的标签中,添加父组件需要传递的数据。

<cpn :childmessage="message" :childmsg="msg">cpn>

冒号后面是在子组件中定义的数据名称,等于的内容是父组件中要传递的变量名称。

注意:父组件向子祖传传递数据时,冒号后面定义的名称不能采用驼峰写法。

2.当在标签中添加后,需要去子组件中添加 props。props 的内容即为标签中定义的名称。

props:['childmessage','childmsg']

3.在子组件的模板中使用props中的数据。

<template id="cpn">
  <div>
    <h2>{{childmessage}}h2>
    <h3>{{ childmsg }}h3>
  div>
template>

注意:当模板中有多个标签时,需要用div将多个标签包起来。

对象方式

当需要对props进行类型等验证时,需要采用对象的写法。

类型验证支持 String、Number、Boolean、Array、Object、Date、Function、Symbol,当有自定义构造函数时,也支持自定义类型。

简单的类型检测:

props:{
  childmessage:String
}

检测多种数据类型:

props:{
  childmessage:[String,Number]
}

提供默认值,此时,就算父子间没有向子组件传递childmessage,此childmessage也会生效,则显示设置的默认值:

props:{
  childmessage:{
    type: String,
    default:'aaaaa' 
  }
}

必填的字符串,当设置了required,那么这个数据是必传的,否则会报错

props:{
  childmessage:{
    type: String,
    required:true
  }
}
5.2 子级向父级传递

当子组件需要向父组件传递数据时,要要用到自定义事件。

v-on不仅仅可以用于监听DOM事件,也可以用于组件间的自定义事件。

自定义事件流程:在子组件中,通过$emit()来触发事件。在父组件中,通过v-on来监听子组件事件。

下面以 子组件点击按钮传值给父组件为例说明。

1.在子组件中定义数据,该数据为数组类型。

data() {
  return {
    list:[{id:'18271',name:'热门推荐'},{id:'18272',name:'手机数码'},{id:'18273',name:'电脑办公'}]
  }

2.在模板中遍历数据,并且为每一项注册点击事件,并将每一项的 item 传给该事件。

<template id="cpn">
  <div>
    <button v-for="item in list" @click="cpnclick(item)">{{item.name}}button>
  div>
template>

3.在子组件中定义cpnclick 函数,通过$emit()来触发事件,并将 item 传给emitclick() 。

cpnclick(item){
  this.$emit('emitclick',item)
}

4.在应用的子组件标签中添加如下内容,通过v-on来监听子组件事件。

<cpn @emitclick="btnclick">cpn>

5.在父组件中获取传递的内容

btnclick(item){
  console.log(item);
}

6. 父子组件的访问

有时候我们需要父组件直接访问子组件,子组件直接访问父组件,或者是子组件访问跟组件。

父组件访问子组件:使用 c h i l d r e n 或 children或 childrenrefs。

子组件访问父组件:使用$parent

$children

this.$children 是一个数组类型,它包含所有子组件对象。

父组件中定义三个子组件

<template id="parent-cpn">
  <div>
    <h2>我是父组件h2>
    <child-cpn>child-cpn>
    <child-cpn>child-cpn>
    <child-cpn>child-cpn>
    <button @click="pbtnclick">访问子组件button>
  div>
template>
pbtnclick(){
    console.log(this.$children);// [VueComponent, VueComponent, VueComponent]
}

打印出来的是三个子组件的内容,可以使用 this.$children[0] 这种方式来访问各个组件。

$children的缺陷:

通过$children访问子组件时,是一个数组类型,访问其中的子组件必须通过索引值。

但是当子组件过多,我们需要拿到其中一个时,往往不能确定它的索引值,甚至还可能会发生变化。

$refs

有时候,我们想明确获取其中一个特定的组件,这个时候就可以使用$refs。

$refs的使用:

首先,通过ref给某一个子组件绑定一个特定的ID。

<template id="parent-cpn">
  <div>
    <h2>我是父组件h2>
    <child-cpn ref="child1">child-cpn>
    <child-cpn ref="child2">child-cpn>
    <child-cpn ref="child3">child-cpn>
    <button @click="pbtnclick">访问子组件button>
  div>
template>

然后,通过this.$refs.ID就可以访问到该组件了。

pbtnclick(){
    console.log(this.$refs.child2.message);
}

$parent

在子组件中直接访问父组件,可以通过 this.$parent 后面可以追加父组件中的信息。

注意事项:

尽管在Vue开发中,我们允许通过$parent来访问父组件,但是在真实开发中尽量不要这样做。

子组件应该尽量避免直接访问父组件的数据,因为这样耦合度太高了。

如果我们将子组件放在另外一个组件之内,很可能该父组件没有对应的属性,往往会引起问题。

另外,更不好做的是通过$parent直接修改父组件的状态,那么父组件中的状态将变得飘忽不定,很不利于我的调试和维护。

7. slot 插槽

7.1 编译作用域

父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。

在使用的时候,整个组件的使用过程是相当于在父组件中出现的。

那么他的作用域就是父组件,使用的属性也是属于父组件的属性。

因此,isShow使用的是Vue实例中的属性,而不是子组件的属性。

7.2 为什么使用 slot

组件的插槽也是为了让我们封装的组件更加具有扩展性。让使用者可以决定组件内部的一些内容到底展示什么。也就是,组件有些地方不能被写死,而是可以让使用者根据自己的需求,决定插槽中插入什么内容

7.3 slot 的基本使用

在子组件中,使用特殊的元素就可以为子组件开启一个插槽。

<div id="app">
  <cpn><button>哈哈哈button>cpn>
div>
<template id="cpn">
  <div>
      <slot><span>我是插槽默认内容span>slot>
  div>
template>

使用组件时,即可为插槽填写内容,button 将会覆盖默认的 span。

7.4 具名插槽

当子组件的功能复杂时,子组件的插槽可能并非是一个。需要分别为插槽设置内容。此时,就需要给插槽起一个名字。

<div id="app">
  <cpn><button slot="center">中间button>cpn>
div>
<template id="cpn">
  <div>
    <slot name="left">左边slot>
    <slot name="center">中间slot>
    <slot name="right">右边slot>
  div> 
template>

为每一个插槽起名之后,就可以针对性的插入内容,并且不会影响其他插槽。

7.5 作用域插槽

子组件中有一些数据,希望在父组件中分别以不同形式展示,比如列表,横向,或者直接展示一个数组。

在父组件使用子组件时,可以拿到这些数据,然后就可以对这些数据进行操作了。

例如子组件中的数据

data() {
  return {
    list:['java','c++','python','go']
  }
}

在子组件的插槽中将数据传给data,data名称可以任意取

<template id="cpn">
  <div>
    <slot :data="list">slot>
  div> 
template>

在使用子组件时,从子组件拿到数据,通过

<div id="app">
  <cpn>
    <template slot-scope="slotProps">
      <ul>
        <li v-for="item in slotProps.data">
          {{ item }}
        li>
      ul>
    template>
  cpn>
  <cpn>
    <template slot-scope="slotProps">
      <button v-for="item in slotProps.data">{{item}} button>
    template>
  cpn>
div>

更多Vue组件内容见官网 Vue组件

你可能感兴趣的:(vue,vue组件化)