el-form-renderer 使用指南

目录

前言

起步 

使用

update-form && getFormValue

表单项动态显示或隐藏(hidden)

表单数据联动(on)

输入/输出格式化(inputFormat/outputFormat)

set-options

 get-component-by-id 获取组件

el-form-renderer 实践案例

案例一

案例二

自定义组件接入指南

实战记录 

添加全局类名 省去 inline属于 一行排列

添加表单校验规则 rules

 v-model

自定义下拉组件

扩展阅读

Vue中$props、$attrs和$listeners的使用详解

v-model

什么是v-model?

如何在表单元素上使用v-model?

在自定义组件上使用v-model


前言
 

vue2版本

el-form-renderer是基于element的表单渲染器,动态渲染,数据驱动

el-form-renderer/README-zh.md at dev · FEMessage/el-form-renderer · GitHub

vue3版本  


自己改的 clone 下来拉到自己项目

https://gitee.com/childe-jia/form-render.git

el-form-renderer是基于 element-ui 封装的表单渲染器,但不局限于 element-ui 组件。在完整继承了 element 的form表单属性的基础上进行了简单扩展,一些非表单组件或者封装的自定义组件,如图片上传、富文本等也可进行整合,从而用户能够通过使用一段预设的数据渲染出一个完整的表单。

起步 

​# Step1 确认你已经正确安装并使用了 element-ui
yarn add @femessage/el-form-renderer
<template>
  <el-form-renderer :content="content"></el-form-renderer>
</template>

<script>
  import ElFormRenderer from '@femessage/el-form-renderer'

  export default {
    components: {
      ElFormRenderer,
    },
    data() {
      return {
        content: [],
      }
    },
  }
</script>

使用

支持 el-form 上的所有属性。

readonly 只读

form v-model 的值。传入 后会优先使用

 disabled:禁用所有表单项目

content:[ObjectArray] 定义表单的内容,每一个 Object 代表一个原子表单 el-input, el-select, ...,一切 el-form-item 上的属性都在此声明,而对于 el-input 等之上的属性在 $el 属性上进行声明,该 Object 上还存在其他属性,例如: id, type,label, options可选的,等。还有hidden定义其是否隐藏等属性

  • id: id: string  每一个原子都存在 id,用于存储该原子的值,不能重复
  • type: string  可以是element提供的所有表单组件类型,如传入'input',则渲染出'el-input,当type="group"时使用 items内依然遵循同一层级的id不重复的原则
  • readonly 只读的   当 type === 'input' 时展示文本值, 当 type === 'select' 时展示对应。 label 对于其他组件等同于 disabled = true
  • default: 默认值
  • options ({label: string; value?: any}[])具有选择功能的原子表单可用此定义可选项 select, radio-group, radio-button, checkbox-group, checkbox-button
  • hidden 传入一个方法,并返回 boolean,返回 true 时则隐藏该表单项 * formValue 为当前 form 值,item 为当前表单项的定义
  • el  用于定义具体原子表单(如el-input)的属性,比如定义el-input的placeholder
  • component   component适用于渲染局部注册组件和自定义组件,而type适用于带el-前缀的全局组件
  • label 设置el表单项的标签
  • inputFormat:用于处理输入值,输入的值包括:1. default;2. v-model;3. updateForm。参数为整个表单的值对象或 updateForm 传入的对象,如果 inputFormat 返回 undefined,则不会更新此表单项
  • outputFormat 用于处理输出值,参数为对应组件返回值,如果处理后的值是对象类型,会覆盖(Object.assign)到整个表单的值上
  • rules 设置el表单项的规则
  • on  监听表单项发出的事件(该事件发出的内容,updateForm-与methods.updateForm相同)
resetFields()

重置表单为初始值

getFormValue()

{strict: Boolean — } 默认 false

当 strict 为 true 时,只返回设置的表单项的值, 过滤掉冗余字段

updateForm()

