Vue基础(32)_TodoList案例

TodoList案例总结:

1.组件化编码流程:

(1)拆分静态组件 :组件要按照功能点拆分,命名不要与html元素 冲突。

(2)实现动态组件 :考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用?

一个组件在用 一些组件在用
放在组件自身即可。 放在他们共同的父组件上(状态提升)

(3)实现交互:从绑定事件开始。

2.props适用于:

父组件==>子组件 子组件==>父组件
父亲给子传递数据【通信】 子给父亲传递数据【通信】(要求父先给子一个函数)

3.使用v-model时要切记:

v-model 绑定的值不能是props传过来的值,因为props是不可以修改的

4.props传过来的如果是对象类型的值:

修改对象中的属性时Vue不会报错,但不推荐这样做。

示例:main.js

javascript 复制代码
// 引入Vue
import Vue from "vue";
// 引入App
import App from "./App.vue";
// 关闭生产提示
Vue.config.productionTip = false;

// 去除浏览器默认样式
import './assets/reset.css'

// 引入插件
// import plugins from "./plugins";

// 应用(使用)插件【多次调用同一插件时,只生效一次】
// Vue.use(plugins,1,2,3);

// 创建vm
new Vue({
    el: '#app',
    render: h => h(App)
})

App.vue

javascript 复制代码
<template>
  <div class="box">
    <div class="container">
      <HeadSection :AddListItem="AddListItem" />
      <ListSection
        :ListObj="ListObj"
        :UpdateCheckboxLi="UpdateCheckbox"
        :DeleteButtonLi="DeleteButton"
      />
      <FootSection
        :CountAllChecked="CountAllChecked"
        :CheckBoxTotal="CheckBoxTotal"
        :UpdateAllCheckbox="UpdateAllCheckbox"
      />
    </div>
  </div>
</template>

<script>
import FootSection from "./components/FootSection.vue";
import HeadSection from "./components/HeadSection.vue";
import ListSection from "./components/ListSection.vue";

export default {
  name: "App",
  data() {
    return {
      ListObj: [
        { id: "001", title: "打代码", completed: true },
        { id: "002", title: "睡觉", completed: false },
        { id: "003", title: "吃饭", completed: true },
      ],
    };
  },
  computed: {
    // 统计用户勾选列表的数量
    CountAllChecked() {
      return this.ListObj.reduce(
        (per, value) => per + (value.completed ? 1 : 0),
        0
      );
    },
    CheckBoxTotal() {
      return this.ListObj.length;
    },
  },
  methods: {
    // 用户输入字符时,添加一个列表项。
    AddListItem(e) {
      this.ListObj.unshift(e);
    },
    // 用户点击列表中某一列表项的复选框时,更新该列表项的checked值(布尔值)。
    UpdateCheckbox(x) {
      this.ListObj.forEach((item) => {
        if (item.id == x) {
          item.completed = !item.completed;
        }
      });
    },
    // 删除用户点击的某个列表项。
    DeleteButton(val) {
      if (confirm("确实要删除吗?")) {
        const index = this.ListObj.indexOf(val);
        this.ListObj.splice(index, 1);
      }
    },
    // 【全选/全不选】用户点击最底层的复选框时,更新所有列表项的checked值(布尔值)。
    UpdateAllCheckbox(value) {
        this.ListObj.forEach((item) => {
            item.completed = value;
        });
      }   
  },
  components: {
    ListSection,
    FootSection,
    HeadSection,
  },
};
</script>

<style scoped>
.box {
  width: 570px;
  border: 5px rgb(218, 215, 215) solid;
  margin: 20px;
  box-shadow: 1px 1px 10px rgb(218, 215, 215);
}

.container {
  width: 520px;
  min-height: 50px;
  border: 1px solid gray;
  border-radius: 10px 10px 10px 10px;
  padding: 2px;
  margin: 20px;
}
</style>

HeadSection.vue

javascript 复制代码
<template>
  <div>
    <input
      type="text"
      name="UserInformation"
      placeholder="请输入你的任务名称,按回车键确认..."
      @keyup.enter="ReceiveListItem"
    />
  </div>
</template>

<script>
import { nanoid } from "nanoid";
export default {
  name: "HeadSection",
  data() {
    return {};
  },
  methods: {
    ReceiveListItem(e) {
      // 校验数据。trim():去掉空格。清空内容。
      if (!e.target.value.trim()) {
        e.target.value = "";
        return alert("输入不能为空");
      }
      // 把输入的字符包装成一个列表项(对象)
      const NewListItem = {
        id: nanoid(),
        title: e.target.value,
        completed: false,
      };
      // 以函数调用的形式向父组件(App.vue)传递参数。
      this.AddListItem(NewListItem);
      // 清空输入的内容。
      e.target.value = "";
    },
  },
  props: ["AddListItem"],
};
</script>

<style scoped>
div {
  width: 500px;
  height: 30px;
  margin-left: 10px;
  margin-top: 10px;
}

input {
  width: 496px;
  height: 28px;
  border: 2px rgb(182, 221, 246) solid;
}
</style>

ListSection.vue

