Vue3.x + Vite2.x 入门实战 03:二次封装el-input组件

4,657 阅读1分钟

element-plus 提供了非常多通用的组件,但要满足特定产品需求效果还是略有差异,所以需再次封装。

概要内容

  • 怎么封装成子组件?
  • 怎么使用封装组件?

效果对比

  • 原始效果

  • 封装后效果

怎么封装成子组件?

<template>
  <div class="contain">
    <el-input
      class="input"
      :class="{ 'red-border': tips.length > 0 }"
      v-model="value"
      @input="onInput"
      @change="$emit('onChange')"
      :placeholder="placeholder"
    >
      <template #prefix>
        <i :class="['iconfont', iconName]"></i>
      </template>
    </el-input>

    <div class="tips" v-if="tips.length > 0">
      {{ tips }}
    </div>
  </div>
</template>

<script>
import { defineComponent, reactive, ref, watch, toRefs } from "vue";
import { ElInput } from "element-plus";

export default defineComponent({
  name: "CustomInput",
  components: { ElInput },
  props: {
    modelValue: {
      type: [String, Number],
      default: "",
    },
    placeholder: { type: String, default: "" },
    oninput: { type: String, default: "" },
    iconName: { type: String, default: "" },
    tips: { type: String, default: "" },
  },
  emits: ["input", "update:modelValue", "onChange"],
  setup(props, context) {
    // 绑定控件的值
    const value = ref("");

    // 监听属性,给 value 赋值
    watch(
      () => props.modelValue,
      (v1, v2) => {
        value.value = v1;
      }
    );
    return {
      value,
      props,
    };
  },
  methods: {
    getIconName() {
      return "iconfont " + this.iconName;
    },
    /** 向父组件提交事件更新数据 */
    onInput(e) {
      this.$emit("update:modelValue", e);
      this.$emit("input", e);
    },
  },
});
</script>

<style lang="scss">
.input {
  height: 50px;
  text-align: left;

  .iconfont {
    font-size: 22px;
    color: #127ffc;
    display: inline-block;
    margin-right: 14px;
  }
}

.red-border .el-input__inner {
  border: 1px solid #ff6666;
}

.tips {
  font-size: 14px;
  color: #ff6666;
  text-align: left;
  margin: 5px auto 20px;
}
</style>

怎么使用封装组件?

  • 引入

    import CustomInput from "/@/components/CustomInput/index.vue";
    
    export default defineComponent({
      components: { CustomInput },
    	...
    });
    
  • 使用

    <template>
    ...
    <CustomInput
                class="input-tel"
                v-model="tel"
                placeholder="请输入手机号码"
                iconName="iconshoujihaoma"
                oninput="`(value = value.replace(/[^\d]/g, ''))`"
                :tips="telTips"
                @onChange="telTips = ''"
              >
              </CustomInput>
    ...
    </template>
    

总结

  1. 子组件需watch值变化,然后通过emit 事件上抛值,否则子组件value值变化,上层组件还是原来的值
  2. 更改子组件默认样式,需要将style 标签中的scoped 去掉,否则会导致怎么也无法覆盖子组件样式情况

参考文献


以上: 如发现有问题,欢迎留言指出,我及时更正