newValue:object--key是项的id,value是新值

更新表单值
setOptions()

id: string —
options: array

更新options

getComponentById()

id: string —

获取自定义组件

update-form && getFormValue

  • update-form 更新表单方法  默认情况下,updateForm 来者不拒,不在表单设置内的值,也可以存储进去
  • getFormValue 默认情况下,通过 updateForm 设置的所有值都会输出。 如果只想输出根据 content 设置的表单项的值,可传入 {strict: true}
<template>
  <div class="update-form">
    <el-form-renderer :content="content" inline ref="formRender">
      <el-button @click="setValue">更新表单</el-button>
      <div>
        <el-button type="primary" @click="getValue(false)">获取数据</el-button>
        <el-button type="primary" @click="getValue(true)"
          >获取数据过滤掉字段</el-button
        >
      </div>
    </el-form-renderer>
    <pre>{{ value }}</pre>
  </div>
</template>

<script>
export default {
  name: "update-form",
  data() {
    return {
      value: {},
      content: [
        {
          id: "name",
          type: "input",
          label: "name",
          el: {
            placeholder: "name",
          },
        },
        {
          id: "area",
          type: "select",
          label: "area",
          el: {
            placeholder: "area",
          },
          options: [
            {
              label: "shanghai",
              value: "shanghai",
            },
            {
              label: "beijing",
              value: "beijing",
            },
          ],
        },
      ],
    };
  },
  methods: {
    getValue(strict) {
      const value = this.$refs.formRender.getFormValue({ strict });
      this.value = value;
    },
    setValue() {
      this.$refs.formRender.updateForm({
        name: "alvin",
        area: "shanghai",
        // 设置冗余字段
        extraKey: "extraValue",
      });
    },
  },
};
</script>

表单项动态显示或隐藏(hidden)

以通过 hidden 控制某一表单项的显示或隐藏。

<template>
  <div>
    <el-form-renderer :content="content"></el-form-renderer>
  </div>
</template>

<script>
import ElFormRenderer from "@femessage/el-form-renderer";

export default {
  components: {
    ElFormRenderer,
  },
  data() {
    return {
      content: [
        {
          type: "select",
          id: "selected",
          label: "选择项目",
          options: [
            {
              label: "项目A",
              value: "optionA",
            },
            {
              label: "项目B",
              value: "optionB",
            },
          ],
        },

        {
          label: "资料",
          type: "input",
          id: "data",
          el: {
            placeholder: "项目B的具体内容",
          },
          hidden: (form, item) => {
            return this.hiddenChange(form, item);
          },
        },
      ],
    };
  },
  methods: {
    hiddenChange(form, item) {
      console.log(form); //form 收集的数据
      console.log(item); //触发元素
      return form.selected !== "optionB";
    },
  },
};
</script>

表单数据联动(on)

可以通过 on 来监听 blur , focus 等事件来实现表单联动 监听表单项发出的事件
<template>
  <div>
    <el-form-renderer :content="content"></el-form-renderer>
  </div>
</template>

<script>
import ElFormRenderer from "@femessage/el-form-renderer";

export default {
  components: {
    ElFormRenderer,
  },
  data() {
    return {
      content: [
        {
          label: "英文名",
          type: "input",
          id: "fullName",
          on: {
            blur: ([event], updateForm) => {
              const value = event.target.value;
              const lastName = value.split(" ")[1]; // 通过空格分割出内容
              updateForm({ lastName }); // 更新其他表单项
            },
          },
        },
        {
          label: "姓氏",
          type: "input",
          id: "lastName",
        },
      ],
    };
  },
};
</script>

输入/输出格式化(inputFormat/outputFormat)

拿 日期范围选择器 为例,组件输出的值是一条字符串,但后端接口格式是两个字段 {startDate, endDate},则此时需要对数据进行格式化处理

inputFormat 转换输入的数据, 使其变成表单项需要的数据格式

<template>
  <el-form-renderer :content="content" ref="form" />
