Vue.js改变道具

时间:2016-11-24 07:53:38

标签: javascript vue.js vue-component

我对如何更改组件内的属性感到有点困惑,假设我有以下组件:

{
    props: {
        visible: {
            type: Boolean,
            default: true
        }
    },
    methods: {
         hide() {
              this.visible = false;
         }
    }
} 

虽然它有效但会发出以下警告:

  

避免直接改变道具,因为只要父组件重新渲染,该值就会被覆盖。而是根据prop的值使用数据或计算属性。支持变异:“可见”   (在组件中找到)

现在我想知道处理这个问题的最佳方法是什么,显然在DOM中创建组件时会传入visible属性:<Foo :visible="false"></Foo>

7 个答案:

答案 0 :(得分:13)

引用your fiddle

中的代码

不知何故,你应该决定一个地方居住,而不是两个。我不知道是否更适合在Alert中或仅在其父项中使用它,但是你应该选择一个。

如何决定国家生活的地方

父级或任何兄弟组件是否依赖于状态?

  • 是:那么它应该在父母(或在某些外部国家管理中)
  • 否:然后让它更容易处于组件本身的状态
  • 有点儿:见下文

在极少数情况下,您可能需要组合。也许你想让父母和孩子都有隐藏孩子的能力。那么你应该在父母和孩子都有状态(所以你不必在孩子里面编辑孩子的道具)。

例如,如果出现以下情况,则可以看到子项:visible && state_visible,其中visible来自道具并反映父项状态中的值,state_visible来自孩子的状态。

我不确定这是否是你想要的行为,但是here is a fiddle。我会假设您实际上只想在单击子组件时调用父组件的toggleAlert

答案 1 :(得分:4)

在阅读了您的最新评论后,似乎您担心在父母上显示/隐藏警报的逻辑。因此,我建议如下:

<强>父

# template
<alert :alert-visible="alertVisible"></alert>

# script
data () {
  alertVisible: false,
  ...
},
...

然后在儿童警报中,您将观察道具的价值并将所有逻辑移至警报中:

孩子(提醒)

# script
data: {
  visible: false,
  ...
},
methods: {
  hide () {
    this.visible = false
  },
  show () {
    this.visible = true
  },
  ...
},
props: [
  'alertVisible',
],
watch: {
  alertVisible () {
    if (this.alertVisible && !this.visible) this.show()
    else if (!this.alertVisible && this.visible) this.hide()
  },
  ...
},
...

答案 2 :(得分:3)

如果道具仅适用于此子组件,请为孩子提供prop initialVisibledata mutableVisible ,并在created钩子(组装组件的数据结构时调用),只需this.mutableVisible = this.initialVisible

如果道具由父组件的其他子项共享,则您需要将其设为父项data,以使其可供所有子项使用。然后在孩子this.$emit('visibleChanged', currentVisible)中通知家长更改visible。在父模板中,使用<ThatChild ... :visibleChanged="setVisible" ...>。请查看指南:http://vuejs.org/v2/guide/components.html

答案 3 :(得分:2)

为了帮助任何人,我遇到了同样的问题。我只是将我的var里面的v-model =“”从props数组改为数据。记住道具和数据之间的区别,我的情况不是改变它的问题,你应该重视你的决定。

E.g:

return EMPTY;

在:

<v-dialog v-model="dialog" fullscreen hide-overlay transition="dialog-bottom-transition">

后:

export default {
    data: function () {
        return {
            any-vars: false
        }
    },
    props: {
            dialog: false,
            notifications: false,
            sound: false,
            widgets: false
        },
    methods: {
        open: function () {
            var vm = this;

            vm.dialog = true;
        }
    }
}

答案 4 :(得分:0)

也许它看起来像黑客并违反了单个数据源的概念,但它的工作) 此解决方案是创建本地代理变量并从props继承数据。接下来使用代理变量。

Vue.component("vote", {
    data: function() {
        return {
            like_: this.like,
            dislike_: this.dislike,
        }
    },

    props: {
        like: {
            type: [String, Number],
            default: 0
        },
        dislike: {
            type: [String, Number],
            default: 0
        },
        item: {
            type: Object
        }
    },

    template: '<div class="tm-voteing"><span class="tm-vote tm-vote-like" @click="onVote(item, \'like\')"><span class="fa tm-icon"></span><span class="tm-vote-count">{{like_}}</span></span><span class="tm-vote tm-vote-dislike" @click="onVote(item, \'dislike\')"><span class="fa tm-icon"></span><span class="tm-vote-count">{{dislike_}}</span></span></div>',

    methods: {
        onVote: function(data, action) {
            var $this = this;
            // instead of jquery ajax can be axios or vue-resource
            $.ajax({
                method: "POST",
                url: "/api/vote/vote",
                data: {id: data.id, action: action},
                success: function(response) {
                    if(response.status === "insert") {
                        $this[action + "_"] = Number($this[action + "_"]) + 1;
                    } else {
                        $this[action + "_"] = Number($this[action + "_"]) - 1;
                    }
                },
                error: function(response) {
                    console.error(response);
                }
            });
        }
    }
});

使用组件并传递道具

<vote :like="item.vote_like" :dislike="item.vote_dislike" :item="item"></vote>

答案 5 :(得分:0)

根据the Vue.js component doc

  

当父属性更新时,它将向下传递给子节点,但不会反过来。那么,当事情发生时,我们如何与父母沟通?这就是Vue的自定义事件系统的用武之地。

使用来自孩子的$emit('my-event)将事件发送给父母。通过v-on:my-event(或@my-event)在父级内的子声明中接收事件。

工作示例:

&#13;
&#13;
// child

Vue.component('child', {
  template: '<div><p>Child</p> <button @click="hide">Hide</button></div>',
  methods: {
    hide () {
      this.$emit('child-hide-event')
    }
  },
})

// parent

new Vue({
  el: '#app',
  data: {
    childVisible: true
  },
  methods: {
    childHide () {
      this.childVisible = false
    },
    childShow () {
      this.childVisible = true
    }
  }
})
&#13;
.box {
  border: solid 1px grey;
  padding: 16px;
}
&#13;
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<div id="app" class="box">
  <p>Parent | childVisible: {{ childVisible }}</p>
  <button @click="childHide">Hide</button>
  <button @click="childShow">Show</button>
  <p> </p>
  <child @child-hide-event="childHide" v-if="childVisible" class="box"></child>
</div>
&#13;
&#13;
&#13;

答案 6 :(得分:0)

我想知道为什么警告提示时其他人会错过它

避免直接更改prop,因为每当父组件重新渲染时,该值就会被覆盖。而是根据道具的值使用数据或计算属性。道具被突变:“可见”(位于组件中)

尝试从子组件中接收的prop中创建计算属性

computed: {
  isVisible => this.visible
}

并使用在您的子组件中计算出的值,并将更改发送给您的父组件。