添加和更新时VueJS DOM不更新-与删除一起使用

时间:2019-02-21 00:45:47

标签: javascript vuejs2 google-cloud-firestore

我是VueJS的新手,由于我的日常工作,不得不休息几个月。我现在尝试取回我的项目,但是仍然没有解决一个问题:

我已经看过其他的“ DOM未更新”帖子,但是无法找到解决方案。我正在尝试为初学者创建一个任务应用,并且该应用已经可以从Firestore加载,添加一个新应用并删除其中一个。我有两个问题,但我想从第一个开始。当我添加或更新任务时,尽管Vuex存储中的各个数组已正确更新,但DOM并未动态更新。当我重新加载页面时,它正在更新。当我删除帖子时,DOM会更新。

我已经添加了组件和商店的代码,希望在正确的位置查找,但是我有一种感觉。

预先感谢

商店代码:

import Vue from 'vue'
import Vuex from 'vuex'
import router from '@/router'
import db from '@/db'
import firebase from '@/firebase'

Vue.use(Vuex)

export const store = new Vuex.Store({
  state: {
    appTitle: 'ESNHWR task app',
    formMode: 'add',
    taskFormVisible: false,
    addedTask: false,
    loadedTasks: false,
    deletedTasks: false,
    user: null,
    error: null,
    loading: false,
    datePicker: null,
    timePicker: null,
    tasks: [],
    // tempTask: {},
    task: {
      taskId: '',
      title: '',
      description: '',
      tags: [],
      dueTime: '',
      dueDate: '',
      reminderFlag: false,
      quadrant: '',
      userId: '',
      urgencyFlag: false,
      importanceFlag: false,
      dueTimestamp: ''
    }
  },
  // Mutations (synchronous): change data in the store
  mutations: {
    setUser (state, payload) {
      state.user = payload
      state.task.userId = firebase.auth().currentUser.uid
    },
    setError (state, payload) {
      state.error = payload
    },
    setLoading (state, payload) {
      state.loading = payload
    },
    addedTask (state, payload) {
      state.addedTask = payload
    },
    loadedTasks (state, payload) {
      state.loadedTasks = true
    },
    deletedTask (state, payload) {
      state.deletedTask = payload
    },
    DELETE_TASK (state, payload) {
      state.tasks = state.tasks.filter(task => {
        return task.taskId !== payload
      })
    },
    UPDATE_TASK (state, payload) {
      const item = state.tasks.find(task => {
        return task.taskId === payload.taskId
      })
      const index = state.tasks.indexOf(item)
      Vue.set(state.tasks, index, payload)
    },
    ADD_NEW_TASK (state, payload) {
      state.tasks.push(payload)
    },
    GET_TASKS (state, payload) {
      state.tasks = payload
    },
    GET_TASK_DETAILS (state, payload) {
      var moment = require('moment')
      var date = new Date()
      date = this.state.task.dueTimestamp
      var s = moment(date).format('YYYY-MM-DD')
      var t = moment(date).format('HH:mm')
      state.task.dueDate = s
      state.datePicker = s
      state.task.dueTime = t
      state.timePicker = t
      state.task = payload
    },
    CHANGE_TASKFORM_VISIBILITY (state, payload) {
      state.taskFormVisible = payload
    },
    SET_FORMMODE (state, payload) {
      state.formMode = payload
    },
    RESET_TASK_FORM (state) {
      state.task.taskId = ''
      state.task.title = ''
      state.task.description = ''
      state.task.tags = []
      state.task.dueTime = ''
      state.task.dueDate = ''
      state.task.reminderFlag = false
      state.task.quadrant = ''
      state.task.userId = ''
      state.task.urgencyFlag = false
      state.task.importanceFlag = false
      state.task.dueTimestamp = ''
      state.datePicker = null
      state.timePicker = null
    }
  },
  // Actions (asynchronous/synchronous): change data in the store
  actions: {
    autoSignIn ({ commit }, payload) {
      commit('setUser', { email: payload.email })
    },
    userSignUp ({ commit }, payload) {
      commit('setLoading', true)
      firebase.auth().createUserWithEmailAndPassword(payload.email, payload.password)
        .then(firebaseUser => {
          commit('setUser', { email: firebaseUser.user.email })
          commit('setLoading', false)
          router.push('/home')
          commit('setError', null)
        })
        .catch(error => {
          commit('setError', error.message)
          commit('setLoading', false)
        })
    },
    userSignIn ({ commit }, payload) {
      commit('setLoading', true)
      firebase.auth().signInWithEmailAndPassword(payload.email, payload.password)
        .then(firebaseUser => {
          commit('setUser', { email: firebaseUser.user.email })
          commit('setLoading', false)
          commit('setError', null)
          router.push('/home')
        })
        .catch(error => {
          commit('setError', error.message)
          commit('setLoading', false)
        })
    },
    userSignOut ({ commit }) {
      firebase.auth().signOut()
      commit('setUser', null)
      router.push('/')
    },
    changeTaskformVisibility ({ commit }) {
      if (this.state.taskFormVisible === false) {
        commit('CHANGE_TASKFORM_VISIBILITY', true)
        commit('SET_FORMMODE', 'add')
      } else {
        commit('CHANGE_TASKFORM_VISIBILITY', false)
        commit('SET_FORMMODE', 'add')
      }
    },
    addNewTask ({ commit }, payload) {
      db.collection('tasks').add({
        title: payload.title,
        userId: firebase.auth().currentUser.uid,
        createdOn: firebase.firestore.FieldValue.serverTimestamp(),
        testOn: firebase.firestore.Timestamp.fromDate(payload.dueTimestamp),
        description: payload.description,
        dueDateAndTime: payload.dueTimestamp,
        reminderFlag: payload.reminderFlag,
        quadrant: payload.quadrant,
        tags: payload.tags,
        updatedOn: firebase.firestore.FieldValue.serverTimestamp(),
        urgencyFlag: payload.urgencyFlag,
        importanceFlag: payload.importanceFlag,
        isCompleted: false
      })
        .then(() => {
          commit('ADD_NEW_TASK', payload)
          commit('SET_FORMMODE', 'add')
          commit('CHANGE_TASKFORM_VISIBILITY', false)
        })
        .catch(error => {
          commit('setError', error.message)
        })
    },
    getTasks ({ commit }) {
      db.collection('tasks').orderBy('createdOn', 'desc').get().then(querySnapshot => {
        querySnapshot.forEach(doc => {
          const data = {
            'taskId': doc.id,
            'title': doc.data().title,
            'quadrant': doc.data().quadrant
            // add due date and time
            // add isCompleted Flag
          }
          this.state.tasks.push(data)
        })
        commit('GET_TASKS', this.state.tasks)
      })
    },
    getTaskDetails ({ commit }, payload) {
      db.collection('tasks').doc(payload).get().then(doc => {
        this.state.task.taskId = doc.id
        this.state.task.title = doc.data().title
        this.state.task.quadrant = doc.data().quadrant
        this.state.task.description = doc.data().description
        this.state.task.tags = doc.data().tags
        this.state.task.dueTimestamp = doc.data().dueDateAndTime
        this.state.task.reminderFlag = doc.data().reminderFlag
        this.state.task.urgencyFlag = doc.data().urgencyFlag
        this.state.task.importanceFlag = doc.data().importanceFlag
        // add isCompleted Flag
      }).then(() => {
        commit('GET_TASK_DETAILS', this.state.task)
        commit('SET_FORMMODE', 'update')
        commit('CHANGE_TASKFORM_VISIBILITY', true)
      }).catch(function (error) {
        commit('setError', error.message)
      })
    },
    updateTask ({ commit }, payload) {
      db.collection('tasks').doc(payload.taskId).update({
        title: payload.title,
        description: payload.description,
        dueDateAndTime: payload.dueTimestamp,
        reminderFlag: payload.reminderFlag,
        quadrant: payload.quadrant,
        tags: payload.tags,
        updatedOn: firebase.firestore.FieldValue.serverTimestamp(),
        urgencyFlag: payload.urgencyFlag,
        importanceFlag: payload.importanceFlag
        // add isCompleted Flag
      }).then(() => {
        commit('UPDATE_TASK', payload)
        commit('CHANGE_TASKFORM_VISIBILITY', false)
        commit('SET_FORMMODE', 'add')
      }).catch(function (error) {
        commit('setError', error.message)
      })
    },
    deleteTask ({ commit }, payload) {
      db.collection('tasks').doc(payload).delete().then(() => {
        commit('DELETE_TASK', payload)
      }).catch(function (error) {
        // console.error('Error removing document: ', error)
        commit('setError', error.message)
      })
    },
    resetTaskForm ({ commit }) {
      commit('RESET_TASK_FORM', 'true')
    }
  },
  // Getters: receive data from the store
  getters: {
    isAuthenticated (state) {
      return state.user !== null && state.user !== undefined
    }
  }
})