</template>

<script>
export default {
  data() {
    return {
      content: [
        {
          el: {
            type: 'daterange',
            placeholder: '选择日期',
            valueFormat: 'yyyy-MM-dd'
          },
          type: 'date-picker',
          id: 'date',
          label: '日期',
          // 接口设计的时间范围是两个字段 '2019-07-23','2019-07-24'
          // 处理后的值为 [ '2019-07-23', '2019-07-24' ]
          inputFormat: row => ([row.startDate, row.endDate])
        }
      ]
    }
  }
}
</script>

outputFormat 转换输出的数据, 使其变成需要的(接口期望的)数据格式

<script>
export default {
  data() {
    return {
      content: [
        {
          el: {
            type: 'daterange',
            placeholder: '选择日期',
            valueFormat: 'yyyy-MM-dd'
          },
          type: 'date-picker',
          id: 'date',
          label: '日期', 
          // 处理前的值为 date: [ '2019-07-23', '2019-07-24' ]
          // 处理后的值为 {startDate: '2019-07-23', endDate: '2019-07-24'}
          outputFormat: val => {
            if (!val) {
              return {startDate: '', endDate: ''}
            }
            return {
              startDate: val[0],
              endDate: val[1]
            }
          }
        }
      ]
    }
  }
}
</script>

set-options

使用setOptions更新选择选项

<template>
  <el-form-renderer ref="form" :content="content" inline>
    <el-button @click="setOptions">更新options</el-button>
  </el-form-renderer>
</template>
<script>
export default {
  name: "select-demo",
  data() {
    return {
      content: [
        {
          id: "area",
          type: "select",
          label: "select",
          el: {
            placeholder: "select",
          },
          options: [
            {
              label: "shanghai",
              value: "shanghai",
            },
            {
              label: "beijing",
              value: "beijing",
            },
          ],
        },
      ],
    };
  },
  methods: {
    setOptions() {
      this.$refs.form.setOptions("area", [
        {
          label: "guangzhou",
          value: "guangzhou",
        },
        {
          label: "hangzhou",
          value: "hangzhou",
        },
      ]);
    },
  },
};
</script>

 get-component-by-id 获取组件

<template>
  <div>
    <el-form-renderer inline :content="content" ref="form">
    </el-form-renderer>
    <el-button @click="getComponent('id')">获取id input</el-button>
    <el-button @click="getComponent('first')">获取first name input</el-button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      data: {},
      content: [
        {
          id: 'id',
          type: 'input',
          label: 'id',
          el: {
            placeholder: 'id'
          }
        },
        {
          type: 'group',
          label: 'name',
          id: 'name',
          items: [
            {
              id: 'first',
              label: 'first name',
              type: 'input'
            },
            {
              id: 'last',
              label: 'last name',
              type: 'input'
            }
          ]
        }
      ]
    }
  },
  methods: {
    getComponent(id){
      console.log(this.$refs.form.getComponentById(id))
    }
  },
}
</script>

el-form-renderer 实践案例

案例一

A 系统有一个解析简历的功能,后端接口只能解析电话、邮箱,也即接口只返回 phone、email 两个字段。后来接口更新了,支持解析姓名:

后端:简历解析接口更新了,现在会返回多一个字段 name,你前端那边也更新一下吧。 前端:您随便加,接口直接更新就行了,前端不用改。 后端:这么神奇的吗?这是怎么做到的?

 那么前端是如何做到接口返回多一个字段,自己却不用修改代码的呢?

分析

原因在于使用了 el-form-renderer 使用了 updateForm 来更新表单值。 updateForm 方法接受一个对象,只要传入对象的 key 与表单的 id 对应上即可更新数据。代码片段如下:

<template>
  <el-form-renderer :content="content" ref="form" />
</template>

