element table中插槽使用
项目安装启动
设置私服镜像
npm config set registry http://172.18.248.130
安装插件
npm install --force or --legacy-peer-deps
aysnc await promise
async 关键字用于声明一个异步函数。在异步函数中,可以使用 await 关键字来等待一个 Promise 对象的结果。
异步函数总是返回一个 Promise 。如果函数体没有显式返回任何值,它会隐式返回一个已解决(resolved)的 Promise ;如果函数体中有 return 语句,则返回的值会被包裹在一个已解决的 Promise 中;如果在函数体内抛出错误,则返回一个拒绝(rejected)的 Promise 。
await必须结合async一起使用,右边的Promise对象必须处于reslove状态,后续代码才能正常执行。
async await相当于Promise.resolve('XX').then(res => {这里执行的是await后面的代码})
解决ts报错 'this' implicitly has type 'any' because it does not have a type annotation
"noImplicitThis": false
flex
flex属性介绍
- flex属性其实是一种简写,是flex-grow,flex-shrink和flex-basis的缩写形式。
- 默认值为0 1 auto。前两个属性可选。
flex-grow
flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大
flex-shrink
flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小
flex-basis
flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。 它可以设为跟width或height属性一样的值(比如350px),则项目将占据固定空间
解决设置flex: 1的情况下再设置width不生效
flex: 0 0 width; // 元素不放大不缩小 占据的空间为width对应的数值大小
能源一体化
监听粘贴操作,获取剪贴板中图片base64数据
文件上传
- 如果调用通用的文件上传接口
/store/attach/upload,不能传文件的二进制流,这样接口会无法识别文件扩展名,报5000。需转为file格式上传,且入参需是表单形式。
后续
通过监听paste事件,可直接获取图片的blob,再通过const file = new File([blob], fileName, { type: fileType })将blob转为file。之前是blob转base64再转file,多走一步。
//绑定粘贴事件 Ctrl+V
bindPaste();
//绑定粘贴事件
function bindPaste(){
//定义变量存储获取的图片内容
var blob;
//获取body对象
var body = document.getElementsByTagName("body");
//定义body标签绑定的粘贴事件处理函数
var fun=function(e){
//获取clipboardData对象
var data=e.clipboardData||window.clipboardData;
//获取图片内容
blob=data.items[0].getAsFile();
const file = new File([blob], fileName, { type: fileType }); // 将blob转为file
}
//通过body标签绑定粘贴事件,注意有些标签绑定粘贴事件可能出错
body[0].removeEventListener('paste',fun);
body[0].addEventListener('paste',fun);
}
页面优化 老界面截图 便于数据验证
IT人员修改位置
智慧中心7楼中大屏适配
智慧中心7楼中大屏分辨率为14560*3402,能源一体化首页是按照1920*1080的分辨率进行设计以及开发的,如果不做任何配置,在大屏上展示的效果如下
为了进行适配,进行一下调整:
- 根节点html fontSize根据屏幕宽
高进行计算。在调试的过程中发现,根节点html fontSize在屏幕大于3840时被限制为40px,找到相关代码
进行相应调整
注意:在屏幕宽度大于3000时,不仅需要根据屏幕宽度计算fontSize,还需要考虑屏幕的宽高比,用屏幕高宽比除以1080/1920得到scaleY,再用baseSize * scaleX * scaleY计算出fontSize。之所以要乘以scaleY,是因为大屏的横向拉伸幅度较大,就是过宽过矮,不是按照1920*1080等比例拉伸的;
-
在进行大屏开发的时候,字体大小变量推荐使用px,而不是vw,图片大小设置也用px,之前使用vw进行开发,导致字体以及图片在大屏上异常大,原因在于大屏宽度过高;
-
关于echarts图表的大屏适配,X轴、Y轴的字体大小不能写死,需要根据屏幕根节点fontSize进行计算,同理折线图的线宽也不能写死;
解决根据表格数据动态修改表格高度时报错(2024-10-24)
能源一体化项目的页面现在都改为一屏展示,所以页面中的表格在数据比较多的时候需要结合其他区块的高度计算出页面剩余高度赋予表格,然而当数据比较少时,表格的高度就是表格数据全部展示时的高度。
在开发工序精管发电能源计划页面时,如果没有给表格高度变量tableHeight赋初始值,会报错:Uncaught (in promise)TypeError:Cannot read properties of null(reading style')at TableLayout.setHeight(table-layout.ts:74:10)。
所以切记表格高度变量tableHeight必须要有初始,不能为空字符串。
props type为多个类型时,需用||进行分割,而不是|
相关报错如下:
正确语法:
echarts 如何设置 legend 展示为虚线或者实线
如果通过itemStyle: {opacity: 0}设置虚线,会导致虚线的高度无法调整,在大屏上只是一根细线。
可通过icon:'path://' + svg path,采用svg图片生成legend,进行解决。注意path://不能忘记拼接,不然不会生效。
echarts 如何设置 legend 展示为虚线或者实线
element plus组件Image图片使用注意事项
使用Image加载assets目录下的图片,直接传入相对地址,会报404
解决方法有两种:
- 将图片放在public文件夹下
- 使用import引入assets下的图片
首页工序能耗点击标题右侧箭头 如何跳转至对应工序首页时 左侧菜单也切换至工序精管菜单
实现步骤:
- 点击箭头进行页面跳转时,先跳转至工序精管整个模块的首页(AppMain.vue),在跳转的路径后面拼接实际要跳转的页面地址(childPath)
- 在AppMain.vue页面获取页面地址,如果地址后面拼接了childPath,则再进行一次页面跳转。
解决报错:TypeError:Cannot read properties of undefined (reading'产量')
报错的原因是使用el-tab来进行模块切换,在页面加载时,三个子模块的相应dom也会进行加载,如果html元素包裹的数据是通过对象匹配key进行获取的,且对象为空,或对象匹配不上key,会报上面的错误,导致包含此类数据的dom都无法加载。
html元素包裹的数据是通过对象匹配key进行获取
解决方法是在数据匹配时使用?.链判断运算,它允许开发人员读取深度嵌套在对象链中的属性值,而无需验证每个引用,当引用为空时,表达式停止计算并返回 undefined
解决el-tab切换时 图表无法计算宽高 导致图表展示大小和位置不合适
解决方法:
不要通过%来设置表格的宽高,需通过px/rem/vw/wh来明确指定表格宽高
组件defineExpose响应式对象上的一个属性,怎么保持相应响应性?
通过toRef()基于响应式对象上的一个属性,创建一个对应的 ref。这样创建的 ref 与其源属性保持同步。
proxy.$refs
proxy.$refs访问组件或者元素,可用于遍历时访问组件并调用其expose出来的方法。从而避免为创建多个ref对象 导致代码冗余。
不推荐
推荐
name + alias ?? label
+的优先级高于??,上式等同于(name + alias) ?? label,如果先要执行??,则需给??运算加括号name + (alias ?? label)
parseInt取整不会进行四舍五入,对接口数据取整应使用Math.round
element plus 表头换行
之前是通过div分割来实现换行,现在可通过换行符\n结合css样式white-space: pre-line来实现
之前实现方式
现在实现方式
参考:[ ]()通过max-height设置表格最大高度
这个高度应该是页面一屏展示的情况下,整个屏幕高度减去除了表格以外其他区域的高度得到到的数值,从而在表格高度超过max-height时,显示滚动条,不超过则不显示。
这样比之前根据接口返回数据条数乘以行高再加上表头高度来获取整个表格高度,并判断表格不加滚动条完全展示的情况下,页面能不能一屏展示,如果不能一屏展示,则需要将页面高度减去其他区域高度而获得的剩余高度,设置为表格高度要方便的多。
左侧菜单收起与展开 echarts自适应
实现代码:
注意点: 包裹echarts的父元素必须明确指定宽高,宽度不可用flex: 1来代替,不然会导致包裹echarts的父元素宽度计算不正确,从而resize失败
热风炉换烧模型 排班与统计 表格滚动至箭头所在行
可通过scrollTo/scrollTop来实现
滚动容器
- overflow: auto:只有在内容溢出的情况下才会显示滚动条,这是最常用的选项。
- overflow: scroll:即使内容未溢出,也会始终显示滚动条。
scrollTo
用于将滚动容器的元素滚动到 指定的坐标位置。
// 使用 scrollTo
function useScrollTo() {
const container = document.getElementById('scroll-container'); // 滚动到绝对位置 使用对象参数进行平滑滚动
container.scrollTo({ top: 200, left: 0, behavior: 'smooth' });
}
scrollTop & scrollLeft
表示滚动容器当前已经滚动的水平或垂直距离。可以用来获取或设置滚动容器的滚动位置
参考:浏览器滚动能力完全解析:scroll, scrollTo, scrollBy, scrollIntoView
首页消息代办点击跳转至对应页面打开详情弹窗
该功能分三步来完成:
- 先跳转至sems.nisco.cn/index?path=xxxx 确保左侧菜单切换
- 再跳转至子页面 例如sems.nisco.cn/licenseApprove/addForm
- 在子页面根据id打开消息详情弹窗
之前使用window.location.href来进行页面跳转,相比于Vue Router,window.location.href会重新加载页面,导致页面加载时间长,在上面的1、2两步之间过度时间长 页面很长时间右侧处于空白状态。为了优化用户体验,采用Vue Router来实现1、2两步。具体步骤如下:
- 先在src/views/portal/components/PortalHeader/PortalHeader.vue文件中监听消息点击事件,根据消息id调接口获取1、2两步跳转的路由地址,并通过
query(params无法携带参数,切记)在跳转时携带childPath以及businessId两个参数。通过pinia存储一级菜单path 用于左侧菜单匹配。
关于左侧菜单匹配,跳转至sems.nisco.cn/index?path=xxxx 会在src/layout/components/SidebarUtils/src/layout/components/SidebarUtils.ts文件中根据pinia存储的一级菜单path来进行子系统菜单以及子系统名称匹配。
- 跳转至sems.nisco.cn/index?path=xxxx 页面后 在src/layout/components/AppMain.vue文件中会获取路由参数,完成第二步的子页面跳转
- 最后在子页面中通过在hooks中定义的useOpenDetail打开详情弹窗
注意点
Vue router无法通过params携带参数,需使用query- 在src/layout/components/AppMain.vue文件中进行子页面跳转时 需加个延时器 延时建议为1000ms 不然子页面可能不能正常打开
- 从首页消息队列打开详情页面 再点击菜单popover进行一级菜单切换
需设置sideMenuPath为'',不然左侧菜单不刷新。相关代码在src/layout/components/Sidebar/index.vue文件中
解决npm run build报NODE OPTIONS不是内部或外部命令,也不是可运行的程序或批处理文件
为了解决npm run build打包内存溢出报错
在package.json->scripts/build添加NODE OPTIONS=--max old space size=8192
cmd运行npm run build 报'NODE OPTIONS'不是内部或外部命令,也不是可运行的程序或批处理文件
解决方法:
运行 npm install -g win-node-env
然后再运行npm run build就可以成功打包了!
参考:
Vue编译报错内存溢出问题解决方式
'NODE_OPTIONS' 不是内部或外部命令,也不是可运行的程序
解决echarts引用了markPoint或者markLine没有效果
import 'echarts/lib/component/markPoint'
import 'echarts/lib/component/markLine'
参考: echarts引用了markPoint或者markLine没有效果
IOT数据相加
系统管理/公共配置/业务字典 点击新增
- strKey参考已有数据进行填充,
- value1为需要相加的数据的strValue以英文分号(;)分割
- value2为数据名称,参考上方的strValue2
- 不同strValue3的数据无法相加,因为来自不同的IOT设备。
v-for遍历对象
表格滚动条滚动时加粗 便于操作
通过伪类active,在滚动条滚动时设置纵向/横向滚动条高度/宽度,实现滚动时加粗。
使用ref定义的数组通过forEach方法修改数值 会失去响应性
在Vue 3中,使用ref定义响应式数据时,如果直接使用forEach遍历数组并对其进行操作,可能会导致数组内的元素不再具有响应式特性,即失去“响应性”。这是因为forEach不会创建新的作用域,因此在其内部进行的任何赋值操作都不会被Vue的响应式系统跟踪。
解决方法:直接给数组重新赋值,下面图片中的三个方法未必有效。
报表修改settMonth
解决节能技术/项目资料管理/项目资料信息 资料汇总弹窗查看的附件与关联项目不对应
原因是每个文件类型都有一个对应的el-dialog,里面包含文件上传组件。如果el-dialog未设置destory-on-close,会导致弹窗关闭后,文件上传组件依然存在。进而导致proxy.$refs.fileUploader.init(row.id)获取的文件上传组件不是当前打开的弹窗内的文件上传组件,而是第一个打开的弹窗内的文件上传组件。从而导致弹窗中展示数据变化了,但是附件没有变化。
解决方法:
1、共用一个弹窗,进而共用一个文件上传组件;(推荐,这样可以减少冗余代码)
2、给每个弹窗设置destory-on-close。(项目中使用的是这个方案,因为按照1来调整的话,改动量过大)
解决首页用电组成日月切换时 日图表中会残留月中的尖点数据
echarts在series数组长度发生变化时,需将notMerge设置为true,这样可以避免旧数据残留的问题。WangCharts组件默认设置的notMerge为false,为了避免旧数据残留,在setOption时使用clear方法对图表进行情况
热网平衡模型三维插件使用
设置有效期
在js中找到2025-或2024-,修改其时间
设置有效期后页面仍为空白
找到截图中相应代码进行调整
解决氧气模型产能设置checkboxGroup间隔相等
刚开始使用100%来计算marginTop,后来发现百分比是相对于该元素的包含块的宽度(width)来计算的,所以需将百分比改成代表高度vh
解决节能技术-安全绩效增删改同一条数据编辑id跟更新id不一致
接口返回的数据均为字符串,导致elInputNumber的加减按钮无法正常点击,故在获取接口数据后将数字字符串转换为数字,这一操作导致id转为数字后跟之前的值后四位不一致。原因在于Number方法只能处理16 位的整数,超出则精度丢失,而接口返回的id有19位
若需处理超过 16 位的整数:
1、将超长数字以字符串形式保存,运算时通过专门的库处理(如 big.js、decimal.js)
2、用 BigInt 类型:ES2020 引入的 BigInt 支持任意精度整数,可直接表示超长整数(需在数字后加 n 标识)
const bigInt1 = 12345678901234567890123n; // 23位BigInt
const bigInt2 = 98765432109876543210987n;
console.log(bigInt1 + bigInt2); // 111111111011111111101110n(准确运算)
在本案例中,在字符串转数字时,直接略过id
金恒平台页面中生命周期钩子执行顺序
1、 在创建菜单时使用缓存为false
- 初始打开页面 watch->onMounted->onActivated
- 跳转至其他页面触发watch->onDeactivated 不触发onBeforeUnmount
- 再次打开页面,不管面包屑里有没有该页面 触发watch->onActivated 不触发onMounted
- 页面通过面包屑关闭或者切换到其他页面会一直触发onDeactivated
- 页面的watch监听一直生效
2、在创建菜单时使用缓存为true
- 初始打开页面 watch->onMounted->onActivated
- 跳转至其他页面触发watch->onDeactivated 不触发onBeforeUnmount
- 再次打开页面,不管面包屑里有没有该页面 触发watch->onActivated 不触发onMounted
- 页面通过面包屑关闭或者切换到其他页面会一直触发onDeactivated
- 页面的watch监听一直生效
由此可推断创建菜单时不管是否使用缓存,页面打开后一直处于缓存状态,刷新浏览器才能去除缓存。这是因为平台所有页面均使用keep-alive,所以创建菜单那个使用缓存的配置形同虚设。
占位菜单
因为目前平台仅支持到四级菜单,为了使四级菜单按功能进行排序,即同一个模块的菜单处于一行,考虑使用占位菜单调整菜单排序。占位菜单只能占位,不展示菜单名称,也不可点击跳转,具体实现代码:
具体菜单配置:
钢轧集控(二期)
keepAlive页面切换至其他页面如何清除定时器
通过onActivated在页面展示时设置定时器,onDeactivated页面隐藏时清除定时器。
解决数据更新时echarts需要重复加载
在调用setOption更新数据时,如果传入的notMerge属性,则将其设置为false
解决代码发布报错
sass相关
这种报错一般是样式编写不正确 例如scss的@for循环中不支持#{$i - 1}的写法。
免登录实现流程
- 编写免登录页面,调用登录接口,传入用户名与密码等参数,接口报2000后,根据路由中传入的redirect参数,跳转至指定页面;
2.在router/index.ts中注册autoLogin.vue页面路由
3. 在src/permission.ts中将免登录页面路由加入访问白名单;
4. 在浏览器中输入地址,即可免登录跳转。
.native
记住Vue鼠标修饰符,让你拿捏鼠标! 欢迎大佬补充~
修饰符 .native 用于在父组件监听子组件触发的原生事件。
如何在缩放页面时表格列宽随之调整
- 在hooks/userScaleSize中定义
getRatioSize方法
2. 在el-table-column中通过
getRatioSize计算minWidth或width大小
缩放页面发现,会再次调用getRatioSize方法重新计算表格中列表的宽度。疑惑点:
1、为啥缩放页面会再次调用getRatioSize方法;
2、el-table属性中min-width与width的使用场景。
grid情况下父元素宽度变化时子元素保持等分
通过 minmax(0, 1fr),可以实现父容器任意宽度下的严格等分,且兼容内容动态变化。这是 Grid 布局中处理等分问题的常用技巧。
解决一图连铸甘特图与时间轴不能完全对应
1、使用element.getBoundingClientRect().width代替element.offsetWidth,因为前者可以保留小数位 2、通过labelWidth加总的dateWidth来获取甘特图宽度,比document.querySelector(xxx).getBoundingClientRect().width更精确,因为前者剔除了右侧滚动条的宽度
妙用ResizeObserver监听系统左侧菜单收起/展开以及炼钢全流程左侧菜单收起/展开 右侧甘特图自适应
ResizeObserver可以精准监听任意 DOM 宽高变化
new ResizeObserver(([e]) => chart.resize(e.contentRect.width)).observe(dom);
LCA
解决yarn安装不上 需要删除yarn.lock
金相
ref获取vue组件报错
Uncaught (in promise) TypeError: dataOptions.call is not a function
Uncaught (in promise) TypeError:convert object to primitive value
Vue文件中使用的组件未import
在使用reactive定义一个对象xx,获取接口数据后,使用for(let key in xx)对对象进行赋值,会报相关错误,只用改成通过ref定义对象,再通过xx.value给对象赋值,才不会报相关错误,原因不解。
el-dialog居中展示且可丝滑拖拽
通过设置overlay的flex代替dialog的position
解决el-dialog打开 数据展示区域为空 不能展示接口返回数据
先将v-model绑定的数据设置为true 再调用接口给弹窗中关联的数据赋值。
el-image图片放大会被遮挡
解决图片无法正常访问
浏览器快捷方式/目标后贴上--ignore-certificate-errors --allow-running-insecure-content 注意这段字符串前面要加一个空格。
el-image 设置lazy后图片不展示
element table插槽使用inputNumber,加减号各点一次后数据不再改变
刚开始以为是数据深层嵌套,丢失响应响应性,试图通过ref(reactive(...))的方式使数据保持响应性,无效。
后百度建议使用.sync修饰符,但是vue3已弃用。
最后发现是因为使用.modelValue替代v-model是问题所在。
v-model 的本质
-
默认行为(Vue 3):
<ChildComponent v-model="parentValue" />等价于:
<ChildComponent :modelValue="parentValue" @update:modelValue="parentValue = $event" />
子组件需声明 modelValue prop,并通过 emit('update:modelValue', newValue) 更新。
总结
v-model是:modelValue与@update:modelValue的结合,所以用:modelValue替代v-model是不可行的,这样会无法监听modelValue的变化,导致加减号各点一次后数据不再改变。
v-for循环数字
v-for循环数字是从1开始的,故匹配对应数组的值时,i要减1。
excel、zip文件下载接口为5000的特殊处理
文件下载主要是将Axios的responseType设为blob来将响应数据解析为 Blob 对象。使用Axios时,可以通过设置responseType为'blob'来指示Axios将响应数据作为Blob对象处理,通常用于处理二进制数据(如图片、PDF、excel文件等)
说明:
- responseType: 'blob':这个配置告诉Axios将响应数据作为Blob对象处理。
- 创建Blob URL:使用
window.URL.createObjectURL方法,我们可以为Blob对象生成一个临时URL,这个URL可以赋给<a>标签的href属性。 - 触发下载:通过编程方式创建一个
<a>标签,设置其download属性(指定下载的文件名),然后模拟点击它来触发下载。 - 清理:下载后,移除创建的
<a>标签,并使用window.URL.revokeObjectURL释放Blob URL,以避免内存泄漏。
注意事项:
- 如果后端返回的是文件流,确保后端设置了正确的响应头(如
Content-Disposition),这样前端才能正确获取文件名。不过,在前端代码中,我们可以通过link.setAttribute('download', 'filename.ext')来指定下载的文件名。 - 如果后端返回的文件名是动态的,可能需要从响应头中获取。例如:
const contentDisposition = response.headers['content-disposition'];
const fileName = decodeURIComponent(contentDisposition.split('filename=')[1]);
重点因为将响应数据解析为Blob对象,会导致前端无法辨别HTTP状态码非2000的情况。可通过检查content-type是否为application/json,如果是application/json,则将Blob转换为文本,进而读取错误信息,并将其抛出。
一图连铸
解决使用sortable.js拖拽表格改变某两行顺序后提交接口 再刷新表格数据 表格重新渲染后行排序不对
需要指定表格的row-key
使用v-for生成的div 设置data-xx属性 在css中通过attr(data-xx)无法使用该属性
按照如下截图方式
直接在style中设置变量名以及对应值,再在css中通过var()使用
解决报错'Uncaught (in promise) TypeError: Cannot read properties of null (reading "shapeFlag")'
原因在于定义一个对象时,这个对象中使用的变量未定义
巨能
页面中使用watch监听路由变化后无法取消监听
使用watch监听路由变化的页面不可缓存
能源监视各页面不可使用缓存,不然会导致监听路由变化的watch一直执行(可能会造成内存溢出等性能问题),即使是非能源监视的页面跳转也会触发。尝试在onBeforeUnmount生命周期钩子中调用stopWatch来关闭watch,但是切换页面onBeforeUnmount不执行。
解决打开同时几个报表页面 通过面包屑关闭页面后 前一个报表页面无法正常展示 屏幕展示为空
因为报表页面的路由地址都为reportView?reportId=xxxxxxxxx,如果关闭面包屑后通过router.push的path来打开上一个报表页,path中?reportId=xxxxxxxxx相当于query参数而非路由地址,项目中无reportView路径,故页面展示为空
router.push({
path: 'reportView?reportId=xxxxxxxxx'
})
router.push({
path: 'reportView',
query: {
reportId: xxxxxxxxx
})
})
可通过router.push的name来匹配路由,从而解决路由中携带?的问题(这种情况下,?后面的内容也是路由中的一部分 而非携带的参数)
echarts图例过多 tooltip展示不完整
1、对图例进行滚动处理
2、通过appendToBody : true将 tooltip 的 DOM 节点添加为 HTML的body的子节点,并通过 position 自定义 tooltip 显示位置
appendToBody : true可避免tooltip 超出 echarts容器范围被截断position自定义可让tooltip的起始位置一直处于图表的顶部,避免数值越大tooltip越往上,上部区域溢出body容器范围被截断
永钢
keep-alive的页面如何清除定时器
如果你的组件被 <keep-alive> 包裹,onUnmounted 不会触发。此时,你需要使用 onDeactivated 和 onActivated 钩子来管理定时器
注意: 因为每次打开页面都会触发
onActivated生命周期钩子,所以定时器定义后只要在onActivated回调中调用,不能重复调用,不然会导致定时器无法清除(因为重复调用会导致有两个以上定时器存在)