Vue3和Chrome插件Storage API碰撞出的奇怪问题

133 阅读2分钟

背景

Chrome插件Bulk URL Opener挺好用,用来临时存储链接并且可以批量打开。但是吧,UI我不是很喜欢,并且操作繁琐,各种操作需要中间页面。于是,秉持着自给自足的原则,我做了一个插件。但是,在做的过程中我发现一个奇怪的问题。

PS:使用Vue3+vite搭建Chrome插件项目

问题的发现

Chrome插件用来存储数据绕不开Storage API,这是类似WebSorage的API,但是专用于插件数据的存储,我的插件就是用这个来存链接。下面是主要代码。

// 定义
const dynamicForm = reactive({
  name: '',
  urls: [{ url: '', title: '' }],
});
// 存
chrome.storage.local
  .set({ [dynamicForm.name]: dynamicForm.urls })
  .then(() => {
    message.success(isNew.value ? '保存成功' : '修改成功');
  });
// 取
chrome.storage.local.get(val, (result) => {
  dynamicForm.name = val;
  dynamicForm.urls = result[val];
});

理论上,dynamicForm.urls是个数组,存进去是数组取出来应该也是数组,并且在页面上看上去也都能展示。但是,当我做完实际去使用dynamicForm.urls这个数组的方法时,比如数组的splice用来删除,控制台告诉我方法找不到!?哎,我就纳了闷了,不是数组吗。于是我把取出来的数据log出来,果然不是,是以数组下标为键的对象!

屏幕截图 2023-09-06 113523.png

问题原因

数组变对象了,虽然数组本质就是对象,不过在原型上有其数组特殊的方法。

这里插播一下,不是广告,推荐一下一本小册《JavaScript 语言编程进阶》,这本书作者通读W3C标准文档,把JS的底层设计讲的非常通透。

好了问题找到了,但导致问题的原因是什么。我原本以为是chrome故意这样设计的,但是同行告诉我他是可以正常存取数组的,我也在控制台了操作了一下,也是正常的。到这我大概能猜到了,应该是Vue响应式导致的问题。众所周知,Vue3和Vue2最大的不同点之一就是响应式了,Vue3用了ES6的Proxy来实现响应式,这也是不支持IE的原因,这是没有垫片的语法无法转化成ES5。而Proxy是个对象,那么是不是Chrome在处理Proxy的时候就只按照对象来处理了,不管Proxy的内容是什么,这就不得而知了,如果有人知道请在评论区里告诉我\color{red}{如果有人知道请在评论区里告诉我}

问题解决

以上都是猜测,还是得实践一下才行。我的第一种解决方式就是用JSON.stringify破坏原先的结构直接存字符串,但不够优雅。我想起来Vue好像有对应的方法,于是找了找文档,toRow,试了试完美解决问题。