<script>
export default {
  data() {
    return {
      content: [
        {
          type: 'input',
          id: 'name',
          label: '名称'
        },
        {
          type: 'input',
          id: 'phone',
          label: '电话'
        },
        {
          type: 'input',
          id: 'email',
          label: '邮箱'
        },
        // ...
      ],
    }
  },
  methods: {
    async fetch() {
      const data = await fetchData()  // data: Object
      // data 中返回多了一个字段 name,也不需要修改代码
      this.$refs.form.updateForm(data)
    }
  }
}
</script>

所以,即使后端丰富了这个 data ,前端也可以“照吃不误”

如果直接使用 el-form 则无法完成这种操作:你需要手动去更新每个与 el-form-item 绑定的 data 值

<template>
  <el-form ref="form" :model="form">
    <el-form-item label="名称">
        <el-input v-model="form.name"></el-input>
    </el-form-item>
  </el-form>
</template>

<script>
export default {
  data() {
    return {
      form: {
        // 每一个表单项需要主动绑定
        name: '',
        phone: '',
        email: '',
      },
    }
  },
  methods: {
    async fetch() {
      const {name} = await fetchData()  // data: Object
      this.form.phone = data.phone
      this.form.email = data.email
      // data 中返回多了一个字段 name,需要多写下面一行代码
      this.form.name = name
    }
  }
}
</script>

案例二

场景

B 系统的表单页面比较多,其中不乏带有复杂组件的表单,如下图红框片所示:

直接使用 el-form 开撸,整个页面耦合在一起代码超过 1000 行。

使用 el-form-renderer 后,通过拆分组件,整个页面代码量在 300 行左右,业务组件代码量在 100~300 行之间。

明显能感觉到页面简洁了许多,维护性大大提高。

那么,el-rorm-renderer 是怎么做到精简主页面代码的呢?

分析

秘诀在于 el-form-renderer 支持通过 component 属性渲染自定义组件、在组件内部定义检验规则,提高了拆分页面的可能性。

下面代码示例中,把选择优惠券的表格,抽离成了一个单独的组件。

<!--表单主页面-->
<template>
  <el-form-renderer :content="content" ref="form" />
</template>
<script>
import SelectTableList from './select-table-list.vue'
export default {
  data() {
    return {
      content: [
        // ...
        {
          id: 'selectedCoupon',
          // 渲染自定义 table 组件
          component: SelectTableList,  
          label: '选择优惠券'
        },
        // ...
      ],
    }
  }
}
</script>

下面是自定义 table 组件示例代码。

<!--自定义 table 组件示例代码-->
<template>
  <div class="select-table-list">
    <el-button type="primary" size="small" @click="visible = true">选择</el-button>
    <el-table :data="selectedList" border></el-table>
    <!--
            省略一些代码
    -->
  </div>
</template>
<script>
export default {
  name: 'select-table-list',
  // 自定义校验规则
  rules: [
    {
      required: true,
      message: '自定义组件的提醒消息'
    }
  ],
  props: ['value'],
  data() {
    return {
      visible: false,
      selectedList: []
    }
  },
  methods: {
    confirm() {
      const selectedVal = 'table选中的值'
      // 更新 value 值,这样 el-form-renderer 可以通过 getFormValue() 拿到该值
      this.$emit('input', selectedVal)
      this.visible = false
    }
  }
}
</script>

自定义组件接入指南

el-form-renderer 的 type 有限, 默认只能渲染普通的表单项, 假如现在要渲染一个上传组件, type 就不够用了, 那怎么办呢? 这时候 component 选项就派上用场了

本文将介绍如何开发符合 el-form-renderer 接入标准的自定义组件, 实现对自定义组件的渲染

自定义组件接入的关键是在组件内部实现 v-model

建议在自定义组件上绑定 $attrs 和 $listeners

el-form-renderer 对 v-model 的要求是:

  • 有一个 props 为 value
  • 对外触发 input 事件
<template>
  <el-form-renderer :content="content" />
</template>

