Vue——组件封装天龙八步

关键词:
data/$data         数据依赖
props/$props       父组件传值通道
slot                分发
created             Vue生命周期
$listeners         静态函数传递
$emit              事件传递
$on                    事件绑定
watch               监听数据变化
provide             向父组件传递数据
inject              子组件接受接收
$attrs             静态数据传递
inheritAttrs        标签美化
中心思想

子组件拥有自身状态的同时,允许父组件对自身进行任何操作

生命周期

组件的进阶封装,需要对Vue生命周期有简单的了解

需要了解的小伙伴请查看我的另一篇博客:

Vue——神秘的生命周期

本文以button组件封装为例

基础组件
export const GlobelButton = {
  template: `
  <div>
    <button type="button" :style="style">
      {{title}}
    </button>
  </div>
  `,
  data () {
    return {
      style: {
        backgroundColor: '#b50136',
        fontSize: '12px',
        color: '#fff'
      },
      title: 'title'
    }
  }
}

暴露出一个button组件,已经在子组件内部写好样式,父组件可以直接引用

允许父组件控制title属性
export const GlobelButton = {
  template: `
  <div>
    <button type="button" :style="style">
      {{title}}
    </button>
  </div>
  `,
  data () {
    return {
      style: {
        backgroundColor: '#b50136',
        fontSize: '12px',
        color: '#fff'
      }
      ####################
      // title: 'title'
      ####################
    }
  },
  ####################
  props: {
    // innerHtml 文案
    title: {
      type: String,
      default: function () { return '暂未定义title' }
    }
  }
  #####################
}

允许父组件传入的title值覆盖子组件本身数据,并为子组件提供默认数据 #区域为修改区域

为组件增加插槽
export const GlobelButton = {
  template: `
  <div>
      ###########
      <slot name="first"></slot>
      ########
        <button type="button" :style="style">
          {{title}}
        </button>
      ###########
      <slot name="end"></slot>
      #############
  </div>
  `,
  data () {
    return {
      style: {
        backgroundColor: '#b50136',
        fontSize: '12px',
        color: '#fff'
      }
    }
  },
  props: {
    // innerHtml 文案
    title: {
      type: String,
      default: function () { return '暂未定义title' }
    }
  }
}

插槽的添加很多程度上扩展了组件的灵活性,允许父组件任意的增加DOM

将样式控制交给父组件
export const GlobelButton = {
  template: `
  <div>
      <slot name="first"></slot>
        <button type="button" :style="style">
          {{title}}
        </button>
      <slot name="end"></slot>
  </div>
  `,
  ######################
  created () {
    const styled = this.styled || {}

    if (!styled) return

    if (styled instanceof Object || JSON.stringify(styled) !== '{}') {
      for (const key in styled) {
        this.style[key] = styled[key]
      }
    }
  },
  #######################
  data () {
    return {
      style: {
        backgroundColor: '#b50136',
        fontSize: '12px',
        color: '#fff'
      }
    }
  },
  props: {
    // innerHtml 文案
    title: {
      type: String,
      default: function () { return '暂未定义title' }
    },
    ########################
    // 样式
    styled: {
      type: Object,
      default: function () { return {} }
    }
    #######################
  }
}

组件中的样式是通过对象style来控制的,如何才能做到让父组件动态控制style对象的值呢?在Vue——神秘的生命周期一文中我们知道,created生命周期中 data d a t a 、 props都已经准备完毕,那么我们就可以在这里做一些改变。

改变父组件状态
export const GlobelButton = {
  template: `
  <div>
      <slot name="first"></slot>
      ################
        <button type="button" :style="style"  @click="changeBg">
      #################
          {{title}}
        </button>
      <slot name="end"></slot>
  </div>
  `,
  created () {
    const styled = this.styled || {}

    if (!styled) return

    if (styled instanceof Object || JSON.stringify(styled) !== '{}') {
      for (const key in styled) {
        this.style[key] = styled[key]
      }
    }
  },
  data () {
    return {
      style: {
        backgroundColor: '#b50136',
        fontSize: '12px',
        color: '#fff'
      }
    }
  },
  ########################
  methods: {
    changeBg () {
      this.style.backgroundColor = 'green'
      this.$emit('change-color', 'green')
    }
  },
  ########################
  props: {
    // innerHtml 文案
    title: {
      type: String,
      default: function () { return '暂未定义title' }
    },
    // 样式
    styled: {
      type: Object,
      default: function () { return {} }
    }
  }
}

我们经常会遇到需要同步改变子组件以及父组件状态的情况,如dialog的显示和隐藏状态的触发,然而Vue并不建议我们直接修改props的值,此时我们可以借助 emitthis. e m i t 触 发 t h i s . listeners中由父组件$on绑定的方法,自然也可以配合watch使用,监听父组件的值并同步修改子组件状态

接受父组件公共状态
export const GlobelButton = {
  template: `
  <div>
      <slot name="first"></slot>
        <button type="button" :style="style"  @click="changeBg">
          {{title}}
        </button>
        #############
        {{inject}}
        #############
      <slot name="end"></slot>
  </div>
  `,
  created () {
    const styled = this.styled || {}

    if (!styled) return

    if (styled instanceof Object || JSON.stringify(styled) !== '{}') {
      for (const key in styled) {
        this.style[key] = styled[key]
      }
    }
  },
  data () {
    return {
      style: {
        backgroundColor: '#b50136',
        fontSize: '12px',
        color: '#fff'
      }
    }
  },
  #################
  inject: ['inject'],
  #################
  methods: {
    changeBg () {
      this.style.backgroundColor = 'green'
      this.$emit('change-color', 'green')
    }
  },
  props: {
    // innerHtml 文案
    title: {
      type: String,
      default: function () { return '暂未定义title' }
    },
    // 样式
    styled: {
      type: Object,
      default: function () { return {} }
    }
  }
}

对于某些情况下,一个父组件可能拥有多个子组件,此时父组件的功能状态可以通过provide: { inject: ‘test provide’ }传递,子组件中inject接受到的数据可以直接用this访问

静态属性的传递
export const GlobelButton = {
  template: `
  <div>
      <slot name="first"></slot>
        <button type="button" :style="style"  @click="changeBg">
          {{title}}
        </button>
        {{inject}}
      <slot name="end"></slot>
  </div>
  `,
  created () {
    const styled = this.styled || {}

    if (!styled) return

    if (styled instanceof Object || JSON.stringify(styled) !== '{}') {
      for (const key in styled) {
        this.style[key] = styled[key]
      }
    }
  },
  data () {
    return {
      style: {
        backgroundColor: '#b50136',
        fontSize: '12px',
        color: '#fff'
      },
      ##############
      attrs: this.$attrs
      ##############
    }
  },
  #################
  inheritAttrs: false
  #################
  inject: ['inject'],
  methods: {
    changeBg () {
      this.style.backgroundColor = 'green'
      this.$emit('change-color', 'green')
    }
  },
  props: {
    // innerHtml 文案
    title: {
      type: String,
      default: function () { return '暂未定义title' }
    },
    // 样式
    styled: {
      type: Object,
      default: function () { return {} }
    }
  }
}

在开发过程中经常会出现父组件向孙子组件传值,父组件向子组件传递多个静态属性,此时我们可以借助$attrs来接受所有没有在props中定义,但是父组件调用子组件确绑定了的值,同时为了使绑定值不出现在DOM渲染中,从而保证DOM树的整洁,我们需要借助:inheritAttrs: false

需要注意的是$attrsbeforeCreate中已经准备好了,并且不会进行响应式数据变化,所以传递的一定要是静态属性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值