Vue todos to do list function

Keywords: html5 Vue Vue.js css

Today's notes are todos to-do items   

I believe you can't wait to realize some functions after learning the Vue foundation, so I'll use Vue basic grammar and some js knowledge to combine them

Maybe the notes are not very good   I won't share the source code. If you want to see the source code, you'd better read it yourself and type it out

Create your own sub components and style css under the directory

todos - create projects and components

The contents are as follows

 

 

  The content of base.css is as follows

hr {
	margin: 20px 0;
	border: 0;
	border-top: 1px dashed #c5c5c5;
	border-bottom: 1px dashed #f7f7f7;
}

.learn a {
	font-weight: normal;
	text-decoration: none;
	color: #b83f45;
}

.learn a:hover {
	text-decoration: underline;
	color: #787e7e;
}

.learn h3,
.learn h4,
.learn h5 {
	margin: 10px 0;
	font-weight: 500;
	line-height: 1.2;
	color: #000;
}

.learn h3 {
	font-size: 24px;
}

.learn h4 {
	font-size: 18px;
}

.learn h5 {
	margin-bottom: 0;
	font-size: 14px;
}

.learn ul {
	padding: 0;
	margin: 0 0 30px 25px;
}

.learn li {
	line-height: 20px;
}

.learn p {
	font-size: 15px;
	font-weight: 300;
	line-height: 1.3;
	margin-top: 0;
	margin-bottom: 0;
}

#issue-count {
	display: none;
}

.quote {
	border: none;
	margin: 20px 0 60px 0;
}

.quote p {
	font-style: italic;
}

.quote p:before {
	content: '"';
	font-size: 50px;
	opacity: .15;
	position: absolute;
	top: -20px;
	left: 3px;
}

.quote p:after {
	content: '"';
	font-size: 50px;
	opacity: .15;
	position: absolute;
	bottom: -42px;
	right: 3px;
}

.quote footer {
	position: absolute;
	bottom: -40px;
	right: 0;
}

.quote footer img {
	border-radius: 3px;
}

.quote footer a {
	margin-left: 5px;
	vertical-align: middle;
}

.speech-bubble {
	position: relative;
	padding: 10px;
	background: rgba(0, 0, 0, .04);
	border-radius: 5px;
}

.speech-bubble:after {
	content: '';
	position: absolute;
	top: 100%;
	right: 30px;
	border: 13px solid transparent;
	border-top-color: rgba(0, 0, 0, .04);
}

.learn-bar > .learn {
	position: absolute;
	width: 272px;
	top: 8px;
	left: -300px;
	padding: 10px;
	border-radius: 5px;
	background-color: rgba(255, 255, 255, .6);
	transition-property: left;
	transition-duration: 500ms;
}

@media (min-width: 899px) {
	.learn-bar {
		width: auto;
		padding-left: 300px;
	}

	.learn-bar > .learn {
		left: 8px;
	}
}

The index.css style is as follows

html,
body {
	margin: 0;
	padding: 0;
}