javascript 复制代码
<template>
  <ul>
    <UserItem
      v-for="ListItem in ListObj"
      :key="ListItem.id"
      :todo="ListItem"
      :UpdateCheckboxIt="UpdateCheckboxLi"
      :DeleteButtonIt="DeleteButtonLi"
    />
  </ul>
</template>

<script>
import UserItem from "./UserItem.vue";

export default {
  name: "ListSection",
  data() {
    return {};
  },
  props: ["ListObj", "UpdateCheckboxLi", "DeleteButtonLi"],
  components: {
    UserItem,
  },
};
</script>

<style>
</style>

UserItem.vue

javascript 复制代码
<template>
  <li>
    <span><input type="checkbox" :checked="todo.completed" @change="UpdateCheck(todo.id)"/>{{ todo.title }}</span>
    <input type="button" value="删除"  class="UsersDeleteButton" @click="DeleteButton(todo)"/>
  </li>
</template>

<script>
export default {
  name: "UserItem",
  props: ['todo',"UpdateCheckboxIt",'DeleteButtonIt'],
  methods:{
    UpdateCheck(a){
      this.UpdateCheckboxIt(a);
    },
    DeleteButton(t){
      this.DeleteButtonIt(t);
    }
  }
}
</script>

<style scoped>
li {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 500px;
  height: 30px;
  line-height: 30px;
  border: 1px rgb(170, 164, 164) solid;
  border-bottom: none;
  margin-left: 10px;
  font-size: 14px;
}

li:hover {
  background-color: rgb(231, 226, 226);
}

/* 列表第一行与输入框的边距 */
ul > li:first-child {
  margin-top: 20px;
}

/* 列表最后一行底边框添加样式 */
ul > li:last-child {
  border-bottom: 1px rgb(170, 164, 164) solid;
}

/* li子元素span,左对齐 */
li > span {
  justify-content: flex-start;
}

/* li子元素.UsersDeleteButton右对齐 */
li > .UsersDeleteButton {
  justify-content: flex-end;
  border-radius: 6px;
  box-shadow: 1px 1px 2px rgb(54, 41, 41);
}

/* 为li子元素 【删除按钮(.UsersDeleteButton)】 设置样式 */
.UsersDeleteButton {
  width: 50px;
  height: 26px;
  border: none;
  font-weight: bold;
  background-color:coral;
  opacity: 0.6;
  color: azure;
  margin-right: 20px;
  visibility: hidden;
}

li:hover .UsersDeleteButton {
  visibility: visible;
}

.UsersDeleteButton:hover {
  opacity: 1;
}
</style>

FootSection.vue

javascript 复制代码
<template>
  <div v-show="CheckBoxTotal">
    <span>
      <input type="checkbox" v-model="CheckedStatus" />已完成{{CountAllChecked}}/全部{{ CheckBoxTotal }}
    </span>
    <input type="button" value="清除已完成任务" class="DeleteTaskBut" />
  </div>
</template>

<script>
export default {
  computed: {
    CheckedStatus: {
      get() {
        return (
          this.CountAllChecked == this.CheckBoxTotal && this.CheckBoxTotal > 0
        );
      },
      set(value) {
        this.UpdateAllCheckbox(value);
      },
    },
  },
  props: ["CountAllChecked", "CheckBoxTotal", "UpdateAllCheckbox"],
};
</script>

<style scoped>
div {
  display: flex;
  justify-content: space-between;
  width: 500px;
  height: 30px;
  line-height: 30px;
  margin-top: 20px;
  margin-left: 10px;
  font-size: 14px;
}

/* 为【清除任务按钮】设置样式 */
.DeleteTaskBut {
  width: 110px;
  height: 26px;
  border: none;
  color: azure;
  background-color: coral;
  opacity: 0.9;
  border-radius: 6px;
  box-shadow: 1px 1px 2px rgb(54, 41, 41);
  visibility: hidden;
}

div:hover .DeleteTaskBut {
  visibility: visible;
}

.DeleteTaskBut:hover {
  opacity: 1;
}
</style>
相关推荐
青春喂了后端1 小时前
IntelliGit 前端订阅边界重构
前端·重构
lichenyang4531 小时前
HarmonyOS HMRouter 路由库 Demo 练习总结:从路由配置到商品管理增删改查
前端
李剑一1 小时前
520了,程序员就得有点儿独特的浪漫
前端·three.js
initialD大辉1 小时前
打破 3D 开发壁垒:一个低代码/零代码数字孪生平台的前后端全栈架构演进
前端·数据可视化
VOLUN1 小时前
🚀 Vue3 + Element Plus 实战:封装一个“可配置列 + 拖拽 + 固定 + 全屏”的 TableSetting 组件
前端
前端小蜗2 小时前
转生到 AI 时代,我不再相信一键生成代码的传说
前端·人工智能·架构
文心快码BaiduComate2 小时前
520,Comate Mission模式跨越界限,和你达成最「深」联动
前端·数据库·后端
来恩10032 小时前
Java Web三大作用域对象
java·开发语言·前端
在繁华处2 小时前
轻棋局(四):前端 SPA 实战
前端