【问题标题】:How to Two-way Data Binding Between Parents and grandchildren in Vue.jsVue.js 中如何在父孙之间进行双向数据绑定
【发布时间】:2015-10-25 05:53:34
【问题描述】:

我遇到了一个问题,我通过 cookie 解决了它,但我想在没有 cookie 的情况下解决问题。我有一个名为 app-header 的组件,它还有另一个名为 outmodal 的组件。 现在,我的第一个 Vue 实例需要组件 app-header。

var vue = new Vue({
    el : "html",
    data : {
        title       : "Site Title",
        description : "description of page",
        keywords    : "my keywords",
        view        : "home",
        login       : "login"
    },
    components:{
        "app-header" :require("../../components/header"),
        "app-footer" :require("../../components/footer"),
        "home"       :require("../../views/home")
    },
});

app-header 代码

var Vue     = require("vue");

Vue.partial("login",require("../../partials/login.html"));
Vue.partial("logged",require("../../partials/logged.html"));

module.exports = {
    template    : require("./template.html"),
    replace     : true,
    components  : {
        outmodal : require("../outmodal")
    },
    props : ['login']
}

模态代码

var Vue = require("vue");
Vue.partial("loginModal",require("../../partials/loginModal.html"));

module.exports = {
    template    : require("./template.html"),
    replace     : true,
    props       : ['name'],
    data        : function () {
            return  {
                userLogin : { mail  :   "", password    :   "", remember    :   ""}
            }

    },
    methods : {
        formSubmit : function(e){
                e.preventDefault();
                this.$http.post("http://example.com/auth/login",{ "email": this.userLogin.mail , "password": this.userLogin.password },function(data,status,request){
                    $.cookie("site_token",data.token,{expires : 1})
                }).error(function(data,status,request){

                });

        }
    }, ready  : function(){
        console.log("it works")
    }
}

在 outmodal 组件中,我连接 API 并检查登录,如果登录成功,我想更改 Vue 实例中登录变量的值。我使用 web pack 来构建所有需求。所以我不知道如何在这些文件之间进行数据绑定。

我该如何解决?我

【问题讨论】:

标签: data-binding components vue.js


【解决方案1】:

【讨论】:

【解决方案2】:

我发现这个更准确。 https://vuejs.org/v2/guide/components.html#sync-Modifier 仅在 2.3.0+ 中。 老实说,它仍然不够好。应该只是“双向”数据绑定的简单选择。所以这些选项都不好。

尝试改用 vuex。他们为此目的有更多选择。 https://vuex.vuejs.org/en/state.html

【讨论】:

    【解决方案3】:

    有几种方法可以做到,其他答案中也提到了一些:

    1. 使用props on components
    2. 使用v-model attribute
    3. 使用sync modifier
    4. 使用Vuex

    对于双向绑定,请记住,它可能会导致难以维护的突变链, 引用自文档:

    不幸的是,真正的双向绑定会产生维护问题,因为子组件可以使父组件发生变异,而该变异的来源在父组件和子组件中都不明显。

    以下是可用方法的一些详细信息:

    1.) 在组件上使用道具

    道具易于使用,是解决最常见问题的理想方法。
    因为how Vue observes changes,所有属性都需要在对象上可用,否则它们将不会是反应性的。 如果在 Vue 完成使它们可观察之后添加任何属性,则必须使用 'set'

     //Normal usage
     Vue.set(aVariable, 'aNewProp', 42);
     //This is how to use it in Nuxt
     this.$set(this.historyEntry, 'date', new Date());
    

    该对象对组件和父级都是响应式的:

    如果您将对象/数组作为道具传递,它会自动进行双向同步 - 更改 子,它在父中被改变了。

    如果您传递简单的值(字符串、数字) 通过道具,您必须明确使用.sync modifier

    引自 --> https://stackoverflow.com/a/35723888/1087372

    2.) 使用 v-model 属性

    v-model 属性是一种语法糖,可以在父子节点之间轻松进行双向绑定。它与同步修饰符的作用相同,只是它使用特定的道具和特定的事件进行绑定

    这个:

     <input v-model="searchText">
    

    和这个是一样的:

     <input
       v-bind:value="searchText"
       v-on:input="searchText = $event.target.value"
     >
    

    prop 必须是 value 且 event 必须是 input

    3.) 使用同步修饰符

    sync 修饰符也是语法糖,与 v-model 的作用相同,只是 prop 和 event 名称由所使用的任何内容设置。

    在父级中可以如下使用:

     <text-document v-bind:title.sync="doc.title"></text-document>
    

    可以从子级发出事件以通知父级任何更改:

     this.$emit('update:title', newTitle)
    

    4.) 使用 Vuex

    Vuex 是一个可以从每个组件访问的数据存储。 可以订阅更改。

    通过使用 Vuex 存储,可以更轻松地查看数据突变的流动,并且它们是明确定义的。通过使用vue developer tools,可以轻松调试和回滚所做的更改。

    这种方法需要更多样板,但如果在整个项目中使用,它会成为一种更清晰的方式来定义如何进行更改以及从何处进行更改。

    getting started guide

    【讨论】:

      【解决方案4】:

      我更喜欢文档中推荐的事件驱动更新。但是,我受到已经使用props$emit 的现有(“第三方”)组件的限制。这个组件是我的孙子。以下是我的解决方案(使用propssync 通过子级传递值并使用$emit 计算值。

      欢迎评论。

      Value可以在父孙中修改不报错:

      孙子(简化的第三方组件):

      <template>
        <div v-show="value">{{ value}}</div>
        <button @click="closeBox">Close</button>
      </template>
      
      <script>
      export default {
        props: {
          value: null
        },
        methods: {
          closeBox() {
            this.$emit('update:value', null);
          }
        }
      }
      </script>
      

      孩子:

      <template>
        <grandchild-component :value.sync="passedValue" />
      </template>
      
      <script>
      export default {
        props: {
          value: null
        },
        computed: {
          passedValue: {
            get() {
              return this.value;
            },
            set(newVal) {
              this.$emit('update:value', newVal);
            }
          }
        }
      }
      </script>
      

      家长:

      <template>
        <child-component :value.sync="value" />
      </template>
      <script>
      export default {
        data() {
          return {
            value: null,
          }
        },
        // ... e.g. method setting/modifying the value
      }
      </script>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-01-08
        • 2018-02-13
        • 2017-05-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-03
        • 1970-01-01
        相关资源
        最近更新 更多