前言

最近在做一个很多复合表格需要展示和编辑的项目,想分享一下如何build屎山

如何优雅的编写难以维护的代码

本项目用的是vue3+vite+ts

需求

如何优雅的编写难以维护的代码

如图所示,有很多块区域,每块区域可以单独编辑保存,互不干扰。

点击编辑时,该区域内可以编辑的地方都变成输入框

上图测试手机是否被监控只是简单演示,实际上有非常多格子,会有合并单元格情况,甚至一块区域有多个表格。

设计

如何优雅的编写难以维护的代码

  1. Block:区域组件,封装数据的请求和保存,封装标题和编辑按钮。
  2. Ta输入框显示不出来ble:表格组件,封装表格布测试你适合学心理学吗局的组件。
  3. Row:行组件,表示表格每一行的组件。
  4. Col:列组件,表示表格每一列的组件,就是单元格。
  5. Edit:编辑组件,编辑时变成输入框,不编辑时显示文本。

可以通过不停嵌套搭配row和col通信形成合并单元格。

开淦

如何优雅的编写难以维护的代码

Block组件内部请求拿到的数据,通过作用域插槽暴露出来给Edit绑定使用。

现在elementary是什么意思还差了一点,由于编辑状态封装在B嵌套查询sql语句lock里面,所以也要暴露isEdit来控制Edit是否展示输入框。

如何优雅的编写难以维护的代码

我们可以发现这样做看起来挺蠢的,上千个格子,每个Edit组件都要显式的绑定一下isEdit

当时我正在苦思,突然想到element的Form组件可以设置size属性,来控制里面的表单组件大小,然后读了一下源码发现是用Pro嵌套vide/Inject实现的,于是我也这样做。vb输入框

// Block.vue
provide('isEdit', isEdit)
// Edit.vue
<template>
  <el-input v-if="isEdit" :modelValue="modelValue" v-bind="$attrs" />
  <span v-else >{{ modelValue }}</span>
</template>
<script setup>
const isEdit = Inject('isEdit')
</script>

到目前为止,项目还算正常。

迭代

现在业务提出需求,编辑过的区域需要高亮显示变红,而且是永久记录,事情开始有趣了

如何优雅的编写难以维护的代码

当时我们一群人输入框激烈的讨论了好久实现的思嵌套循环路。

{
    id1: { a: { original: '123', fresh: '456' }, b: { original: '789', fresh: '456' } },
    id2: { c: { original: '123', fresh: '456' } },
}

如上图所示,接口这样返回,这里表示id1这条Element数据的字段a测试抑郁程度的问卷段b修改过,id2通信工程专业条数据的字段c字段b修改过,只要在这里出现的,就意味着修改过。

为什么会有多个id呢,因为有些区elementary域可能是对象,自然就一个id,有些区域可能是数组,就是多个id,如下图所示:

如何优雅的编写难以维护的代码

如果是嵌套数组的话,就直接拍扁。

至于{ orelementaryiginal: '123', fre输入框不显示sh: '456' }是为了日后预留,万一以后提出要看到以前修改的旧值的需求呢。

然后Block组件内置请求,通过不同的参数来获取该区域相应的编辑记录。

现在拿到数据了,那该怎么比对呢?

如何优雅的编写难以维护的代码

这是我一开始设想过的各种输入框不显示方式,传记录、id和属性名,在Edit里面判断或者直接判断。但无论如何看起来都很蠢,首先v-model里面已经通信技术专业绑定的变量写了amount,然后判断是否编辑过还要再写一次amount

这样写js输入框虽然解决了重复问题,但是仍然要修改非常多代码,因为有非常非常非常多的格子,Element每个格子都要这样修改累死人了。输入框显示不出来

毕竟懒才是第一生产力,我决定尽量保持原输入框显示不出来来的业务代码不变,那Edit组件vb输入框到底怎么获取记录,id,还要属性名呢?

id利用v-for遍历Row组件时设置kqq输入框ey属性来获取,如果不是遍历,那就手动设置key属性。

属性名通过截取v-model绑定的值来获取。

快来瞧瞧具体实现吧。

获取记录

// Block.vue
provide('records', records)
// Edit.vue
const records = Inject('records')

isE通信地址是写什么地址dit一样,通过Provide/Inject传递

这里还算正常,下嵌套循环面全是骚操作了

获取属性名

// Edit.vue
<template>
  <el-input v-if="isEdit" :modelValue="modelValue" v-bind="$attrs" />
  <span v-else >{{ modelValue }}</span>
</template>
// 使用
<Edit v-model="item.amount" />

先来回顾一下Edit组件是这样编写与使用,我并没有手动输入框绑定input事件嵌套分类汇总怎么做emit出去,而是利用v-model的语法糖自通信地址是写什么地址动生成更新事件,放在attrs中,然后内部v−bind=”attrs中,然后内部 v-bind=”attrs” 就可以绑定事件了,不知道的同学可以看看这个 v3.cn.vuejs.org/guide/migra…

