RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 985247
Accepted
Sergei R
Sergei R
Asked:2020-05-25 02:26:40 +0000 UTC2020-05-25 02:26:40 +0000 UTC 2020-05-25 02:26:40 +0000 UTC

Vue.js - 如何将数据返回到父组件?

  • 772

我有一个父组件,在 data() 中我想从子组件传递一个计算属性。

// ParentComponent.vue
<template>
  <div>
    <ChildComponent :parent="parent"/>
  </div>
</template>

<script>
import ChildComponent from '@/components/ChildComponent';

export default {
  name: 'ParentComponent',
  components: {
    ChildComponent,
  },
  data() {
    return {
      parent: {
        parentData: '',
      }
    };
  },
</script>

在子组件中,计算属性是字符串的串联,子组件的数据属性的字段。

<template>
  <div>
    <div class="control">
      <input
        v-model="salarySumm"
        class="input"
        type="text"
        placeholder="Add the estimated salary (1000 - 2000)"
      >
      <div class="select">
        <select v-model="salaryCode">
          <option disabled value>Select currency</option>
          <option
            v-for="(el, index) in currency"
            :key="index"
            :value="el.code"
          >{{ el.title }}</option>
        </select>
      </div>
  </div>
</template>

<script>  
export default {
  name: 'ChildComponent',
  props: ['parent'],
  data() {
    return {
      salarySumm: '',
      salaryCode: '',
    }
  },
  created() {
    // Тут я получаю массив объектов в виде 
    // [{ title: 'string', code: 'string' }]
    this.$store.dispatch('getCurrencies')
  },
  computed: {
    currency() {
      let list = this.$store.getters.currencies.data
      const currencyList = []
      if (list !== undefined) {
        for (const el of list) {
          if (el.code == '(none)' || el.code == null) el.code = ''
          if (el.name !== null) {
            currencyList.push({ title: `${el.name} | ${el.code}`, code: el.code })
          }
        }
      }
      return currencyList
    },
    salary() {
      // Здесь я получаю строку в том виде, в котором хочу передать ее в родительский компонент.
      return this.salarySumm + ' ' + this.salaryCode
    },
</script>

如何将计算的属性薪水传递给父组件,更具体地说是 parent.parentData?

javascript
  • 2 2 个回答
  • 10 Views

2 个回答

  • Voted
  1. Best Answer
    user256824
    2020-05-25T13:35:05Z2020-05-25T13:35:05Z

    您将属性传递给子组件,并从子组件到父组件调用$emit属性更改事件:

    // Родительский компонент.
    <template>
      <child-component :someProps="parent" @updateParent="onUpdateSalary" />
    </template>
    
    <script>
      export default {
        // Локальные данные компонента.
        data() {
          return {
            parent: {
              parentData: '',
            }
          }
        },
    
        methods: {
          onUpdateSalary(someData) {
            // Выполняем необходимые действия с `someData`
          }
        }
      }
    </script>
    
    // Дочерний компонент.
    <template>
      <button type="button" @click="doSomething">Передать родителю</button>
    </template>
    
    <script>
      export default {
        // Входящие свойства из родителя.
        props: ['someProps'],
    
        // Локальные данные компонента.
        data() {
          return {
            amount: '',
            code: '',
          }
        },
    
        methods: {
          doSomething() {
            this.$emit('updateParent', {
              amount: this.amount,
              code: this.code
            })
          }
        }
      }
    </script>
    

    如果您需要将计算属性传递给computed父组件,那么您必须使用观察者watch,它被赋予一个处理函数,每当计算(并且不仅)属性发生变化时都会调用该处理函数。下面是一个例子。

    // Отключим ненужные для примера
    // сообщения в консоли.
    Vue.config.productionTip = false
    Vue.config.devtools = false
    
    Vue.component('parent-component', {
      template: `
            <div>
                <child-component :someProps="parent" @updateParent="onUpdateSalary" />
                <p v-if="parentSalary">
                    Значение <b>parentSalary</b>, отображаемое в "parent-component": <pre>{{ parentSalary }}</pre>
                </p>
            </div>`,
      data() {
        return {
          // Родительское значение.
          parentSalary: null,
          parent: {
            parentData: '... из поля data',
          }
        }
      },
      methods: {
        onUpdateSalary(data) {
          this.parentSalary = data
        }
      }
    })
    
    Vue.component('child-component', {
      template: `
            <div>
                <pre>Свойство из родительского компонента: {{ someProps.parentData }}</pre>
                <div v-if="currencies.length" class="control">
                    <input type="number" v-model.number="amount" class="input" />
                    <select v-model="code">
                        <option disabled selected>Select currency</option>
                        <template v-for="(currency, index) in currencies">
                            <option :key="index" :value="currency.code">{{ currency.name }}</option>
                        </template>
                    </select>
                </div>
                <div v-else>Нет данных для отображения.</div>
                <p v-if="salary">Значение <b>salary</b>, отображаемое в "child-component": <b>{{ salary }}</b></p>
            </div>`,
      props: ['someProps'],
      data() {
        return {
          amount: '',
          code: '',
    
          currencies: [{
              "code": "EUR",
              "name": "Euro"
            },
            {
              "code": "GBP",
              "name": "U.K. Pound Sterling"
            },
            {
              "code": "JPY",
              "name": "Japanese Yen"
            }
          ]
        }
      },
    
      computed: {
        salary() {
          return this.amount + ' ' + this.code
        }
      },
    
      watch: {
        // Эта функция запускается при любом изменении значений
        // в вычисляемом свойстве `salary`.
        salary(newValue, oldValue) {
          // Пробрасываем данные родительскому компоненту,
          // ч/з вызов метода.
          this.$emit('updateParent', {
            amount: this.amount,
            code: this.code
          })
        }
      }
    })
    
    new Vue({
      el: '#app',
      data: {}
    })
    <div id="app">
      <div>
        <parent-component></parent-component>
      </div>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10"></script>

      computed: {
        salary() {
          return this.amount + ' ' + this.code
        }
      },
    
      watch: {
        // Эта функция запускается при любом изменении значений
        // в вычисляемом свойстве `salary`.
        salary(newValue, oldValue) {
          // Пробрасываем данные родительскому компоненту,
          // ч/з вызов метода.
          this.$emit('updateParent', {
            amount: this.amount,
            code: this.code
          })
        }
      }
    

    this.$store.dispatch看起来您正在使用代码vuex。在这种情况下,您可以将所有逻辑传输到存储库。这将使您免于不断检查每个组件中接收到的数据。

    // Отключим ненужные для примера
    // сообщения в консоли.
    Vue.config.productionTip = false
    Vue.config.devtools = false
    
    // Список доступных мутаций (сеттеры).
    const CASH_INIT = 'CASH_INIT'
    const CASH_SET_AMOUNT = 'CASH_SET_AMOUNT'
    const CASH_SET_CODE = 'CASH_SET_CODE'
    
    const store = new Vuex.Store({
      state: {
        amount: null,
        code: null,
        currencies: []
      },
    
      getters: {
        amount: state => state.amount,
        code: state => state.code,
        currencies: state => state.currencies,
        salary: state => {
          if (state.amount && state.code) {
            return state.amount + ' ' + state.code
          }
    
          return null
        }
      },
    
      // Обработчики мутаций обязаны быть синхронными.
      mutations: {
        [CASH_INIT](state, currencies) {
          state.currencies = currencies
        },
        [CASH_SET_AMOUNT](state, amount) {
          amount = parseFloat(amount)
    
          if (!isNaN(amount)) {
            state.amount = amount
          } else {
            state.amount = ''
            alert('Ошибка в типе данных: `amount`.')
          }
        },
        [CASH_SET_CODE](state, code) {
          code = code.toString()
    
          if (code) {
            state.code = code
          } else {
            state.code = ''
            alert('Ошибка в типе данных: `code`.')
          }
        }
      },
    
      actions: {
        getCurrencies(context) {
          try {
            // В своем проекте используйте `fetch` или axios, например.
            // const response = await fetch('http://www.floatrates.com/daily/usd.json')
            // const data = await response.json()
            // context.commit('CASH_INIT', data)
    
            context.commit('CASH_INIT', [{
              "code": "EUR",
              "name": "Euro"
            }, {
              "code": "GBP",
              "name": "U.K. Pound Sterling"
            }, {
              "code": "JPY",
              "name": "Japanese Yen"
            }, {
              "code": "AUD",
              "name": "Australian Dollar"
            }, {
              "code": "CAD",
              "name": "Canadian Dollar"
            }, {
              "code": "CHF",
              "name": "Swiss Franc"
            }, {
              "code": "UYU",
              "name": "Uruguayan Peso"
            }])
          } catch (e) {
            console.log(e)
          }
        },
    
        calculate(context, {
          amount,
          code
        }) {
          context.commit('CASH_SET_AMOUNT', amount)
          context.commit('CASH_SET_CODE', code)
        },
      }
    })
    
    Vue.component('child-component', {
      template: `
    <div>
      <div v-if="currencies.length" class="control">
        <input type="number" v-model.number="amount" class="input" />
        <select v-model="code">
          <option disabled selected>Select currency</option>
          <template v-for="(currency, index) in currencies">
          <option :key="index" :value="currency.code">{{ currency.name }}</option>
          </template>
        </select>
        <button type="button" @click="send">Отправить данные во vuex</button>
      </div>
      <div v-else>Нет данных для отображения.</div>
    </div>`,
      data() {
        return {
          amount: '',
          code: '',
        }
      },
    
      computed: {
        // При компонентном подходе ...mapGetters()
        ...Vuex.mapGetters(['currencies']),
      },
    
      mounted() {
        this.getCurrencies()
      },
    
      methods: {
        // При компонентном подходе ...mapActions().
        // Теперь в компоненте доступны методы:
        // this.getCurrencies() и this.calculate(...)
        ...Vuex.mapActions(['getCurrencies', 'calculate']),
    
        send() {
          this.calculate({
            amount: this.amount,
            code: this.code
          })
        }
      }
    })
    
    Vue.component('parent-component', {
      template: `
    <div>
      <child-component />
      <p v-if="salary">Значение <b>salary</b>, отображаемое в "parent-component": <b>{{ salary }}</b></p>
    </div>`,
      data() {
        return {}
      },
    
      computed: {
        ...Vuex.mapGetters([
          'salary',
        ]),
      },
    })
    
    new Vue({
      el: '#app',
      store,
      data: {},
    
      // Используя vuex получаем доступ к хранилище
      // не только в дочерних и родительских компонентах.
      computed: {
        ...Vuex.mapGetters([
          'salary',
        ]),
      },
    })
    <div id="app">
      <div>
        <p v-if="salary">Значение <b>salary</b> в корне приложения: <b>{{ salary }}</b></p>
        <parent-component></parent-component>
      </div>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10"></script>
    <script src="https://unpkg.com/vuex@2.0.0"></script>

    在这些答案984023、975447中查看更多示例。

    • 5
  2. Sergei R
    2020-05-27T01:21:00Z2020-05-27T01:21:00Z

    稍微处理了这个话题,我想给出我的答案。

    第一个选项: 但是这个选项有一个缺点,如果我们不在组件中显示计算属性的结果,那么我们不会“拉”它,它不会被计算。那些。仅当您想在同一方法中使用计算属性时,此方法才有效

    <div>Salary: {{ salary }}</div>
    

    Я покажу как можно прокинуть данные в родителя с помощью $emit но без якобы использования события. Все дело в том, что $emit и есть наше собственное событие. Вот полезная статья про Пользовательские события.

    В дочернем компоненте, я использую computed потому что он всегда пересчитывает данные которые меняются и сам факт пересчета и есть в неком смысле событие. Computed кроме возврата значения может создает некие побочные эффекты, запись данных куда то в данном случает в событие input (см. computed ниже). Останется только прописать пропс в дочернем компоненте и именем value.

    // ChildComponent.vue
    <script>  
    export default {
      name: 'ChildComponent',
      props: ['value'],
      data() {
        return {
          salarySumm: '',
          salaryCode: '',
        }
      },
      created() {
        this.$store.dispatch('getCurrencies')
      },
      computed: {
        currency() {
          let list = this.$store.getters.currencies.data
          const currencyList = []
          if (list !== undefined) {
            for (const el of list) {
              if (el.code == '(none)' || el.code == null) el.code = ''
              if (el.name !== null) {
                currencyList.push({ title: `${el.name} | ${el.code}`, code: el.code })
              }
            }
          }
          return currencyList
        },
        salary() {
          let salary = this.salarySumm + ' ' + this.salaryCode
          this.$emit('input', salary)
          return salary
        },
    </script>
    

    и далее в родителе получить эти данные через v-model

    // ParentComponent.vue
    <template>
      <div>
        <ChildComponent v-model="parent.parentData"/>
      </div>
    </template>
    
    <script>
    import ChildComponent from '@/components/ChildComponent';
    
    export default {
      name: 'ParentComponent',
      components: {
        ChildComponent,
      },
      data() {
        return {
          parent: {
            parentData: '',
          }
        };
      },
    </script>
    

    Второй вариант. Я использую внутренние события для того что бы вызвать метод который создать пользовательское событие $emit

    // ParentComponent.vue
    // Все то же самое что и в варианте 1
    
    // ChildComponent.vue
    // В шаблоне я явно привязываю событие к моему методу который склеит строки и создаст пользовательское событие. Этот метод в варианте 1 был вычисляемым свойством.
    div class="control">
      <input
        v-model="salarySumm"
        class="input"
        type="text"
        placeholder="Add the estimated salary (1000 - 2000)"
        v-on:input="salary"
      >
      <div class="select">
        <select v-model="salaryCode" @change="salary()">
          <option disabled value>Select currency</option>
          <option
            v-for="(el, index) in currency"
            :key="index"
            :value="el.code"
          >{{ el.title }}</option>
        </select>
      </div>
    </div>
    
    // Вместо вычисляемого свойства computed я создаю метод
    methods: {
      salary() {
        this.$emit('input', this.salarySumm + ' ' + this.salaryCode)
      },
    }
    
    • 1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5