如何优雅的封装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>
复制代码