【Vue2-ElementUI】:model、v-model、prop

一、示例代码

html 复制代码
<!-- 1. :model 语法:el-form 表单绑定 -->
<el-form :rules="inputRules" :model="searchForm" ref="searchForm" ...>

  <!-- 2. prop 语法:el-form-item 表单校验绑定 -->
  <el-form-item label="起始日期" prop="startDate">
    <!-- 3. v-model 语法:el-date-picker 输入控件双向绑定 -->
    <el-date-picker v-model.trim="searchForm.startDate" ... />
  </el-form-item>

  <el-form-item label="结束日期" prop="endDate">
    <el-date-picker v-model.trim="searchForm.endDate" ... />
  </el-form-item>

</el-form>

这三个语法,是 Vue2 + Element UI 表单开发的黄金三角,缺一不可,各自承担完全不同的核心职责,下面逐个进行讲解。

二、详解一::model(v-bind:model)表单数据的根容器

1. 语法本质

:modelv-bind:model 的缩写,属于 Vue2 最基础的单向 Prop 绑定,核心是「数据从父级(页面)单向传递给子组件(el-form)」,子组件只能读取,不能直接修改。

2. 在代码里的作用

代码中 :model="searchForm" 是 Element UI el-form 组件的强制必填属性,作用是:

  • 把你在 data() 中定义的 searchForm 对象,绑定为 el-form 的数据源,作为整个表单的「数据根容器」;
  • el-form 能够读取 searchForm 里的字段值,用于表单校验、数据回显、输入关联
  • 作为你后续发送接口请求的参数载体,所有用户输入最终都会汇总到这个对象中,直接传给后端。

3. 代码的底层逻辑

data() 中定义了 searchForm: {...}el-form 通过 :model="searchForm" 拿到这个对象后,就会把内部所有 v-model 绑定的字段,都关联到这个对象上。

当你点击「查询」按钮时,最终发送给后端的请求参数,就是这个 searchForm 对象:

javascript 复制代码
// 代码里的查询方法
search(title) {
  // ...
  let query = Object.assign(
    {
      pageIndex: (this.page - 1) * this.per_page,
      pageSize: this.per_page
    },
    this.searchForm // 这里就是 :model 绑定的数据源,直接作为接口参数
  )
  this.$axios({
    method: 'post',
    url: Api.PT1721,
    params: query
  })
  // ...
}

4. 核心特性

  • 单向数据流:el-form 只会读取 searchForm,不会直接修改它,数据修改完全由内部的 v-model 完成;
  • 只读性:不能用 v-model 替换 :model,否则会破坏 Vue 单向数据流原则,导致表单校验失效、数据错乱;
  • 全局关联性:el-form 内部所有 el-form-item、输入控件,都依赖这个 :model 绑定的对象,是整个表单的「数据底座」。

5. 关键小细节

那么如果Data()里的searchForm没有定义是空的呢?

例如:

javascript 复制代码
data() {
  return {
    searchForm: {} // 空对象
  }
}

**其实这样依旧可以绑定查询条件发送给后端,**但是!!!

这根本原因是 v-model,虽然data 中只有空对象 searchForm: {},但 v-model 具有 「动态给对象添加属性并触发响应式」 的特殊能力,所以数据能收集到。

当你在页面输入内容或选择日期时,通过事件触发赋值:

javascript 复制代码
// 伪代码
this.searchForm.startDate = '2026-04-06'

哪怕这个 startDate 属性在 data 里原本不存在,Vue 也会动态给 searchForm 增加这个属性,并且让它变成响应式的。所以数据确实能收集到,提交时也能发给后端。

虽然 数据收集(v-model) 能工作,但 表单校验(rules) 是绝对会失效的。

  • datasearchForm: {}(没有 startDate)。
  • Element UI 的校验逻辑 :它会在挂载瞬间,去 searchForm 里找 startDate 字段。
  • 结果 :因为找不到,Element UI 内部会报错(通常是 Cannot read property 'trigger' of undefined),或者直接完全忽略该字段的校验规则。

searchForm: {}会出现的问题

------------- 问题1

假设你有一个编辑 / 回显的场景,需要后端返回数据填充表单:

javascript 复制代码
// 后端返回的数据
const res = { endDate: "2026-04-10" }

// 直接赋值
this.searchForm = res

如果你的 data 里定义了 searchForm: { endDate: '' },没问题。

但如果你的 data 里是 searchForm: {},且你是靠 v-model 动态加字段:

  • 第一次进入编辑页,searchForm 会有 endDate,显示正常。
  • 但是!一旦你点击重置按钮 ,执行 this.searchForm = {} 清空。
  • 你的表单里的 el-date-picker 会瞬间变成 NaNInvalid Date,因为 Vue 无法监听对象属性的删除(这是 Vue 2 的限制),导致组件内部状态混乱。
------------- 问题2

