Day19——组件化开发

一. 回顾

前面学习了Day18——v-model双向绑定,今天学习一下组件化开发

二. 组件化开发

2.1 什么是组件化?

一个完整的页面可以分成多个组件,每一个组件实现特定的功能,而每个组件可以再进行细分,如下:
在这里插入图片描述

2.2 使用组件的3个步骤

  1. 创建组件构造器(使用Vue.extend()
const cpn = Vue.extend({
  template: `
    xxxxxxx
  `
});

extend()方法要求传入一个参数,这个参数是一个对象,所以用{}。这个对象通常要求定义一个template属性,template属性的内容就是我们要在DOM渲染出来的东西。

  1. 注册组件(使用Vue.component()
Vue.component('xxx', 组件构造器)

component()方法将刚才的组件构造器注册为一个组件,并且给他起一个组件的标签名称。

  1. 使用组件。组件必须挂在某个vue实例下,否则它不会生效。也就是要在vue管理的区域内使用组件。

2.3 使用组件的简单例子

<body>
<div id="app">
  <!--3. 使用组件-->
  <my-cpn></my-cpn>
  <my-cpn></my-cpn>
  <my-cpn></my-cpn>
  <my-cpn></my-cpn>

</div>
<script src="../js/vue.js"></script>
<script>

  //1. 创建组件构造器对象
  //符号`与单引号,双引号的作用一样,但是它能支持不加‘+’换行
  const cpnC = Vue.extend({
    template: ` 
    <div>
      <h2>我是标题</h2>
      <p>我是内容,哈哈哈哈哈</p>
      <p>我是内容,呵呵呵呵呵呵</p>
    </div>`,
  });

  //2.注册组件
  Vue.component('my-cpn', cpnC);

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
    }
  })
</script>
</body>

2.4 全局组件和局部组件

在vue实例外注册的组件是全局组件,在vue实例内注册的是局部组件。全局组件在所有vue实例管理的区域都能使用,而局部组件只能在 组件注册的vue实例 管理的区域使用。

开发中常用局部组件,而且一般只有一个实例,没有多个实例。

例子:

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

<div id="app2">
  <cpn></cpn>
</div>
<script src="../js/vue.js"></script>
<script>

  //1. 创建组件构造器
  const cpnC = Vue.extend({
    template: `
      <div>
        <h2>我是标题</h2>
        <p>我是内容,哈哈哈哈啊哈</p>
      </div>
    `
  })

  //2. 注册组件(全局组件:可以在多个Vue实例下面使用)
  // Vue.component('cpn', cpnC);

  //怎么注册局部组件呢?答:在vue实例里面注册就是局部组件

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
    },
    components: {
      cpn: cpnC,//在vue实例里面注册的是局部组件
    }
  })

  const app2 = new Vue({
    el: '#app2'
  })
</script>
</body>

2.5 父组件和子组件

在组件构造器里面注册的组件是子组件。 如下:

 const cpnC2 = Vue.extend({
    template: `
      <div>
        <h2>我是标题2</h2>
        <p>我是内容,呵呵呵呵</p>
        <cpn1></cpn1>
      </div>
    `,
    components:{
      cpn1: cpnC1, //组件构造器1在组件构造器2里面注册,cpn1是子组件
    }
  })

例子:

<body>
<div id="app">
  <cpn2></cpn2>
</div>
<script src="../js/vue.js"></script>
<script>

  //创建第一个组件构造器(子组件)
  const cpnC1 = Vue.extend({
    template: `
      <div>
        <h2>我是标题1</h2>
        <p>我是内容,哈哈哈哈</p>
      </div>
    `
  })

  //创建第二个组件构造器(父组件)
  const cpnC2 = Vue.extend({
    template: `
      <div>
        <h2>我是标题2</h2>
        <p>我是内容,呵呵呵呵</p>
        <cpn1></cpn1>
      </div>
    `,
    components:{
      cpn1: cpnC1, //组件构造器1在组件构造器2里面注册,cpn1是子组件
    }
  })

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
    },
    components: {
      cpn2: cpnC2, //组件构造器2在Vue实例里面注册
    }
  })
