共同学习Vue.js --- Vue组件化


Vue组件化

什么是组件化

如果我们将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及扩展.

但是如果我们将一个页面拆分为一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就变得非常容易了.如下图所示:

组件化图

Vue组件化思想

组件化是Vue.js中的重要思想:

  • 它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用
  • 任何的应用都会被抽象成一颗组件树
    如下图:
    在这里插入图片描述

组件化思想的应用:

  • 有了组件化的思想,在开发中就要充分的利用它
  • 尽可能的将页面拆分成一个个小的, 可复用的组件
  • 这样让我们的代码更加方面组织和管理,并且扩展性也更强

注册组件的基本步骤

组件的使用分成三个步骤:

  • 创建组件构造器
  • 注册组件
  • 使用组件

在这里插入图片描述

注册组件步骤解析:

  • Vue.extend():

    • 调用Vue.extend()创建的是一个组件构造器
    • 通常在创建组件构造器时,传入template代表我们自定义组件的模板
    • 该模板就是在使用到组件的地方,要显示的HTML代码
  • Vue.component():

    • 调用Vue.component()是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称
    • 所以需要传递两个参数: 1.注册组件的标签名 2.组件构造器
  • 组件必须挂载在某个Vue实例下,否则不会生效

    如图在这里插入图片描述

全局组件 和 局部组件

当我们通过调用Vue.component()注册组件时,组件是全局的.

这意味着该组件可以在任意Vue实例下使用.

如果我们注册的组件时挂载在某个实例中,那么就是一个局部组件

<script>
  // 1.创建组件构造器
  const comC = Vue.extend({
    template:`
    <div>
    <h2>我是标题</h2>
    <p>我是内容...</p>
	</div>`
  });
  // 2.注册组件(全局组件,意味着可以在多个Vue实例下使用)
  // Vue.component('cmp',comC);
  const app = new Vue({
    el: '#app', // 用于挂载要管理的元素
    components: {
      // 注册局部组件
      cmp: comC
    }
  })
</script>

父组件和子组件

子组件和父组件的基本使用

<script>
  // 创建组件构造器(子组件)
  const comp1 = Vue.extend({
    template: `
    <div>
      <h2>我是子组件</h2>
      <p>我的内容1.....</p>
    </div>`
  });
  // 创建组件构造器(父组件)
  const comp2 = Vue.extend({
    template: `
    <div>
      <h2>我是父组件</h2>
      <p>我的内容2.....</p>
    <cmp1></cmp1>
    </div>`,
    components: {
      cmp1: comp1
    }
  })
  const app = new Vue({
    el: '#app', // 用于挂载要管理的元素
    components: {
      cmp2: comp2
    }
  })
</script>

注册组件语法糖

Vue为了简化这个过程,提供了注册的语法糖

主要是省去了调用Vue.extend()的步骤,而是可以直接使用一个对象来代替

<script>
  // 注册组件语法糖
  // const cmpC = Vue.extend({
  //   template: `
  //   <div>
  //     <h2>标题</h2>
  //     <p>内容....</p>
  //   </div>`
  // });
  // 注册组件
  Vue.component('cnp',{
    template: `
    <div>
      <h2>全局组件</h2>
      <p>内容....</p>
    </div>`
  });
  const app = new Vue({
    el: '#app', // 用于挂载要管理的元素
    components: {
      'cmp': {
        template: `
    <div>
      <h2>局部组件</h2>
      <p>内容....</p>
    </div>`
      }
    }
  })
</script>

模板的分离

Vue提供了两种方案来定义HTML模板内容:

  • 使用<script type="text/x-template> 标签

  • 使用标签

<body>
<div id="app">
  <com-script></com-script>
</div>
<!--1.script标签模板-->
<script type="text/x-template" id="scriptId">
  <div>
    <h3>我是script标签模板</h3>
  </div>
</script>
<!--2.template标签模板-->
<template id="templateId">
  <div>
    <h3>我是template标签模板</h3>
  </div>
</template>
<script src="../js/vue.js" ></script>
<script>
  // Vue.component('comScript',{
  //   template: "#scriptId"
  // })
  const app = new Vue({
    el: '#app', // 用于挂载要管理的元素
    components: {
      // 'comScript': {
      //   template: "#scriptId"
      // },
      'comScript': {
        template: "#templateId"
      }
    }
  })
</script>
</body>

组件访问

组件可以访问Vue实例数据吗?
组件是一个单独功能模块的封装;Vue组件不能访问Vue实例数据,这个模块有属于自己的HTML模板,也应该有属于自己的数据data.

Vue可以通过两种方法访问组件

  • $children
  • $refs

点击按钮去访问第二个组件的name(通过$refs.xxx.xxxx去访问组件中的具体属性)

<body>
<div id="app">
  <conp></conp>
  <conp ref="xxx"></conp>
  <conp></conp>
  <button @click="butClick">按钮</button>
</div>
<template id="conpId">
  <div>
    我是子组件
  </div>
