vue组件化

  • 什么是组件化
    将一个完整的页面分成很多个组件,每个组件用于实现页面的一个功能块,每一个组件又可以细分。
  • 组件化基本使用
    • 组件化使用三个步骤:
      1.创建组件构造器
      2.注册组件
      3.使用组件


      组件化使用步骤
<div id="app">
  <!--  3.使用组件-->
  <my-cpn></my-cpn>
</div>
<script>
  // 用``定义字符串可以换行
  // 1.创建组件构造器对象
  const cpnC = Vue.extend({
    template: `
      <div>
        <h2>我是标题1</h2>
        <p>我是内容111</p>
        <p>我是内容222</p>
      </div>`
  })
  // 2.注册组件
  Vue.component('my-cpn', cpnC);

  const app = new Vue({
    el: '#app',
    data: {
      
    }
  })
</script>
  • 全局组件
    全局组件:
// 注册组件(全局组件),可以在多个vue实例下使用
Vue.component('my-cpn', cpnC);

局部组件:

  const app = new Vue({
    el: '#app',
    data: {

    },
    // 注册局部组件,只能在该vue实例中使用
    components: {
      my_cpn: cpnC
    }
  })
  • 父组件和子组件
<div id="app">
  <my_cpn2></my_cpn2>
</div>
<script>
  // 创建第一个组件构造器(子组件)
  const cpn_c1 = Vue.extend({
    template:`
      <div>
        <h2>标题1</h2>
        <p>内容1</p>
      </div>`
  })
  // 创建第二个组件构造器(父组件)
  const cpn_c2 = Vue.extend({
    template:`
      <div>
        <h2>标题2</h2>
        <p>内容2</p>
        <my_cpn1></my_cpn1>
      </div>`,
    // 在组件2中注册组件1,就可以在组件2中使用组件1
    components: {
      my_cpn1: cpn_c1
    }
  })

  const app = new Vue({
    el: '#app',
    data: {

    },
    components: {
      my_cpn2: cpn_c2
    }
  })
</script>
  • 注册组件语法糖和组件模板抽离写法
<div id="app">
  <my-cpn1></my-cpn1>
  <my_cpn2></my_cpn2>
</div>

<template id="my-cpn">
  <div>
    <h2>我是标题1</h2>
    <p>我是内容111</p>
  </div>
</template>
<script>
  // 注册全局组件
  Vue.component('my-cpn1', {
    template: '#my-cpn'
  });
  const app = new Vue({
    el: '#app',
    data: {

    },
    // 注册局部组件,只能在该vue中使用
    components: {
      'my_cpn2': {
        template: '#my-cpn'
      }
    }
  })
</script>
  • 组件中的data和方法
<div id="app">
  <my_cpn></my_cpn>
  <my_cpn></my_cpn>
</div>

<template id="cpn">
  <div>
    <h2>当前计数:{{counter}}</h2>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
  </div>
</template>

<script>
  const app = new Vue({
    el: '#app',
    components: {
      'my_cpn': {
        template: '#cpn',
        // 存放组件的数据
        data() {
          return {
            counter: 0
          }
        },
        methods: {
          increment() {
            this.counter ++;
          },
          decrement() {
            this.counter --;
          }
        }
      }
    }
  })
</script>
  • 组件通信
    1.父传子props
    父子组件通信

    在组件中使用props来声明需要从父级接收的数据
    props的值有两种方式:
    方式一:字符串数组,数组中的字符串就是传递时的名称
    方式二:对象,对象可以设置传递时的类型,也可以设置默认值等
  function Person(name){
    this.name = name
  }
  Vue.component('my-conmponent', {
    props: {
      // 基础类型检查(null匹配任何类型)
      itemA: Number,
      // 多个可能的类型
      itemB: [String, Number],
      // 必须传的
      itemC: {
        type: String,
        required: true
      },
      // 有默认值的
      itemD: {
        type: String,
        default: 'ABC'
      },
      // 有默认值的数组
      itemE: {
        type: Array,
        default() {
          return [];
        }
      },
      // 有默认值的对象
      itemF: {
        type: Object,
        default() {
          return {message: 'hello'}
        }
      },
      // 自定义验证函数
      itemG: {
        validator(value) {
          return ['success','warning','danger'].indexOf(value) !== -1
        }
      },
      // 验证自定义类型
      itemH: Preson
    }
  })

举例:

<div id="app">
  <my_cpn v-bind:cmovies="movies" :msg="message"></my_cpn>
</div>
<template id="cpn">
  <ul>
    <li v-for="item in cmovies">{{item}}</li>
  </ul>
  <h3>{{msg}}</h3>
</template>
<script>
  const my_cpn = {
    template: '#cpn',
    // props: ['cmovies', 'msg']
    props: {
      // 1.类型限制
      // cmovies: Array,
      // msg: String
      // 2.提供默认值
      msg: {
        type:String,
        default: 'hi',
        // 必传值(要使用my_cpn组件,必须传msg)
        required: true
      },
      cmovies: {
        type: Array,
        default() {
          return []
        }
      }
    }
  }
  const app = new Vue({
    el: '#app',
    data: {
      movies: ['送你一朵小红花', '金刚川', '少年的你'],
      message: 'hello'
    },
    components: {
      my_cpn
    }
  })
</script>

2.子传父

<div id="app">
  <my_cpn @item-click="in_cpn_click"></my_cpn>
</div>

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

