上一個章節實現數據在組件之間的傳遞 。這一章主要是完成添加任務到任務欄、刪除任務欄、統計任務完成情況。主要還是參數在各個組件之間的傳遞。
上一章節的鏈接地址:

文章目錄

  • 1、實現的效果演示
  • 2、需求實現的大致流程
  • 3 、代碼(這裏只給出主要部分代碼、詳細代碼請看第一章節)
  • 3.1 App.vue(省略了樣式)
  • 3.2 TheList.vue (省略了樣式)
  • 3.3 TheItem.vue(樣式改進:刪除按鈕只有停留在對應行才會顯示出來)
  • 3.4 TheHeader.vue (省略了樣式)
  • 3.5 TheFooter.vue (省略了樣式)
  • 4、實現的效果

1、實現的效果演示

Vue組件實戰應用完成任務功能演示

2、需求實現的大致流程

  • 添加任務到任務欄:需要考慮TheHeader中的數據怎樣傳入到TheList組件中
  • 刪除一個任務:需要拿到待刪除的任務主鍵標識、然後在數組對象中刪除(遍歷的形式)
  • 勾選任務:根據對象中的勾狀態、取反
  • 初次加載勾選已完成任務:在checkbox中 根據任務的狀態展示完成情況(checked)
  • 統計任務完成情況:根據對象中的任務完成狀態 遍歷數組。累加計算

3 、代碼(這裏只給出主要部分代碼、詳細代碼請看第一章節)

3.1 App.vue(省略了樣式)

<template>
  <div id="root">
    <div class="todo-container">
      <div class="todo-wrap">
        <TheHeader :addTodo="addTodo" />
        <TheList
          :todos="todos"
          :checkTodo="checkTodo"
          :deleteTodo="deleteTodo"
        />
        <TheFooter
          :todos="todos"
          :checkAllTodo="checkAllTodo"
          :clearAllTodo="clearAllTodo"
        />
      </div>
    </div>
  </div>
</template>

<script>
import TheHeader from "./components/TheHeader";
import TheList from "./components/TheList";
import TheFooter from "./components/TheFooter.vue";

export default {
  name: "App",
  components: { TheHeader, TheList, TheFooter },
  data() {
    return {
      //由於todos是MyHeader組件和MyFooter組件都在使用,所以放在App中(狀態提升)
      todos: [
        { id: "001", title: "吃飯", done: true },
        { id: "002", title: "睡覺", done: false },
        { id: "003", title: "打豆豆", done: true },
      ],
    };
  },
  methods: {
    //添加一個todo
    addTodo(todoObj) {
      this.todos.unshift(todoObj);
    },
    //勾選or取消勾選一個todo
    checkTodo(id) {
      this.todos.forEach((todo) => {
        if (todo.id === id) todo.done = !todo.done;
      });
    },

    //刪除一個todo
    deleteTodo(id) {
      this.todos = this.todos.filter((todo) => todo.id !== id);
    },
    //全選or取消全選
    checkAllTodo(done) {
      this.todos.forEach((todo) => {
        todo.done = done;
      });
    },
    //清除所有已經完成的todo
    clearAllTodo() {
      this.todos = this.todos.filter((todo) => {
        return !todo.done;
      });
    },
  },
};
</script>

3.2 TheList.vue (省略了樣式)

<template>
  <ul class="todo-main">
    <TheItem
      v-for="todoObj in todos"
      :key="todoObj.id"
      :todo="todoObj"
      :checkTodo="checkTodo"
      :deleteTodo="deleteTodo"
    />
  </ul>
</template>

<script>
import TheItem from "./TheItem";

export default {
  name: "TheList",
  components: { TheItem },
  //聲明接收App傳遞過來的數據,其中todos是自己用的
  props: ["todos", "checkTodo",'deleteTodo'],
};
</script>

3.3 TheItem.vue(樣式改進:刪除按鈕只有停留在對應行才會顯示出來)