下次查询时候还会携带之前的查询条件

比如你上次搜了 "张三",这次不输入,点查询 → 依然带着 userName=张三

只要data 里的searchForm没有你输入的字段,Vue 响应式系统监听不到这种动态属性的删除

推荐正规写法

1. data 里必须初始化所有字段
javascript 复制代码
data() {
  return {
    searchForm: {
      userName: '',
      phone: '',
      status: '',
      startDate: '',
      endDate: ''
      // 所有用到的字段都写出来
    }
  }
}
2. 重置方法必须这样写
javascript 复制代码
reset() {
  // 直接重置为初始状态
  this.searchForm = {
    userName: '',
    phone: '',
    status: '',
    startDate: '',
    endDate: ''
  }
}

三、详解二:v-model ------ 输入控件的「双向同步器」

1. 语法本质

v-model 是 Vue2 内置的双向绑定语法糖 ,底层等价于 :value="数据" + @input="数据=$event.target.value",自动实现「数据更新 → 视图刷新,视图输入 → 数据同步」,无需手动监听事件。

在 Element UI 组件中,v-model 被封装为 :value + @change,适配日期选择器、下拉框等组件的输入逻辑。

2. 代码里的作用

代码中 v-model.trim="searchForm.startDate" / v-model.trim="searchForm.endDate",是 el-date-picker 日期选择器的核心绑定属性,作用是:

  • 双向同步用户输入:你在日期选择器中选择了日期,v-model 会自动把值更新到 searchForm.startDate / searchForm.endDate 中;
  • 自动回显数据:如果 searchForm 里有初始值,v-model 会自动把值渲染到日期选择器上,实现编辑回显;
  • 保证接口参数最新:你在 search() 方法中做的日期校验 this.searchForm.startDate - this.searchForm.endDate > 0,能拿到最新的用户选择值,完全依赖 v-model 的自动同步。

3. 代码的底层逻辑

el-input.trim 修饰符,作用是自动去除输入值的首尾空格。

v-model 绑定的 searchForm.startDate,和 el-form :model="searchForm" 是同一个对象,这就实现了「输入控件 → 表单容器 → 接口参数」的完整数据链路:用户选择日期v-model 自动同步到 searchFormel-form 读取 searchForm 做校验search() 方法把 searchForm 作为参数发送给后端

4. 核心特性

  • 双向绑定:视图和数据双向自动同步,改数据 = 改页面,改页面 = 改数据;
  • 输入控件专属 :所有用户输入类组件(input、select、date-picker、radio、checkbox 等),必须用 v-model 绑定;
  • 修饰符支持.trim(去空格)、.number(转数字)、.lazy(失焦同步),优化输入体验;
  • 接口请求核心:收集用户输入的所有数据,是保证接口参数准确的核心。

5. 业务场景总结

  • **100% 的使用场景:**所有表单输入控件,是前端收集用户输入的核心方式;
  • **接口请求作用:**实时同步用户输入,保证请求参数是最新、最准确的值;
  • **核心价值:**告别手动监听 @input/@change 事件,大幅简化表单开发。

四、详解三:prop ------ 表单校验的「规则映射器」

1. 语法本质

prop 是 Element UI el-form-item 组件的专属属性,本质是「表单校验规则的映射字段」,作用是把 el-form-item:model 绑定的对象中的某个字段、rules 中的某条校验规则,三者关联起来。

2. 代码里的作用

代码中 prop="startDate" / prop="endDate",是 el-form-item 的校验绑定属性,作用是:

  • 把当前 el-form-item,和 :model="searchForm" 中的 startDate/endDate 字段做绑定;
  • 把当前 el-form-item,和你在 data() 中定义的 inputRules 校验规则中的 startDate/endDate 规则做绑定;
  • el-form 执行 validate() 校验时,能精准找到对应的字段和规则,完成校验、错误提示。

3. 代码的底层逻辑

data() 中定义了校验规则:

javascript 复制代码
inputRules: {
  startDate: [
    { required: true, message: '起始日期不能为空', trigger: 'blur' }
  ],
  endDate: [
    { required: true, message: '结束日期不能为空', trigger: 'blur' }
  ]
}

当你给 el-form-itemprop="startDate" 时,el-form 就会自动做三件事:

  • :model="searchForm" 中,读取 startDate 字段的值;
  • inputRules 中,读取 startDate 对应的校验规则;
  • 当用户触发 blur 失焦事件,或调用 this.$refs.searchForm.validate() 时,执行校验,不符合规则就显示错误提示。

如果不写 prop 属性,el-form 就无法找到对应的字段和规则,表单校验会完全失效,这是 Element UI 表单校验的核心要求。