</template>
<script src="../js/vue.js" ></script>
<script>
  const conp = {
    template: '#conpId',
    data() {
      return {
        name: '我是子组件name'
      }
    },
    methods: {
      showMessage() {
        console.log('我是子组件方法');
      }
    }
  }
  const app = new Vue({
    el: '#app', // 用于挂载要管理的元素
    components: {
      conp
    },
    methods: {
      butClick() {
        // $refs =>对象类型,默认为一个空对象,ref='xxx'
        console.log(this.$refs.xxx.name);
      }
    }
  })
</script>
</body>

在这里插入图片描述
通过点击按钮访问整个组件元素使用$children:
在这里插入图片描述

组件数据的存放

组件自己的数据存放在哪里?

  • 组件对象也有一个data属性
  • 只是这个data属性必须是一个函数,不能为对象
  • 而且这个函数返回一个对象,对象内部保存着数据
 Vue.component('comPon',{
    template: '#cnp',
    data() {
      return {
        title: '组件'
      }
    }
  })

父子组件的通信

在开发中,有一些数据需要从上层传递到下层

  • 如在一个页面中,我们从服务器请求到了很多的数据
  • 其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示
  • 这个时候,并不会让子组件再次发送一个网路请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)

如何进行父子组件间的通信?

  • 通过Props 向子组件传递数据
  • 通过事件向父组件发送消息

在这里插入图片描述

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

props基本使用

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

props的值有两种方式:

  • 方式一:字符串数组,数组中的字符串就是传递的名称
  • 方式二: 对象,对象可以设置传递时的类型,也可以设置默认值等
<body>
<div id="app">
  <obj :cmovies="movies" :cmessage="message"></obj>
</div>
<template id="tempId">
  <div>
    <ul>
      <li v-for="item in cmovies">{{item}}</li>
    </ul>
    <h2>{{cmessage}}</h2>
  </div>
</template>
<script src="../js/vue.js" ></script>
<script>
  const obj = {
    template: "#tempId",
    // 一、数组写法
    // props: ['cmovies','cmessage'],
    // 二、对象写法,当需要对props进行类型等验证时,需用对象写法
    props: {
      // 1. 类型限制
      // cmovies: Array,
      // cmessage: String
      // 2. 提供一些默认值
      cmovies: {
        type: Array,
        // 类型是对象或者数组时,默认值必须是一个函数
        default() {
          return []
        }
      },
      cmessage: {
        type: String,
        default: 'Vue defalut', // 当在#app元素下div中,如果没有上下赋值会给默认值
        required: true   // 当为true时,cmessage属性必填的
      }
    },
    data() {
      return {}
    }

  }
  const app = new Vue({
    el: '#app', // 用于挂载要管理的元素
    data: { // 定义数据
      message: 'Hello Vue',
      movies: ['海贼王','进击的巨人','海尔兄弟','熊大']
    },
    components: {
      obj
    }
  })
</script>
</body>
子组件访问父组件
  1. 访问父组件 $parent
  2. 访问根组件 $root
<body>
<div id="app">
  <cnpp></cnpp>
</div>
<template id="tteId">
  <div>
    <h3>我是tteId子组件</h3>
    <button @click="cnppClick">按钮</button>
  </div>
</template>
<script src="../js/vue.js" ></script>
<script>
  const cnpp = {
    template : '#tteId',
    methods: {
      cnppClick() {
        // 1. 访问父组件 $parent
        console.log(this.$parent.message);
        // 2. 访问根组件 $root
        console.log(this.$root.message);
      }
    }
  }
  const app = new Vue({
    el: '#app', // 用于挂载要管理的元素
    data: { // 定义数据
      message: 'Hello Vue'
    },
    components: {
      cnpp
    }
  })
</script>
</body>

子级传向父级(自定义事件)

什么时候需要使用自定义事件呢?

  • 当子组件需要向父组件传递数据时,就要用到自定义事件
  • v-on不仅仅可以用于监听DOM事件,也可以用于组件键的自定义事件

自定义事件的流程

  • 在子组件中,通过$emit() 来触发事件
  • 在父组件中,通过v-on来监听子组件事件
<body>
<div id="app">
  <!-- 第二步:监听自定义事件 -->
  <cnp @item-click="cnpClick"></cnp>
</div>
<template id="temId">
  <div>
    <button v-for="item in categories" @click="butClick(item)">{{item.name}}</button>
  </div>
</template>
<script src="../js/vue.js" ></script>
<script>
  const cnp = {
    template: '#temId',
    data() {
      return {
        categories: [
          {id:'aaa',name:'热门推荐'},
          {id:'bbb',name:'手机数码'},
          {id:'ccc',name:'家用家电'},
          {id:'ddd',name:'电脑办公'},
        ]
      }
    },
    methods: {
      butClick(item) {
        // 第一步:发射自定义事件
        this.$emit('item-click',item)
      }
    }
  }
  const app = new Vue({
    el: '#app', // 用于挂载要管理的元素
    components: {
      cnp
    },
    methods: {
      cnpClick(item) {
        console.log("子组件传父组件的数据:",item);
      }
    }
  })
</script>
</body>

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值