文章目录

  • 1.注册组件的基本步骤
    • 1.1 原始的创建方法
    • 1.2语法糖创建方法
  • 2.全局组件与局部组件
    • 2.1 全局组件
    • 2.2 局部组件
    • 2.3语法糖局部组件(最简写法)
  • 3. 父子组件
  • 4.组件中的动态数据
  • 5. 父子组件传值
    • 5.1 父传子
    • 5.2 子传父($emit)

1.注册组件的基本步骤

1.1 原始的创建方法

组件的使用分为个步骤:

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

下面按上面步骤实现简易组件:

<body><div class="container"><!-- 使用组件 my-comp --><my-comp></my-comp></div><script src="./vue.js"></script><script>// 1.创建组件构造器const comp = Vue.extend({template: `<div><p>这个世界只在乎你是否在到达了一定的高度,而不在乎你是踩在巨人的肩膀上上去的,还是踩在垃圾上上去的。</p><imgsrc="https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1689507601,2788277149&fm=26&gp=0.jpg"/></div>`,});// 2.注册组件Vue.component("my-comp", comp);var app = new Vue({el: ".container",data: {},methods: {},});</script></body>

组件能正常使用:

讲解:

  • Vue.extend()中参数是一个对象,里面有很多属性。这里只使用了template属性,定义了组件的模板,这就实现了创建组件构造器。
  • Vue.component(参数1,参数2):参数1定义的是使用组件的标签名,参数2传入的是第一步创建的组件构造器。
  • 直接使用第二部的参数1使用组件:例如< my-comp ></ my-comp >。

注意:组件一定要在vue实例中使用才有效,上面的container容器就是一个vue实例。

1.2语法糖创建方法

有了语法糖,我们这里就不需要使用组件构造器函数了。

<body><div class="container1"><!-- 使用组件 --><my-comp></my-comp></div><script src="./vue.js"></script><script>Vue.component("my-comp", {template: `<div><p>这个世界只在乎你是否在到达了一定的高度,而不在乎你是踩在巨人的肩膀上上去的,还是踩在垃圾上上去的。</p><imgsrc="https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=852066810,2008608422&fm=26&gp=0.jpg"/></div>`,});// vue实例1var app1 = new Vue({el: ".container1",});</script></body>

注意:直接使用Vue.component()来实现了组件创建,在Vue.component()内部调用了Vue.extend()。这是vue帮我们实现了。

在实际开发中,我们不是在Vue.component()的第二个参数来装载模板的,一个组件的元素并不像我们上面的那么简单,如果都写在参数中,就显得js代码特别臃肿。

开发中这样写:

 <body><template id="component"><div><p>这个世界只在乎你是否在到达了一定的高度,而不在乎你是踩在巨人的肩膀上上去的,还是踩在垃圾上上去的。</p><imgsrc="https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=852066810,2008608422&fm=26&gp=0.jpg"/></div></template><div class="container1"><!-- 使用组件 --><my-comp></my-comp></div><script src="./vue.js"></script><script>Vue.component("my-comp", {template: component});// vue实例1var app1 = new Vue({el: ".container1"});</script></body>

单独利用template标签来装载模板内容,然后设置id,在Vue.component()中使用这个id来创建组件。

以上就实现了简易的组件构建与使用。

2.全局组件与局部组件

全局组件与局部组件如何区分?

1.当组件在vue实例中注册时,则是局部组件,只能在该vue实例中使用。
2.当组件不是在实例中注册时,则是全局组件,在任意的vue实例都可以使用。

2.1 全局组件

我们在上面定义的my-comp组件就是全局组件,他可以在任意vue实例使用:

 <body><div class="container1"><!-- 使用组件 --><my-comp></my-comp></div><div class="container2"><!-- 使用组件 --><my-comp></my-comp></div><script src="./vue.js"></script><script>// 1.创建组件构造器const comp = Vue.extend({template: `<div><p>这个世界只在乎你是否在到达了一定的高度,而不在乎你是踩在巨人的肩膀上上去的,还是踩在垃圾上上去的。</p><imgsrc="https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=852066810,2008608422&fm=26&gp=0.jpg"/></div>`,});// 2.注册组件Vue.component("my-comp", comp);// vue实例1var app1 = new Vue({el: ".container1",data: {},methods: {},});// vue实例2var app2 = new Vue({el: ".container2",});</script></body>

上面定义了app1、app2两个vue实例,都使用了my-comp组件:

2.2 局部组件