4. 核心特性

  • el-form-item 专属:仅用于 el-form 内部的 el-form-item 组件,其他组件不支持;
  • 校验映射核心:是 el-form 表单校验生效的必要条件,没有 prop 就没有校验;
  • 字段一致性要求:prop 的值,必须和 :model 绑定对象的字段名、rules 中的规则名完全一致(比如 prop="startDate"searchForm 必须有 startDate 字段,rules 必须有 startDate 规则);
  • 错误提示关联:校验不通过时,错误提示会自动显示在当前 el-form-item 下方,和 prop 绑定的字段一一对应。

5. 业务场景总结

  • **唯一使用场景:**Element UI el-form 表单的 el-form-item 组件,用于表单校验;
  • **接口请求作用:**保证用户输入符合业务规则,避免无效数据发送给后端;
  • **核心价值:**实现表单的自动化校验,无需手动写校验逻辑,大幅提升开发效率。

五、三者核心区别

对比维度 :model(v-bind:model) v-model prop
语法本质 单向 Prop 绑定(v-bind 缩写) 双向绑定语法糖 el-form-item 专属校验映射属性
绑定对象 el-form 表单组件 输入控件(el-date-picker/el-input 等) el-form-item 表单项组件
核心作用 表单数据根容器,承载所有接口参数 输入控件双向同步,收集用户输入 校验规则映射,让表单校验生效
数据流向 页面 → el-form(单向只读) 输入控件 ↔ searchForm(双向自动同步) 无数据传递,仅做规则映射
代码中的位置 <el-form :model="searchForm"> <el-date-picker v-model="searchForm.startDate"> <el-form-item prop="startDate">
接口请求作用 存储最终发送的请求参数 同步用户输入,保证参数最新 校验输入合法性,过滤无效请求
是否必填 el-form 必写,否则表单无数据源 输入控件必写,否则无法收集输入 有校验需求必写,否则校验失效
依赖关系 是 v-model、prop 的数据基础 依赖 :model 绑定的对象 依赖 :model 和 rules 校验规则
底层原理 v-bind 单向传值 :value + @input(语法糖) 字段 - 规则 - 表单项的映射关联

六、三者协同工作的完整链路

我们用「日期查询表单」,完整走一遍三者的协作流程:

步骤 1:页面初始化

  1. data() 中定义 searchForminputRules 等数据;
  2. el-form 通过 :model="searchForm" 绑定数据源,通过 :rules="inputRules" 绑定校验规则;
  3. el-form-item 通过 prop="startDate"/prop="endDate",把表单项、searchForm 字段、inputRules 规则三者关联;
  4. el-date-picker 通过 v-model="searchForm.startDate",把输入控件和 searchForm 字段双向绑定。

步骤 2:用户操作(选择日期)

  1. 用户在 el-date-picker 中选择起始日期;
  2. v-model 自动把选择的日期,同步到 searchForm.startDate 中;
  3. 用户失焦时,el-form 根据 prop="startDate" 找到对应的字段和规则,执行校验;
  4. 校验通过,无错误提示;校验不通过,显示「起始日期不能为空」的错误提示。

步骤 3:点击「查询」按钮,发送接口请求

  1. 执行 search() 方法,先做日期大小校验 this.searchForm.startDate - this.searchForm.endDate > 0
  2. 调用 this.$refs.searchForm.validate() 触发表单校验,el-form 根据 prop 映射的规则,校验 searchForm 中的字段;
  3. 校验通过后,把 searchForm 拼接到 query 对象中,作为接口参数发送给后端;
  4. 后端返回数据,渲染到表格中,完成一次完整的查询流程。

步骤 4:点击「重置」按钮

  1. 执行 resetForm() 方法,重置 searchForm 中的 startDate/endDate 字段;
  2. v-model 监听到 searchForm 数据变化,自动清空 el-date-picker 的显示;
  3. el-form 调用 resetFields() 方法,根据 prop 映射的字段,清空校验状态,移除错误提示。
相关推荐
Jenlybein9 小时前
快速了解熟悉 Vite ,即刻上手使用
前端·javascript·vite
Ailrid9 小时前
@virid/core:用游戏引擎的思维来写应用-高度确定性的应用开发引擎
javascript
SuperEugene11 小时前
Vue3 组件复用设计:Props / 插槽 / 组合式函数,三种复用方式选型|组件化设计基础篇
前端·javascript·vue.js
nFBD29OFC11 小时前
利用Vue元素指令自动合并tailwind类名
前端·javascript·vue.js
i220818 Faiz Ul13 小时前
动漫商城|基于springboot + vue动漫商城系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·动漫商城系统
zk_one13 小时前
【无标题】
开发语言·前端·javascript
AIBox36514 小时前
openclaw api 配置排查与接入指南:网关启动、配置文件和模型接入全流程
javascript·人工智能·gpt
precious。。。14 小时前
1.2.1 三角不等式演示
前端·javascript·html
阿珊和她的猫15 小时前
TypeScript 中的 `extends` 条件类型:定义与应用
javascript·typescript·状态模式