Vue: Как использовать компонент проп в mapFields - PullRequest
0 голосов
/ 22 февраля 2019

У меня есть общий компонент и магазин vuex.Для простого двустороннего связывания я использую vuex-map-fields .На стороне компонента есть метод mapFields, который создает get & set с мутациями.Я хочу передать namespace из модуля vuex с props, но это кажется невозможным.

<my-component namespace="ns1" />

// my-component code
export default {
  props: ["namespace"],
  computed: {
    ...mapFields(??this.namespace??, ["attr1", "attr2"])
  }
}

Конечно, нет способа использовать this таким образом, поэтому мы не будемиметь доступ к реквизиту.Как я могу указать пространство имен как проп в таком случае?

1 Ответ

0 голосов
/ 23 февраля 2019

Проблема (как вы, вероятно, поняли) состоит в том, что вычисляемые свойства создаются до того, как станет доступен this, но вы можете обойти его, отложив разрешение свойства this.namespace до вызова вызываемого свойства (что не будетпроизойдет до тех пор, пока не будет завершено построение компонента).

Концепция основана на этом посте Генерация вычисляемых свойств на лету .

Основной шаблон заключается в использовании вычисляемого с get() и set()

computed: {
  foo: {
    get() { this.namespace...},
    set() { this.namespace...},
  }
}

, но вместо того, чтобы вводить все это в компоненте, мы можем создать вспомогательную функцию на основе функции vuex-map-fields mapFields() (см. здесь для оригинала).

Функция normalizeNamespace(), которая поставляется с полями vuex-map-fields, не поддерживает то, что мы хотим сделать, поэтому мы отбрасываем ее и предполагаем, что пространство именвсегда передается (и что модуль store использует стандартные функции getField и updateField).

Я адаптировал одно из примеров кодов-полей vuex-map-fields здесь .
нетт. е. пространство имен находится в data, а не props для удобства, но props также должно работать.

Шаблон

<template>
  <div id="app">
    <div>
      <label>foo </label> <input v-model="foo" /> <span> {{ foo }}</span>
    </div>
    <br />
    <div>
      <label>bar </label> <input v-model="bar" /> <span> {{ bar }}</span>
    </div>
  </div>
</template>

Помощник

<script>

const mapFields2 = (namespaceProp, fields) => {
  return Object.keys(fields).reduce((prev, key) => {
    const path = fields[key];
    const field = {
      get() {
        const namespace = this[namespaceProp];
        const getterPath = `${namespace}/getField`;
        return this.$store.getters[getterPath](path);
      },
      set(value) {
        const namespace = this[namespaceProp];
        const mutationPath = `${namespace}/updateField`;
        this.$store.commit(mutationPath, { path, value });
      }
    };
    prev[key] = field;
    return prev;
  }, {});
};

export default {
  name: "App",
  data() {
    return {
      nsProp: "fooModule"
    };
  },
  computed: {
    ...mapFields2("nsProp", { foo: "foo", bar: "bar" })
  }
};
</script>

Магазин

import Vue from "vue";
import Vuex from "vuex";
import { getField, updateField } from "vuex-map-fields";
import App from "./App";

Vue.use(Vuex);
Vue.config.productionTip = false;

const store = new Vuex.Store({
  modules: {
    fooModule: {
      namespaced: true,
      state: {
        foo: "initial foo value",
        bar: "initail bar value"
      },
      getters: {
        getField
      },
      mutations: {
        updateField
      }
    }
  }
});

new Vue({
  el: "#app",
  components: { App },
  store,
  template: "<App/>"
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...