v-formly: 自定义组件

618 阅读2分钟

自定义组件

v-formly 内置了很多组件,一般业务场景基本可以满足,除了内置组件外,v-formly 还提供了自定义组件的能力。

自定义组件需要遵循一定的规则,总的来说有四步:

注意

一般情况下,我们自定义组件需要新增两个文件,比如我们下面的 Password 密码框组件,我们需要新增:

Password.vue

password.meta.js

1. 命名组件.vue中的name

通常我们以v-${id}来命名我们的组件,其中id代表你注册时的组件idregisterFormComponent("v-string", VString)中的第一个参数)。

2. 导入 mixin 到.vue组件中

导入 mixincomponentMixin到组件中,此 mixin 包含了一些通过的propsdata等供组件使用。

3. 新建并初始化 context 到.meta.js文件中

新建一个 context js 类,比如string.meta.js, 在组件的data中初始化 context:

data() { return { context: new StringMeta(this.state, this.id, this.meta), }; },

4. 绑定context.value.vue文件模板中

v-formly 中的每个组件都对应一个 context,其中包含了组件的数据存储及校验逻辑等,我们需要把context.value绑定到组件的模板中去,这样组件才能响应数据的变化。

自定义 Password 密码框组件

好了,我们对自定义组件应该有了一个大致的了解,下面我们举例说明如何创建一个自定义 Password 组件。

具体实现

Password.vue

对应上面的自定义组件四步,理解一下这个文件。

<template>
  <!-- 必须要使用 v-wrapper 来包裹我们的模板 -->
  <v-wrapper :id="id" :meta="meta">
    <a-input
      v-bind="ui"
      :defaultValue="meta.defaultValue"
      :disabled="meta.readOnly"
      :maxLength="meta.maxLength"
      :type="type"
      v-model="value"
      @change="change"
    >
      <template v-slot:suffix>
        <div style="cursor: pointer" @click="toggle">
          <a-icon v-if="!eyeVisible" type="eye-invisible" />
          <a-icon v-if="eyeVisible" type="eye" />
        </div>
      </template>
    </a-input>
  </v-wrapper>
</template>
<script>
import { PasswordMeta } from "./password.meta.js";
import { componentMixin } from "@/formly.js";
export default {
  name: "v-password",
  // 导入mixin
  mixins: [componentMixin],
  data() {
    return {
      // 初始化 context
      context: new PasswordMeta(this.state, this.id, this.meta),
      eyeVisible: false,
      type: "password",
    };
  },
  computed: {
    // 这个是绑定到模板的 v-model 值
    value: {
      get() {
        return this.context.value;
      },
      set(val) {
        this.context.value = val || undefined;
      },
    },
  },
  methods: {
    change() {
      if (this.ui.change) {
        this.ui.change(this.value);
      }
    },
    toggle() {
      this.eyeVisible = !this.eyeVisible;
      this.type = this.eyeVisible ? "text" : "password";
    },
  },
};
</script>
<style lang="less" scoped></style>

password.meta.js

因为密码框组件比较简单,只有一些 UI 样式的操作,所以.meta.js文件非常简单,只在setValue中设置value时去除两边的空格。

import { BaseMeta } from "@/formly.js";
class PasswordMeta extends BaseMeta {
  constructor(state, id, meta) {
    super(state, id, meta);
  }

  setValue(val) {
    this._value = (val && val.trim()) || undefined;
  }
}

export { PasswordMeta };

注册自定义组件

我们可以在main.js文件中注册,如下所示:

import VPassword from "@/examples/components/password/Password.vue";
import VChkInput from "@/examples/components/chk-input/ChkInput.vue";
import { registerFormComponent } from "@/formly.js";

Vue.config.productionTip = false;

Vue.use(VFormly, {
  ui: {
    errors: {
      required: "必填项",
    },
  },
});

registerFormComponent("v-password", VPassword);
registerFormComponent("v-chkinput", VChkInput);

接下来,我们就可以直接使用自定义组件了。

代码演示

以上就是我们自定义的密码框组件,其实我们在String 文本框中通过内置的v-string组件也实现了 Password,但是比较一下代码就知道,v-string中是通过传入slot然后增加了一些逻辑来实现了它。

我们在来看下下面的使用代码,没有任何多余的逻辑处理,只是在ui中增加了一行component: "password"就可以了,剩余的逻辑都在自定义组件里面帮我们实现了,所以对终端用户来说创建表单非常简单!

image.png

深入

我们还在@/examples/components/chk-input文件夹下定义了一个复杂一点的选择输入框的自定义组件:当你选择“Others”的时候,会多出一个输入框让你输入自定义内容。有兴趣的可以自己查看

image.png