在vue实例中注册组件:

 <body><div class="container1"><!-- 使用组件 --><my-comp></my-comp></div><div class="container2"><!-- 使用组件 --><my-comp></my-comp></div><script src="./vue.js"></script><script>// 1.创建组件构造器const comp = Vue.extend({template: `<div><p>这个世界只在乎你是否在到达了一定的高度,而不在乎你是踩在巨人的肩膀上上去的,还是踩在垃圾上上去的。</p><imgsrc="https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=852066810,2008608422&fm=26&gp=0.jpg"/></div>`,});// vue实例1var app1 = new Vue({el: ".container1",//  注册组件components: {"my-comp": comp,},});// vue实例2var app2 = new Vue({el: ".container2",});</script></body>

上面我只在app1中注册了组件:

很明显,app2实例没有注册组件,所以无法使用该组件,这就是局部组件。

2.3语法糖局部组件(最简写法)

在vue实例中注册组件使用的是components属性,key是组件标签名,value是组件构造器。

 <body><template id="component"><div><p>哈哈哈</p></div></template><div class="container1"><!-- 使用组件 --><my-component></my-component></div><script src="./vue.js"></script><script>// vue实例1var app1 = new Vue({el: ".container1",data: {},components: {// 在vue实例注册组件,形成父子关系,局部组件"my-component": {template: "#component",},},});</script></body>

3. 父子组件

简单来说:父子组件是嵌套关系,子组件被包含在父组件中。子组件在父组件中“注册”。

<body><template id="father"><div><p>这个世界只在乎你是否在到达了一定的高度,而不在乎你是踩在巨人的肩膀上上去的,还是踩在垃圾上上去的。</p><imgsrc="https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=852066810,2008608422&fm=26&gp=0.jpg"/><my-son></my-son></div></template><template id="son"><div><p>爱你哟</p><imgsrc="https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2346251443,2005527457&fm=26&gp=0.jpg"/></div></template><div class="container1"><!-- 使用组件 --><my-father></my-father></div><script src="./vue.js"></script><script>// 1.子组件构造器const son = Vue.extend({template: "#son",});// 2.父组件构造器const father = Vue.extend({template: "#father",// 注意:在父组件中注册子组件components: {"my-son": son,},});//  3.父组件注册Vue.component("my-father", father);// vue实例1var app1 = new Vue({el: ".container1",});</script></body>


注意

  • 子组件的“注册”是发生在父组件的构造器中利用components属性注册的。
  • 在父组件的template模板中引用子组件的标签。
  • 子组件是局部组件,只能在父组件中被引用。

特别注意:vue实例也是一个组件,而且是根组件,因此father组件也是根组件的子组件。

4.组件中的动态数据

什么是动态数据?

上面我们的数据是直接写死的,我们都知道标签元素中要想内容是动态的就使用胡子语法,属性想要是动态的就是用v-bind,这里我们重点关注元素标签中的数据是在何处定义以及如何定义。

<body><template id="component"><div><p>{{content}}</p><img v-bind:src="imgSrc" /></div></template><div class="container1"><!-- 使用组件 --><my-component></my-component></div><script src="./vue.js"></script><script>Vue.component("my-component", {template: "#component",data: function () {return {content:"这个世界只在乎你是否在到达了一定的高度,而不在乎你是踩在巨人的肩膀上上去的,还是踩在垃圾上上去的。",imgSrc:"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=852066810,2008608422&fm=26&gp=0.jpg",};},});// vue实例1var app1 = new Vue({el: ".container1",});</script></body>

正常显示:

注意这段代码:

 Vue.component("my-component", {template: "#component",data: function () {return {content:"这个世界只在乎你是否在到达了一定的高度,而不在乎你是踩在巨人的肩膀上上去的,还是踩在垃圾上上去的。",imgSrc:"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=852066810,2008608422&fm=26&gp=0.jpg",};},});

看到我们的data属性了吗?

特别注意:

  • 我们组件中要使用的数据不是在vue实例的data属性中定义的,而是在Vue.component()中利用data属性定义的。
  • 组件中data属性是一个函数,且返回一个对象,对象中包含组件想要的数据,而vue实例的data属性直接就是一个对象。

a.为什么组件的data属性必须是一个函数,再通过函数返回一个对象?

倘若我们data属性就是一个对象,会有“数据共享”的问题。
一个组件的封装可以使我们在很多地方复用组件,那么我们复用组件时,组件显示的内容往往是不一样的,假如data属性是一个对象,那么我们在复用组件时,都是显示同一组数据,从而无法实现显示不同内容的效果。

为什么会数据共享呢?

这得根据我们的内存来谈,对象是“栈堆存储”

