【问题标题】:Vuejs 2, VUEX, data-binding when editing dataVuejs 2,VUEX,编辑数据时的数据绑定
【发布时间】:2017-06-11 06:04:57
【问题描述】:

我有一个用户个人资料部分,我试图让用户编辑他们的信息。我正在使用 vuex 存储用户配置文件数据并将其拉入表单。编辑表单位于 userProfile 组件的子组件中 - 它加载数据保存并将其提交到 VUEX。

所以我可以使用来自 VUEX 的数据填充表单,但是一旦我更改了表单中的任何值,它也会更改我的父组件中的值。

在保存表单之前,我不会对 VUEX 进行更改,因此这意味着数据以两种方式绑定到 VUEX。我的印象是这是不可能的。在这种情况下,这是不希望的,因为如果用户更改了一些数据,然后在没有实际单击“保存”的情况下导航离开,则 VUEX 的数据仍然被更改。

注意,这是一个简化的例子。我实际上使用路由器视图来加载子组件,或者我会通过道具传递数据。我已经测试了直接加载编辑配置文件组件,如下所示,我遇到了同样的问题。

请看下面的代码,我找不到数据被发送回商店的原因。任何帮助是极大的赞赏。

在父级中,我设置检索用户数据,如下所示:

<template>
    <div class="content">
        <h1>{{getUserDetails.firstname}} {{getUserDetails.lastname}} </h1>
        <edit-profile></edit-profile>
    </div>
</template>
<script>
    import { mapGetters } from 'vuex';
    import EditProfile from './Edit.vue';

    export default {
        data() {
            return {
                // data
            }
        },
        created () {
            this.fetchData();
        },
        components: {
            EditProfile:EditProfile
        },
        computed: mapGetters([
            'getUserDetails'
        ]),
        methods: {
            fetchData: function () {
                var _this = this;
                // ajax call - then
                _this.$store.commit('setData', {
                    name: 'userDetails',
                    data: response.data.data.userDetails
                });
            }
        }
    }
</script>

这会加载结果并将它们存储在商店中,效果很好。

我的商店有这个:

const store = new Vuex.Store({
    state: {
        userDetails: {}
    },
    mutations: {
        setData(state, payload){
            state[payload.name] = payload.data;
        }
    },
    getters: {
        getUserDetails: state => {
            return state.userDetails;
        }
    }
}

这里一切正常。

在我的带有编辑表单的子组件中,我正在像这样填充表单:

<template>
    <form>
        <label>Name</label>
        <input name="firstname" v-model="profile.firstname">
        <input name="lastname" v-model="profile.lastname">
        <button v-on:click="save">submit</button>
     </form>
</template>

<script>
import {mapGetters } from 'vuex';

export default {
    data() {
        return {
            profile:{}
        }
    },
    watch: {
        getUserDetails (newData){
            this.profile = newData;
        }
    },
    created (){
        this.profile = this.$store.getters.getUserDetails;
    },
    computed: mapGetters([
        'getUserDetails'
    ]),
    methods:{
        save (){
            var _this = this;
            // ajax call to POST this.profile then
            _this.$store.commit('setData', {
                name: 'userDetails',
                data: this.profile
            });
        }
    }
}
</script>

【问题讨论】:

    标签: data-binding vue.js vuejs2 vue-router vuex


    【解决方案1】:

    如果您正在寻找具有 vuex 的非绑定解决方案,您可以克隆对象并将本地版本用于 v-model,而不是在提交时提交。

    在您创建的生命周期函数中执行以下操作:

    created (){
        this.profile = Object.assign({}, this.$store.getters.getUserDetails);
    },
    

    【讨论】:

    • 谢谢。这工作得很好,虽然看起来应该有更优雅的方式来做到这一点。
    • 未来的用户,请注意,它只是对您的 JSON 进行浅拷贝。在此处了解深拷贝与浅拷贝:we-are.bookmyshow.com/…
    【解决方案2】:

    为什么我认为它没有像你预期的那样工作:你正在接收一个对象,将它绑定到一个本地属性。然后,当您更改该本地属性时,它由对象指针(/内存地址)绑定到存储对象。 创建一个新对象并根据状态的用户配置文件对象的属性设置该新对象的属性应该可以解决问题,因为新对象将在内存中拥有自己的地址,将指向另一个地方......

    插图:

    created (){
        // create a new object with {...}
        this.profile = {
            // assign values to properties of same name
            firstName: this.$store.getters.getUserDetails.firstName,
            lastName: this.$store.getters.getUserDetails.lastName,
        };
    },
    

    然而如果这些属性(名字、姓氏)是对象或数组(通过指向内存地址的指针访问的任何东西),那么这也不起作用。


    所以...在这种情况下,我最有可能自己做的事情是这样的:

    data() {
        return {
            firstName: '',
            lastName: ''
        }
    },
    

    这定义了本地属性。加载数据时,您将使用 Vuex 存储中的配置文件数据填充本地值。

    created() {
        let profile = this.$store.getters.getUserDetails;
        if (profile.firstName && profile.lastName) {
            this.firstName = profile.firstName;
            this.lastName = profile.lastName;
        }
    },
    

    然后,在保存时,您可以使用本地变量来更新商店的值。

    methods: {
        save() {
            let profile = {
                firstName: this.firstName,
                lastName: this.lastName
            };
    
            // ajax call to POST this.profile then
            this.$store.commit('setData', {
                name: 'userDetails',
                data: profile
            });
        }
    }
    

    我是从头到尾写这篇文章的,所以这里可能存在错误或错字……但我希望至少我的逻辑是正确的;-P 并且对你来说很清楚。

    专业版:在您准备好保存编辑后的信息之前,您不会在其他任何地方反映它。

    缺点:如果您需要反映临时更改(可能在用户个人资料预览区域中),这可能会或可能不会起作用,具体取决于您应用的结构。在这种情况下,您可能希望将 @input 绑定或保存到 state.temporaryUserProfile 对象?

    我还是 Vue.js 的新手,两周前开始使用它。希望这是清晰和正确的:)

    【讨论】:

      【解决方案3】:

      问题是由使用带有 mapGetters 的 v-model 引起的 - 这会创建您所描述的双向绑定。简单的解决方案是使用 value 代替:

      :value="profile.firstName"
      

      这样表单只会更改字段的本地副本,而不会将更改推送回 Vuex 存储。

      【讨论】:

      • 不,不要在 Vue 中使用 value,与用户输入的值没有绑定,对象不会更新,所以你不会知道输入的值,单向绑定应该在 store 和组件之间完成
      【解决方案4】:

      @Afik​​Deri 解决方案很棒,但它只会创建一个浅拷贝(例如,如果您有嵌套对象,它就不会工作,这很常见),要解决这个问题,您可以 serialize 然后 解析你的vuex状态对象getUserDetails,如下:

      created (){
          this.profile = JSON.parse(JSON.stringify(this.$store.getters.getUserDetails));
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-08-26
        • 1970-01-01
        • 1970-01-01
        • 2019-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-16
        相关资源
        最近更新 更多