element 组件的二次封装,超级简单

2,153 阅读1分钟

首先,我们需要使用到 Vue API 中的两大高级应用属性

  • vm.$attrs
  • vm.$listeners
  • 在组件上使用 v-model 自定义事件也可以用于创建支持 v-model 的自定义输入组件。记住:
<input v-model="searchText">

等价于:

<input
  v-bind:value="searchText"
  v-on:input="searchText = $event.target.value"
>

当用在组件上时,v-model 则会这样:

<custom-input
  v-bind:value="searchText"
  v-on:input="searchText = $event"
></custom-input>

为了让它正常工作,这个组件内的 <input> 必须: 将其 value attribute 绑定到一个名叫 value 的 prop 上 在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出 写成代码之后是这样的:

Vue.component('custom-input', {
  props: ['value'],
  template: `
    <input
      v-bind:value="value"
      v-on:input="$emit('input', $event.target.value)"
    >
  `
})

现在 v-model 就应该可以在这个组件上完美地工作起来了:

<custom-input v-model="searchText"></custom-input>

到目前为止,关于组件自定义事件你需要了解的大概就这些了,如果你阅读完本页内容并掌握了它的内容,我们会推荐你再回来把自定义事件读完。

image.png

image.png

二次封装 button 组件

<template>
  <div>
    <el-button v-bind="$attrs" v-on="$listeners" icon="el-icon-search" type="primary">{{btnName}}</el-button>
  </div>
</template>

<script>
export default {
  name: 'd2Button',
  props: {
    btnName: {
      type: String,
      default: '搜索'
    }
  }
}
</script>

如何使用二次封装的 button

// 注册组件
Vue.component('d2-button', () => import('./d2-button'))

<d2-button/>

二次封装日期选择组件

<template>
  <div class="el-input-group">
    <div class="el-input-group__prepend" v-if="pickerName">{{pickerName}}</div>
    <el-date-picker v-bind="$attrs" value-format="timestamp" v-on="$listeners" :value="value" @change="change($event)" :type="type" :picker-options="pickerOptions" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" align="right"/>
  </div>
</template>

<script>
export default {
  name: 'd2DateTimePicker',
  props: {
    type: {
      type: String,
      default: 'datetimerange'
    },
    value: {
      type: Array,
      default: () => []
    },
    pickerName: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      pickerOptions: {
        shortcuts: [{
          text: '最近一周',
          onClick (picker) {
            const end = new Date()
            const start = new Date()
            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
            picker.$emit('pick', [start, end])
          }
        }, {
          text: '最近一个月',
          onClick (picker) {
            const end = new Date()
            const start = new Date()
            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
            picker.$emit('pick', [start, end])
          }
        }, {
          text: '最近三个月',
          onClick (picker) {
            const end = new Date()
            const start = new Date()
            start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
            picker.$emit('pick', [start, end])
          }
        }]
      }
    }
  },
  watch: {
    value (newVal) {
      this.$emit('input', newVal)
      this.$emit('change', newVal)
    }
  },
  methods: {
    change ($event) {
      this.$emit('input', $event.target.value)
      this.$emit('change', $event.target.value)
    }
  }
}
</script>

<style lang="scss" scoped>
.el-input-group {
  line-height: normal;
  display: inline-table;
  width: auto;
  border-collapse: separate;
  border-spacing: 0;
}
</style>

使用

<d2-date-time-picker pickerName="时间范围" v-model="searchParams.orderTimer"/>
二次封装 input
<template>
  <el-input v-bind="$attrs" v-on="$listeners" class="mw300 d2-mr" :value="value" @input="input" :placeholder="placeholder">
    <template slot="prepend" v-if="inputName">{{inputName}}</template>
  </el-input>
</template>

<script>
export default {
  name: 'd2Input',
  props: {
    value: {
      type: [Number, String, Array]
    },
    inputName: {
      type: String,
      default: ''
    },
    placeholder: {
      type: String,
      default: ''
    }
  },
  methods: {
    input ($event) {
      this.$emit('input', $event.target.value)
    }
  }
}
</script>

使用

<d2-input inputName="订单号码" v-model="searchParams.orderNum" :clearable="true" placeholder="请输入订单号"/>

二次封装 select

<template>
  <div class="el-input-group el-input-group--prepend mw300 d2-mr">
    <div class="el-input-group__prepend" v-if="selectName">{{selectName}}</div>
    <el-select v-bind="$attrs" :value="selectData" @input="change($event)" :placeholder="placeholder">
      <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"/>
    </el-select>
  </div>
</template>

<script>
export default {
  name: 'd2Select',
  props: {
    value: [Number, String, Array],
    selectName: {
      type: String,
      default: ''
    },
    options: {
      type: Array,
      default: () => []
    },
    placeholder: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      selectData: this.value
    }
  },
  watch: {
    'value' (newValue) {
      this.selectData = newValue
      this.$emit('input', newValue)
    }
  },
  created () {
    this.selectData = this.value
  },
  methods: {
    change (val) {
      this.$emit('input', val)
    }
  }
}
</script>

使用

<d2-select selectName="订单状态" :options="orderStatus" v-model="searchParams.orderStatus" :clearable="true" placeholder="请选择订单状态"/>

具体效果如下:

image.png