即存储对象时,存储了变量名和一个地址,当我们调用变量时,是通过地址去找到相应的数据,同一个对象只有一个地址。因此,假如data属性是一个对象,则只要调用该对象,都是指向那个地址的同一数据,所以每个组件的data都是相同的。不符合我们实际。

举例说明:(非函数返回的对象)

 const obj = {name: "大白",age: 20,};let a = obj;let b = obj;let c = obj;console.log("修改前:", a.name, b.name, c.name);a.name = "小白";console.log("修改后:", a.name, b.name, c.name);


组件中的data属性如果不是通过函数返回对象,就会像上面的obj对象一样,无论复用多少组件,数据都一样,而且修改一个实例,其它实例的数据也同样被改变。这就是为什么组件中的data属性是一个函数返回的对象的原因。

b.为什么使用函数返回一个对象就不会数据共享呢?

我们应该知道函数是有自己独立的作用域的,每个函数实例都有一个独立的作用域。

看实例:

function test() {return {name: "大白",age: 22,};}let a = test();let b = test();let c = test();console.log("修改前:", a.name, b.name, c.name);a.name = "小白";console.log("修改后:", a.name, b.name, c.name);

a、b、c分别是test函数返回的对象,它们都有自己的独立作用域,所以在修改对象a时,它是不会影响b、c对象的属性值的。

5. 父子组件传值

在实际开发中,往往一些数据需要从上层传递到下层:

  • 比如在一个页面中,我们从服务器中请求到很多数据
  • 其中一部分数据,并非都是整个页面的大组件来显示的,而是需要里面的子组件进行显示
  • 这时,我们并不会在子组件再发送一次网络请求,而是让父组件将数据传递给子组件。

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

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

5.1 父传子

注意:vue实例是一个根组件,这里使用根组件与一个自定义组件形成父子组件。

props基本用法:

  • 在组件中,使用选项props来声明需要从父级接收到的数据。
  • props的值有两种方式:
    1. 字符串数组,数组中的字符串就是传递时在子组件使用数据的名称。
    2. 对象,对象可以设置传递时的类型,也可以设置默认值等。

a.字符串数组格式:

<body><template id="component"><div><p>{{content1}}</p><img v-bind:src="img1" /></div></template><div class="container1"><!-- 使用组件 --><my-componentv-bind:content1="content"v-bind:img1="imgSrc"></my-component></div><script src="./vue.js"></script><script>// vue实例1var app1 = new Vue({el: ".container1",data: {content:"这个世界只在乎你是否在到达了一定的高度,而不在乎你是踩在巨人的肩膀上上去的,还是踩在垃圾上上去的。",imgSrc:"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=852066810,2008608422&fm=26&gp=0.jpg",},components: {// 在vue实例注册组件,形成父子关系,局部组件"my-component": {template: "#component",props: ["content1", "img1"],},},});</script></body>

使用思路:

  • 在父组件的data属性中定义传给子组件的数据
