精通Vue(5):组件

360影视 欧美动漫 2025-09-16 08:25 2

摘要:结果又把这个代码写了一遍,如果后面再有呢?原样又写一遍。重复多了,我们就会发现,这片代码外观不变,只是数据不同,那么我们就把这片代码抽象成组件,只要提供给它不同的数据即可,如下所示:

这几天事情比较多,所以没有更新了。

这篇研究组件的问题,我们写慢点,争取将一个问题说清楚。

写下作者的理解,比如你要显示某个用户的信息,代码如下:

姓名:bob年龄:20地址:广州天河区

没有问题,过了一会,又要显示一个人的信息:

姓名:bob年龄:20地址:广州天河区.........姓名:peter年龄:23地址:广州黄浦区

结果又把这个代码写了一遍,如果后面再有呢?原样又写一遍。重复多了,我们就会发现,这片代码外观不变,只是数据不同,那么我们就把这片代码抽象成组件,只要提供给它不同的数据即可,如下所示:

我们抽象出来一个组件名为user,在vue2.x的版本中,要求必须有一个根标签,所以作者这里添加了一个红色div表示根标签。那么在使用的时候就变成下面这样:

............

视觉上清爽多了。

除了这些,它还有很多优点,随着学习会一步步加深了解。

使用vue.extend创建,代码如下:

姓名:{{name}}年龄:{{age}}地址:{{address}}//创建一个组件的构造函数var user = Vue.extend({template: '#user',data {return {}},props: {name: String,age: Number,address: String}})//全局注册Vue.component('user', user)

我们看这个组件,就像一个独立的模块,有自己专有的模板,数据,方法等,和Vue这个构造几乎一样,如果我们能将它们等价类比也是可以的。

组件创建好之后,我们就可以拿来使用它,如下所示:

组件就像是一个独立模块,五脏俱全,在当前例子中,这个组件唯一欠缺的就是不知道数据是多少。举个通俗的例子,我们买了一台做馒头的机器,它可以自己执行各个流程不需要外界干扰,但唯一缺的就是加工原料,假如把原料输给它之后,后面我们就什么都不管了。那么如何把原料送给它呢?这就是组件通信的问题。

我想把一个人的信息发给user组件让它显示出来,怎么做呢?这个问题我们需要好好的研究一下,但是我们不看组件,而是先看C的函数调用,比如C语言定义一个函数:

void foo(int a,char b,bool c){ //操作 printf("%d,%c,%d",a,b,c);}

我们知道,函数声明就像是一个契约,它表示这个函数能接收多少个参数,而且每个参数是什么类型,图示如下:

函数foo如果能说话的话,它就会说:我有三个参数(也就是三个入口),请传给我三个数据,类型分别是int,char,bool。我们看到这个声明,马上就明白怎么发数据给它。

回到组件,它和这个原理几乎相同。站在组件这一方,它肯定会想,我怎么能让别人知道传什么数据给我呢?这是首要解决的问题。其次,站在调用方的角度,比如说我们,怎么知道传哪些数据给它呢?那么组件就想,干脆我也学C语言好了,做个声明。

组件的“函数声明”就是props。

//创建一个组件的构造函数var user = Vue.extend({template: '#user',data {return {}},props: {name: String,age: Number,address: String}})

在组件的props字段中,定义了三个参数,然后,这个组件可能会在文档上给我们暴露,让我们知道要传这三个数据给它。

那么数据怎么传呢?有很多种方式,但是在当前这个例子中只有一个地方可以传,就是在组件的属性上,如下:

这种方式是最符合正常思维的,因此我们作为第一种方式特别拿出来举例。

这是其一。

其二,我们传的基本都是数据,不会出现style,class等相关的内容,因为这个标签是被替换掉的,它不是真正的HTML标签。因此组件就认为我们传过来的都是数据。

首先,组件在内部已经声明好了三个“变量”,然后我们把数据送进来。但是它和C语言的函数有下面不同:

1、数据传送没有顺序的区分,比如我们写成这样没有问题。

2、数据的个数不受限制(这个后面讨论)。

所以我们是类比C语言的函数,而不是说它俩是一样的。数据进来之后组件会查看一下,比如第一个我们传送的是name="bob",那么组件就看看自己肚子里面有没有名叫name的变量(或者说prop),如果正好有,然后再看看类型是否匹配?就像C语言的int,char一样,这个我们也在后面再展开说。假如一切都通过检查,那么内部的name就得到了值bob。其余以此类推。

所以prop是以名字做为唯一标识的,最终结果如下:

和C语言函数不同的是,组件prop的数据类型检查似乎没有那么严格,因为我们都知道JS的数据是乱套的,串转值、值转串之类的自动转换经常发生,所以我们就不能苛求它像C那样做严格的检查,比如:

明明组件定义的age类型为Number,但是我们传给它的却是一个字符串,结果它只能警告一下。所以prop的数据类型定义只是要求我们尽量遵守,我们需要知道这个事情。

再比如,还有一种情况:

//创建一个组件的构造函数var user = Vue.extend({template: '#user',data {return {}},props: ['name','age','address']})

这个props的定义只有一个名字,更省略了,言外之意就是不管啥数据只要名字一样就可以了,也就是说连数据类型也不检查了。

当然,除了这个,还有其它各种用法,大家可以自行看文档,我们在这里主要是讨论原理,只要理解原理,其它的用法就能懂,所以不再多写。

比如我们除了传prop,还多传了一个phone:

组件并不会因为它不是prop而不接收,而是照单接收。但是做为attrs来存储了,如下所示:

因此,我们需要理解什么是attrs。

attrs就是标签的属性,也就是说凡是标签上面挂着的都算是属性,比如:

在这个标签上挂着的所有xx=yy都算是属性,还包括有名无值的xx。

因此,组件在接收数据的时候,会把传过来的数据全部看作是attrs(我的理解),只是这些属性中恰好有几个和它内部定义的props的名字是一样的,于是组件拿到值之后顺带过滤掉了,而没有过滤的自然就存储到组件的attrs中,这样逻辑上能通顺。

下面我们先看最终的结果:

可以看到它把多余的属性设置到组件的根标签上了。如果不想让它挂上去可以吗?也是可以的,组件提供一个下面的属性:

//创建一个组件的构造函数var user = Vue.extend({template: '#user',data {return {}},inheritAttrs:false,props: {name: String,age: Number,address: String}})

将inheritAttrs设置为false,那么就不再设置HTML标签的attributes。

根据上面的分析,我们知道如果数据没有被prop处理,就会转到组件的$attrs中,假如我们把这个$attrs绑定着继续往下传,就可以将祖先的数据一直往下传,就像穿透了组件一样。

分析:数据传下来时,先被props过滤,剩下的存储到this.$attrs,接着我们把$attrs继续往下传,下方组件依然先props过滤,接着再存储....以此类推。这样就实现了一个简单的组件数据通信。

{{name}}{{age}}{{address}}点我

//1.定义手机组件var phone = Vue.extend({template: '

{{phone}}

',props: {phone: String}})Vue.component('phone', phone)//2.定义user组件var user = Vue.extend({template: '#user',data {return {}},inheritAttrs: false,props: {name: String,age: Number,address: String},methods: {handleClick {console.log(this.$attrs)}}})Vue.component('user', user)//3.定义根实例var vm = new Vue({el: '#app',data {return {}}})

分析:在组件中使用

组件,并且使用v-bind="$attrs",直接将整个$attrs绑进去了。在vue中如果v-bind绑定的是对象,就表示把该对象内部的字段挨个绑定,这样我们就将$attrs整个的传给phone组件。

不知不觉又写了一大篇,其实1/10都没写到。太长读者会很累,这篇我们就截止到这里。有兴趣的同学可以跟着动手做一遍。

在本篇中,重点说明了props是怎么来的,以及如何传数据的,顺带实现了一个简单的通信。

来源:恋爱脑一点号

相关推荐