Vue3组件(九)Vue3+element+json实现一个动态渲染的表单控件

简介: 这个表单控件是基于 element-plus 的 el-form 做的二次封装,所以首先感谢 element-plus 提供了这么强大的UI库,以前用 jQuery 做过类似的,但是非常麻烦,既不好看,可维护性、扩展性也差,好多想法都实现不了(技术有限)。

一个成熟的表单



表单表单,你已经长大了,你要学会:


  • 动态渲染
  • 支持单列、双列、多列
  • 支持调整布局
  • 支持表单验证
  • 支持调整排列(显示)顺序
  • 依据组件值显示需要的组件
  • 支持 item 扩展组件
  • 可以自动创建 model


这个表单控件是基于 element-plus 的 el-form 做的二次封装,所以首先感谢 element-plus 提供了这么强大的UI库,以前用 jQuery 做过类似的,但是非常麻烦,既不好看,可维护性、扩展性也差,好多想法都实现不了(技术有限)。


现在好了,站在巨人的肩膀上,实现自己的想法了。


实现动态渲染



把表单需要的属性,统统放入json里面,然后用require(方便) 或者aioxs(可以热更新)加载进来,这样就可以实现动态渲染了。 比如要实现公司信息的添加、修改,那么只需要加载公司信息需要的json即可。 想要实现员工信息的添加、修改,那么只需要加载员工信息需要的json。


总之,加载需要的json即可,不需要再一遍一遍的手撸代码了。


那么这个神奇的 json 是啥样子的呢?文件有点长,直接看截图,更清晰一些。


image.png


另外还有几个附带功能:


  • 支持单行下的合并。


在单行的情况下,一些短的控件会比较占空间,我们可以把多个小的合并到一行。


  • 支持多行下的扩展。


多行的情况下,一些长的控件需要占更多的空间,我们可以设置它多占几个格子。


  • 自动创建表单需要的 model。


不需要手动写 model了。


实现多行多列的表单



再次感谢 el-form,真的很强大,不仅好看,还提供了验证功能,还有很多其他的功能。 只是好像只能横着排,或者竖着排。那么能不能多行多列呢?似乎没有直接提供。


我们知道 el-row、el-col 可以实现多行多列的功能,那么能不能结合一下呢?官网也不直说,害的我各种找,还好找到了。(好吧,其实折腾了一阵着的table)


二者结合一下就可以了,这里有个小技巧,el-row 只需要一个就可以,el-col 可以有多个,这样一行排满后,会自动排到下一行。


<el-form
      ref="form"
      :inline="false"
      class="demo-form-inline"
      :model="formModel"
      label-suffix=":"
      label-width="130px"
      size="mini"
    >
      <el-row>
        <!--不循环row,直接循环col,放不下会自动往下换行。-->
        <el-col
          v-for="(ctrId, index) in formColSort"
          :key="'form_'+index"
          :span="formColSpan[ctrId]"
        >
          <el-form-item :label="getCtrMeta(ctrId).label">
            <!--表单item组件,采用动态组件的方式-->
            <component
              :is="ctlList[getCtrMeta(ctrId).controlType]"
              v-model="formModel[getCtrMeta(ctrId).colName]"
              :meta="getCtrMeta(ctrId)"
              @myChange="mySubmit">
            </component>
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
复制代码


  • formColSort


存放组件ID的数组,决定了显示哪些组件以及显示的先后顺序。


  • v-for


遍历 formColSort 得到组件ID,然后获取ID对应的span(确定占位)以及组件需要的meta。


  • formColSpan


存放组件占位的数组。依据el-col的span的24格设定。


  • getCtrMeta(ctrId)


根据组件ID获取组件的meta。 为啥要写个函数呢?因为model的属性不允许中括号套娃,所以只好写个函数。 为啥不用计算属性呢?计算属性好像不能传递参数。


  • component :is="xxx"


Vue提供的动态组件,用这个可以方便加载不同类型的子组件。


  • ctlList


组件字典,把组件类型变成对应的组件标签。


这样一个v-for搞定了很多事情,比如单列、多列,组件的排序问题,组件的占位问题,还有依据用户的选择显示不同的组件的问题,其实就是修改一下 formColSort 里的组件ID的构成和顺序。


自动创建 model



我比较懒,手撸 model 是不是有点麻烦?如果能够自动获得该多好,于是我写了这个函数。