<template>
  <li>
    <label>
      <input
        type="checkbox"
        :checked="todo.done"
        @change="handleCheck(todo.id)"
      />
      <span>{{ todo.title }}</span>
    </label>
    <button class="btn btn-danger" @click="handleDelete(todo.id)">刪除</button>
  </li>
</template>

<script>
export default {
  name: "MyItem",
  //聲明接收todo、checkTodo、deleteTodo
  props: ["todo", "checkTodo",'deleteTodo'],

  methods: {
    //勾選or取消勾選
    handleCheck(id) {
      //通知App組件將對應的todo對象的done值取反
      this.checkTodo(id);
    },
    //刪除
    handleDelete(id) {
      if (confirm("確定刪除嗎?")) {
        //通知App組件將對應的todo對象刪除
        this.deleteTodo(id);
      }
    },
  },
};
</script>
<style scoped>
	/*item*/
	li {
		list-style: none;
		height: 36px;
		line-height: 36px;
		padding: 0 5px;
		border-bottom: 1px solid #ddd;
	}

	li label {
		float: left;
		cursor: pointer;
	}

	li label li input {
		vertical-align: middle;
		margin-right: 6px;
		position: relative;
		top: -1px;
	}

	li button {
		float: right;
		display: none;
		margin-top: 3px;
	}

	li:before {
		content: initial;
	}

	li:last-child {
		border-bottom: none;
	}

	li:hover{
		background-color: #ddd;
	}
	
	li:hover button{
		display: block;
	}
</style>

3.4 TheHeader.vue (省略了樣式)

<template>
  <div class="todo-header">
    <input
      type="text"
      placeholder="請輸入你的任務名稱,按回車鍵確認"
      v-model="title"
      @keyup.enter="add"
    />
  </div>
</template>

<script>
import { nanoid } from "nanoid";
export default {
  name: "TheHeader",
	//接收從App傳遞過來的addTodo
		props:['addTodo'],
  data() {
    return {
      //收集用户輸入的title
      title: "",
    };
  },
  methods: {
    add() {
      //校驗數據
      if (!this.title.trim()) return alert("輸入不能為空");
      //將用户的輸入包裝成一個todo對象
      const todoObj = { id: nanoid(), title: this.title, done: false };
      //通知App組件去添加一個todo對象
      this.addTodo(todoObj);
      //清空輸入
      this.title = "";
    },
  },
};
</script>

3.5 TheFooter.vue (省略了樣式)

<template>
	<div class="todo-footer" v-show="total">
		<label>
			<!-- <input type="checkbox" :checked="isAll" @change="checkAll"/> -->
			<input type="checkbox" v-model="isAll"/>
		</label>
		<span>
			<span>已完成{{doneTotal}}</span> / 全部{{total}}
		</span>
		<button class="btn btn-danger" @click="clearAll">清除已完成任務</button>
	</div>
</template>

<script>
	export default {
		name:'TheFooter',
		props:['todos','checkAllTodo','clearAllTodo'],
		computed: {
			//總數
			total(){
				return this.todos.length
			},
			//已完成數
			doneTotal(){
				//此處使用reduce方法做條件統計
				/* const x = this.todos.reduce((pre,current)=>{
					console.log('@',pre,current)
					return pre + (current.done ? 1 : 0)
				},0) */
				//簡寫
				return this.todos.reduce((pre,todo)=> pre + (todo.done ? 1 : 0) ,0)
			},
			//控制全選框
			isAll:{
				//全選框是否勾選
				get(){
					return this.doneTotal === this.total && this.total > 0
				},
				//isAll被修改時set被調用
				set(value){
					this.checkAllTodo(value)
				}
			}
		},
		methods: {
			/* checkAll(e){
				this.checkAllTodo(e.target.checked)
			} */
			//清空所有已完成
			clearAll(){
				this.clearAllTodo()
			}
		},
	}
</script>

4、實現的效果

vue和elementUI搭建小項目 實現增刪改查_任務欄


整理不易、歡迎白嫖黨一鍵三連 !!! 哈哈哈哈哈哈哈哈哈。曾經我也是白嫖黨