首页 > 解决方案 > 使用 vue getter/setter 指向 localStorage 时的奇怪行为

问题描述

我从这段代码中得到了奇怪的行为。我想使用 getter 和 setter 指向本地存储。

第一次呈现应用程序时,会正确检索项目。之后,当向列表中添加新项目时,它不会被渲染。此外,当添加一个项目时,它只会在添加第一个项目后交换前一个项目的索引处的值。

<input type="text" v-model="term" @keyup.enter="submit()" />
<ul>
  <li v-for="(item, i) in history" :key="i">{{item}}</li>
</ul>
const app = new Vue({
  el: '#app',
  data: {
    term: '',
  },
  computed: {
    history: {
      get() {
         return JSON.parse(localStorage.getItem('history')) || [];
      },
      set(value) {
        localStorage.setItem('history', JSON.stringify(value));
      },
   },
 },
 methods: {
   submit() {
     this.history = [...this.history, this.term];
     this.term = '';
   },
 },
});

您可以在此处查看代码,因为 SO 不允许访问 localStorage。请记住在添加第一项后刷新页面,并调查 localStorage 内部发生的情况。

https://codepen.io/bluebrown/pen/dyMMRKj?editors=1010

这段代码是一些 alpinejs 项目的移植。它在那里奏效了。

也就是说,当我像下面这样写它时,我可以让它工作。但是,我现在很好奇,为什么上面的例子会这样。

const app = new Vue({
  el: '#app',
  data: {
    term: '',
    history: [],
  },
  created() {
    this.history = JSON.parse(localStorage.getItem('history')) || [];
  },
  watch: {
    history: {
      deep: true,
      handler(value) {
        localStorage.setItem('history', JSON.stringify(value));
      },
    },
  },
  methods: {
    submit() {
      this.history = [...this.history, this.term];
      this.term = '';
    },
  },
});

标签: vue.jsvuejs2

解决方案


之所以不起作用,是因为 Vue 只能观察普通对象。localStorageVue 无法观察到诸如此类的原生对象。如果您将某些内容放入本地存储中,Vue 不会知道它,并且您的视图不会自动更新以显示这些更改。

Vue 在该对象的文档中提到了这个限制data

Vue 实例的数据对象。Vue 会递归地将其属性转换为 getter/setter 以使其“反应”。对象必须是普通的:浏览器 API 对象和原型属性等原生对象将被忽略。一个经验法则是数据应该只是数据——不建议观察具有自己状态行为的对象。

这些限制适用于 Vue 的整个反应系统,包括computed属性。


推荐阅读