// 根据表单元素meta,创建 v-model
  const createModel = () => {
    // 依据meta,创建module
    for (const key in formItemMeta) {
      const m = formItemMeta[key]
      // 根据控件类型设置属性值
      switch (m.controlType) {
        case 100: // 文本类
        case 101:
        case 102:
        case 103:
        case 104:
        case 105:
        case 106:
        case 107:
        case 130:
        case 131:
          formModel[m.colName] = ''
          break
        case 110: // 日期
        case 111: // 日期时间
        case 112: // 年月
        case 114: // 年
        case 113: // 年周
          formModel[m.colName] = null
          break
        case 115: // 任意时间
          formModel[m.colName] = '00:00:00'
          break
        case 116: // 选择时间
          formModel[m.colName] = '00:00'
          break
        case 120: // 数字
        case 121:
          formModel[m.colName] = 0
          break
        case 150: // 勾选
        case 151: // 开关
          formModel[m.colName] = false
          break
        case 153: // 单选组
        case 160: // 下拉单选
        case 162: // 下拉联动
          formModel[m.colName] = null
          break
        case 152: // 多选组
        case 161: // 下拉多选
          formModel[m.colName] = []
          break
      }
      // 看看有没有设置默认值
      if (typeof m.defaultValue !== 'undefined') {
        switch (m.defaultValue) {
          case '':
            break
          case '{}':
            formModel[m.colName] = {}
            break
          case '[]':
            formModel[m.colName] = []
            break
          case 'date':
            formModel[m.colName] = new Date()
            break
          default:
            formModel[m.colName] = m.defaultValue
            break
        }
      }
    }
    // 同步父组件的v-model
    context.emit('update:modelValue', formModel)
    return formModel
  }
复制代码


可以根据类型和默认值,设置 model 的属性,这样就方便多了。


创建用户选择的 model



就是用户选了某个选项,表单的组件响应变化后的model。 在我的计划里面是需要一个这样的简单的model,所以我又写了一个函数


// 依据用户选项,创建对应的 model
  const createPartModel = (array) => {
    // 先删除属性
    for (const key in formPartModel) {
      delete formPartModel[key]
    }
    // 建立新属性
    for (let i = 0; i < array.length; i++) {
      const colName = formItemMeta[array[i]].colName
      formPartModel[colName] = formModel[colName]
    }
  }
复制代码


这样就可以得到一个简洁的 model 了。


多列的表单



这个是最复杂的,分为两种情况:单列的挤一挤、多列的抢位置。


单列


image.png


单列的表单有一个特点,一行比较宽松,那么有时候就需要两个组件在一行里显示,其他的还是一行一个组件,那么要如何调整呢?


这里做一个设定:


  • 一个组件一行的,记做1
  • 两个组件挤一行的,记做-2
  • 三个组件挤一行的,记做-3


以此类推,理论上最多支持 -24,当然实际上似乎没有这么宽的显示器。


这样记录之后,我们就可以判断,≥1的记做span=24,负数的,用24去除,得到的就是span的数字。当然记得取整数。


为啥用负数做标记呢?就是为了区分开多列的调整。


多列


image.png


调多了之后发现一个问题,看起来和单列调整后似乎一样的。


image.png


多列的表单有一个特点,一个格子比较小,有些组件太长放不下,这个时候这个组件就要抢后面的格子来用。


那么我们还是做一个设定:


  • 一个组件占一格的,还是记做1
  • 一个组件占两格的,记做2
  • 一个组件占三格的,记做3


以此类推。


这样记录之后,我们可以判断,≤1的,记做 24 / 列数,大于1的记做 24/ 列数 * n。 这样就可以了,可以兼容单列的设置,不用因为单列变多列而调整设置。 只是有个小麻烦,占得格子太多的话,就会提取挤到下一行,而本行会出现“空缺”。 这个暂时靠人工调整吧。 毕竟哪个字段在前面,还是需要人工设置的。


一顿分析猛如虎,一看代码没几行。