<script>
  // 子组件
  const my_cpn = {
    template: '#cpn',
    data() {
      return {
        categories: [
          {id: 1, name: '热门推荐'},
          {id: 2, name: '手机数码'},
          {id: 3, name: '美妆护肤'}
        ]
      }
    },
    methods: {
      btnClick(item) {
        console.log(item.name + '被点击');
        // 告诉父组件被点击的是哪一个item
        // 发射事件
        this.$emit('item-click', item)
      }
    }
  }

  // 父组件
  const app = new Vue({
    el: '#app',
    components: {
      my_cpn
    },
    methods: {
      in_cpn_click(item) {
        console.log('子组件中的' + item.name + '被点击');
      }
    }
  })
</script>
  • 组件访问
    1.父访问子
  <div id="app">
    <cpn></cpn>
    <!-- refs方式需要在使用组件时,添加ref属性 -->
    <cpn ref="cpn2"></cpn>
    <button @click="btnClick()">按钮</button>
  </div>

  <template id="cpn">
    <div>我是子组件</div>
  </template>
  <script>
    
    const app = new Vue({
      el: '#app',
      data: {
        message: 'hello world'
      },
      methods: {
        btnClick() {
          // $children较少用,一般用refs
          // console.log(this.$children);
          // this.$children[0].showMessage()
          // console.log(this.$children[0].name)

          console.log(this.$refs.cpn2.name);
          this.$refs.cpn2.showMessage();
        }
      },
      components: {
        cpn: {
          template: '#cpn',
          data() {
            return {
              name: 'Naruto'
            }
          },
          methods: {
            showMessage() {
              console.log('showMessage');
            }
          },
        }
      }
    })
  </script>

2.子访问父
不建议使用

  • 组件的插槽
    组件的插槽是为了让我们封装的组件更具扩展性,让使用者可以决定组件内部的一些内容到底展示什么。
    将共性抽取到组件中,将不同暴露为插槽。可以让使用者根据自己的需求,决定插槽中插入的内容。
  <div id="app">
    <cpn><button>按钮</button></cpn>
    <cpn><span>哈哈哈</span></cpn>
    <cpn></cpn>
  </div>

  <template id="cpn">
    <div>
      <h2>我是组件标题</h2>
      <p>我是组件内容</p>
      <!-- 插槽即预留一些空间,使用时可以在组件中插入其它标签 -->
      <!-- <slot></slot> -->
      <!-- 如果使用时没有插入标签,则默认显示插槽中的标签 -->
      <slot><button>插槽默认按钮</button></slot>
    </div>
  </template>

  <script>
    const app = new Vue({
      el: '#app',
      data: {
        message: 'hello world'
      },
      components: {
        cpn: {
          template: '#cpn'
        }
      }
    })
  </script>
插槽
  • 具名插槽
  <div id="app">
    <!-- 替换没有name的slot -->
    <cpn><span>span</span></cpn>
    <cpn>
      <template v-slot:left>
        <span>替换左边slot</span>
      </template>
      <template v-slot:right>
        <span>替换右边内容</span>
      </template>
    </cpn>
  </div>

  <template id="cpn">
    <div>
      <h2>组件标题</h2>
      <p>组件内容</p>
      <slot name="left">左边</slot>
      <slot name="center">中间</slot>
      <slot name="right">右边</slot>
      <slot></slot>
    </div>
  </template>

  <script>
    const app = new Vue({
      el: '#app',
      components: {
        cpn: {
          template: '#cpn'
        }
      }
    })
  </script>
具名插槽
  • 作用域插槽
    父组件替换插槽的标签,但是内容由子组件来提供。
  <!-- 父组件替换插槽的标签,但是内容由子组件来提供 -->
  <div id="app">
    <cpn></cpn>
    <cpn>
      <!-- 获取子组件中的pLanguages -->
      <template v-slot:default="slotProps">
      <span v-for="item in slotProps.languages">{{item}} - </span>
      </template>
    </cpn>
  </div>

  <template id="cpn">
    <div>
      <!-- 将子组件的数据传给父组件 -->
      <slot :languages="pLanguages">
        <ul>
          <li v-for="item in pLanguages">{{item}}</li>
        </ul>
      </slot>
    </div>
  </template>
  <script>
    const app = new Vue({
      el: '#app',
      data: {

      },
      components: {
        cpn: {
          template: '#cpn',
          data() {
            return {
              pLanguages: ['JavaScript', 'Java', 'Python', 'c++', 'go', 'Swift']
            }
          }
        }
      }
    })
  </script>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,367评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,959评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,750评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,226评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,252评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,975评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,592评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,497评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,027评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,147评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,274评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,953评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,623评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,143评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,260评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,607评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,271评论 2 358

推荐阅读更多精彩内容

  • Vue的组件化 经过两天的学习,现在终于来到了组件化开发的环节,Vue的组件化是很重要的一个点,一定要认真学习!!...
    waigo阅读 364评论 0 1
  • 认识组件 组件化开发: ​ 将一个完成的页面,划分成一个个的组件,最终由一个个组件来完成整个页面你的开发,这个...
    cj_jax阅读 186评论 0 1
  • Vue 组件官网:https://cn.vuejs.org/v2/guide/components.html 组件...
    璎珞纨澜阅读 454评论 0 1
  • 前言 在工作中经常会用到Vue,包括也会用到很多重要的点例如组件化等等,现在也想对于之前的应用和学习做一个小小的总...
    羊驼驼驼驼阅读 440评论 0 2
  • 一、组件注册使用 组件使用步骤 (全局组件)①创建组件构造器 ②注册组件 ③使用组件 在vue实例对象管理的 域 ...
    shaoyf阅读 184评论 0 1