todo case - creating projects and components

Posted by Jeyush on Sun, 26 Dec 2021 09:07:03 +0100


analysis:
① : initialize todo project
② : create 3 components and internal code
③ : prepare the style file of styles
④: App.vue is introduced for registration. The outermost container class name is todoapp
Prepare in advance: prepare the style file of styles (copy it from the preview materials) in app Vue introduction and use (there is a link behind)

// 1.0 Style Introduction
import "./styles/base.css"
import "./styles/index.css"

1. Laying to-do tasks

Purpose: to display the to-do tasks to todomain On Vue assembly

  • Requirement 1: display the to-do tasks to todomain On Vue assembly
  • Requirement 2: Associate selected status and set related styles

analysis:
①: App.vue – prepare array to pass into todomain Within Vue
② : v-for loop display data
③ The: v-model binding check box is selected
④ : sets the finish dash style according to the selected status
App.vue

 <TodoMain :arr="showArr"></TodoMain>
 
<script>
export default {
  data() {
    return {
      list: [
        { id: 100, name: "having dinner", isDone: true },
        { id: 102, name: "sleep", isDone: false },
        { id: 103, name: "Beat beans", isDone: true },
      ],
    };
  }
};
</script>

TodoMain.vue

<template>
  <ul class="todo-list">
    <!-- 2.2 Circular task-Association selected status-Laying data -->
    <!-- completed: Completed class name -->
    <li :class="{completed: obj.isDone}" v-for="(obj, index) in arr" :key='obj.id'>
      <div class="view">
        <input class="toggle" type="checkbox" v-model="obj.isDone"/>
        <label>{{ obj.name }}</label>
        <!-- 4.0 Register click events -->
        <button  class="destroy"></button>
      </div>
    </li>
  </ul>
</template>

<script>
export default {
  props: ["list"]
};
</script>

<style>
</style>

2. Add task

Objective: enter the task name to be completed in the top input box, and click enter to complete the new function
Demand: enter a task and press enter to add a to-do task
analysis:
①: TodoHeader.vue – input box – keyboard event – enter key
② : pass the child to the parent and send the to-do task – app Vue – add to the array list
③ : if the original array is changed, all the places used will be updated
④ : the input box is empty, prompting the user to enter content
TodoHeader.vue

<template>
  <header class="header">
    <h1>todos</h1>
    <input id="toggle-all" class="toggle-all" type="checkbox" v-model="isAll">
    <label for="toggle-all"></label>
    <!-- 3.0 Keyboard events-Enter key
         3.1 Input box - v-model Get value
     -->
    <input
      class="new-todo"
      placeholder="Enter task name-Enter to confirm"
      autofocus
      @keydown.enter="downFn"
      v-model="task"
    />
  </header>
</template>

<script>
// 3. Objective - new task
export default {
  data(){
    return {
      task: ""
    }
  },
  methods: {
    downFn(){
      if (this.task.trim().length === 0) {
        alert("Task name cannot be empty");
        return;
      }
      // 3.2 (important) - the name of the current task should be added to the list array
      // Son to father Technology
      this.$emit("create", this.task)
      this.task = ""
    }
  }
}
</script>

App.vue

<TodoHeader @create="createFn"></TodoHeader>

methods: {
   createFn(taskName){ // Add task
      // 3.3 push to array
      let id = this.list.length == 0 ? 100 : this.list[this.list.length - 1].id + 1
      this.list.push({
        id: id,
        name: taskName,
        isDone: false
      })
    },
}

3. Delete task

Objective: to achieve point x and delete the task function
Requirement: click x after the task to delete the current task
analysis:
① : x tag – click event – pass in id area
② : pass the child to the parent, and return the id – app In Vue – delete a corresponding object in the array list
③ : if the original array is changed, all the places used will be updated

App.vue - incoming custom event waiting to receive sequence number to be deleted

<TodoMain :arr="showArr" @del="deleteFn"></TodoMain>