// 根据配置里面的colCount,设置 formColSpan
  const setFormColSpan = () => {
    const formColCount = formMeta.formColCount // 列数
    const moreColSpan = 24 / formColCount // 一个格子占多少份
    if (formColCount === 1) {
    // 一列的情况
      for (const key in formItemMeta) {
        const m = formItemMeta[key]
        if (typeof m.colCount === 'undefined') {
          formColSpan[m.controlId] = moreColSpan
        } else {
          if (m.colCount >= 1) {
            // 单列,多占的也只有24格
            formColSpan[m.controlId] = moreColSpan
          } else if (m.colCount < 0) {
            // 挤一挤的情况, 24 除以 占的份数
            formColSpan[m.controlId] = moreColSpan / (0 - m.colCount)
          }
        }
      }
    } else {
      // 多列的情况
      for (const key in formItemMeta) {
        const m = formItemMeta[key]
        if (typeof m.colCount === 'undefined') {
          formColSpan[m.controlId] = moreColSpan
        } else {
          if (m.colCount < 0 || m.colCount === 1) {
            // 多列,挤一挤的占一份
            formColSpan[m.controlId] = moreColSpan
          } else if (m.colCount > 1) {
            // 多列,占的格子数 * 份数
            formColSpan[m.controlId] = moreColSpan * m.colCount
          }
        }
      }
    }
  }
复制代码


最后看看效果,可以动态设置列数:


www.zhihu.com/zvideo/1347…


依据用户的选择,显示对应的组件



这个也是一个急需的功能,否则的话,动态渲染的表单控件适应性就会受到限制。 其实想想也不难,就是改一下 formColSort 里面的组件ID就好了。 我们设置一个watch来监听组件值的变化,然后把需要的组件ID设置给 formColSort 就可以了。


// 监听组件值的变化,调整组件的显示以及显示顺序
  if (typeof formMeta.formColShow !== 'undefined') {
    for (const key in formMeta.formColShow) {
      const ctl = formMeta.formColShow[key]
      const colName = formItemMeta[key].colName
      watch(() => formModel[colName], (v1, v2) => {
        if (typeof ctl[v1] === 'undefined') {
          // 没有设定,显示默认组件
          setFormColSort()
        } else {
          // 按照设定显示组件
          setFormColSort(ctl[v1])
          // 设置部分的 model
          createPartModel(ctl[v1])
        }
      })
    }
  }
复制代码


因为需要监听的组件可能不只一个,所以做了个循环,这样就可以监听所有需要的组件了。


看看效果www.zhihu.com/zvideo/1347…


完整代码



上面的代码比较凌乱,这里整体介绍一下。


  • el-form-manage.js


表单组件的管理类,单独拿出来,这样就可以支持其他UI库了,比如antdv


import { reactive, watch } from 'vue'
/**
 * 表单的管理类
 * * 创建v-model
 * * 调整列数
 * * 合并
 */