组件代码(用于添加和更新):

<template>
  <v-container grid-list-xl>
    <v-form ref="form" lazy-validation>
      <v-card>
        <v-card-text>
          <v-text-field v-model="$store.state.task.title" autofocus ref="taskTitle" label="Add a new task" prepend-icon="check_circle_outline" required>
          </v-text-field>
          <v-layout row wrap>
            <v-flex xs12 sm6 md4>
              <v-menu ref="datePicker" :first-day-of-week="1" locale="us-US" show-current :close-on-content-click="false" v-model="task.datePicker" :nudge-right="40" :return-value.sync="$store.state.task.dueDate" lazy transition="scale-transition" offset-y full-width min-width="200px">
                <v-text-field slot="activator" v-model="$store.state.datePicker" label="Choose due date" prepend-icon="event" readonly></v-text-field>
                <v-date-picker v-model="$store.state.datePicker" @input="$refs.datePicker.save($store.state.datePicker)"></v-date-picker>
              </v-menu>
            </v-flex>
            <v-flex xs12 sm6 md4>
              <v-menu ref="timePicker" :close-on-content-click="false" v-model="task.timePicker" :nudge-right="40" :return-value.sync="$store.state.task.dueTime" lazy transition="scale-transition" offset-y full-width min-width="290px">
                <v-text-field slot="activator" v-model="$store.state.timePicker" label="Choose due time" prepend-icon="access_time" readonly></v-text-field>
                <v-time-picker v-model="$store.state.timePicker" @change="$refs.timePicker.save($store.state.timePicker)"></v-time-picker>
              </v-menu>
            </v-flex>
            <v-flex xs12 sm6 md4>
              <v-switch v-model="$store.state.task.reminderFlag" label="Add reminder" prepend-icon="access_alarm" color="primary" hide-details></v-switch>
            </v-flex>
          </v-layout>
          <v-layout row wrap>
            <v-flex xs12 sm6 md4>
              <v-switch v-model="$store.state.task.importanceFlag" label="Important" prepend-icon="error_outline" color="primary" hide-details></v-switch>
            </v-flex>
            <v-flex xs12 sm6 md4>
              <v-switch v-model="$store.state.task.urgencyFlag" label="Urgent" prepend-icon="update" color="primary" hide-details></v-switch>
            </v-flex>
            <v-flex xs12 sm6 md4>
              <p>Quadrant: {{ identifyQuadrant }}</p>
            </v-flex>
          </v-layout>
          <v-textarea name="description" label="Enter description" auto-grow value="" prepend-icon="description" v-model="$store.state.task.description"></v-textarea>
          <v-combobox v-model="$store.state.task.tags" :items="items" label="Tags" chips prepend-icon="filter_list" solo multiple>
            <template slot="selection" slot-scope="data">
              <v-chip :selected="data.selected" close @input="remove(data.item)">
                <p>{{ data.item }}</p>
              </v-chip>
            </template>
          </v-combobox>
          <v-card-actions>
            <v-spacer></v-spacer>
            <v-btn color="primary" flat @click.prevent="changeTaskformVisibility" v-if="$store.state.formMode === 'add'">Cancel</v-btn>
            <v-btn color="primary" @click.prevent="addNewTask" v-if="$store.state.formMode === 'add'">Add new task</v-btn>
            <v-btn color="primary" flat @click.prevent="cancelUpdateTask" v-if="$store.state.formMode === 'update'">Cancel update</v-btn>
            <v-btn color="primary" @click.prevent="updateTask" v-if="$store.state.formMode === 'update'">Update task</v-btn>
          </v-card-actions>

        </v-card-text>
      </v-card>
    </v-form>
  </v-container>