<script>
import MyInput from "@/components/my-input.vue";
export default {
  data() {
    return {
      content: [
        {
          component: MyInput,
          id: "myInput",
          label: "label",
          // 传入组件属性
          el: {
            placeholder: "请输入一个 title",
            // type: "submit", // submit button
            title: "这是一个标题", // custom defined props
          },
          // 传入组件事件
          on: {
            focus: ([event], updateForm) => {
              console.log(event.target.value); // output: input value
            },
            customEvent: ([value, msg], updateForm) => {
              console.log(msg); // output: 'message'
            },
          },
        },
        {
          id: "document",
          type: "input",
          el: {
            type: "textarea",
          },
        },
      ],
    };
  },
};
</script>
<template>
  <div>
    <!-- 自定义组件 my-input -->
    <el-input
      :value="value"
      @input="onInput"
      v-bind="$attrs"
      v-on="$listeners"
    />
  </div>
</template>
<script>
export default {
  props: {
    value: String,
    title: String,
  },
  watch: {
    value(value) {
      this.$emit("customEvent", value, "message");
    },
  },
  methods: {
    onInput(val) {
      this.$emit("input", "my-input: " + val);
    },
  },
};
</script>

需要注意,on 中的 function 定义,组件 emit 事件的 payload 将以「数组」的方式,回调到第一个参数

第二个参数为 updateForm 方法

实战记录 

添加全局类名 省去 inline属于 一行排列 

去掉 inline与 label-width

一行五个  用 在搜索

 .render-form {
  display: flex;//将.render-form元素设置为弹性布局。
  flex-direction: row; //子元素按行排列
  flex-wrap: wrap; //如果子元素溢出容器宽度,会换行显示
  flex-shrink: 0;//子元素不会收缩。
  flex-grow: 0;//子元素不会扩展。
  background: #fff;//背景颜色为白色。
  margin: -20px -20px 0px;//外边距,上边距为0,左右各为-20px。
  padding: 20px 20px 0;//内边距,上边距为0,左右各为20px。
  gap: 0 calc(4% / 4); //设置子元素之间的间隔,水平间隔为0,垂直间隔为容器宽度的4%除以4。

  // justify-content: space-between;
  .el-form-item {
    width: 18%;
    min-width: 300px;
    display: flex;
    flex-shrink: 0;
    flex-grow: 0;

    &:last-child {
      width: auto;
      min-width: 180px;
    }

    &.date-range {
      width: 440px;
    }

    .el-form-item__content {
      flex: 1;
      margin-left: 0 !important;

      .el-date-editor--datetimerange.el-input,
      .el-date-editor--datetimerange.el-input__inner {
        width: 100%;
      }
    }
  }
}

一行两个用于编辑 

 .render-form-edit  {
   display: flex; //将.render-form元素设置为弹性布局。
   flex-direction: row; //子元素按行排列
   flex-wrap: wrap; //如果子元素溢出容器宽度,会换行显示
   flex-shrink: 0; //子元素不会收缩。
   flex-grow: 0; //子元素不会扩展。
   background: #fff; //背景颜色为白色。
   margin: -20px -20px 0px; //外边距,上边距为0,左右各为-20px。
   padding: 20px 20px 0; //内边距,上边距为0,左右各为20px。
   gap: 0 calc(8% / 2); //设置子元素之间的间隔,水平间隔为0,垂直间隔为容器宽度的4%除以4。

   // justify-content: space-between;
   .el-form-item {
     width: 48%;
     min-width: 300px;
     display: flex;
     flex-shrink: 0;
     flex-grow: 0;

     &:last-child {
       min-width: 180px;
     }

     &.date-range {
       width: 440px;
     }

     .el-form-item__content {
       flex: 1;
       margin-left: 0 !important;

       .el-date-editor--datetimerange.el-input,
       .el-date-editor--datetimerange.el-input__inner,
        .el-input-number,
        .el-cascader,
        .el-select
        {
         width: 100%;
       }
     }
   }
 }

