[TOC]
vue组件封装技巧
1.props参数
最简单父传子的技巧,在父组件传入值,子组件声明props接收就可以了
如下:
父组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <template> <div id="app"> <Table content="外面调用的"></Table> </div> </template>
<script> import Table from './components/Table.vue'; export default { name: 'App', components: { Table } } </script>
|
子组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <template> <div>{{content}}</div> </template> <script> export default { data() { return { } }, props:['content'], mounted() { console.log("父亲过来的",this.$attrs); }, } </script>
|
上面是用的props的数组语法,下面是对象语法,做更近一步处理时可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| props: { propA: Number,
propB: [String, Number],
propC: { type: String, required: true, },
propD: { type: Number, default: 100, },
propK: { type: Array, default: function () { return ["张三"]; }, },
propE: { type: Object, default: function () { return { message: "hello" }; }, },
propF: { validator: function (value) { return ["success", "warning", "danger"].indexOf(value) !== -1; }, }, },
|
2.$attrs
用途:在对组件进行二次封装的时候会出现孙子组件的传值问题,如果都通过prop进行层层传递太过麻烦,可以选择不使用props传值而通过$attrs传递
定义:包含了父作用域中不被认为 (且不预期为) props 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 props 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind=”$attrs” 传入内部组件——在创建更高层次的组件时非常有用。
用法:父组件正常传入数据,子组件通过在孙组件上v-bind=:”$attrs”将未props声明的数据传递,孙组件通过this.$atrs.xxx进行使用
父组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <template> <div id="app"> <Table content="外面调用的" msg="这是测试attrs"></Table> </div> </template>
<script> import Table from './components/Table.vue'; export default { name: 'App', components: { Table } } </script>
|
子组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <template> <div v-bind="$attrs">{{this.$attrs.content}}</div> </template> <script> export default { data() { return {}; },
mounted() { console.log("父亲过来的", this.$attrs); } }; </script>
|
打印台信息:

但这有一个需要注意的点:$attrs将propos未声明的属性会作为HTML属性绑定到组件的根元素上
这时候需要添加:

3.$emit
可以用于子组件向父组件传递消息,触发定义的事件
父组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <template> <div > <last @msgA="msgA"></last> </div> </template> <script> import last from '@/components/last.vue' export default { data() { return {}; }, components:{ last }, methods:{ msgA(name){ console.log("事件被调用了",name); } } }; </script>
|
子组件:
1 2 3 4 5 6 7 8 9 10 11
| <template> <div></div> </template>
<script> export default { created(){ this.$emit('msgA','sssss') }, } </script>
|
可以看到控制台输出的内容

4.$listeners
与 $attrs的用法类似,当我们需要将事件处理函数传递给子组件时,可以利用父组件实例上的 $listeners属性,这个属性包含了组件接收到的事件处理函数,需要在子组件上绑定:v-on=”$listeners”
父组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <template> <div > <last @msgA="msgA"></last> </div> </template> <script> import last from '@/components/last.vue' export default { data() { return {}; }, components:{ last }, methods:{ msgA(name){ console.log("事件被调用了",name); } } }; </script>
|
子组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <template> <div v-bind="$attrs" v-on="$listeners"></div> </template>
<script> export default { created(){ this.$emit('msgA','sssss') }, mounted() { console.log("父亲过来的值", this.$attrs); console.log("父亲传过来的事件",this.$listeners); this.$listeners.msgA('sdddddddd') },
} </script>
|
可以看到控制台打印的信息

简单来说:$attrs与$listeners 是两个对象,$attrs 里存放的是父组件中绑定的非 Props 属性,$listeners里存放的是父组件中绑定的非原生事件。
5.插槽
一个通用组件,往往不能够适应所有应用场景,所以在封装组件的时候只需要完成组件 80% 的功能,剩下的 20% 让父组件通过 solt 解决。比如:某一个公共组件中有两个按钮,一个是“新增”,一个是“删除”,但是在另外的场景中使用这个组件时,两个按钮需要做的事情是不一样的,比如是“查看”和“修改”。所以,我们在封装组件的时候就不要直接写按钮了,而是在合适的位置放置一个slot,其实是一个占位的作用,给按钮的设置提前预留一个位置,然后在父组件中写入按钮即可。
具体插槽如何使用我之前发过一篇文章,见下方链接
插槽