日常bug记录汇总
画布节点部署线上与本地渲染样式不同步问题
- 问题: 项目上线后,会发现画布保存-本地和线上部署的画布节点样式不同步,本地运行的代码和线上部署的代码调用的同一个接口,本地在画布创建的节点保存好之后去上线的地址预览样式会错乱,线上画布创建的节点保存好后,去本地预览一样会样式错乱,但是本地去预览本地创建的画布节点、线上去预览线上创建的节点样式都是正常的
- 解决: 对比了几组线上和本地相同画布的数据发现,根据antv x6官网提供的通过vue自定义画布节点的方法,本地去保存上传的JSON画布数据,经过webpack打包上线后获取的JSON画布数据部分结构不同,本地上传的数据中的vue画布节点的beforCreate及beforeDistory等vue生命周期函数被
JSON.stringfy()JSON格式化之后都变成了空值,无法对函数进行解析储存,对需要JSON格式化的数据中的函数进行处理,JSON格式的数据也可以来存储函数,获取上传的画布JSON数据,也对JSON.parse()进行封装处理,可以对有函数的属性值进行解析,数据相通,画布渲染正常。
mixins异步数据问题
- 问题: mixins在created异步获取接口数据,混入到组件,在组件created、mounted无法获取此数据问题
- 解决: 因为数据是异步获取,在组件created去获取此数据,此时数据还没被请求到,需要在mixins获取该数据的async方法最后reurn一下获取到的数据,组件想要在created获取此数据,就可以直接
const {data} = await 获取数据的方法
路由不跳转对应菜单项也不能激活的问题
- 问题: 点击菜单列表切换路由需监听画布是否保存更新,如果需要保存,则打断路由跳转,操作之后路由不跳转,但对应菜单项却被激活
- 解决: 把router.beforeEach前置路由回调移植到需要操作的组件,让激活项
this.activeIndex = from.path需要加异步setTimeout,确保前置路由监听事件句柄在点击菜单激活子项的操作之后发生,以此来回到路由from项的激活状态
快速点击左侧列表子项误触保存提醒
- 问题: 由一个全局变量isChange控制表示画布是否改变,当画布变化isChange为true时来进行画布保存提醒,但是渲染画布同样会触发画布变化,只是单纯的渲染画布不需要进行画布保存提醒,所以需要做额外的处理;点击不同左侧列表,渲染不同的画布,画布渲染会触发画布改变(触发isChange = true),当点击一个左侧列表子项,开始渲染画布,画布渲染节点需要时间(一般小于500ms),主动去定义一个500ms的定时器,500ms之后给全局变量isChange赋值false,表示画布渲染结束后,不需要提示保存,但由此方案会出现快速点击左侧列表子项误触保存提醒的问题,定时太长:会导致切换其他左侧子项时,isChange还没变为false,触发保存提醒;定时太短:会导致画布还没渲染结束,在渲染过程中isChange变为false,之后还会触发画布变化时间isChange还会被修改为true,仍会误触保存提醒
- 解决: 定义一个计算时间差的方法,去获取两次点击左侧列表子项的时间差,如果这个时间差小于500ms(也就是等待画布渲染结束的定时器的时长),主动去吧全局变量isChange赋值为false,有了这个方法和定时器双重保证渲染误触isChange为true的问题得以解决。
画布节点添加链接桩宽度及间距不适配添加文字的问题
- 问题: 在画布节点添加链接桩的时候,添加中文字符的如果超过五个字会导致换行,如果添加的文字包含英文字母或者数字等数字符号,会导致跟下一个添加的链接桩的间距过大。
- 解决: 在自定义每个链接桩宽度的配置项中,加一个识别当前输入文字所在dom的宽度,方法内,创建一个临时
spanDOM,往dom里面innerText插入文字,并配置和链接桩label文字一样的文字样式,获取dom的宽度offsetWidth,这个dom会根据里面的文字(无论中文、英文还是数字)自动撑开宽度,也就是我们需要给链接桩配置的宽度,最后销毁临时dom,加入这个逻辑之后,链接桩宽度会根据输入文字自动撑开dom宽度来去设定,不再会出现宽度不够被挤换行,宽度太长,导致间距太大的问题。
websocket获取数据后,绑定表单,表单输入卡顿
vue 对象双向绑定响应问题,给对象添加新属性,不能实现实时响应
基于级联选择器的五级地址选择器市辖区数据不统一的问题
- 问题: 基于级联选择器封装了一个五级地址选择器,采用动态加载的方案,点击对应的下拉框子项,会根据当前点击项实时加载渲染下一级地址,选中到第五级的地址,下拉框收起,数据显示到输入框,正常的步骤是这样,但是请求的地址数据会出现不到五级的情况,如一个市的市辖区有的是没有下一级地址的,比如选中厦门市的市辖区,一样会动态加载数据,只不过弹出的框会显示暂无数据,这样的操作虽然地址选择已经到头了,但是并不会触发下拉框正常收起,输入框也不会正常显示地址。
- 解决:
- 想法一: 级联选择器有一个选择任意一级选项解决方案,点击左侧单选按钮,就算地址没有到五级,也可以选择地址,实时显示到输入框上,但这个方案,对于异步请求的数据有bug,点击下拉框子项会正常加载渲染下一级地址数据,但是点击左侧单选按钮,一样会打开下一级下拉框,但是数据不会正常渲染,需要在再点击一下下拉框子项,才能渲染显示数据,很影响用户体验;
- 想法二: 在动态渲染下一级地址的时候,判断每一个地址是否有下一级地址,如果没有下一级地址就让该子项
node.leaf = true定性为叶子节点(不会展开下一级目录),但是此操作会并发大量请求,高度消耗性能;让后端在返回响应数据的时候多加一个hasChild字段,以此来判断是否可以定性为叶子节点,来避免大量请求; - 想法三(最后完美解决方案): 结合大量地址数据会发现只有
name === '市辖区'的地址是有可能没有下一级地址的,所以在动态加载的回调函数里加一层逻辑,获取到当前点击子项的地址数据数组后,map遍历它的每个下一级地址子项,如果该子项的name='市辖区',再做一层判断是否有下一级地址子项,如果没有,给当前子项赋值item.leaf = true定性为叶子节点,这个操作一样可以避免大量并发请求,并且选中尽管不是第五级,但是没有下一级的地址,仍可以正常触发收起下拉框,输入框实时显示数据。需要注意的是,在对地址数据进行map遍历的时候里面的异步操作,会让返回数组没有数据,需要进行异步转同步,并Promise.all()的处理。
const nodes = await Promise.all(
address.map(async (item) => {
// 根据市辖区有无下级地址统一定性叶子节点
if (item.name === '市辖区') {
const children = await this.getRegion(item.code)
if (children.length === 0) {
return {
value: item.code,
label: item.name,
leaf: true,
level,
}
}else {
return {
value: item.code,
label: item.name,
leaf: level >= 5,
level,
}
}
} else {
return {
value: item.code,
label: item.name,
leaf: level >= 5,
level,
}
}
})
)
vuex 通过 getters访问数据为 undefined 问题
- 问题: 用户登录之后,服务器返回一个 token 数据,我将其同步到 vuex module下的 user 模块中。 然后从登录页返回到用户页,并发起 http 请求,获取用户的个人信息。但是在请求时,我会在请求拦截器中获取 vuex 中的 token 数据。如果存在就携带到请求头中和服务器做 OAuth 验证。如果不存在就直接不携带 token。用户登录成功之后,返回到用户页发起请求,但是获取用户信息接口是必须做 OAuth 验证的。问题在于在请求拦截器中 不能通过 vuex 的 getter 正确获取到 token值,而是返回 undefined;
- 解决: 问题在于 token = store.getters[user/token] 获取的值为 undefined,经过排查发现,vuex 中 getters 下的通过 state 获取的字段在 state 中定义为
token: getToken()。getToken函数返回的结果有可能为undefined,如果在state初始化的数据值为undefined,会使其变为不是响应式的。处理一下初始化默认值就行token: getToken() ?? ''
后端已经解决跨域,但前端请求接口仍然遇到跨域问题
- 问题: 项目部署上线后,有两个接口的域名跟项目的域名不一样,前后端分离的项目中肯定会碰到跨域的问题,究其原因还是为了安全。调试过程中发现,即使后端已经允许了跨域,但是前端依然报一个跨域错误:
The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. - 解决: 尝试了很多网上的方法也都没有弄清原因在哪里。索性就仔细研究一下 Access-Control-Allow-Credentials 这个头的作用,这个是服务端下发到客户端的 response 中头部字段,意义是允许客户端携带验证信息,例如 cookie 之类的。这样客户端在发起跨域请求的时候,不就可以携带允许的头,还可以携带验证信息的头,又由于客户端是请求框架是 axios,并且手残的设置了 withCredentials: true,意思是客户端想要携带验证信息头,但是我的服务端设置是 'supportsCredentials' => false, ,表示不允许携带信息头,错误找到了。配置
withCredentials: false问题解决。
切换到某次提交版本测试
- 问题: 单纯的只想切换到某次提交版本查看效果,不需要回滚,不需要修改代码
- 解决: 添加一个测试分支,看如下命令
git branch 新分支名 SHA值git branch test 92c17424b586be562db14c7d9d3e7faae337b325- 如果还想再测试其他记录,删除分支
git branch -d 分支名,再创建git branch 新分支名 SHA值
error in ./src/views/xxx?vue&type=template&id=f8328376&scoped=true& Syntax Error: Unexpected token (1:3934) 报错,根据报错信息不能定位报错位置
- 问题: 老项目vue代码嵌入到新项目,部分js语法不通用、约束规范不统一
- 解决: 问题出现在template标签模板,逐步删除标签块排查bug代码
- 不可以在第一对象加? ep: item?hit
- 对于不确定是否有值的数据{{}}模板里需要加判断默认值不能使用?? ep: {{currep ?? 0}} => {{currep || 0}}
这是个可以开子账户的系统,点击登录跳转页面到新的账户
- 问题: 回到原账户的页面一刷新也会变成新账户
- 解决: 问题出现在token覆盖,跳转新账户网站cookie存储的token被覆盖成最新的账户,回到旧账户的页面一刷新,vuex读取不到原本账户的token,而会读取最新存储的token
- 存储token的时候不再进行单一字符串的存储,而是存储一个map映射对象,key为用户名,value为该用户的token值,一登录新账户,就往map映射数据添加该新账户的一对key-value
- 监听页面刷新事件·
window.addEventListener("beforeunload", () => {})页面刷新前存储用户名,刷新之后去对应用户名的token值即可