methods: {
    deleteFn(theId){ // Delete task
      let index = this.list.findIndex(obj => obj.id === theId)
      this.list.splice(index, 1)
    },
},

TodoMain.vue - pass the id back to delete (delete the data wherever you want)

<!-- 4.0 Register click events -->
<button class="destroy" @click="delFn(obj.id)"></button>

methods: {
     delFn(id){
      // 4.1 son to father
      this.$emit('del', id)
    }
}

4. Bottom statistics

Objective: to display the total number of current tasks
Demand: count the number of current tasks
analysis:
①: App.vue - array list - passed to todofooter vue
② : display / define calculation properties directly on the label for display
③ : as long as the original array is changed, all places where this array is used will be updated

TodoFooter.vue - direct display of received list statistics

<template>
  <footer class="footer">
    <span class="todo-count">surplus<strong>{{ count }}</strong></span>
    <ul class="filters">
      <li>
        <a class="selected" href="javascript:;">whole</a>
      </li>
      <li>
        <a href="javascript:;">hang in the air</a>
      </li>
      <li>
        <a href="javascript:;">Completed</a>
      </li>
    </ul>
    <button class="clear-completed">Cleanup completed</button>
  </footer>
</template>

<script>
export default {
  // 5.0 props definition
  props: ['farr'],
  // 5.1 calculation attribute - task quantity
  computed: {
    count(){
      return this.farr.length
    }
  },
}
</script>

<style>

</style>

App.vue - incoming data

<TodoFooter :farr="showArr"></TodoFooter>

5. Data switching

Purpose: click the bottom to switch data
Requirement 1: click the switch at the bottom - who has a border
Requirement 2: switch different data display correspondingly
analysis:
①: TodoFooter.vue – define isSel – the value is all, yes, no, one of them
② selected: multiple classes determine who should have the class name
③ : Click to modify the value of isSel
④ : pass the child to the parent, and pass the type isSel to app vue
⑤ : define the calculation attribute showArr to determine which data to display to todomain from the list Vue and todofooter vue

App.vue

<TodoFooter :farr="showArr" @changeType="typeFn"></TodoFooter>

<script>
    export default{
       data(){
            return {
              // ... Other omissions
              getSel: "all" // Show all by default
            }
        },
        methods: {
            // ... Other omissions
            typeFn(str){ // 'all', 'yes',' no '/ / modify type
              this.getSel = str
            },
        },
        // 6.5 define showArr array - filtered by list matching conditions
          computed: {
            showArr(){
              if (this.getSel === 'yes') { // Show completed
                return this.list.filter(obj => obj.isDone === true)
              } else if (this.getSel === 'no') { // Show incomplete
                return this.list.filter(obj => obj.isDone === false)
              } else {
                return this.list // show all
              }
            }
          },
    }
</script>

TodoFooter.vue

<template>
  <footer class="footer">
    <span class="todo-count">surplus<strong>{{ count }}</strong></span>
    <ul class="filters" @click="fn">
      <li>
        <!-- 6.1 Determine who should have a highlighted style: dynamic class
            6.2 User clicks to switch isSel Values saved in
         -->
        <a :class="{selected: isSel === 'all'}" href="javascript:;" @click="isSel='all'">whole</a>
      </li>
      <li>
        <a :class="{selected: isSel === 'no'}" href="javascript:;" @click="isSel='no'">hang in the air</a>
      </li>
      <li>
        <a :class="{selected: isSel === 'yes'}" href="javascript:;" @click="isSel='yes'">Completed</a>
      </li>
    </ul>
    <!-- 7. target: Cleanup completed -->
    <!-- 7.0 Click event -->
    <button class="clear-completed" >Cleanup completed</button>
  </footer>
</template>

