实现Element通用表单组件---基础知识

202 阅读2分钟

组件化

vue组件化系统提供了一种抽象,让我们可以使用独立可复用的组件来构建大型应用,任意类型的应用界面都可以抽象为一个组件数。组件化能提高开发效率,方便重复使用,简化调试步骤,提高项目可维护性,便于多人协同开发

组件通信常用方式

  • props 父给子传值
  • 自定义事件 子给父传值
    //child
    this.$emit('eventHandle',value)
    
    //parent
    <Child @eventHandle="childHandle"></Child>
  • event bus 事件总线
    任意两个组件之间传值常用事件总线或vuex方式。
    Bus:事件派发、监听和回调管理,利用的是观察者模式。
    class Bus{
        constructor(){
            this.callbacks = {}
        }
        $on(name,fn){
            this.callbacks[name] = this.callbacks[name] || []
            this.callbacks[name].push(fn)
        }
        $emit(name,args){
            if(this.callbacks[name]){
                this.callbacks[name].forEach(cb => cb(args))
            }
        }
    }
    
    //main.js
    Vue.property.$bus = new Bus()
    
    //child1
    this.$bus.$on('foo',handle)
    //child2
    this.$bus.$emit('foo')
  • vuex 创建唯一的全局数据管理者store,通过它管理数据并通知组件状态变更。

边界情况

  • $parent $root

兄弟组件之间通信可通过共同祖辈搭桥,$partent或$root

  • $children

父组件可以通过children访问子组件实现父子通信

  • $refs

获取子节点引用

  • provide/inject

能够实现祖先和后代之间传值。传参是字符串不支持响应式,如果是做过响应式处理的引用值,则值就是响应式的。

  • 非prop特性
    • $attrs
    • $listeners

    包含了父作用域中不作为prop被识别的特性绑定(class和style除外)。当一个组件没有声明任何prop时,这里会包含所有父作用域的绑定(class和style除外),并且可以通过v-bind="$attrs"传入内部组件——在创建高级别的组件时非常有用(进行隔代传参)。

开发组件要点

开发组件时,边界情况是不推荐的。因为具有很强的耦合性。例如使用$parent调用数据时,就很容易与当前相关联的组件产生耦合。未来如果组件重构时,组件位置发生变化时,就会产生新的问题。破坏了组件的高内聚,低耦合。

插槽

插槽语法是Vue实现的内容发布API,用于复合组件开发。该技术在通用组件库开发中有大量应用。

  • 匿名插槽
    //Parent
    <Child>Vue</child>
    
    //Child
    <div>
        <slot></slot>
    </div>
  • 具名插槽
    将内容分发到子组件指定位置
    //Parent
    <Child>
        //默认插槽用default做参数
        <template v-slot:default></template>
        //具名插槽用插槽名做参数
        <template v-slot:content></template>
    </Child>
    
    //Child
    <div>
        <slot></slot>
        <slot name="content"></slot>
    </div>
  • 作用域插槽
    //Parent
    <Child>
        //把v-slot的值指定为作用域上下文对象
        <template v-slot:default="slotProps">
            来自子组件数据:{{slotProps.foo}}
        </template>
    </Child>
    
    //Child
    <div>
        <slot :foo="foo"></slot>
    </div>