Анимация каждого элемента отдельно в цикле v -for (Vue.JS) - PullRequest
0 голосов
/ 12 марта 2019

Я сделал простое приложение, используя VueJS. Я также добавил vue2-animate (порт Vue.js 2.0 для Animate.css. Для использования со встроенными переходами Vue.) Анимация добавления одного элемента работает корректно.

Но было две проблемы, которые я хотел бы решить без лишнего кодирования :

  1. Отображение анимации для списка загруженных из локального хранилища работает для всех предметов одновременно. Мне нужна анимация для работы последовательно для каждого элемента в отдельности.
  2. Анимация удаления элемента работает некорректно - последний пункт всегда удаляется, а затем следует смена.

P.S .: Посмотрите демонстрацию в JSFiddle, потому что локальное хранилище не работает в SO фрагментах.

Vue.component("adder", {
  data: function() {
    return {
      task: ""
    };
  },
  template: `
    <div class="input-group mb-3">
    <input type="text" class="form-control" placeholder="New task..." aria-label="New task..." aria-describedby="" v-model="task" v-on:keyup.enter="add">
    <div class="input-group-append">
      <button class="btn btn-primary" id="" v-on:click="add" >+</button>
    </div>
    </div>
    `,
  methods: {
    add: function() {
      this.$emit("addtodo", {
        title: this.task,
        done: false
      });
      this.task = "";
    }
  }
});

Vue.component("todo", {
  props: ["item"],
  template: `

    <a href="#" class="list-group-item list-group-item-action task" v-bind:class="{'disabled done' : item.done==true}">
    <label class="form-check-label">
            <input class="form-check-input" type="checkbox" name="" id="" value="checkedValue"  v-model="item.done"> {{item.title}}
        </label>
        <button type="button" class="close" aria-label="Close" v-on:click="del">
            <span aria-hidden="true">&times;</span>
        </button>
    </a>
    
    `,
  methods: {
    del: function() {
      this.$emit("deletetodo");
    }
  }
});

Vue.component("todos", {
  props: ["items"],
  template: `
    <div class="list-group">
        <transition-group name="bounceLeft" tag="a">
            <todo v-for="(item, index) in items" :key="index" :item.sync="item" v-on:deletetodo="delTodo(item)"></todo>
        </transition-group>
    </div>
    `,
  methods: {
    delTodo: function(i) {
      this.$emit("deletetodo", i);
    }
  }
});
Vue.config.devtools = true;

let app = new Vue({
  el: ".todoapp",
  data: {
    title: "Todo App",
    items: []
  },
  methods: {
    addTodo: function(e) {
      this.items.push(e);
    },
    delTodo: function(i) {
      this.items = this.items.filter(e => e != i);
    }
  },
  mounted() {
    if (localStorage.items) {
      this.items = JSON.parse(localStorage.getItem("items"));
    }
  },
  watch: {
    items: {
      handler(val) {
        localStorage.setItem("items", JSON.stringify(this.items));
      },
      deep: true
    }
  }
});
.done>label {
  text-decoration: line-through;
}

.task {
  padding-left: 36px;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <title>Todo App</title>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous" />

  <link rel="stylesheet" href="https://unpkg.com/vue2-animate/dist/vue2-animate.min.css" />
  <link rel="stylesheet" href="style.css" />
</head>

<body>
  <div class="container todoapp">
    <div class="row">
      <br />
    </div>
    <div class="card">
      <div class="card-header">
        {{ title }}
      </div>
      <div class="card-body">
        <adder v-on:addtodo="addTodo"></adder>
        <todos :items.sync="items" v-on:deletetodo="delTodo"></todos>
      </div>
    </div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
  <script src="script.js"></script>
</body>

</html>

JSFiddle demo

Ответы [ 2 ]

1 голос
/ 12 марта 2019

Хорошо, принимая это по одному:

Удаление задачи

Причина, по которой всегда кажется, что последняя задача удаляется, заключается в том, что вы набираете элементы списка с помощью index,Когда вы заменяете весь массив items в своем методе delTodo, это, в свою очередь, дает вам новый массив с новыми ключами для каждого элемента в списке.Введите item, и вы получите правильный результат:

<todo v-for="(item, index) in items" :key="item" :item.sync="item" v-on:deletetodo="delTodo(item)"></todo>

Отображение задач по одному при загрузке

Мой совет - подходить к показу / скрытиюзадач с вычисляемым свойством:

computed: {
    tasks: function(){
        return this.items.filter(item => item.isVisible);
    }
}

Здесь мы покажем / скроем, переключая isVisible для каждой задачи.

Это означает, что когда вы изначально загружаете задачи из локального хранилища, выможно установить для них все значение isVisible: false, а затем использовать setTimeout в цикле for, чтобы отобразить их все по одному:

mounted() {
    // Get your items and set all to hidden
    if (localStorage.items) {
        this.items = JSON.parse(localStorage.getItem("items"))
                     .map(item => item.isVisible = false);
    }

    // Loop through and show the tasks
    for(let i=1; i<=this.items.length; i++){
        // Where 300 is milliseconds to delay
        let delay = i * 300;

        setTimeout(function(){
            this.items[i].isVisible = true;
        }.bind(this), delay);
    }
},
0 голосов
/ 12 марта 2019

Лучше всего пошаговое добавление к массиву предметов:

  mounted() {
    let items = [];
    if (localStorage.items) {
      items = JSON.parse(localStorage.getItem("items"))
    }
    for (let i = 0; i < items.length; i++) {
      let delay = i * 1000;
      setTimeout(
        function() {
          this.items.push(items[i])
        }.bind(this),
        delay
      )
    }
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...