button {
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
	font-size: 100%;
	vertical-align: baseline;
	font-family: inherit;
	font-weight: inherit;
	color: inherit;
	-webkit-appearance: none;
	appearance: none;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

body {
	font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
	line-height: 1.4em;
	background: #f5f5f5;
	color: #111111;
	min-width: 230px;
	max-width: 550px;
	margin: 0 auto;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	font-weight: 300;
}

:focus {
	outline: 0;
}

.hidden {
	display: none;
}

.todoapp {
	background: #fff;
	margin: 130px 0 40px 0;
	position: relative;
	box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
	            0 25px 50px 0 rgba(0, 0, 0, 0.1);
}

.todoapp input::-webkit-input-placeholder {
	font-style: italic;
	font-weight: 300;
	color: rgba(0, 0, 0, 0.4);
}

.todoapp input::-moz-placeholder {
	font-style: italic;
	font-weight: 300;
	color: rgba(0, 0, 0, 0.4);
}

.todoapp input::input-placeholder {
	font-style: italic;
	font-weight: 300;
	color: rgba(0, 0, 0, 0.4);
}

.todoapp h1 {
	position: absolute;
	top: -140px;
	width: 100%;
	font-size: 80px;
	font-weight: 200;
	text-align: center;
	color: #b83f45;
	-webkit-text-rendering: optimizeLegibility;
	-moz-text-rendering: optimizeLegibility;
	text-rendering: optimizeLegibility;
}

.new-todo,
.edit {
	position: relative;
	margin: 0;
	width: 100%;
	font-size: 24px;
	font-family: inherit;
	font-weight: inherit;
	line-height: 1.4em;
	color: inherit;
	padding: 6px;
	border: 1px solid #999;
	box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
	box-sizing: border-box;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

.new-todo {
	padding: 16px 16px 16px 60px;
	border: none;
	background: rgba(0, 0, 0, 0.003);
	box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
}

.main {
	position: relative;
	z-index: 2;
	border-top: 1px solid #e6e6e6;
}

.toggle-all {
	width: 1px;
	height: 1px;
	border: none; /* Mobile Safari */
	opacity: 0;
	position: absolute;
	right: 100%;
	bottom: 100%;
}

.toggle-all + label {
	width: 60px;
	height: 34px;
	font-size: 0;
	position: absolute;
	top: 12px;
	left: -13px;
	-webkit-transform: rotate(90deg);
	transform: rotate(90deg);
	z-index: 9999
}

.toggle-all + label:before {
	content: '❯';
	font-size: 22px;
	color: #e6e6e6;
	padding: 10px 27px 10px 27px;
}

.toggle-all:checked + label:before {
	color: #737373;
}

.todo-list {
	margin: 0;
	padding: 0;
	list-style: none;
}

.todo-list li {
	position: relative;
	font-size: 24px;
	border-bottom: 1px solid #ededed;
}

.todo-list li:last-child {
	border-bottom: none;
}

.todo-list li.editing {
	border-bottom: none;
	padding: 0;
}

.todo-list li.editing .edit {
	display: block;
	width: calc(100% - 43px);
	padding: 12px 16px;
	margin: 0 0 0 43px;
}

.todo-list li.editing .view {
	display: none;
}

.todo-list li .toggle {
	text-align: center;
	width: 40px;
	/* auto, since non-WebKit browsers doesn't support input styling */
	height: auto;
	position: absolute;
	top: 0;
	bottom: 0;
	margin: auto 0;
	border: none; /* Mobile Safari */
	-webkit-appearance: none;
	appearance: none;
}

.todo-list li .toggle {
	opacity: 0;
}

.todo-list li .toggle + label {
	/*
		Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433
		IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/
	*/
	background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E');
	background-repeat: no-repeat;
	background-position: center left;
}

.todo-list li .toggle:checked + label {
	background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E');
}

.todo-list li label {
	word-break: break-all;
	padding: 15px 15px 15px 60px;
	display: block;
	line-height: 1.2;
	transition: color 0.4s;
	font-weight: 400;
	color: #4d4d4d;
}

.todo-list li.completed label {
	color: #cdcdcd;
	text-decoration: line-through;
}

.todo-list li .destroy {
	display: none;
	position: absolute;
	top: 0;
	right: 10px;
	bottom: 0;
	width: 40px;
	height: 40px;
	margin: auto 0;
	font-size: 30px;
	color: #cc9a9a;
	margin-bottom: 11px;
	transition: color 0.2s ease-out;
}

.todo-list li .destroy:hover {
	color: #af5b5e;
}

.todo-list li .destroy:after {
	content: '×';
}

.todo-list li:hover .destroy {
	display: block;
}

.todo-list li .edit {
	display: none;
}

.todo-list li.editing:last-child {
	margin-bottom: -1px;
}

.footer {
	padding: 10px 15px;
	height: 20px;
	text-align: center;
	font-size: 15px;
	border-top: 1px solid #e6e6e6;
}

.footer:before {
	content: '';
	position: absolute;
	right: 0;
	bottom: 0;
	left: 0;
	height: 50px;
	overflow: hidden;
	box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
	            0 8px 0 -3px #f6f6f6,
	            0 9px 1px -3px rgba(0, 0, 0, 0.2),
	            0 16px 0 -6px #f6f6f6,
	            0 17px 2px -6px rgba(0, 0, 0, 0.2);
}

.todo-count {
	float: left;
	text-align: left;
}

.todo-count strong {
	font-weight: 300;
}

.filters {
	margin: 0;
	padding: 0;
	list-style: none;
	position: absolute;
	right: 0;
	left: 0;
}

.filters li {
	display: inline;
}

.filters li a {
	color: inherit;
	margin: 3px;
	padding: 3px 7px;
	text-decoration: none;
	border: 1px solid transparent;
	border-radius: 3px;
}

.filters li a:hover {
	border-color: rgba(175, 47, 47, 0.1);
}

.filters li a.selected {
	border-color: rgba(175, 47, 47, 0.2);
}

.clear-completed,
html .clear-completed:active {
	float: right;
	position: relative;
	line-height: 20px;
	text-decoration: none;
	cursor: pointer;
}

.clear-completed:hover {
	text-decoration: underline;
}

.info {
	margin: 65px auto 0;
	color: #4d4d4d;
	font-size: 11px;
	text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
	text-align: center;
}

.info p {
	line-height: 1;
}

.info a {
	color: inherit;
	text-decoration: none;
	font-weight: 400;
}

.info a:hover {
	text-decoration: underline;
}

/*
	Hack to remove background from Mobile Safari.
	Can't use it globally since it destroys checkboxes in Firefox
*/
@media screen and (-webkit-min-device-pixel-ratio:0) {
	.toggle-all,
	.todo-list li .toggle {
		background: none;
	}

	.todo-list li .toggle {
		height: 40px;
	}
}

@media (max-width: 430px) {
	.footer {
		height: 50px;
	}

	.filters {
		bottom: 10px;
	}
}

Self copy, paste and put

Then we introduce these two CSS style sheets into App.vue

import "./styles/base.css"
import "./styles/index.css"

TodoHeader.vue   TodoMain.vue TodoFooter.vue three sub components will   Distinguish the whole App.vue

  components/TodoHeader.vue - copy labels and class names
 

<template>
  <header class="header">
    <h1>todos</h1>
    <input id="toggle-all" class="toggle-all" type="checkbox" >
    <label for="toggle-all"></label>
    <input
      class="new-todo"
      placeholder="Enter task name-Enter to confirm"
      autofocus
    />
  </header>
</template>

<script>
export default {
 
}
</script>

components/TodoMain.vue - copy labels and class names

<template>
  <ul class="todo-list">
    <!-- completed: Completed class name -->
    <li class="completed" >
      <div class="view">
        <input class="toggle" type="checkbox" />
        <label>Task name</label>
        <button class="destroy"></button>
      </div>
    </li>
  </ul>
  
</template>

<script>
export default {
}
</script>

components/TodoFooter.vue - copy labels and class names

<template>
  <footer class="footer">
    <span class="todo-count">surplus<strong>Quantity value</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 {

}
</script>

Introduced and used in App.vue

<template>
  <section class="todoapp">
    <!-- Except for the hump, You can also use-Conversion link -->
    <TodoHeader></TodoHeader>
    <TodoMain></TodoMain>
    <TodoFooter></TodoFooter>
  </section>
</template>

<script>
// 1.0 Style Introduction
import "./styles/base.css"
import "./styles/index.css"
    
import TodoHeader from "./components/TodoHeader";
import TodoMain from "./components/TodoMain";
import TodoFooter from "./components/TodoFooter";


export default {
  components: {
    TodoHeader,
    TodoMain,
    TodoFooter,
  },
};
</script>

  1. Component creation

  2. Component introduction

  3. Component registration

  4. Component use

  It must be unrealistic for us to complete such a large project at one time  

So I divided them into functions and implemented them one by one. First, I prepared some data to be laid in Todomain and App.vue

todos - laying to-do tasks

  • Requirement 1: display the to-do tasks on the TodoMain.vue component of the page

  • Requirement 2: Associate selected status and set related styles

① : App.vue – prepare the array to be passed into TodoMain.vue

② : v-for loop display data

③ The: v-model binding check box is selected

④ : sets the finish dash style according to the selected status

Put this data into App data  

 <TodoMain :arr="showArr"></TodoMain>
      list: [
        { id: 100, name: "having dinner", isDone: true },
        { id: 201, name: "sleep", isDone: false },
        { id: 103, name: "Beat beans", isDone: true },
      ]

TodoMain.vue

1. Circulating laying obj in arr

2. When the radio box is in the trigger point, let the value be true

3. Dynamic class judges whether there is a completed class name through isDone

4. Give the button a click event, and then write the trigger function

<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 @click="delFn(index)" class="destroy"></button>
      </div>
    </li>
  </ul>
</template>

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

<style>
</style>

  This paragraph relates to

  1. Parent to child Technology

  2. v-for loop

  3. v-model binding

  4. Dynamic class usage

The data laying is finished. Next, try to add tasks

todos - add task

Demand: enter a task and press enter to add a to-do task

Objective: enter the task name to be completed in the top input box, and click enter to complete the new function

analysis:

① : TodoHeader.vue – input box – keyboard event – enter key

② : pass the child to the parent, and add the to-do task - App.vue - 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

1. Listen to the event of clicking enter

2. Bidirectional binding task

3. Judge that the task is not empty and clear the space before and after it

4. Clear the input box after passing the value to the parent App

<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

1. Receive the create trigger function

2. Judge whether the list is empty. If it is empty, the newly added list will start from 100. If it is not empty, judge to start recording from the last id+1

3. Add the received value to the new object and store it in the list

<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
      })
    },
}