data: {content:"这个世界只在乎你是否在到达了一定的高度,而不在乎你是踩在巨人的肩膀上上去的,还是踩在垃圾上上去的。",imgSrc:"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=852066810,2008608422&fm=26&gp=0.jpg",},
  • 注册子组件 中使用props属性使用数组 来定义在子组件使用数据的变量名
 components: {// 在vue实例注册组件,形成父子关系,局部组件"my-component": {template: "#component",props: ["content1", "img1"],},
  • 使用子组件标签中,使用动态绑定属性格式来传递数据,属性名是props属性数组中的变量名,父组件中的变量名
<my-componentv-bind:content1="content"v-bind:img1="imgSrc"
></my-component>
  • 在组件模板中使用动态绑定属性使用关于属性类型的数据,而标签内容则使用胡子语法
<template id="component"><div><p>{{content1}}</p><img v-bind:src="img1" /></div>
</template>

b.对象格式:

看代码:

   <body><template id="component"><div><p>{{content1}}</p><img v-bind:src="img1" /></div></template><div class="container1"><!-- 使用组件 --><my-componentv-bind:content1="content"v-bind:img1="imgSrc"></my-component></div><script src="./vue.js"></script><script>// vue实例1var app1 = new Vue({el: ".container1",data: {content:"这个世界只在乎你是否在到达了一定的高度,而不在乎你是踩在巨人的肩膀上上去的,还是踩在垃圾上上去的。",imgSrc:"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=852066810,2008608422&fm=26&gp=0.jpg",},components: {// 在vue实例注册组件,形成父子关系,局部组件"my-component": {template: "#component",props: {content1: {type: String,default: "我是默认值",},img1: {type: String,required: true,//必须,即务必给组件标签传值,否则报错},},},},});</script></body>


对象形式可设置的属性更多:

  • default:设置默认值
  • required:该数据是否是必须传给子组件

实例:

  <body><template id="component"><div><p>{{content1}}</p><img v-bind:src="img1" /></div></template><div class="container1"><!-- 使用组件 --><my-component v-bind:content1="content"></my-component></div><script src="./vue.js"></script><script>// vue实例1var app1 = new Vue({el: ".container1",data: {content:"这个世界只在乎你是否在到达了一定的高度,而不在乎你是踩在巨人的肩膀上上去的,还是踩在垃圾上上去的。",imgSrc:"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=852066810,2008608422&fm=26&gp=0.jpg",},components: {// 在vue实例注册组件,形成父子关系,局部组件"my-component": {template: "#component",props: {content1: {type: String,default: "我是默认值",},img1: {type: String,default:"https://dss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3743194253,688329487&fm=26&gp=0.jpg",required: true, //},},},},});</script></body>


认真看代码:

<my-component v-bind:content1="content"></my-component>

我们并没有给子组件传递img的属性值,它使用的是默认属性值,所以显示的是小黄熊,而且也在浏览器中报错。

5.2 子传父($emit)

实例:我们从子组件传给父组件,用户鼠标所点击图片对应的id号

<body><template id="component"><div><imgv-for="item in imgData"v-bind:src="item.src"v-on:click="returnData(item.id)"/></div></template><div class="container1"><!-- 使用组件 --><my-component v-on:son="getData"></my-component></div><script src="./vue.js"></script><script>// vue实例1var app1 = new Vue({el: ".container1",methods: {getData(id) {console.log(`点击了id==${id}的图片`);},},components: {// 在vue实例注册组件,形成父子关系,局部组件"my-component": {template: "#component",data: function () {return {imgData: [{id: 1,src:"https://dss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=121777500,749621780&fm=26&gp=0.jpg",},{id: 2,src:"https://dss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=272736508,2842806735&fm=26&gp=0.jpg",},{id: 3,src:"https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2064238529,2898748334&fm=26&gp=0.jpg",},],};},methods: {returnData(id) {//发射事件this.$emit("son", id);},},},},});</script></body>


在上面动图中,我分别点击了第三、第二、第一的图片,查看右边的检查,打印出id,已经正常获得子组件传过来的id。

这个例子中我直接在子组件定义数据,而不是父组件传给子组件数据:

data: function () {return {imgData: [{id: 1,src:"https://dss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=121777500,749621780&fm=26&gp=0.jpg",},{id: 2,src:"https://dss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=272736508,2842806735&fm=26&gp=0.jpg",},{id: 3,src:"https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2064238529,2898748334&fm=26&gp=0.jpg",},],};},

上面我们已经讲过,组件自定义数据是通过data属性定义一个函数,然后返回一个对象。

子传父思路:

  • 在子组件模板中定义好鼠标点击触发事件(或其它触发事件):(v-on:click=“returnData(item.id)”)
     <template id="component"><div><imgv-for="item in imgData"v-bind:src="item.src"v-on:click="returnData(item.id)"/></div></template>
  • 由于我们在子组件中触发函数,所以returnData()(自定义函数名)函数在子组件定义:
methods: {returnData(id) {//发射事件this.$emit("son", id);},},
  • 当鼠标点击触发上面函数,函数内部通过$emit来向父组件发射一个自定义函数和要发送的数据
  • 既然子组件发射函数,那么我们就需要监听接收它发射的函数,在子组件标签接收函数:(v-on:son)son是发射器自定义发射的变量名
    <div class="container1"><!-- 使用组件 --><my-component v-on:son="getData"></my-component></div>
  • getData()是在父组件自定义的处理来自子组件数据的函数:
 methods: {getData(id) {console.log(`点击了id==${id}的图片`);},},

注意:v-on:son="getData"的getData函数不能加括号以及写入参数,它会默认给父组件传递 来自this.$emit(“son”, 参数2)中的参数2,如果数据很复杂,可以使用对象或数组。

vue的组件化+父子组件的通信相关推荐

  1. 谈谈我对前端组件化中“组件”的理解,顺带写个Vue与React的demo

    谈谈我对前端组件化中"组件"的理解,顺带写个Vue与React的demo 前言 前端已经过了单兵作战的时代了,现在一个稍微复杂一点的项目都需要几个人协同开发,一个战略级别的APP的 ...

  2. 组件之间父子组件传值

    组件之间父子组件传值 在components新建父组件和子组件 在父组件里引入子组件 子组件接收父组件中的数据,用props 在子类props里定义接收的参数 在子组件标签上引用 然后在父组件写上准备 ...

  3. 【vue】组件以及父子组件通信

    目录: 一. 认识组件化 1.1. 什么是组件化? 1.2. Vue的组件化 二. 注册一个组件 2.1. 注册全局组件 2.2. 组件的名称 2.3. 注册局部组件 三. Vue的开发模式 3.1. ...

  4. 浏览器 调用 vue 组件_父子组件的通信

    在前端vue框架中,我们常常使用多个页面组成一个组件来创建项目.每个组件都有其自己的功能,基于组件的体系结构使开发和维护应用程序变得容易.在开发过程中,您可能会遇到需要与其他组件共享数据的情况.在本文 ...

  5. vue入门学习篇——父子组件通信

    Vue父子组件之间通信的原理 父组件:props down -- 父组件通过props向下传递数据给子组件 子组件:events up -- 子组件通过事件events向上传递数据给父组件 下面我们来 ...

  6. Vue(一)父子组件通信

    Vue 父子组件通信的三种方案 解决方法 使用props进行通信 使用事件分发机制(EventBus) $parent 属性 vuex方式 (后续补充) 结构图 一. props p r o p s ...

  7. Vue组件化开发--组件通信方式-父传子、子传父、非父子组件传值

    一.概述 以脚手架搭建的Vue项目为笔记背景. 如果将所有的代码逻辑全部放到一个组件中,代码是非常的臃肿和难以维护的. 并且在真实开发中,可能会有更多的内容和代码逻辑,对于扩展性和可维护性来说都是非常 ...

  8. Vue3(撩课学院)笔记02-创建组件,全局组件,局部组件,父子组件,组件标签化,组件的data数据共享,组件间通讯,props,父传子$ref,子传父$parent

    1.创建一个组件 首先要创建一个根组件进行挂载 再创建一个子组件,完成子组件的逻辑 子组件主要使用template模板来完成布局和逻辑 把子组件通过根组件.component的方法挂载到根组件上 &l ...

  9. Vue第二天学习总结—— Vue全家桶之组件化开发(组件化开发思想、组件注册、Vue调试工具用法、组件间数据交互传递、组件插槽、基于组件的案例——购物车)

    (一) 组件化开发思想 1. 现实中的组件化思想体现 组件化即是对某些可以进行复用的功能进行封装的标准化工作 标准:要想组件能够成功组合在一起,每个组件必须要有标准 分治:将不同的功能封装到不同的组件 ...

最新文章

  1. java 中策略模式_JAVA中的策略模式
  2. 我的jQuery动态表格插件二
  3. 浙大通讯与计算机网络离线作业,浙大2015年 通信与计算机网络离线作业
  4. 【ARM】ARM处理器寻址方式
  5. windowsXP用VNC客户端连接centos6桌面后再用tsclient连接windows2003/2008桌面
  6. java imap 标记已读,JavaMail通过IMAP和POP3接收未读以及设置已读邮件
  7. PHP 7.2 新功能介绍
  8. pytest十三:配置文件 pytest.ini
  9. MFC中控件的大小和位置自定义代码
  10. 【笔试/面试】—— Linux 查看 cpu 和内存使用情况
  11. 去除360安全卫士的广告弹窗(亲测有效)
  12. linux 命令两个冒号,为什么两个冒号的错误消息作为bash中的命令(::)有三个冒号,但是一个冒号没有输出?...
  13. socket can 编程
  14. 【Leetcode】1512. Number of Good Pairs
  15. 复旦大学机试题2019A斗牛
  16. MySQL-01.深入理解MySQL底层数据结构
  17. android 语音识别
  18. 新媒体推广:阅读量VS转化率,为何他更看重它?黎想
  19. oracle crm系统叫什么,目前市场上的CRM系统有哪些
  20. MySQL shell连接数据库

热门文章

  1. win10关闭windows defender 和 cortana
  2. 【渝粤教育】国家开放大学2018年秋季 0554-22T立体构成(一) 参考试题
  3. 绝版「游戏」保护计划!
  4. 未来第五代计算机的特点,第五代计算机指具有的新一代计算机,它具有推理,联想,判断,决策,学习等功能A. 自动功能 ......
  5. 如何下载某个网站的ico图标?
  6. java前锋,编程语言世界里的最佳“11人”
  7. 移动h5 图片字体等适配
  8. TOEFL听力2.28
  9. 【王喆-推荐系统】评估篇-(task1)离线评估方法
  10. 「默认程序」Mac如何修改自带的默认程序