页面内添加 一行一个

<style lang="scss" scoped>
.el_edit_renderer ::v-deep {
  // justify-content: space-between;
  .el-form-item {
    width: 48%;
    min-width: 300px;
    display: flex;
    .el-form-item__content {
      flex: 1;
      .el-input,
      .el-select,
      .el-input-number {
        width: 100%;
      }
    }
  }
}
</style>

 

添加表单校验规则 rules

      <el-form-renderer ref="formRenderer" label-width="150px" :content="content">
      </el-form-renderer>

  data() {
    return {
        content:[
        {
          el: {
            placeholder: "代理商名称",
            clearable: true,
          },
          label: "代理商名称",
          type: "input",
          id: "company",
          rules: [{ required: true, message: "请输入代理商名称", trigger: "blur" }],
        },         
        ]
     };
 },


    // 表单提交
    handleSubmit() {
      this.loadingBtn = true;
      this.$refs.formRenderer.validate(async (valid, object) => {
        if (valid) {
          let params = this.$refs.formRenderer.getFormValue({ strict: true });
          try {
            await packageApi.create({ ...this.form, ...params });
            this.getList();
            this.$message({
              message: "操作成功",
              type: "success",
              duration: 5 * 1000,
            });
            this.centerDialogVisible = false;
            this.loadingBtn = false;
          } catch (error) {
            console.log(error);
            this.loadingBtn = false;
          }
          return;
        }
        this.$message({
          message: "请完善信息",
          type: "warning",
          duration: 5 * 1000,
        });
      });
    },

 v-model

<template>
  <el-form-renderer label-width="100px" :content="content" v-model="form" ref="form">
    <el-form-item>
      <el-button @click="resetForm">reset</el-button>
      <el-button @click="setValue">设置名字为小明</el-button>
    </el-form-item>
    <pre>{{form}}</pre>
  </el-form-renderer>
</template>
​
<script>
export default {
  data () {
    return {
      form: {
        "name": "",
        "type": [],
        "startDate": "2019-01-01",
        "endDate": "2019-01-02",
        "region": [],
        "date": [
          "2019-01-01",
          "2019-01-02"
        ]
      },
      content: [
        {
          type: 'input',
          id: 'name',
          label: 'name',
          attrs: { 'data-name': 'form1' },
          el: {
            size: 'mini',
            placeholder: 'test placeholder'
          },
          rules: [
            { required: true, message: 'miss name', trigger: 'blur' },
            { min: 3, max: 5, message: 'length between 3 to 5', trigger: 'blur' }
          ]
        }, {
          type: 'select',
          id: 'region',
          label: 'region',
          options: [
            {
              label: 'shanghai',
              value: 'shanghai'
            },
            {
              label: 'beijing',
              value: 'beijing'
            },
            {
              label: 'guangzhou',
              value: 'guangzhou'
            },
          ],
          el: {filterable: true, multiple: true, multipleLimit: 2},
          rules: [
            { required: true, message: 'miss area', trigger: 'change' }
          ]
        }, {
          type: 'date-picker',
          id: 'date',
          label: 'date',
          el: {
            type: 'daterange',
            valueFormat: 'yyyy-MM-dd'
          },
          rules: [
            { required: true, message: 'miss date', trigger: 'change' }
          ],
          inputFormat: (row) => {
            if (row.startDate && row.endDate) {
              return [row.startDate, row.endDate]
            }
          },
          outputFormat: (val) => {
            if (!val) {
              return {startDate: '', endDate: ''}
            }
            return {
              startDate: val[0],
              endDate: val[1]
            }
          }
        }, {
          type: 'switch',
          id: 'delivery',
          label: 'delivery'
        }, {
          type: 'checkbox-group',
          id: 'type',
          label: 'type',
          default: [],
          options: [{
            label: 'typeA'
          }, {
            label: 'typeB'
          }, {
            label: 'typeC'
          }],
          rules: [
            { type: 'array', required: true, message: 'miss type', trigger: 'change' }
          ]
        }, {
          type: 'radio-group',
          id: 'resource',
          label: 'resource',
          options: [{
            label: 'resourceA',
            value: 'A',
          }, {
            label: 'resourceB',
            value: 'B'
          }],
          rules: [
            { required: true, message: 'miss resource', trigger: 'change' }
          ]
        }, {
          type: 'input',
          id: 'desc',
          label: 'desc',
          el: {
            type: 'textarea'
          },
          rules: [
            { required: true, message: 'miss desc', trigger: 'blur' }
          ]
        }
      ]
    }
  },
  methods: {
    resetForm() {
      this.$refs.form.resetFields();
    },
    setValue() {
      this.form.name = '小明'
    },
  }
}
</script>