</script>
</body>

2.6 组件的语法糖形式

实际是将组件构造器传入的对象,作为注册组件的第二个参数。如下:{}中的就是组件构造器本来的内容

Vue.component('cpn1', {
    template: `
      <div>
        <h2>我是标题1</h2>
        <p>我是内容,哈哈哈哈</p>
      </div>
    `
  })

2.7 组件模板的分离写法

2.7.1 使用<script>标签的写法

通过<script>标签,type属性必须是text/x-template,id属性是必须要有的,如下:

<script type="text/x-template" id="cpn">
  <div>
    <h2>我是标题</h2>
    <p>我是内容,哈哈哈哈</p>
  </div>
</script>

定义好模板后,通过id选择器在注册组件里面建立联系

2.7.2 通过<template>标签的写法

id属性是必须要有的,如下:

<template id="cpn2">
  <div>
    <h2>我是标题</h2>
    <p>我是内容,哈哈哈哈</p>
  </div>
</template>

定义好模板后,通过id选择器在注册组件里面建立联系

2.7.3 例子

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

<!-- 1. 通过script标签,type必须是text/x-template-->
<script type="text/x-template" id="cpn">
  <div>
    <h2>我是标题</h2>
    <p>我是内容,哈哈哈哈</p>
  </div>
</script>

<!-- 2. 通过template标签-->
<template id="cpn2">
  <div>
    <h2>我是标题</h2>
    <p>我是内容,哈哈哈哈</p>
  </div>
</template>

<script src="../js/vue.js"></script>
<script>

  //1. 注册一个全局组件
  Vue.component('cpn', {
    template: '#cpn',
  })
  Vue.component('cpn2', {
      template: '#cpn2',
    })

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
    }
  })
</script>
</body>

2.8 组件中的数据存放问题

组件是一个单独功能模块的封装,因此它应该要有属于自己的数据。组件不能直接访问vue实例里面的data数据,那么组件的数据应该有自己保存的地方。那就是保存在Vue.component中的data中,data必须是一个函数,而且返回的必须是一个对象

总结:组件的data存放在Vue.component()的data中,而且data必须是一个函数,返回的必须是一个对象。

2.8.1 为什么组件的data必须是函数?

因为组件可以复用,如果data不是一个函数而是一个对象,那么一个组件在多处地方都有使用,在任意一处地方修改了某些值,那么其他地方组件的值也被修改了。而我们进行组件复用,希望的就是每个组件都有自己的数据,其他地方与我相同的组件不能修改我的数据。

图例解释:
在这里插入图片描述
在这里插入图片描述
总结:组件的data是一个函数,那么每次使用组件的数据,返回的都是属于自己的数据,其他与我相同的组件也不能修改我的数据

2.9 父组件向子组件通信

2.9.1 储备知识

目前使用的是局部组件,它在vue实例里组件,所以vue实例是父组件。父组件向子组件通信,关键是在子组件里面使用props属性。props可以是数组(即props: [ ]),也可以是对象(即props: { })。如果是对象,可以做类型限制。

总结:父组件向子组件通信,只需在子组件里面使用props属性,定义变量或者对象 接收父组件传来的值

2.9.2 例子

<body>
<div id="app">
  <!--<cpn :cmovies="movies" :cmessage="message"></cpn>-->
  <cpn :cmovies="movies" :cmessage="message"></cpn>
</div>

<template id="cpn">
  <div>
    <ul>
      <li v-for="item in cmovies">{{item}}</li>
    </ul>
    <p>{{cmessage}}</p>
  </div>
</template>

