【问题标题】:Receiving Events in Vue3 - Property was accessed during render but is not defined on instance在 Vue3 中接收事件 - 在渲染期间访问了属性,但未在实例上定义
【发布时间】:2021-11-13 14:02:24
【问题描述】:

Vue 和 JavaScript 初学者 - 但正在学习 ))

我有一个 Vue Mains 应用程序和一个处理表单的子组件(计算 2 个值之间的差异)。

我希望当主应用程序“重置”按钮被点击时,表单的值被重置为初始值。

我有两个问题:

  • 当我点击表单按钮“计算差异”时页面重新加载
  • “重置”并未重置初始值 - 似乎事件未分发到子组件。

在加载页面时,我收到以下无法解释的警告:

[Vue 警告]:在渲染期间访问了属性“reset”,但未在实例上定义。在

这是一页的示例代码:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Difference</title>
  <script src="https://unpkg.com/vue@next"></script>
</head>

<body>

  <div id="app">

    <br> Change Values, Click "Calculate Difference", then "Reset" to set Back to 0
    <br>
    <calculator v-on:reset="reset" :start_val="0" :end_val="0"> </calculator>
    <br>
    <button class="button" v-on:click="onResetButton()"> Reset </button>

  </div>
</body>

<script>
  const vm = Vue.createApp({
    emits: {
      'reset': null
    },
    methods: {
      onResetButton() {
        console.log("onResetButton $emit")
        this.$emit('reset');
      },
    },
  })

  vm.component('calculator', {
    props: ['start_val', 'end_val'],
    data() {
      return {
        calculator: {
          start_val: this.start_val,
          end_val: this.end_val,
          difference: this.end_val - this.start_val,
        },
      }
    },
    methods: {
      onDifference() {
        console.log("onDifference")
        this.calculator.difference = this.calculator.end_val - this.calculator.start_val
        console.log(this.calculator.difference)
      },
      reset() {
        calculator.start_val = this.start_val
        calculator.end_val = this.end_val
        calculator.difference = this.end_val - this.start_val
        console.log("reset calculator")
      }
    },
    template: `
            <hr>
            <form>
                <br> Start Value : <input class="input" type="number"  v-model.number="calculator.start_val">
                <br> End Value   : <input class="input" type="number"  v-model.number="calculator.end_val">
                <br> <button class="button" v-on:click="onDifference()">Calculate Difference  </button>
            </form>
            <p>Difference : {{ calculator.difference }} </p>
            <hr>
  `
  })

  vm.mount('#app');
</script>

</html>

【问题讨论】:

  • vm 中没有 reset。您在 calculator 内部定义它不会影响组件外部发生的事情。
  • 在 vm 中添加了一个重置​​(不确定这是如何为事件共享服务的)。方法:{ reset() { console.log("reset") },给我以下错误:vue@next:7996 [Vue 警告]:无关的非发射事件侦听器(重置)已传递给组件但不能自动继承,因为组件呈现片段或文本根节点。如果侦听器仅用作组件自定义事件侦听器,请使用“emits”选项声明它。在 start_val=0 end_val=0 > 在
  • calculator 发出reset event 并且应该有emits: ['reset']vm 实例应该有 reset 方法。你在vm 中有逻辑而不是组件并不是很常见。考虑用父子组件来弄清楚组件及其道具/事件之间的关系,它更常见并且在示例中有所介绍。
  • 这段代码是一个更大的应用程序的简化版——有十几个子组件。当 vm 顶部组件接收到新数据时,我需要子组件用新值刷新(而不是重置,真正的应用程序使用有效负载发送更新,但我删除了更新以简化事件传递) - 因此(可能是不合适的示例)逻辑在这里。
  • 我明白了。您对组件和道具关系有一个基本问题,我建议您在一个简化的设置中解决它,该设置不涉及更多奇特的事情,例如提供模板作为根元素的子元素 (&lt;div id="app"&gt;)

标签: javascript vue.js events


【解决方案1】:

这里有一个小sn-p,可能会给你一些想法:

const {
  reactive,
  ref,
  toRefs,
  computed
} = Vue

const Calculator = {
  props: {
    startVal: {
      type: Number,
      default: 0,
    },
    endVal: {
      type: Number,
      default: 0,
    },
  },
  emits: ['update:startVal', 'update:endVal'],
  setup(props, {
    emit
  }) {
    const start_val = computed({
      get() {
        return props.startVal
      },
      set(val) {
        emit('update:startVal', val || 0)
      },
    })
    const end_val = computed({
      get() {
        return props.endVal
      },
      set(val) {
        emit('update:endVal', val || 0)
      },
    })
    return {
      start_val,
      end_val
    }
  },
  template: `
    <div>
      {{ start_val }} / {{ end_val }}<br />
      StartVal: <input v-model.number="start_val" /><br />
      EndVal: <input v-model.number="end_val" />
    </div>
  `
}

const initState = () => ({
  startVal: 0,
  endVal: 0
})

const App = {
  setup() {
    const state = reactive(initState())

    const result = computed(() => {
      return state.startVal + state.endVal
    })

    const resetState = () => {
      const defaultState = initState()
      for (let key in state) {
        state[key] = defaultState[key]
      }
    }

    return {
      result,
      ...toRefs(state),
      resetState,
    }
  },
  template: `
    <div>
      Result: {{ result }}<br />
      <button
        @click="resetState"
      >
        RESET
      </button>
      <Calculator
        v-model:startVal="startVal"
        v-model:endVal="endVal"
      />
    </div>
  `
}

const vm = Vue
  .createApp(App)

vm.component('Calculator', Calculator)

vm.mount('#app')
<script src="https://unpkg.com/vue@next"></script>

<div id="app"></div>

【讨论】:

    猜你喜欢
    • 2021-11-05
    • 2021-10-12
    • 2021-11-14
    • 2022-01-12
    • 2021-04-26
    • 1970-01-01
    • 1970-01-01
    • 2021-11-16
    • 1970-01-01
    相关资源
    最近更新 更多