自定义下拉组件

Myselect

<template>
  <el-select
    :value="value"
    placeholder="请选择"
    reserve-keyword
    @change="selsctchange"
    :remote="remote"
    v-bind="$attrs"
    :loading="loading"
    :filterable="filterable"
    @clear="handleClear"
    :remoteMethod="remoteMethod"
  >
    <el-option
      v-for="item in options"
      :key="item.value"
      :label="item.label"
      :value="item.value"
      :disabled="item.status == 0"
    >
      <span style="float: left">{{ item.label }}</span>
      <span style="float: right; color: #8492a6; font-size: 13px">{{ item.value }}</span>
    </el-option>
  </el-select>
</template>
<script>
export default {
  props: {
    remote: {
      type: Boolean,
      default: true,
    },
    filterable: {
      type: Boolean,
      default: true,
    },
    remoteMethod: {
      type: Function,
      default: () => {},
    },
    value: {
      type: String,
      default: "",
    },
  },
  created() {},
  computed: {
    options() {
      let parent = this.$parent;
      while (parent && !parent.options) {
        parent = parent.$parent;
      }
      return parent.options || [];
    },
  },
  data() {
    return {
      loading: false,
    };
  },
  methods: {
    selsctchange(val) {
      console.log(val);
      this.$emit("change", val);
    },
    handleClear(val) {
      this.$emit("clear", val);
    },
  },
};
</script>

页面使用

      <el-form-renderer ref="formRenderer" label-width="150px" :content="content">
      </el-form-renderer>

  data() {
    return {
        content:[
                {
          component: Myselect,
          id: "agentId",
          label: "选择代理商",

          el: {
            placeholder: "请搜索代理商",
            remoteMethod: (query) => {
              this.remoteMethod(query, "formRenderer");
            },
            remote: true,
            filterable: true,
            clearable: true,
            loading: false,
          },
          hidden: () => store.getters.userName == "agent",
          on: {
            clear: ([event], updateForm) => {
              this.$refs.formRenderer.setOptions("agentId", []);
            },
          },
          options: [],
          rules: [{ required: true, message: "请选择代理商", trigger: "blur" }],
        },      
        ]
     };
 },

import Myselect from "@/views/account/components/myselect.vue";
components: {
  Myselect,
},
async remoteMethod(query, ref) {
      console.log(query);
      let refs = ref || "queryForm";
      let agentList = [];
      let formComponent = this.$refs[refs].getComponentById("agentId");
      formComponent.loading = true;
      if (!query) {
        this.$refs[refs].setOptions("agentId", agentList);
        formComponent.loading = false;
        return;
      }
      let res = await agentApi.findAgentList({ company: query });
      const data = res.data;
      agentList = data.map((item) => ({
        label: item.company,
        value: item.agentId,
        status: item.status,
      }));
      this.$nextTick(() => {
        formComponent.loading = false;
        this.$refs[refs].setOptions("agentId", agentList);
      });
    },

扩展阅读

Vue中$props、$attrs和$listeners的使用详解

