vue.js 从子组件中修改属性值

pieyvz9o  于 2023-05-07  发布在  Vue.js
关注(0)|答案(6)|浏览(239)

我是Vue的新手,试图构建一个“下拉”组件。我想从父组件使用它,如下所示:

<my-dropdown v-model="selection"></my-dropdown>

其中,selection在父节点上存储为data,应该更新以反映用户的选择。要做到这一点,我相信我的下拉组件需要一个value prop ,它需要在选择更改时发出input事件。
但是,我还想从子对象本身修改value,因为我希望能够单独使用下拉组件(我需要修改它,因为如果单独使用组件,UI将不会更新以反映新选择的值)。
有没有一种方法可以像上面那样绑定v-model,但也可以在子对象内部修改值(似乎我不能,因为value是一个prop,子对象不能修改自己的prop)。

e1xvtsh3

e1xvtsh31#

您需要有一个本地值的计算属性代理来处理输入/值。

props: {
  value: {
    required: true,
  }
},
computed: {
  mySelection: {
    get() {
      return this.value;
    },
    set(v) {
      this.$emit('input', v)
    }
  }
}

现在你可以设置你的模板使用mySelection值来管理你在这个组件中的数据,当它改变时,数据会正确地发出,并且当你在父组件中使用它时,数据总是与v-model(selected)同步。

3b6akqbq

3b6akqbq2#

Vue的理念是:“** prop 下降,事件上升**"。它甚至在文档中这样说:组成组件。
组件应该一起使用,最常见的是父子关系:组件A可以在其自己的模板中使用组件B。他们不可避免地需要彼此沟通:父母可能需要将数据向下传递给孩子,孩子可能需要将孩子发生的事情通知父母。然而,通过一个明确定义的接口,尽可能地保持父节点和子节点的解耦也是非常重要的。这确保了每个组件的代码都可以相对独立地编写和推理,从而使它们更易于维护,也更容易重用。
在Vue中,父子组件关系可以总结为props down,events up。父节点通过props将数据传递给子节点,子节点通过事件向父节点发送消息。让我们看看他们接下来是如何工作的。
不要尝试从子组件内部修改值。告诉父组件一些事情,如果父组件关心的话,它可以做一些事情。让child组件改变事情会给child太多的责任。

62lalag4

62lalag43#

您可以使用以下模式:
1.接受1个输入属性
1.在数据中添加其他变量
1.在创建时,将传入的prop写入数据变量
1.使用监视器,监视传入的 prop 的更改
1.在组件内部进行更改时,将更改发送出去
演示:

'use strict';
Vue.component('prop-test', {
  template: "#prop-test-template",
  props: {
    value: { // value is the default prop used by v-model
      required: true,
      type: String,
    },
  },
  data() {
    return {
      dataObject: undefined,
      // For testing purposes:
      receiveData: true,
      sendData: true,
    };
  },
  created() {
    this.dataObject = this.value;
  },
  watch: {
    value() {
      // `If` is only here for testing purposes
      if(this.receiveData)
      this.dataObject = this.value;
    },
    dataObject() {
      // `If` is only here for testing purposes
      if(this.sendData)
      this.$emit('input', this.dataObject);
    },
  },
});

var app = new Vue({
  el: '#app',
  data: {
    test: 'c',
  },
});
<script src="https://unpkg.com/vue@2.0.1/dist/vue.js"></script>
<script type="text/x-template" id="prop-test-template">
  <fieldset>
    <select v-model="dataObject">
      <option value="a">a</option>
      <option value="b">b</option>
      <option value="c">c</option>
      <option value="d">d</option>
      <option value="e">e</option>
      <option value="f">f</option>
      <option value="g">g</option>
      <option value="h">h</option>
      <option value="i">i</option>
      <option value="j">j</option>
    </select>
    <!-- For testing purposed only: -->
    <br>
    <label>
      <input type="checkbox" v-model="receiveData">
      Receive updates
    </label>
    <br>
    <label>
      <input type="checkbox" v-model="sendData">
      Send updates
    </label>
    <!--/ For testing purposed only: -->
  </fieldset>
</script>
<div id="app">
  <prop-test v-model="test"></prop-test>
  <prop-test v-model="test"></prop-test>
  <prop-test v-model="test"></prop-test>
</div>

请注意,这个演示有一个功能,您可以关闭每个选择框的事件传播,因此您可以测试值是否在本地正确更新,这当然不是生产所需的。

pdsfdshx

pdsfdshx4#

如果你想在组件中修改一个prop,我建议你传递一个“默认值”prop给你的组件。我会这么做

<MyDropdownComponent
  :default="defaultValue"
  :options="options"
  v-model="defaultValue"
/>

接下来我有两个选择

选项1 -自定义下拉元素

由于您使用的是自定义HTML,因此无法设置选定的属性。所以你的方法要有创意。在组件内部,可以在创建组件时将默认值prop设置为数据属性。您可能希望以不同的方式执行此操作,并使用watcher。我已经将其添加到下面的示例中。

export default {
  ...
  data() {
    return {
      selected: '',
    };
  },
  created() {
    this.selected = this.default;
  },
  methods: {
    // This would be fired on change of your dropdown.
    // You'll have to pass the `option` as a param here,
    // So that you can send  that data back somehow
    myChangeMethod(option) {
      this.$emit('input', option);
    },
  },
  watch: {
    default() {
      this.selected = this.default;
    },
  },
};

$emit将把数据传递回父组件,而父组件不会被修改。如果您使用的是标准的select元素,则不需要这样做。

选项2 -标准select

<template>
  <select
    v-if="options.length > 1"
    v-model="value"
    @change="myChangeMethod"
  >
    <option
      v-for="(option, index) of options"
      :key="option.name"
      :value="option"
      :selected="option === default"
    >{{ option.name }}</option>
  </select> 
</template>

<script>
export default {
  ...
  data() {
    return {
      value: '',
    };
  },
  methods: {
    // This would be fired on change of your dropdown
    myChangeMethod() {
      this.$emit('input', this.value);
    },
  },
};
</script>

这个方法绝对是最简单的,这意味着您需要使用默认的select元素。

8i9zcol2

8i9zcol25#

您可以使用自定义表单输入组件
使用自定义事件的表单输入组件
基本上,自定义组件应该接受value属性,并在值更改时发出input事件

azpvetkf

azpvetkf6#

与@zero298的answer相呼应,Vue 3指南明确指出,组件不修改(内部) prop 是一种最佳实践:

对象/数组 prop 突变

当对象和数组作为prop传递时,虽然子组件不能改变prop绑定,但它将能够改变对象或数组的嵌套属性。这是因为在JavaScript中,对象和数组是通过引用传递的,而Vue要防止这种变化是不合理的。
这种变化的主要缺点是,它允许子组件以一种对父组件不明显的方式影响父组件的状态,这可能会使将来更难以推理数据流。作为最佳实践,您应该避免这种变化,除非父级和子级在设计上是紧密耦合的。在大多数情况下,子节点应该发出一个事件,让父节点执行变异。
因此,即使它是“可能的”,它也不是“最佳实践”。$emit事件,并让父级修改自己的状态。

相关问题