vue.js 我如何重置一个对象的属性而不改变我推入它的数组?

3ks5zfa0  于 2023-11-21  发布在  Vue.js
关注(0)|答案(1)|浏览(166)

我正在从Vue的Options API过渡到Composition API,为此,我已经整合了一个小型Todo App。
components\AddUpdate中,我有:

<template>
  <form
    class="card-footer"
    @submit.prevent="$emit('add-update-todo', text)"
    autocomplete="off"
  >
    <input id="toDoText" type="text" placeholder="Add todo" v-model="text" />
    <button type="submit">Ok</button>
  </form>
</template>

<script>
import { ref, onMounted, watch } from 'vue';
export default {
  name: 'AddUpdateTodo',

  setup() {
    const text = ref('');
    return { text };
  },
};
</script>

字符串
App.vue中,我有:

<template>
  <div id="app">
    <ErrorMessage
      v-if="!isValid"
      message="The todo body has to be at least 3 characters long"
    />

    <SuccessMessage v-if="allDone" message="You can relex! :)" />

    <div class="card">
      <Header />
      <List
        :todos="todos"
        @delete-todo="deleteTodo"
        @edit-todo="editTodo"
        @toggle-todo="toggleTodo"
      />
      <AddUpdateTodo @add-update-todo="AddUpdateTodo" />
    </div>
  </div>
</template>

<script>
import { ref, computed } from 'vue';
import ErrorMessage from './components/ErrorMessage.vue';
import SuccessMessage from './components/SuccessMessage.vue';
import Header from './components/Header.vue';
import List from './components/List.vue';
import AddUpdateTodo from './components/AddUpdate.vue';

export default {
  name: 'App',
  components: {
    ErrorMessage,
    SuccessMessage,
    Header,
    List,
    AddUpdateTodo,
  },

  setup() {
    const todos = ref([]);
    const currentItem = ref(null);
    const isValid = ref(true);
    const isUpdate = ref(false);
    const allDone = computed(
      () => todos.value.length && todos.value.every((todo) => todo.done)
    );

    return { todos, isValid, isUpdate, allDone };
  },

  methods: {
    toggleTodo: function (index) {
      this.todos[index].done = !this.todos[index].done;
    },

    deleteTodo: function (index) {
      if (confirm('Are you sure?')) {
        this.todos.splice(index, 1);
      }
    },

    editTodo: function (index) {
      this.isUpdate = true;
      let formField = document.getElementById('toDoText');
      // Get current Item
      this.currentItem = this.todos[index];
      // Prepopulate form with existing value
      formField.value = this.currentItem.text;
    },

    AddUpdateTodo: function (text) {
      let newTodo = {
        done: false,
        text: '',
      };

      if (text.length > 2) {
        this.isValid = true;
        if (!this.isUpdate) {
          newTodo.text = text;
          this.todos.push(newTodo);
        } else {
          this.currentItem.text = document.getElementById('toDoText').value;
          this.isUpdate = false;
        }
        document.getElementById('toDoText').value = '';
      } else {
        this.isValid = false;
      }
    },
  },
};
</script>


一旦将newTodo.text的值更改为长度大于2的字符串,即使表单字段为空,后续执行AddUpdateTodo也会满足验证条件。


的数据
我试图通过在this.todos.push(newTodo)之后添加newTodo.text = ''来解决这个问题,但这会导致所有todos都为空。
我做错了什么?

v9tzhpje

v9tzhpje1#

AddUpdate组件中,使用v-model将其输入与父组件绑定,然后使用parent(currentItem)中的绑定值来更新/添加todo,然后通过访问DOM重置它。我重构了您的代码以仅使用复合API:

<template>
  <div id="app">
    <ErrorMessage
      v-if="!isValid"
      message="The todo body has to be at least 3 characters long"
    />

    <SuccessMessage v-if="allDone" message="You can relex! :)" />

    <div class="card">
      <Header />
      <List
        :todos="todos"
        @delete-todo="deleteTodo"
        @edit-todo="editTodo"
        @toggle-todo="toggleTodo"
      />
      <AddUpdateTodo @add-update-todo="AddUpdateTodo" v-model="currentItem" />
      {{ currentItem }}
    </div>
  </div>
</template>

<script>
import { ref, computed } from 'vue';
import ErrorMessage from './components/ErrorMessage.vue';
import SuccessMessage from './components/SuccessMessage.vue';
import Header from './components/Header.vue';
import List from './components/List.vue';
import AddUpdateTodo from './components/AddUpdate.vue';

export default {
  name: 'App',
  components: {
    ErrorMessage,
    SuccessMessage,
    Header,
    List,
    AddUpdateTodo,
  },

  setup() {
    const todos = ref([]);
    const currentItem = ref(null);
    const isValid = ref(true);
    const isUpdate = ref(false);
    const updateAtIndex = ref(-1);

    const allDone = computed(
      () => todos.value.length && todos.value.every((todo) => todo.done)
    );

    const toggleTodo = (index) => {
      todos.value[index].done = !todos.value[index].done;
    };

    const deleteTodo = (index) => {
      if (confirm('Are you sure?')) {
        todos.value.splice(index, 1);
      }
    };

    const editTodo = (index) => {
      isUpdate.value = true;
      updateAtIndex.value = index;
      currentItem.value = todos.value[index].text;
    };

    const AddUpdateTodo = () => {
      let newTodo = {
        done: false,
        text: '',
      };
      const text = currentItem.value;

      if (text && text.length > 2) {
        isValid.value = true;
        if (!isUpdate.value) {
          newTodo.text = text;
          todos.value.push(newTodo);
        } else {
          todos.value[updateAtIndex.value].text = text;
          isUpdate.value = false;
        }
        currentItem.value = '';
      } else {
        isValid.value = false;
      }
    };

    return {
      todos,
      isValid,
      isUpdate,
      allDone,
      toggleTodo,
      deleteTodo,
      editTodo,
      AddUpdateTodo,
      currentItem,
    };
  },
};
</script>

字符串
AddUpdate

<template>
  <form
    class="card-footer"
    @submit.prevent="$emit('add-update-todo')"
    autocomplete="off"
  >
    <input id="toDoText" type="text" placeholder="Add todo" v-model="text" />
    <button type="submit">Ok</button>
  </form>
</template>

<script>
import { ref, onMounted, watch, computed } from 'vue';
export default {
  name: 'AddUpdateTodo',
  props: ['modelValue'],
  setup(props, { emit }) {
    const text = computed({
      get() {
        return props.modelValue;
      },
      set(value) {
        emit('update:modelValue', value);
      },
    });
    return { text };
  },
};
</script>


LIVE DEMO

相关问题