</template>

<script>
export default {
  data () {
    return {
      // task: {},
      items: [], // tags - to be renamed
      date: null,
      time: null,
      datePicker: false,
      timePicker: false,
      task: {
        title: '',
        description: '',
        tags: [],
        dueTime: '',
        dueDate: '',
        reminderFlag: false,
        quadrant: '',
        urgencyFlag: false,
        importanceFlag: false,
        dueTimestamp: ''
      }
    }
  },
  methods: {
    dateTimeToTimestamp () {
      var dateFromPicker = this.$store.state.task.dueDate
      var timeFromPicker = this.$store.state.task.dueTime

      var dateParts = dateFromPicker.split('-')
      var timeParts = timeFromPicker.split(':')
      var localDate = new Date(dateParts[0], dateParts[1] - 1, dateParts[2], timeParts[0], timeParts[1])

      return localDate
    },
    addNewTask () {
      this.$store.state.task.dueTimestamp = this.dateTimeToTimestamp()
      this.$store.dispatch('addNewTask', this.$store.state.task)
      this.$store.dispatch('resetTaskForm', 'true')
    },
    updateTask () {
      this.$store.state.task.dueTimestamp = this.dateTimeToTimestamp()
      this.$store.dispatch('updateTask', this.$store.state.task)
      this.$store.dispatch('resetTaskForm', 'true')
    },
    cancelUpdateTask () {
      this.$store.dispatch('changeTaskformVisibility')
    },
    cancelAddTask () {
      console.log('cancelling ...')
    },
    changeTaskformVisibility () {
      this.$store.dispatch('changeTaskformVisibility')
    }
  },
  computed: {
    identifyQuadrant () {
      if (this.$store.state.task.importanceFlag === true && this.$store.state.task.urgencyFlag === true) {
        this.$store.state.task.quadrant = 'do'
      } else if (this.$store.state.task.importanceFlag === true && this.$store.state.task.urgencyFlag === false) {
        this.$store.state.task.quadrant = 'plan'
      } else if (this.$store.state.task.importanceFlag === false && this.$store.state.task.urgencyFlag === true) {
        this.$store.state.task.quadrant = 'delegate'
      } else if (this.$store.state.task.importanceFlag === false && this.$store.state.task.urgencyFlag === false) {
        this.$store.state.task.quadrant = 'eliminate'
      }
      return this.$store.state.task.quadrant
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped>
.container {
  max-width: 1200px;
}

/* Extras */
a:visited {
  color: #888;
}

a {
  color: #444;
  text-decoration: none;
}

p {
  margin-bottom: 0.3em;
}
</style>

组件代码(用于删除(并将任务详细信息加载到上面的组件中)):

<template>
  <div>{{task.title}} ({{task.taskId}})<v-spacer></v-spacer> delete: {{deleteConfirmation}}, complete: {{completeConfirmation}}
    <v-scroll-x-transition>
      <v-btn flat icon color="secondary" v-show="!deleteConfirmation && !completeConfirmation" @click="completeConfirmation = !completeConfirmation">
        <v-icon>done</v-icon>
      </v-btn>
    </v-scroll-x-transition>
    <v-scroll-x-transition>
      <v-btn flat icon color="primary" v-show="!deleteConfirmation && !completeConfirmation" @click="getTaskDetails(task.taskId)">
        <v-icon>edit</v-icon>
      </v-btn>
    </v-scroll-x-transition>
    <v-scroll-x-transition>
      <v-btn flat icon color="primary" v-show="!deleteConfirmation && !completeConfirmation" @click="deleteConfirmation = !deleteConfirmation">
        <v-icon>delete</v-icon>
      </v-btn>
    </v-scroll-x-transition>

    <!-- Confirm or cancel deletion -->
    <v-scroll-x-transition>
      <v-btn flat icon color="green" v-show="deleteConfirmation" @click="deleteConfirmation = !deleteConfirmation">
        <v-icon>cancel</v-icon>
      </v-btn>
    </v-scroll-x-transition>

    <v-scroll-x-transition>
      <v-btn flat icon color="red" v-show="deleteConfirmation" @click="deleteConfirmation = !deleteConfirmation; deleteTask(task.taskId)">
        <v-icon>check_circle</v-icon>
      </v-btn>
    </v-scroll-x-transition>

    <!-- Confirm or cancel completion -->
    <v-scroll-x-transition>
      <v-btn flat icon color="red" v-show="completeConfirmation" @click="completeConfirmation = !completeConfirmation">
        <v-icon>cancel</v-icon>
      </v-btn>
    </v-scroll-x-transition>

    <v-scroll-x-transition>
      <v-btn flat icon color="green" v-show="completeConfirmation" @click="completeConfirmation = !completeConfirmation; markTaskAsCompleted(task.taskId)">
        <v-icon>check_circle</v-icon>
      </v-btn>
    </v-scroll-x-transition>
    </li>
  </div>
</template>

<script>

export default {
  data () {
    return {
      deleteConfirmation: false,
      completeConfirmation: false
    }
  },
  props: ['task'],
  computed: {

  },
  methods: {
    deleteTask (taskId) {
      this.$store.dispatch('deleteTask', taskId)
    },
    getTaskDetails (taskId) {
      this.$store.dispatch('getTaskDetails', taskId)
    },
    markTaskAsCompleted (taskId) {
      this.$store.dispatch('markTaskAsCompleted', taskId)
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped>

</style>

非常感谢帮助初学者!

1 个答案:

答案 0 :(得分:0)

我认为我想出了增加的方法-我处理了商店中的所有任务。我现在将其更改为本地任务对象,并且工作正常。现在,我在更新方面遇到了另一个挑战,但是我将把它发布为另一个问题。