vue 中 基于el-input 封装 多文本框自定义输入框

该代码段展示了如何在Vue.js中扩展ElementUI的输入框组件,添加自定义的标签功能。通过数据更新、虚拟DOM的更新以及DOM操作,实现了在输入框内显示和管理可关闭的标签。同时,提供了表单校验和禁用状态的支持。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

// 关键就是在数据更新 虚拟dom更新 生成真实dom后在操作 其样式,最终配合定位技术,修改element-input中 原有的样式,添加自己定义的tag标签

<!--
 * @Author: 张沐阳 zhangshuyang@semi-tech.com
 * @Date: 2023-04-24 17:13:17
 * @LastEditors: 张沐阳 zhangshuyang@semi-tech.com
 * @LastEditTime: 2023-04-26 12:03:35
 * @FilePath: \fullyauto-front\src\components\customeInputMutlpleVal\index.vue
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE,
-->
<template>
  <div>
    <!-- 模拟利用element ui实现自定义input的表单的校验 -->
    <el-input v-model="form[modelKey]" readonly placeholder="" ref="cust_input">
    </el-input>
    <div id="tagsBox" ref="tagsBoxRef" style="display: none;">
      <div
        class="cust_input_placeholder"
        v-if="$attrs.placeholder && form[modelKey].length == 0"
      >
        {{ $attrs.placeholder }}
      </div>
      <template v-if="!$slots || Object.keys($slots).length == 0">
        <el-tag
          v-for="(item, index) in form[modelKey]"
          :key="item.id + index + Date.now()"
          :closable="closabledComputed(item)"
          :style="defaultTagStyle"
          @close="onCloseTag(item, index)"
          v-bind="$attrs"
          v-on="$listeners"
          >{{ item[defaultProps.label] }}</el-tag
        >
      </template>
      <slot></slot>
      <slot name="content"></slot>
    </div>
  </div>
</template>

<script>
export default {
  name: "mutipleValInput",
  inheritAttrs: false,
  props: {
    // tag样式
    tagStyle: {
      type: Object,
      default: () => {
        return {
          display: "inline-block",
          marginRight: "5px",
          marginBottom: "5px"
        };
      }
    },
    // tag取值key
    defaultProps: {
      type: Object,
      default: () => {
        return {
          label: "name"
        };
      }
    },
    // 内部所有tag 统一配置
    canAllclosable: {
      type: Boolean,
      default: true
    },
    // 表单校验的form
    form: {
      type: Object,
      default: () => {}
    },
    // 绑定v-model的key
    modelKey: {
      type: String
    }
  },
  methods: {
    onCloseTag(row, index) {
      this.form[this.modelKey].splice(index, 1);
    },
    setElInputTagBox() {
      this.$nextTick(() => {
        console.log(
          this.$refs.cust_input,
          this.$refs.cust_input.$el,
          this.$refs.cust_input.$refs.input,
          "updated"
        );
        const elInputBox = this.$refs.cust_input.$el;
        const relaInput = this.$refs.cust_input.$refs.input;
        const tagBox = this.$refs.tagsBoxRef;
        elInputBox.style.position = "relative";
        tagBox.style.display = "block";
        this.$attrs.disabled ? tagBox.classList.add("cust_input_disabled") : ""; //添加禁用类名
      });
    }
  },
  data() {
    return {
      defaultTagStyle: {
        display: "inline-block",
        marginRight: "5px",
        marginBottom: "5px"
      }
    };
  },
  computed: {
    closabledComputed() {
      return item => {
        if (this.$attrs.disabled) {
          return !this.$attrs.disabled;
        }
        if (this.canAllclosable) {
          return this.canAllclosable;
        }
        return item.closable;
      };
    }
  },
  created() {
    this.defaultTagStyle = Object.assign(this.defaultTagStyle, this.tagStyle);
  },
  mounted() {
    this.setElInputTagBox()
  },
  updated() {
    this.setElInputTagBox()
  },
  destroyed() {
    console.log(this.form, this.modelKey, "destroyed");
  }
};
</script>

<style lang="scss" scoped>
#tagsBox {
  position: absolute;
  z-index: 2;
  height: 90%;
  width: 99%;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  margin: auto;
  background: #fff;
  padding: 0 15px;
  cursor: pointer;
}
.cust_input_placeholder {
  color: #c0c4cc;
}
.cust_input_disabled {
  background-color: #f5f7fa !important;
  border: 1px solid #e4e7ed !important;
  color: #c0c4cc !important;
  cursor: not-allowed !important;
  height: 100% !important;
  width: 100% !important;
  border-radius: 4px;
}
</style>

要验证 `el-input` 文本框中输入的内容是否是数组,你可以使用 Vue自定义指令或者计算属性来实现。下面是一个使用自定义指令的示例: ```html <template> <div> <el-input v-model="inputValue" v-array-validator></el-input> <p v-if="!isValidArray">输入的内容不是数组</p> </div> </template> <script> export default { data() { return { inputValue: "", isValidArray: true }; }, directives: { arrayValidator: { bind(el, binding, vnode) { el.addEventListener("input", () => { const value = el.value; try { const arr = JSON.parse(value); if (Array.isArray(arr)) { vnode.context.isValidArray = true; vnode.context.inputValue = arr; } else { vnode.context.isValidArray = false; } } catch (error) { vnode.context.isValidArray = false; } }); } } } }; </script> ``` 在上面的示例中,我们创建了一个 `v-array-validator` 自定义指令来监听输入框的内容变化。当输入框内容发生变化时,我们尝试将其解析为 JSON,并检查是否为数组类型。如果输入的内容是一个数组,我们将 `isValidArray` 设置为 `true`,并将解析后的数组赋值给 `inputValue`。如果输入的内容不是数组,我们将 `isValidArray` 设置为 `false`。 然后,我们在模板中使用 `v-if` 指令来根据 `isValidArray` 的值来判断是否显示验证失败的提示信息。 请注意,这个示例仅验证输入的内容是否为数组,而不会检查数组中的元素类型。如果需要更复杂的验证逻辑,你可能需要增加更多的代码。 希望这对你有所帮助!如果还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值