前言

 

出现问题的场景是一个用户桌面管理系统 

用户在桌面上 可以增删改查应用, 文件夹 相关设定 

当拖动 应用, 文件夹的时候 前端需要发送更新请求给服务端 来保存布局

但是出现的问题是 在测试环境 拖动文件夹能够正常的发送请求

但是 却存在一些 情况下面 拖动了 文件到文件夹之后, 然后再拖动 文件夹 就不能正常的发送保存布局的请求了

请求发送的正常调用流程

这个问题我们也主要是 直接看正常的调试流程

拖动 默认分组5 之后, 前端这边 正常的发送了请求

20 特定的操作之后响应式对象不“响应“了(一)_深拷贝

查看一下 网路请求的调用堆栈, 是在 组件 mouseUp 之后发起的

然后 回调的是 文件夹组件的 stopDrag

然后再上层是 文件夹组件的 item 的 watcher 的 handler 

然后是 桌面组件的 saveOrUpdateUserAndGroup 操作 

然后 稍微观察一下代码, 大致的流程是 拖动结束之后会回调 stopDrag, 然后这里面会更新当前 文件夹的坐标, 然后 有一个文件夹信息的 watcher, 里面监听了文件夹信息的变化, 提交变化给了父组件, 然后父组件调用 saveOrUpdateUserAndGroup 来保存

我们这里的问题的调试 主要是围绕着 这几个回调 来进行调试

20 特定的操作之后响应式对象不“响应“了(一)_html_02

BTW, 顺便一提 一些 webpack 打包之后的一些调试思路, 这些方法主要用于 测试环境, 线上, 等等情况 

这个一方面可以参考开发环境的 函数名称, 比如 handleMouseUp, stopDrag, handler, saveOrUpdateUserAndGroup, 这部分的名称主要是用于定位 相关的 js 的关键代码, 方便用于 打断点之类

另外一个 tips, chunk-vendoer 相关的是 第三方的包, chunk-$摘要 是业务代码相关

在 webpack 打包之后, 可以重点关注这部分 chunk-$摘要 相关的js 

20 特定的操作之后响应式对象不“响应“了(一)_html_03

问题的调试

继续往下, 我们复现问题, 将一个文件 拖动到 一个文件夹中

然后 问题就复现了, 此时 无论我们怎么 拖动文件夹, 都不会再发送请求了 

将 通讯录 拖动到 默认分组5 中

20 特定的操作之后响应式对象不“响应“了(一)_JSON_04

然后 随意拖动 默认分组5 三次, 没有再发送期望的请求  

20 特定的操作之后响应式对象不“响应“了(一)_序列化_05

然后接下来是调试阶段, 首先 我们需要定位到几个关键的函数

stopDrag, handler, saveOrUpdateUserAndGroup

格式化一下 混淆之后的 js, 然后找到上面三个函数 打上断点

20 特定的操作之后响应式对象不“响应“了(一)_序列化_06

然后拖动文件夹, 可以来到 stopDrag 的断点 

然后 放掉断点 查看情况

20 特定的操作之后响应式对象不“响应“了(一)_html_07

放掉断点之后, 断点就直接过了 

因为接下来的流程关系着 item 的 watcher, 所以我们看一下 item 的情况 

可以看到这个 这个 item 中只有相关属性, 并没有 vue 响应式支持所需要的 setter, getter

20 特定的操作之后响应式对象不“响应“了(一)_深拷贝_08

然后我们看一下 正常情况的 item

所以 到这里 大致的原因 应该也就出来了吧, 呵呵 

 

20 特定的操作之后响应式对象不“响应“了(一)_JSON_09

一个关键的信息是 应用添加到文件夹之后, 拖动文件夹自动发送请求这项功能就失效了 

那我们 来看一下 这里的情况

这里 updateFolderItem 的处理就是更新当前文件夹下面所有的信息 

可以看到 到这里这个 e.data 就已经没有了 getter, setter 了, 再往上追溯 

 

20 特定的操作之后响应式对象不“响应“了(一)_序列化_10

可以看到的是这里通过 JSON.parse(JSON.stringify(toCopyObject)) 来进行深拷贝 

这就是 造成问题的地方了

20 特定的操作之后响应式对象不“响应“了(一)_深拷贝_11

可以看到的是 this.item 初始化的时候 vue 是为其初始化了相关 setter, getter

但是 JSON.parse(JSON.stringify(toCopyObject)) 深拷贝了之后, 新的对象 r 没有了相关 sttter, getter 也没有注册的相关响应式注册的相关事件 

20 特定的操作之后响应式对象不“响应“了(一)_响应式_12

问题的解决

所以调整的方式就是 调整这里的深拷贝的方式 或者 考虑其他的设计

具体的模型设计, 我们这里不去考虑, 假设合理, 我们这里调整一下 深拷贝的方式

调整一下 copyItemObj 的方式, 注意这里 cloneObj 是为了这里需要 随意注册的一个 vue响应式对象, 否则 后面 this.$set 不会拷贝 originalItem 相关的 setter, getter

20 特定的操作之后响应式对象不“响应“了(一)_响应式_13

查看一下 调整之后的情况, 初始化状态如下  

20 特定的操作之后响应式对象不“响应“了(一)_序列化_14

将通讯录拖到 默认分组5 之后情况如下, 发送了两个 saveOrUpdateUserAndGroup 的请求 

20 特定的操作之后响应式对象不“响应“了(一)_序列化_15

随意拖动 默认分组5 三次之后, 前端多发送了 三次请求

20 特定的操作之后响应式对象不“响应“了(一)_响应式_16

storage 相关奇奇怪怪的收货 

关于 store 相关, 这里是在 路由的 gurder 中从 store 中获取 access_token

奇怪的是 从调试界面中获取响应的值获取不到, 但是 程序中/console.log 可以输出对应的值

20 特定的操作之后响应式对象不“响应“了(一)_深拷贝_17

20 特定的操作之后响应式对象不“响应“了(一)_html_18

完