在 Svelte 自定义方法中使用 getters/setters

Use getters/setters in Svelte Custom methods

在自定义方法中使用 get/set 对时,我无法编译我的 svelte 组件。这不支持吗?还是我做错了什么?

示例:

假设我想要一个显示名称的组件并且我想使用它来设置名称。 com.name = 'The new name';

但是我只希望组件在名称中没有空格时使用该名称。

<h1>Hello {{name}}!</h1>

<script>
    export default {
        data () {
            return {
                name: 'The Name',
            }
        },
        methods: {
            get displayName() {
                return this.get('name'); 
            },
            set displayName(val) {
                if (val.indexOf(' ') < 0) {
                    this.set('name', val);
                }
            }
        }
    }
</script>

问题是当我尝试编译它时,它说有一个重复的键。

    Duplicate property 'displayName'

    49:             return this.get('name');
    50:         },
    51:         set displayName(val) {

这是一个 REPL - https://svelte.technology/repl?version=1.13.2&gist=0eeab5717526694139ba73eae766bb30

我在文档中没有看到任何关于此的信息。我不能使用 setter,但我希望能够。

编辑: 正如 Rich Harris 在下面的评论中指出的那样,getters 和 setters 在 data 中不起作用因为 Svelte 在内部将属性复制到普通 JS 对象(因此忽略 getters 和 setters)。我认为你可以做的下一个最好的事情是制作一个方法 name,它可以像 name() 作为 getter 和 name(value) 作为 setter 一样被调用。

精简代码:

<h1>Hello {{_name}}!</h1>

<script>
  export default {
    data() {
      return {
        _name: 'The Name'
      }
    },
    methods: {
      name(value) {
        if (value === void 0) return this.get('_name')
        this.set('_name', value)
      }
    }
  }
</script>

原文Post:

你的 getter 和 setter 应该在你的 data 而不是你的 methods,因为它们最终会创建一个 属性。此 属性 与您在原始 data 方法中定义为等于 'The Name'name 冲突。我建议改用 "private" 属性 _name

精简代码(REPL):

<h1>Hello {{name}}!</h1>

<script>
  export default {
    data() {
      return {
        _name: 'The Name',
        get name() {
          return this._name
        },
        set name(value) {
          / /.test(this._name) || (this._name = value)
        }
      }
    }
  }
</script>

tl;dr 这是可能的 wrapper object

这里的错误消息有点令人困惑——问题不在于重复的 属性,而是你不能在 methods 中使用 getter 和 setter,这在任何情况下都是分开的来自填充组件内部状态的 data 对象(以及实例化时提供的数据和可能存在的任何计算值)。我已经为此 here.

打开了一个问题

data 本身也不能有 getter 和 setter — 或者更确切地说,它可以,但是它们不会被使用,因为从你的 data 函数返回的对象不是与内部状态对象相同(否则我们都可能 运行 陷入与突变相关的错误中)。

但是创建一个允许您获取和设置组件数据的包装器对象实际上相当容易:

function wrap (component) {
  var wrapper = {};
  var data = component.get();

  Object.keys(data).forEach(key => {
    Object.defineProperty(wrapper, key, {
      get() {
        return component.get()[key];
      },
      set(value) {
        component.set({ obj[key]: value });
      }
    })
  });

  return wrapper;
}

var component = new Component({...});
var wrapper = wrap(component);

wrapper.name = 'Rich';

如果你愿意,你甚至可以做 component.data = wrap(component) — 然后你可以操纵 component.data.name 等等。

我整理了一份 small repo demoing that approach — see it in action here