如何优雅的封装vue组件
在编写组件时,最好考虑好以后是否要进行复用。一次性组件间有紧密的耦合没关系,但是可复用组件应当定义一个清晰的公开接口,同时也不要对其使用的外层数据作出任何假设。 Vue 组件的 API 来自三部分——prop、事件和插槽:
- Prop 允许外部环境传递数据给组件;
- 事件允许从组件内触发外部环境的副作用;
- 插槽允许外部环境将额外的内容组合在组件中。
在开发过程中,结合 Vue 组件化的特性,开发通用组件是很基础且重要的工作。通用组件必须具备==高性能、低耦合==的特性。
props(数据从父组件传入)
通常的props是这样定义的:
props:['data','type','state']
复制代码
但是通用组件的的应用场景比较复杂,对 props 传递的参数应该添加一些验证规则
props:{
data:{
type: Array,
required: true
},
type: [String, Number],
state: {
type: Boolean,
default: false
}
}
复制代码
对于通过 props 传入的参数,不建议对其进行操作,因为会同时修改父组件里面的数据
// vue2.5已经针对 props 做出优化,这个问题已经不存在了
如果一定需要有这样的操作,可以这么写:
let myData = JSON.stringify(this.data);
myData = JSON.parse(myData);
复制代码
为什么不直接写 let myData = this.data 呢?
因为直接赋值,并不能解除双向绑定。改变 myData 的时候,会改变 this.data,父组件的 data 也会变
而通过 JSON 转换之后,就能任性的操作了
在父组件处理事件
在通用组件中,通常会需要有各种事件, 比如复选框的 change 事件,或者组件中某个按钮的 click 事件
这些事件的处理方法应当尽量放到父组件中,通用组件本身只作为一个中转
//子组件中的方法
hanleSubmit (data) {
this.$emit('submit', data);
}
复制代码
//在父组件中处理
<child-form @sumit='parentSubmit'></child-form>
复制代码
这样既降低了耦合性,也保证了通用组件中的数据不被污染
不过,并不是所有的事件都放到父组件处理
比如组件内部的一些交互行为,或者处理的数据只在组件内部传递,这时候就不需要用 $emit 了
使用插槽slot实现内容分发
一个通用组件,往往不能够完美的适应所有应用场景
所以在封装组件的时候,只需要完成组件 80% 的功能,剩下的 20% 让父组件通过 solt 解决
比如一个弹框组件,弹框下班的操作按钮,有可能是‘取消’,‘确定’,可能是‘重置’,‘提交’....按钮的事件操作也不一样,这种场景就适合用内容分发了。
// 子组件
<div class='modal'>
<h3>标题</h3>
<div class='con'>
.......
</div>
<div class='act-group'>
<slot name='buttonGroup'></slot>
</div>
</div>
复制代码
// 父组件
<modal>
<div slot='buttonGroup'>
<button>取消</button>
<button>确定</button>
</div>
</modal>
复制代码