<script>
// 5. Objective: quantity statistics
export default {
  // 5.0 props definition
  props: ['farr'],
  // 5.1 calculation attribute - task quantity
  computed: {
    count(){
      return this.farr.length
    }
  },
  // 6. Goal: who lights up
  // 6.0 variable isSel
  data(){
    return {
      isSel: 'all' // All: 'all', completed 'yes', incomplete' no '
    }
  },
  methods: {
    fn(){ // Toggle filter criteria
      // 6.3 child - > parent type string is passed to app vue 
      this.$emit("changeType", this.isSel)
    }
  }
}
</script>

6. Emptying completed

Purpose: click the button in the lower right corner to clear the completed tasks
Requirements: click the link tab in the lower right corner to clear the completed tasks
analysis:
① : empty tab – click event
② Child to parent – app Vue – an emptying method
③ : filter the incomplete overlay list array (regardless of recovery)

App.vue - pass in a custom event first - because you have to receive todofooter Click events in Vue

<TodoFooter :farr="showArr" @changeType="typeFn" @clear="clearFun"></TodoFooter>

<script>
    methods: {
        // ... Omit others
        clearFun(){ // Cleanup completed
          this.list = this.list.filter(obj => obj.isDone == false)
        }
    }
</script>

TodoFooter.vue

<!-- 7. target: Cleanup completed -->
<!-- 7.0 Click event -->
<button class="clear-completed" @click="clearFn">Cleanup completed</button>

<script>
	methods: {
        clearFn(){ // Empty completed tasks
          // 7.1 trigger app clearFun method corresponding to events in Vue
          this.$emit('clear')
        }
    }
</script>

7. Data cache

Purpose: after adding / modifying status / deleting, synchronize the data to the local storage of the browser immediately
Requirements: no matter what changes – ensure that the data is still after refresh
analysis:
①: App.vue - Listen list array change - depth
② : overwrite save locally – note that only JSON strings can be saved locally
③ : refresh the page – the list should take value locally by default – empty array without data should be considered

App.vue

<script>
    export default {
        data(){
            return {
                // 8.1 default value from local
                list: JSON.parse(localStorage.getItem('todoList')) || [],
                // 6.4 first transfer receiving type string
                getSel: "all" // Show all by default
            }
        },
        // 8. Target: data cache
        watch: {
            list: {
                deep: true,
                handler(){
                    // 8.0 as long as the list changes - overwrite save to localStorage
                    localStorage.setItem('todoList', JSON.stringify(this.list))
                }
            }
        }
    };
</script>

8. Select all function

Objective: click the v in the upper left corner to set one key to complete, and then click again to cancel the selection of all
Requirement 1: click Select all – the small selection box is affected
Requirement 2: select all the small boxes (manually) – select all and select automatically
analysis:
①: TodoHeader.vue – calculate attributes - isAll
②: App.vue – pass in the array list – affect the small checkbox in the set of isAll
③ : count the last status of the small selection box in the get of isAll, affect isAll – affect the status of all selection
④ : consider the empty array without data - select all and should not be checked
Tip: it is to traverse all objects and modify the value of their completion status attribute

TodoHeader.vue

<!-- 9. target: Select all status
9.0 v-model Associated select all status
 Page change(Tick true, Unchecked false) -> v-model -> isAll variable
-->
<input id="toggle-all" class="toggle-all" type="checkbox" v-model="isAll">
<script>
    export default {
        // ... Other omissions
        // 9.1 defining calculation attributes
        computed: {
            isAll: {
                set(checked){ // Only true / false
                    // 9.3 isDone attribute that affects the binding of each small checkbox in the array
                    this.arr.forEach(obj => obj.isDone = checked)
                },
                get(){
                    // 9.4 statistical status of small selection box - > select all box
                    // 9.5 if there is no data, directly return false - do not make all checked
                    return this.arr.length !== 0 && this.arr.every(obj => obj.isDone === true)
                }
            }
        },
    }
</script>

App.vue

<TodoHeader :arr="list" @create="createFn"></TodoHeader>

Download all codes -- Click here -- extraction code: 8888

Topics: Javascript Front-end Vue Vue.js