todos delete task

The laying data and new data are all completed. The next task is to delete

Implement point x and delete task function

① Distinguished x tag – click event – incoming id

② : pass the child to the parent, return the id to – App.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)
    }
}

What technical points are involved?

  1. Click the event and send it to the index

  2. Son to father

  3. Array delete an element, v-for update

todos bottom statistics

Count the number of current tasks

① : in 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 - receive list statistics and display directly

<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>
  1. Father to son

  2. Calculation properties

  3. Array update – affected everywhere

todos data switching

target

Click the bottom to switch data

explain

  • 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 values are 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 transfer the type isSel to App.vue

⑤ : define the calculation attribute showArr to determine which data to display in the list to TodoMain.vue and TodoFooter.vue

App.vue

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

<script>
    export default{
       data(){
            return {
              // ... other omitted
              getSel: "all" // Show all by default
            }
        },
        methods: {
            // ... other omitted
            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 passed to App.vue 
      this.$emit("changeType", this.isSel)
    }
  }
}
</script>

What technical points are involved?

  1. Dynamic class – cooperation judgment

  2. Son to father Technology

  3. Calculation attribute + array filtering method

todos emptying completed

Click the button in the lower right corner - clear the completed tasks

explain

  • 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 - first pass in a custom event - because you have to receive the click event in TodoFooter.vue

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

<script>
    methods: {
        // ... omit other
        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 clearFun method corresponding to event in App.vue
          this.$emit('clear')
        }
    }
</script>
  1. Son to father Technology

  2. Array filtering method

todos data cache

We don't have a server for the time being. We can't store these data   In this case, the data disappears as soon as it is refreshed

Here we store the data into the browser cache   As long as the browser cache data is not cleared, it will always exist

Similar token values can be stored in this way

After adding / modifying status / deleting, synchronize the data to the local storage of the browser immediately

explain

  • Requirements: no matter what changes – ensure that the data is still after refresh

analysis:

① : App.vue - listening 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>
  1. Deep listening

  2. Data cache

  3. serialization and deserialization

Then it's the last point  

Select all function

todos select all function

Click the v sign in the upper left corner to set one key to complete, and then click again to cancel the selection of all

explain

  • 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 properties - 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 omitted
        // 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>

What technical points are involved?

  1. Calculation attribute complete writing method

  2. The every method returns true if it does not traverse

Then the rendering is completed, and there is no waste of traffic at the front

I will write a separate article and put the full version of the code. Let's study it by ourselves

So tired

Posted by nscipione on Sun, 26 Sep 2021 23:40:44 -0700