深入理解vue组件
栏目: JavaScript · 发布时间: 5年前
内容简介:在在运用组件的时候,会出现想在这个标签内使用组件,但这个标签内并不支持的情况,如下我们看到
在 html
语法中, table
标签内就必须是 tr
标签, tr
标签下就必须是 td
标签, ul
标签下就必须是li标签 等等 标签间的嵌套规则
在运用组件的时候,会出现想在这个标签内使用组件,但这个标签内并不支持的情况,如下
<div id="app"> <table> <tbody> <tr> <td>this is a row</td> </tr> <tr> <td>this is a row</td> </tr> <tr> <td>this is a row</td> </tr> </tbody> </table> </div> 复制代码
我们看到 tr
标签这一部分重复了几次,我们可以试着用组件的方式,写出它,如下
<div id="app"> <table> <tbody> <row></row> <row></row> <row></row> </tbody> </table> </div> <script> Vue.component("row", { template:"<tr><td>this is a row</td></tr>" }); var app = new Vue({ el: "#app" }); </script> 复制代码
然后,我们打开浏览器测试下,
虽然展示结果一样,但我们可以看待 tr
这部分标签出现在了 table
标签外部,这就是 table
标签不支持内部嵌套 不是 tr
标签的情况
这时候,我们就可以使用is了
<table> <tbody> <tr is="row"></tr>//采用table内支持的标签,is后面接组件的名字 </tbody> </table> 复制代码
这里就不贴图了,这时,table标签的嵌套就正常了
组件中data的使用
在子组件中,data必须是一个函数,并且该函数要返回一个对象
这是因为子组件会重复使用,而他们之间需要有独立数据存储内存,这样数据才不会互相影响,如果在组件中data是一个对象,那么,所有组件的数据都指向同一块内存。
需要操作dom实例时,$refs出现了
如果你需要在父组件中,直接访问子组件的实例
可以通过 ref
给子组件加个id
ref="one"
然后父组件中,这样访问
this.$refs.one
现在我们用 ref
来做个小例子
当我们点击上面的两个小数,会自增,最下的数字是两个小数是总回
子组件代码
Vue.component("count",{ data:function(){ return { number:0, } }, template:"<div @click='add'>{{number}}</div>", methods:{ add:function(){ this.number++; this.$emit("change")//当被点击时,会触发父组件的change事件 } } }) 复制代码
html代码
<div id="app"> <count ref="one" @change="allNum"></count>//用ref给子组件设置一个id,one <count ref="two" @change="allNum"></count> <div>{{all}}</div> </div> 复制代码
父组件代码
var app = new Vue({ el:"#app", data:{ all:0 }, methods:{ allNum:function(){ this.all=this.$refs.one.number+this.$refs.two.number; //在父组件中,可以通过this.$refs.ref来获取子组件的实例, } } }) 复制代码
二、父子组件间的传值
父组件想要给子组件传值,必须在调用子组件的html上写上要传值的属性名和值,如下
<count :count="3"></count>
这里要注意 :属性名
后面接的都是一个js表达式,所以这里的3是一个数值类型
而在子组件中,要接受父组件的传值,则必须在 propps:[]
中加一个同样的属性名, props:["count"]
重点,在这里要注意vue的单向数据流概念,就是父组件可以给子组件传值, 但子组件不能随意直接修改父组件传过来的值,必须先将父组件传过来的值复制一份,放在子组件的data中后,然后对data中的值进行修改
如下
Vue.component("count",{ props:['count'], data:function(){ return { number:this.count } } }) 复制代码
如上,只能对父组件传过来的值的 副本 进行操作,这是因为,传进的是 基础数据类型 还好,如果父组件传递的是一个 引用型 的数据,那么子组件直接改动这个数据,就有可能对其他引用该数据的组件造成干扰
子组件给父组件传值,要借助$emit去触发父组件自定义的事件,
this.$emit("change",1)
;change是父组件自定义的事件,而1,就是我们要传递的值了,
现在我们来利用父子组件的传值,做一个简单的计数器
<div id="app"> <count :count="one" @change="allNum"></count> //@change是父组件自定义的事件,触发了change//就会去执行allNum函数 <count :count="two" @change="allNum"></count> //:count 是要传递的属性名,two是要传递的值,在data中,two对应0; {{all}} </div> <script> var count = { props:['count'],//用count来接受父组件传递过来的值 data:function(){ return { number:this.count,//记得单项数据流,要将父组件的传值,复制一份,放在子组件data中 } }, template:'<div @click="add">{{number}}</div>', methods:{ add:function(){ this.number++; this.$emit("change",1);//触发change事件,传值是1; } } } var app = new Vue({ el:"#app", data:{ all:0, one:0, two:0 }, components:{ count:count, }, methods:{ allNum:function(value){//value来接受$emit的传值 this.all+=value; } } }) 复制代码
效果如下:
三、组件参数校验与非Props特性
组件参数校验
当父组件给子组件传值时,我们希望对该值进行约束,如下
props:{ content:{ type:String,//限制传过来的值必须是字符串, required:false,//是否必须传递该值 default:'default value',//默认值 validator:function(value){// return (value.length>5);//该值的长度必须大于5 } } } 复制代码
props特性
父组件给子组件传值时,切好子组件的props中有对应的prop进行接收,那么这就是props特性,,父组件给子组件传递的值,不会显示在html中,
向相反,非props特性,则会显示在html中
四、给组件绑定原生事件
父组件在子组件上绑定了一个事件,想要触发该事件,只能通过 触发自定义事件的方式 去触发,或者在加上事件修饰符.native
先看第一种,不加修饰符,不触发自定义事件
<div id="app"> <child @click="onClick"></child> </div> <script> Vue.component('child',{ template:'<div>child</div>', }) var app = new Vue({ el:"#app", methods:{ onClick:function(){ alert('click'); } } }) </script> 复制代码
在浏览器中,我们发现,点击child并没有任何效果,
这就是想要触发父组件在子组件上绑定的事件,只能通过触发自定义事件的方式去触发,现在改代码如下:
<div id="app"> <child @click="onClick"></child> </div> <script> Vue.component('child',{ template:'<div @click="childClick">child</div>', methods:{ childClick:function(){ this.$emit("click");//触发父组件的自定义事件,click } } }) var app = new Vue({ el:"#app", methods:{ onClick:function(){ alert('click'); } } }) </script> 复制代码
或者给加上一个事件修饰符.native也可以达到相同的效果
<child @click.native="onClikc"></child> 复制代码
五、非父子组件间的传值
这里先介绍一种总线的模式。
<div id="app"> <child content="胡"></child> <child content="志武"></child> </div> <script> Vue.prototype.bus = new Vue(); Vue.component("child",{ props:['content'], data:function(){ return { name:this.content, } }, template:'<div @click="exchange">{{name}}</div>', methods:{ exchange:function(){ this.bus.$emit("change",this.name) } }, //组件被挂载时, mounted:function(){ var that = this; this.bus.$on("change",function(msg){ that.name=msg; }) } }) var app = new Vue({ el:"#app", }) </script> 复制代码
我们在 Vue
的 prototype
上挂载了一个 bus
,这个bus是一个 vue
的实例,子组件要互相传值时,就可以用这个共同的祖先bus来监听和触发相应的事件,并借助这个共同的祖先来传值
六、使用插槽
slot可以让我们在组件的某个位置插入想要的内容
Vue.component("child",{ template:`<div> <slot name="header">默认内容</slot> <div>content</div> <slot name="footer">默认内容</slot> </div>` })V 复制代码
<div id="app"> <child> <div slot="header">我是头部</div> <div slot="footer">我是尾部</div> </child> </div> 复制代码
如果在插槽位置没有插入内容,则会显示默认内容
作用域插槽
当子组件在做遍历,而希望这个遍历的dom结构由外部决定时,可以使用作用域插槽
<div id="app"> <child > <template slot-scope="props">//template是必须写的 <h1>{{props.item}}</h1>//props可以任意写,而item必须和template中的`:item`一致 </template> </child> </div> <script> Vue.component("child",{ data:function(){ return { list:[1,2,3,4,5] } }, template:` <ul> <slot v-for="item of list" :item=item>//这里的:item是要传值给html实际插槽部分的 </slot> </ul> ` }) new Vue({ el:"#app", }) </script> 复制代码
动态组件和v-once
<component>
是vue自带标签,
<component :is="组件名">
component会根据is后面组件名的不同而动态加载不同的组件
v-once可以把组件放在内存中,可以有效提高性能
template:`<div v-once>child ONE</div>` 复制代码
以上所述就是小编给大家介绍的《深入理解vue组件》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- [译] 深入理解 React 高阶组件
- Vue 深入学习之组件通信
- 深入剖析Vue源码 - 组件基础
- 深入剖析Vue源码 - 组件进阶
- 深入浅出理解 React高阶组件
- element ScrollBar滚动组件源码深入分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Base64 编码/解码
Base64 编码/解码
MD5 加密
MD5 加密工具