<script src="../js/vue.js"></script>
<script>

  const cpn = {
    template: '#cpn',
    //props是数组类型
    // props: ['cmovies', 'cmessage'],
    //props是对象类型
    props: {
      //可以做类型限制
      // cmovies: Array,
      // cmessage: String,
      cmovies: {
        type: Array,
        default(){ //如果变量的类型是一个对象或者数组时,默认值必须是一个函数
          return []
        }
      },
      cmessage: {
        type: String,
        default: 'aaaaaaaa', //如果没有传cmessage,而又要在dom层显示cmessage,那么默认值就是aaaaaaaa
        required: true, //表示用此组件的时候,必须要把cmessage变量传进来
      }
    }
  }

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
      movies: ['海王', '海贼王', '海尔兄弟'],
    },
    components: {
      cpn
    }
  })
</script>
</body>

2.9.3 props中的驼峰标识

props不支持驼峰标识,在props中定义了驼峰标识格式的变量(比如cInfo),绑定的时候需要使用c-info

总结:在没有用脚手架写vue代码的情况下,尽量不要用驼峰标识书写props属性相关的代码。可以用‘-’、‘_'隔开。

例子:

<body>
<div id="app">
  <!-- props不支持驼峰标识,在props中定义了驼峰标识格式的变量(比如cInfo),绑定的时候需要使用c-info-->
  <cpn :c-info="info" :child-my-message="message"></cpn>
</div>

<template id="cpn">
  <div>
    <h2>{{cInfo}}</h2>
    <h2>{{childMyMessage}}</h2>
  </div>
</template>
<script src="../js/vue.js"></script>
<script>

  const cpn = {
    template: '#cpn',
    props: {
      cInfo: {
        type: Object,
        default() {
          return [];
        }
      },
      childMyMessage: {
        type: String,
        default: '',
      }
    }
  };

  const app = new Vue({
    el: '#app',
    data: {
      info: {
        name: 'why',
        age: 12,
        height: 1.88,
      },
      message: 'aaaaa',
    },
    components: {
      cpn,
    }
  })
</script>
</body>

2.10 子组件传给父组件

2.10.1 情景

有些时候在子组件发生的事件,要传给父组件,父组件进而根据传来的信息做出对应的处理(比如请求服务器某些数据,然后返回给子组件)

2.10.2 子传父的步骤

  1. 子组件监听发生在自己身上的事件
  2. 子组件定义方法,发射(使用this.$emit(‘事件名(自定义,不要使用驼峰标识)’);) 发生的事件 给父组件
  3. 父组件监听子组件传来的事件(注意不要使用驼峰标识),定义处理事件的方法

2.10.3 例子

<body>

<!--父组件模板-->
<div id="app">
  <!--注意,这里监听的事件不能使用驼峰命名,不支持-->
  <!--处理事件的方法默认会将子组件传来的参数接收,不需要在父组件这里显式定义参数接收-->
  <cpn @item-click="cpnClick"></cpn>
</div>

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

<script src="../js/vue.js"></script>
<script>

  /**
   * 子组件向父组件传递信息:
   * 1.子组件监听发生在自己身上的事件
   * 2.子组件定义方法,发射(使用this.$emit('事件名(自定义,不要使用驼峰标识)');) 发生的事件 给父组件
   * 3.父组件监听子组件传来的事件(注意不要使用驼峰标识),定义处理事件的方法
   *
   * @type {{template: string, data(): {categories: [{name: string, id: string}, {name: string, id: string}, {name: string, id: string}, {name: string, id: string}]}, methods: {btnClick(*): void}}}
   */

  //1.子组件
  const cpn = {
    template: '#cpn',
    data(){
      return {
        categories: [
          {id: 'aaa', name: '热门推荐'},
          {id: 'bbb', name: '手机数码'},
          {id: 'ccc', name: '家用家电'},
          {id: 'ddd', name: '电脑办公'},
        ],
      }
    },
    methods: {
      btnClick(item){
        this.$emit('item-click', item);//this.$emit是发送事件, 第二个参数传递给父组件使用
      }
    }
  }

  //2.父组件
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
    },
    components: {
      cpn,
    },
    methods: {
      cpnClick(item){
        console.log(item);
      }
    }
  })
</script>
</body>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值