如何使用 Vue JS 在子组件中保留数字和增量?

Posted

技术标签:

【中文标题】如何使用 Vue JS 在子组件中保留数字和增量?【英文标题】:How can I keep number and increment in child component with Vue JS? 【发布时间】:2020-09-20 13:46:39 【问题描述】:

练习用 Vue JS 做一个 todo 应用

输入项保存在localStrage中。

更新

当您添加了一些列表并重新加载页面时,ID 号从 1 开始(默认)。

理想行为:

重新加载页面时,ID 号继续编号递增。 如果删除了一些项目,那么,添加新项目,ID号应该是数组中最大的ID号(如果8)+1(应该是9)。

我的代码:Link

问题就在这里。

Child2.vue

  created() 
    let keyObject = JSON.parse(localStorage.getItem(this.keyName));

    if (keyObject) 
      this.$emit("update:todos", keyObject);
     else 
      return;
    

    if (this.todos.length > 0) 
      console.log(this.todos.id);
      const setId = this.todos.reduce(function(a,b) return a > b.id ? a : b.id ,0)
      this.todos.id = setId + 1
      console.log(this.todos.id);

      this.$emit('update:todos', keyObject)
      // this.$emit('update:todos', this.todos.id)
    
  ,

你知道吗?

【问题讨论】:

问题是this.todos.push(keyObject);,因为它会创建一个嵌套数组。您需要使用 concat 附加数组,或者改为在 keyObject 的每个元素上调用 push。举例来说,如果您保存了项目 A、B、C,则该行将创建 [[A, B, C]] 并添加您现在拥有的第四个项目 [[A, B, C], D]。每次重新加载应用程序时,嵌套都会累积。 我不确定你的目标是什么,因为你说了 3 个不同的目标 @Chris G,感谢您的评论。我会尝试使用concat 来更新todos 数组。 @Billal Begueradj,很抱歉造成混乱。我对vue很陌生,我正在练习并试图理解它 【参考方案1】:

你可以避免直接使用.sync修饰符来修改props:

App.vue:

<Child2 :todos.sync="todos" :keyName="keyName"/>

Child2.vue:

if (keyObject) 
     this.$emit('update:todos', keyObject);

为了获取下一个 id,您可以在从本地存储中获取数组时发出此值:

App.vue:

<Child2 :todos.sync="todos" @setTargetId="setTargetId" :keyName="keyName"/>
methods: 
    // ...
    setTargetId(newTargetId)
        this.$set(this.target, 'id', newTargetId );
    


Child2.vue:

// ...
created() 
    let keyObject = JSON.parse(localStorage.getItem(this.keyName));

    // Check keyObject 
    if (keyObject) 
        // update todo on App.vue
        this.$emit("update:todos", keyObject);

        // set target.id
        const setId = keyObject.reduce(function(a,b) return a > b.id ? a : b.id ,0)
        this.$emit('setTargetId', setId + 1)
     
,

请看这里:https://codesandbox.io/s/keen-gates-q7efo

【讨论】:

非常感谢。问题解决了。现在另一个问题发生了。我想在重新加载页面时保持 ID 号递增。现在它从id: 1, 重新启动,这会导致错误。是否可以通过 this.$emit('update:todos', keyObject) 连接 this.todos.id ?代码更新:codesandbox.io/s/boring-meninsky-jywtq 添加 id 增量 Child2.vue ``` if (this.todos.length > 0) ..here.. `` 你可以在获取数组时发出一个事件,我更新我的答案和代码框链接 刚刚看到您的代码。从未见过$set,但现在我知道如何使用了。非常感谢你的帮助。我很感激。【参考方案2】:

根据我对您的问题的理解,您希望从子组件更新道具的值。

为此,您可能希望将更改从子组件发送回父组件。

以下是这样做的一种方法:

在您的子组件中:

this.todosArray = this.todosArray.concat(keyObject); //concat with an existing array
this.$emit("updateTodos", this.todosArray); //emit new array back to parent

在你的父组件中,你注册你的子组件:

<Child2 :todos="todos" :keyName="keyName" @updateTodos="updateTodos"/>

然后添加一个方法来使用来自子组件的值更新原始数组。

updateTodos(value) 
 this.todos = value

我希望它有所帮助。祝你好运!

【讨论】:

非常感谢。我从未使用过concat,但现在我知道如何使用它了:)【参考方案3】:

keyObject 和 this.todos 格式不一致(this.todos 实际上是嵌套的),你不应该改变 props。

还要注意 ID 增量以避免循环中出现重复错误

我的建议 App.vue:

methods: 
    addBtn() 

      const todo =  id: this.target.id, name: this.target.name, done: false ;
      this.todos.push(todo);
      localStorage.setItem(this.keyName, JSON.stringify(this.todos));
      this.target.name = "";
      //it is important to increment the id based on current length
      this.target.id = this.todos.length + 1;
    ,
    onInputChange(val) 
      this.target.name = val;
    
  ,
  created() 
     let todosObject  = JSON.parse(localStorage.getItem(this.keyName));
     if(todosObject)
       this.todos = todosObject
       //again base the id on the current length, to avoid duplicate error in loops later 
       this.target.id = this.todos.length+1
     

  

孩子2:

<template>
  <div>
    <ul>
      <li v-for="todo in todos" :key="todo.id">
        ID:  todo.id  / Name:  todo.name 
        <input
          type="checkbox"
          v-model="todo.done"
          @click="status(todo)"
        >
        <button @click="removeBtn(todo)">Remove item</button>
      </li>
    </ul>
  </div>
</template>

<script>
export default 
  props: 
    todos: 
      type: Array,
      required: true
    ,
    keyName: 
      type: String,
      required: true
    
  ,

  methods: 
    removeBtn(item) 
      const index = this.todos.indexOf(item);
      this.todos.splice(index, 1);
      localStorage.setItem(this.keyName, JSON.stringify(this.todos));
      if (this.todos.length === 0) 
        console.log("no item");
      
    ,
    status(todo) 
      todo.done = !todo.done;
      localStorage.setItem(this.keyName, JSON.stringify(this.todos));
    
  
;
</script>

【讨论】:

非常感谢。并感谢您的想法。我实际上有麻烦。 this.target.id = this.todos.length+1 对我来说还不够。删除某些项目并重新加载页面时,最大的 id 数字和 todos.length 并不总是相同的。在这种情况下,如果添加新项目,则会发生错误。我想根据最大的target.id 递增。有可能吗? 是的,我的代码就是这样做的,请参阅 App.vue 中的 created() 部分,刷新时它总是从 localStorage 获取当前长度并将其增加 1

以上是关于如何使用 Vue JS 在子组件中保留数字和增量?的主要内容,如果未能解决你的问题,请参考以下文章

Vue.js 父子组件,为啥我的 prop 在子组件中还没有?

如何在 Vue.js 中保留自定义组件标签名称

vue.js 如何获取某个组件实例?

Vue js:如何在两个组件中使用 mixin 功能?通过执行错误

vue打包后很多数字开头的js

Vue.js 更新的属性不会在子组件上更改