// vue2
console.log(this.$attrs)
// vue3
setup(props, { attrs }) {
    console.log(attrs)
}

我们可以打输入框印出来瞧瞧百度输入框

如何优雅的编写难以维护的代码

const fn = String(attrs['onUpdate:modelValue'])
const temp = fn.slice(0, fn.lastIndexOf('=')).trim()
const key = temp.slice(temp.lastIndexOf('.') + 1)

这样可以拿到<Edit v-model="item.amo测试智商unt" />绑定的属性名amo嵌套if函数unt

  • modelValue是vue3的v-modelementary是什么意思el默认绑定的qq输入框变量名
  • 别被控elements制台迷惑,attrs['onUpdate:modelValue']拿到的函数,我这里使用String()把它vb输入框转为字符串
  • fn打印出来就类似这样了$event => item.amount = $event,我们可以通过字符串剪切来获取amount

当然这输入框在哪里有大坑,我们等下再说

获取id

如何优雅的编写难以维护的代码

上面我们说到既然v-for时要设置k输入框ey值,而key值是用id值来设置的嵌套原理有哪些实例,我们可以利用此来传递id

于是正常思路就通过props设置key来获取,可您猜怎么着,居然拿不到!

然后我再把attrs打印出来,也没有!

奇了怪了,这个key到底去哪了,于是vb输入框通信把this打印出来

如何优雅的编写难以维护的代码

最终在$_中里面的通信行程卡vnode中找到

原来是被vue用作虚拟dom中使用了

// Row.vue
setup(){
    const { vnode } = getCurrentInstance()
    provide(businessId, vnode.key)
}
// Edit.vue
const businessId = Inject('businessId**')**

vue3我嵌套分类汇总怎么做们可以百度输入框这样获取key,并通信技术专业和之前一样,通过Provide/Inject通信,不过这样做是有坑的,下面会说到

然后Edit组件就可以判断是否编辑过了,完整的代码如下:

const records = inject<Ref>('records', ref({}))
const businessId = inject<string>('businessId', '')
const hasEdit = computed(() => {
      if (!businessId) return false
      const fn = String(attrs['onUpdate:modelValue'])
      const temp = fn.slice(0, fn.lastIndexOf('='))
      const key = temp.slice(temp.lastIndexOf('.') + 1)
      return !!records.value[businessId]?.[key]
})

?.是es6可选链操测试纸怀孕图片作符,不懂的童鞋可以查一下

虽然我们拿到id了,但还可以做的更好

如何优雅的编写难以维护的代码

首先封装成hook

如何优雅的编写难以维护的代码

然后在RowTable组件中使用,因为有些并不是数测试抑郁症的20道题组,就一个对象,而且有多个Row,直接在Table通信一次id就方便许多。

拿不到id

这个时候坑就来了,有很多地方居然拿不到id, 这就牵扯到通信地址一个问题了,大家想一想,如父组件Provide一个变量叫a,然后子组件也Provide一个变量叫a,那请问孙输入框组件Inject接收到的变量a到底是谁的值?

然后我试了试,答案拿到的是子组件,这是符合直觉的,就像样式position: absolute一直向上找到最近的position: relative,还有访问对象的属性一直跟着原型链向上找到为止。

出问题的原因是,虽然直通信技术接在Table设置key,Row测试手机是否被监控用设key了,可Row还是在Pelement滑板rovide,所以要改成这样:

如何优雅的编写难以维护的代码

加个判断,只有当设置了key值才Provide

嵌套if函数些格子是没法正常反显

<Edit v-model="a ? item.b : item.c" />

这样写的话,我们上面的获取属性名的方法就失效了,所以就改嵌套原理有哪些实例成这样即可:

<Edit v-if="a" v-model="item.b" />
<Edit v-else v-model="item.c" />

其实还有更好的解决方法,但我懒了

测试环境所有的格子都是没法正常显示

element翻译过排查发现,是在获取属性名的时候出问题了:

// dev
e => item.a = e
// test
e=>item.a=e

千万别利用空格截取字符串,因为只有开发环境才有空格,打包后的代码因为有压缩,所以是没有空格的

为了兼容不同的环境,所以可以使用trim()去除空格

结束语

其实这篇文章我主要分享的是嵌套分类汇总怎么做利用key传递属性截取v-model绑定的属性名这两个歪门邪道,就本身这块业务来说有非常多的点我没有说,通信大数据行程卡比如万一绑定的属性是a.b.celement滑板.d,那样该怎么做呢?编辑的时候格子太多,一下子变成输入框可能会卡顿,所以使用requestAnimationFrame分批更改是否编输入框辑的状态。再比如,如果某个区域有多个table的话,那是不是该封装一个专门用来provide key的组件来包裹更方便嵌套原理呢,不用每个table都设置key等等非常多问题。

最后祝大家虎年虎虎生威,愿大家只用拉屎山第一坨翔,不用接着别人的拉

如何优雅的编写难以维护的代码