const formManage = (props, context) => {
  // 定义 完整的 v-model
  const formModel = reactive({})
  // 定义局部的 model
  const formPartModel = reactive({})
  // 确定一个组件占用几个格子
  const formColSpan = reactive({})
  // 定义排序依据
  const formColSort = reactive([])
  // 获取表单meta
  const formMeta = props.meta
  console.log('formMeta', formMeta)
  // 表单元素meta
  const formItemMeta = formMeta.itemMeta
  // 表单验证meta,备用
  // const formRuleMeta = formMeta.ruleMeta
  // 根据表单元素meta,创建 v-model
  const createModel = () => {
    // 依据meta,创建module
    for (const key in formItemMeta) {
      const m = formItemMeta[key]
      // 根据控件类型设置属性值
      switch (m.controlType) {
        case 100: // 文本类
        case 101:
        case 102:
        case 103:
        case 104:
        case 105:
        case 106:
        case 107:
        case 130:
        case 131:
          formModel[m.colName] = ''
          break
        case 110: // 日期
        case 111: // 日期时间
        case 112: // 年月
        case 114: // 年
        case 113: // 年周
          formModel[m.colName] = null
          break
        case 115: // 任意时间
          formModel[m.colName] = '00:00:00'
          break
        case 116: // 选择时间
          formModel[m.colName] = '00:00'
          break
        case 120: // 数字
        case 121:
          formModel[m.colName] = 0
          break
        case 150: // 勾选
        case 151: // 开关
          formModel[m.colName] = false
          break
        case 153: // 单选组
        case 160: // 下拉单选
        case 162: // 下拉联动
          formModel[m.colName] = null
          break
        case 152: // 多选组
        case 161: // 下拉多选
          formModel[m.colName] = []
          break
      }
      // 看看有没有设置默认值
      if (typeof m.defaultValue !== 'undefined') {
        switch (m.defaultValue) {
          case '':
            break
          case '{}':
            formModel[m.colName] = {}
            break
          case '[]':
            formModel[m.colName] = []
            break
          case 'date':
            formModel[m.colName] = new Date()
            break
          default:
            formModel[m.colName] = m.defaultValue
            break
        }
      }
    }
    // 同步父组件的v-model
    context.emit('update:modelValue', formModel)
    return formModel
  }
  // 先运行一次
  createModel()
  // 向父组件提交 model
  const mySubmit = (val, controlId, colName) => {
    context.emit('update:modelValue', formModel)
    // 同步到部分model
    if (typeof formPartModel[colName] !== 'undefined') {
      formPartModel[colName] = formModel[colName]
    }
    context.emit('update:partModel', formPartModel)
  }
  // 依据用户选项,创建对应的 model
  const createPartModel = (array) => {
    // 先删除属性
    for (const key in formPartModel) {
      delete formPartModel[key]
    }
    // 建立新属性
    for (let i = 0; i < array.length; i++) {
      const colName = formItemMeta[array[i]].colName
      formPartModel[colName] = formModel[colName]
    }
  }
  // 根据配置里面的colCount,设置 formColSpan
  const setFormColSpan = () => {
    const formColCount = formMeta.formColCount // 列数
    const moreColSpan = 24 / formColCount // 一个格子占多少份
    if (formColCount === 1) {
    // 一列的情况
      for (const key in formItemMeta) {
        const m = formItemMeta[key]
        if (typeof m.colCount === 'undefined') {
          formColSpan[m.controlId] = moreColSpan
        } else {
          if (m.colCount >= 1) {
            // 单列,多占的也只有24格
            formColSpan[m.controlId] = moreColSpan
          } else if (m.colCount < 0) {
            // 挤一挤的情况, 24 除以 占的份数
            formColSpan[m.controlId] = moreColSpan / (0 - m.colCount)
          }
        }
      }
    } else {
      // 多列的情况
      for (const key in formItemMeta) {
        const m = formItemMeta[key]
        if (typeof m.colCount === 'undefined') {
          formColSpan[m.controlId] = moreColSpan
        } else {
          if (m.colCount < 0 || m.colCount === 1) {
            // 多列,挤一挤的占一份
            formColSpan[m.controlId] = moreColSpan
          } else if (m.colCount > 1) {
            // 多列,占的格子数 * 份数
            formColSpan[m.controlId] = moreColSpan * m.colCount
          }
        }
      }
    }
  }
  // 先运行一次
  setFormColSpan()
  // 设置组件的显示顺序
  const setFormColSort = (array = formMeta.colOrder) => {
    formColSort.length = 0
    formColSort.push(...array)
  }
  // 先运行一下
  setFormColSort()
  // 监听组件值的变化,调整组件的显示以及显示顺序
  if (typeof formMeta.formColShow !== 'undefined') {
    for (const key in formMeta.formColShow) {
      const ctl = formMeta.formColShow[key]
      const colName = formItemMeta[key].colName
      watch(() => formModel[colName], (v1, v2) => {
        if (typeof ctl[v1] === 'undefined') {
          // 没有设定,显示默认组件
          setFormColSort()
        } else {
          // 按照设定显示组件
          setFormColSort(ctl[v1])
          // 设置部分的 model
          createPartModel(ctl[v1])
        }
      })
    }
  }
  return {
    // 对象
    formModel, // v-model createModel()
    formPartModel, // 用户选择的组件的 model
    formColSpan, // 确定组件占位
    formColSort, // 确定组件排序
    // 函数
    createModel, // 创建 v-model
    setFormColSpan, // 设置组件占位
    setFormColSort, // 设置组件排序
    mySubmit // 提交
  }
}
export default formManage
复制代码


  • el-form-map.js


动态组件需要的字典


import { defineAsyncComponent } from 'vue'
/**
 * 组件里面注册控件用
 * * 文本
 * ** eltext 单行文本、电话、邮件、搜索
 * ** elarea 多行文本
 * ** elurl
 * * 数字
 * ** elnumber 数字
 * ** elrange 滑块
 * * 日期
 * ** eldate 日期、年月、年周、年
 * ** eltime 时间
 * * 选择
 * ** elcheckbox 勾选
 * ** elswitch 开关
 * ** elcheckboxs 多选组
 * ** elradios 单选组
 * ** elselect 下拉选择
 */