当在Vue.js中使用组件时,了解$props$attrs$listeners可以帮助你更好地管理组件之间的数据传递和事件处理。让我详细解释它们的用法:

  1. $props:

    • $props是一个包含了从父组件传递给子组件的所有属性的对象。
    • 这些属性是只读的,意味着你不能在子组件中直接修改它们。
    • 通过访问this.$props,你可以轻松地查看和使用这些属性

示例:

// 父组件
<template>
  <child-component :message="parentMessage" />
</template>
<script>
export default {
  data() {
    return {
      parentMessage: "Hello from parent!",
    };
  },
};
</script>

// 子组件
<template>
  <div>{{ $props.message }}</div>
</template>
<script>
export default {
  props: {
    message: String,
  },
};
</script>

$attrs:

  • $attrs是一个包含了传递给子组件但未被子组件声明的属性的对象。
  • 这在需要将属性传递给子组件但不想声明所有属性时非常有用。
  • 可以使用v-bind="$attrs"将这些属性绑定到子组件的HTML元素上。
// 父组件
<template>
  <child-component title="Child Title" />
</template>

// 子组件
<template>
  <div v-bind="$attrs">{{ title }}</div>
</template>

$listeners:

  • $listeners是一个包含了父组件传递给子组件的所有事件监听器的对象。
  • 这使得子组件可以监听和响应父组件触发的事件。
  • 使用v-on="$listeners"将这些事件监听器绑定到子组件的元素上。
// 父组件
<template>
  <child-component @click="handleClick" />
</template>
<script>
export default {
  methods: {
    handleClick() {
      // 处理点击事件
    },
  },
};
</script>

// 子组件
<template>
  <button v-on="$listeners">Click me</button>
</template>

v-model

当我们讨论Vue.js时,v-model 是一个非常强大且方便的指令,用于实现双向数据绑定。它使得在Vue组件中管理用户输入和组件状态变得非常简单。

什么是v-model?

v-model 实际上是Vue.js提供的一种语法糖,用于实现表单元素和组件状态之间的双向数据绑定。它背后的原理是通过绑定数据属性和监听输入事件来保持数据同步。

如何在表单元素上使用v-model?

首先,让我们看一下如何在表单元素上使用 v-model。假设我们有一个输入框,我们想要将其值绑定到Vue组件的数据属性。我们可以这样做:

<template>
  <div>
    <input v-model="message" />
    <p>输入的内容:{{ message }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: ""
    };
  }
};
</script>

在上面的示例中,v-model 指令将 <input> 元素的值绑定到了组件的 message 数据属性上。这意味着当用户在输入框中键入内容时,message 的值会自动更新,反之亦然。

在自定义组件上使用v-model

v-model 也可以用于自定义组件,使其支持双向数据绑定。要实现这一点,我们需要在组件内部使

用 model 选项,同时定义 value 和 input 属性。以下是一个简单的示例:

<template>
  <div>
    <custom-input v-model="message" />
    <p>输入的内容:{{ message }}</p>
  </div>
</template>

<script>
import CustomInput from './CustomInput.vue';

export default {
  components: {
    CustomInput
  },
  data() {
    return {
      message: ''
    };
  }
};
</script>

在上面的示例中,我们在父组件中使用 v-model 将 message 数据属性绑定到了 CustomInput 组件上。在 CustomInput 组件内部,我们需要定义 value 和 input 属性:

<template>
  <input :value="value" @input="$emit('input', $event)" />
</template>

<script>
export default {
  props: ['value']
};
</script>

这样,当我们在父组件中使用 v-model 来操作 message 数据属性时,会同时影响到 CustomInput 组件内部的输入框值。

总结一下,v-model 是Vue.js中用于实现双向数据绑定的强大工具,不仅适用于表单元素,还可以用于自定义组件。通过简单的语法糖,它使得数据在视图和组件之间的同步变得轻而易举。这是Vue.js框架中一个非常有用的功能,有助于构建交互性强、响应式的应用程序。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值