const formItemList = {
  // 文本类 defineComponent
  eltext: defineAsyncComponent(() => import('./t-text.vue')),
  elarea: defineAsyncComponent(() => import('./t-area.vue')),
  elurl: defineAsyncComponent(() => import('./t-url.vue')),
  // 数字
  elnumber: defineAsyncComponent(() => import('./n-number.vue')),
  elrange: defineAsyncComponent(() => import('./n-range.vue')),
  // 日期、时间
  eldate: defineAsyncComponent(() => import('./d-date.vue')),
  eltime: defineAsyncComponent(() => import('./d-time.vue')),
  // 选择、开关
  elcheckbox: defineAsyncComponent(() => import('./s-checkbox.vue')),
  elswitch: defineAsyncComponent(() => import('./s-switch.vue')),
  elcheckboxs: defineAsyncComponent(() => import('./s-checkboxs.vue')),
  elradios: defineAsyncComponent(() => import('./s-radios.vue')),
  elselect: defineAsyncComponent(() => import('./s-select.vue')),
  elselwrite: defineAsyncComponent(() => import('./s-selwrite.vue'))
}
/**
 * 动态组件的字典,便于v-for循环里面设置控件
 */
const formItemListKey = {
  // 文本类
  100: formItemList.elarea, // 多行文本
  101: formItemList.eltext, // 单行文本
  102: formItemList.eltext, // 密码
  103: formItemList.eltext, // 电话
  104: formItemList.eltext, // 邮件
  105: formItemList.elurl, // url
  106: formItemList.eltext, // 搜索
  // 数字
  120: formItemList.elnumber, // 数组
  121: formItemList.elrange, // 滑块
  // 日期、时间
  110: formItemList.eldate, // 日期
  111: formItemList.eldate, // 日期 + 时间
  112: formItemList.eldate, // 年月
  113: formItemList.eldate, // 年周
  114: formItemList.eldate, // 年
  115: formItemList.eltime, // 任意时间
  116: formItemList.eltime, // 选择固定时间
  // 选择、开关
  150: formItemList.elcheckbox, // 勾选
  151: formItemList.elswitch, // 开关
  152: formItemList.elcheckboxs, // 多选组
  153: formItemList.elradios, // 单选组
  160: formItemList.elselect, // 下拉
  161: formItemList.elselwrite, // 下拉多选
  162: formItemList.elselect // 下拉联动
}
export default {
  formItemList,
  formItemListKey
}
复制代码


  • el-form-div.vue


表单控件的代码 模板


<div >
    <el-form
      ref="form"
      :inline="false"
      class="demo-form-inline"
      :model="formModel"
      label-suffix=":"
      label-width="130px"
      size="mini"
    >
      <el-row>
        <!--不循环row,直接循环col,放不下会自动往下换行。-->
        <el-col
          v-for="(ctrId, index) in formColSort"
          :key="'form_'+index"
          :span="formColSpan[ctrId]"
        >
          <el-form-item :label="getCtrMeta(ctrId).label">
            <!--表单item组件,采用动态组件的方式-->
            <component
              :is="ctlList[getCtrMeta(ctrId).controlType]"
              v-model="formModel[getCtrMeta(ctrId).colName]"
              :meta="getCtrMeta(ctrId)"
              @myChange="mySubmit">
            </component>
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
  </div>
复制代码


js


import { watch } from 'vue'
import elFormConfig from '@/components/nf-el-form/el-form-map.js'
import formManage from '@/components/nf-el-form/el-form-manage.js'
export default {
  name: 'el-form-div',
  components: {
    ...elFormConfig.formItemList
  },
  props: {
    modelValue: Object,
    partModel: Object,
    meta: Object
  },
  setup (props, context) {
    // 控件字典
    const ctlList = elFormConfig.formItemListKey
    // 表单管理类
    const {
      formModel, // 依据meta,创建 Model
      formColSpan, // 依据meta,创建 span
      formColSort,
      setFormColSpan,
      setFormColSort, // 设置组件排序
      mySubmit
    } = formManage(props, context)
    // 监听列数的变化
    watch(() => props.meta.formColCount, (v1, v2) => {
      setFormColSpan()
    })
    // 监听reload
    watch(() => props.meta.reload, (v1, v2) => {
      setFormColSpan()
      setFormColSort()
    })
    // 监听组件值的变化,
    // 依据ID获取组件的meta,因为model不支持【】嵌套
    const getCtrMeta = (id) => {
      return props.meta.itemMeta[id] || {}
    }
    return {
      formModel,
      formColSpan,
      formColSort,
      ctlList,
      getCtrMeta,
      mySubmit
    }
  }
}
复制代码


这里就简单多了,因为实现具体功能的js代码都分离出去了。要么做成子组件,要么组成独立的js文件。 这里主要就是负责重新渲染表单组件。


表单验证



这个使用 el-form 提供的验证功能。 目前暂时还没有归纳好 el-form 的验证,因为需要把这个验证用的数据写入到json里面,然后读取出来设置好即可。 所以肯定没难度,只是需要点时间。


支持 扩展组件



自带的组件肯定是不够的,因为用户的需求总是千变万化的,那么新组件如何加入到表单控件里面呢?可以按照接口定义封装成符合要求的组件,然后做一个map字典,就可以设置进去了。


因为接口统一,所以可以适应表单控件的调用。


简单的方法是,直接修改两个js文件。 如果不方便修改的话,也可以通过属性传递进来。目前暂时还没有想好细节,不过似乎不是太难。


源码



github.com/naturefwvue…



相关文章
|
22天前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
126 64
|
22天前
|
JavaScript 前端开发 API
Vue 3 中 v-model 与 Vue 2 中 v-model 的区别是什么?
总的来说,Vue 3 中的 `v-model` 在灵活性、与组合式 API 的结合、对自定义组件的支持等方面都有了明显的提升和改进,使其更适应现代前端开发的需求和趋势。但需要注意的是,在迁移过程中可能需要对一些代码进行调整和适配。
101 60
|
22天前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
28 8
|
21天前
|
存储 JavaScript 数据管理
除了provide/inject,Vue3中还有哪些方式可以避免v-model的循环引用?
需要注意的是,在实际开发中,应根据具体的项目需求和组件结构来选择合适的方式来避免`v-model`的循环引用。同时,要综合考虑代码的可读性、可维护性和性能等因素,以确保系统的稳定和高效运行。
21 1
|
21天前
|
JavaScript
Vue3中使用provide/inject来避免v-model的循环引用
`provide`和`inject`是 Vue 3 中非常有用的特性,在处理一些复杂的组件间通信问题时,可以提供一种灵活的解决方案。通过合理使用它们,可以帮助我们更好地避免`v-model`的循环引用问题,提高代码的质量和可维护性。
32 1
|
22天前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
|
1月前
|
JavaScript 索引
Vue 3.x 版本中双向数据绑定的底层实现有哪些变化
从Vue 2.x的`Object.defineProperty`到Vue 3.x的`Proxy`,实现了更高效的数据劫持与响应式处理。`Proxy`不仅能够代理整个对象,动态响应属性的增删,还优化了嵌套对象的处理和依赖追踪,减少了不必要的视图更新,提升了性能。同时,Vue 3.x对数组的响应式处理也更加灵活,简化了开发流程。
|
1月前
|
存储 JavaScript 开发者
Vue 组件间通信的最佳实践
本文总结了 Vue.js 中组件间通信的多种方法,包括 props、事件、Vuex 状态管理等,帮助开发者选择最适合项目需求的通信方式,提高开发效率和代码可维护性。
|
1月前
|
存储 JavaScript
Vue 组件间如何通信
Vue组件间通信是指在Vue应用中,不同组件之间传递数据和事件的方法。常用的方式有:props、自定义事件、$emit、$attrs、$refs、provide/inject、Vuex等。掌握这些方法可以实现父子组件、兄弟组件及跨级组件间的高效通信。
|
1月前
|
JavaScript 数据管理 Java
在 Vue 3 中使用 Proxy 实现数据双向绑定的性能如何?
【10月更文挑战第23天】Vue 3中使用Proxy实现数据双向绑定在多个方面都带来了性能的提升,从更高效的响应式追踪、更好的初始化性能、对数组操作的优化到更优的内存管理等,使得Vue 3在处理复杂的应用场景和大量数据时能够更加高效和稳定地运行。
59 1
下一篇
DataWorks