(二十八)Vue之组件化编码流程

news2024/11/18 11:20:48

文章目录

  • 组件化编码流程
    • 拆分静态组件
    • 实现动态组件
    • 实现交互
      • 实现添加
      • 实现勾选
      • 实现删除
      • 实现全选与全不选
      • 实现清除已完成任务
  • TodoList案例小细节

Vue学习目录

上一篇:(二十七)Vue组件的样式

先看一个需求:TodoList案例
功能:添加任务;任务项可以勾选,表示已完成任务;鼠标移动到任务项高亮并显示删除按键,点击删除按键可以进行删除单个任务项;左下角展示已完成和全部的任务项数,有一个勾选框,勾选可以让任务项全部勾选上,有一个清除已完成任务的按钮,点击可以清除勾选的任务项。
在这里插入图片描述
请添加图片描述
下面我们就来完成这个功能

组件化编码流程

  • (1)拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。
  • (2)实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:
    • 1.一个组件在用:放在组件自身即可。
    • 2.一些组件在用:放在他们共同的父组件上(状态提升)。
  • (3).实现交互:从绑定事件开始。

拆分静态组件

一般拆分组件会按功能进行拆分
需求的拆分为:App、Top、List、Item、Footer组件
请添加图片描述
先实现静态页面
App组件:

<template>
  <div id="root">
    <div class="todo-container">
      <div class="todo-wrap">
        <Top/>
        <List/>
        <Footer/>
      </div>
    </div>
  </div>
</template>
<script>
import Top from "@/components/Top";
import List from "@/components/List";
import Footer from "@/components/Footer";
export default {
  name: "App",
  components:{
    Footer,
    List,
    Top,
  }
  
}
</script>
<style>
body {
  background: #fff;
}
.btn {
  display: inline-block;
  padding: 4px 12px;
  margin-bottom: 0;
  font-size: 14px;
  line-height: 20px;
  text-align: center;
  vertical-align: middle;
  cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
  border-radius: 4px;
}

.btn-danger {
  color: #fff;
  background-color: #da4f49;
  border: 1px solid #bd362f;
}

.btn-danger:hover {
  color: #fff;
  background-color: #bd362f;
}

.btn:focus {
  outline: none;
}

.todo-container {
  width: 600px;
  margin: 0 auto;
}
.todo-container .todo-wrap {
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 5px;
}
</style>

Top组件:

<template>
  <div class="todo-header">
      <input type="text" placeholder="请输入你的任务名称,按回车键确认"/>
  </div>
</template>

<script>
import {nanoid} from "nanoid";

export default {
  name: "Top",
}
</script>

<style scoped>
.todo-header input {
  width: 560px;
  height: 28px;
  font-size: 14px;
  border: 1px solid #ccc;
  border-radius: 4px;
  padding: 4px 7px;
}

.todo-header input:focus {
  outline: none;
  border-color: rgba(82, 168, 236, 0.8);
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
}

/*main*/
.todo-main {
  margin-left: 0px;
  border: 1px solid #ddd;
  border-radius: 2px;
  padding: 0px;
}

.todo-empty {
  height: 40px;
  line-height: 40px;
  border: 1px solid #ddd;
  border-radius: 2px;
  padding-left: 5px;
  margin-top: 10px;
}
</style>

List组件:

<template>
  <ul class="todo-main">
    <Item/>
    <Item/>
    <Item/>
  </ul>
</template>

<script>
import Item from "@/components/Item";
export default {
  name: "List",
  components: {Item},
}
</script>

<style scoped>

</style>

Item组件:

<template>
  <li>
    <label>
      <input type="checkbox"/>
      <span>xxxxx</span>
    </label>
    <button class="btn btn-danger">删除</button>
  </li>
</template>

<script>
export default {
  name: "Item",
}
</script>

<style scoped>
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: cyan;
}
li:hover button{
  display: block;
}
</style>

Footer组件:

<template>
  <div class="todo-footer">
    <label>
      <input type="checkbox"/>
    </label>
    <span>
      <span>已完成</span> / 全部
</button>-->
  </div>
</template>

<script>
export default {
  name: "Footer",
}
</script>

<style scoped>
.todo-footer {
  height: 40px;
  line-height: 40px;
  padding-left: 6px;
  margin-top: 5px;
}

.todo-footer label {
  display: inline-block;
  margin-right: 20px;
  cursor: pointer;
}

.todo-footer label input {
  position: relative;
  top: -1px;
  vertical-align: middle;
  margin-right: 5px;
}

.todo-footer button {
  float: right;
  margin-top: 5px;
}

</style>

效果:
在这里插入图片描述

实现动态组件

我们需要先创建数据,由于所有组件都在使用,所以放在共同的父组件App身上

  • id:任务项的唯一标识
  • title:任务项的名字
  • done:任务项是否完成
data(){
    return{
      todos:[
        {id:'001',title:'吃饭',done:true},
        {id:'002',title:'睡觉',done:false},
        {id:'003',title:'玩游戏',done:true}
      ]
    }
  },

数据创建好之后需要传给List组件做展示,而List组件通过v-for对数据进行遍历,并把数据传到Item组件进行展示,Footer组件里展示已完成和全部的任务项也需要数据,所以也需要App传过去
App组件:
传递数据

<Top/>
<List :todos="todos"/>
<Footer :todos="todos"/>

List组件:
接收数据

props:['todos']

遍历数据并给Item传递数据

<Item v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj"/>

Item组件:
接收数据

props:['todo']

展示数据

	<input type="checkbox" :checked="todo.done"/>
    <span>{{todo.title}}</span>
<!--      <span>xxxxx</span>-->

Footer组件:
接收数据

props:['todos']

展示数据,因为全部任务项逻辑比较简单,所以使用插值表达式是可以的,但是对已完成的任务项展示,需要遍历数据读取done属性,所以需要写成计算属性

<span>已完成{{doneTodo}}</span> / 全部{{todos.length}}

doneTodo计算属性,这里有两种写法

  • 1.创建计数i,对数据进行遍历、操作,最后返回计数
  • 2.调用数组的reduce方法,这个方法两个参数
    • 第一个是函数,这个函数会受到的参数

      • 第一个total:必需。初始值, 或者计算结束后的返回值。
      • 第二个currentValue:必需。数组的当前元素
      • 第三个currentIndex:可选。当前元素的索引
      • 第四个arr:可选。当前元素所属的数组对象。
    • 第二个参数initialValue:可选。传递给函数的初始值

computed:{
    doneTodo() {
      /*let i=0
      this.todos.forEach((todo)=>{
        if (todo.done) i++
      })
      return i;*/
      return this.todos.reduce((pre, todo) => {
        return pre + (todo.done ? 1 : 0)
      }, 0)
    }
  }

效果:
在这里插入图片描述

实现交互

实现添加

因为需要收取到用户传递的数据,可以给文本框双向绑定一个空数据title,也可以在绑定键盘事件,在事件回调通过event接收数据,当然我们是在使用Vue,所以尽量避免操作DOM
Top组件:
空数据

data(){
    return{
      title: ''
    }
  }

绑定数据和键盘事件

<input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="title" @keyup.enter="add"/>

将用户的输入包装成一个todo对象 ,这里要生产id,可以使用uuid的变种,nanoid,安装命令 npm i nanoid
这个todo对象需要添加到App里的todos数组里,所以需要App进行配合,首先app要创建一个回调函数,这个函数里往todos数组添加Top里包装成的对象,如何把这个回调函数通过props传给Top进行调用即可
App组件:
声明回调

methods:{
    //添加一个todo
    addTodo(todoObj){
      //console.log('App组件',todoObj)
      this.todos.unshift(todoObj)
    }
}

传递回调

<Top :addTodo="addTodo"/>

Top组件:
接收回调

props:['addTodo']

在键盘事件里调用回调

methods:{
    add(){
      if (!this.title.trim()) return alert("输入不能为空")
      const todoObj = {id:nanoid(),title:this.title,done:false}
      this.addTodo(todoObj)
      this.title=''
    }
  }

效果:成功添加
在这里插入图片描述

实现勾选

我们当前勾选任务项时,是不会改变数据的done属性值的,并且下方已完成任务项也不会变
在这里插入图片描述
实现任务项的勾选可以绑定两种事件,一种是click点击事件,另一种是change改变事件
同样需要在App声明一个回调函数,给Item组件调用
由于我们还没有学全局事件总线、消息订阅与发布等等,我们只能把这个回调函数传给List组件,通过List组件再传给Item组件
App组件:
声明回调

	//修改done值(勾选与取消勾选)
    checkTodo(id){
      this.todos.forEach((todo)=>{
        if (todo.id === id) todo.done = !todo.done
      })
    }

传递回调

<List :todos="todos" :checkTodo="checkTodo"/>

List组件:
接收回调

props:['todos','checkTodo']

传递回调

<Item v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj" :checkTodo="checkTodo"/>

Item组件:
接收回调

props:['todo','checkTodo']

定义事件

	<!-<input type="checkbox" :checked="todo.done" @click="handleCheck(todo.id)"/>-->
    <input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)"/>

定义事件回调

methods: {
    handleCheck(id) {
      //通知App组件将对应的todo对象的done取反
      this.checkTodo(id)
    },
  }

效果:请添加图片描述
请添加图片描述

实现删除

于勾选相同
App组件:
声明回调

	//删除一个todo
    deleteTodo(id){
      this.todos = this.todos.filter((todo)=>{
        return todo.id !== id
      })
    },

传递回调

<List :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"/>

List组件:
接收回调

props:['todos','checkTodo','deleteTodo']

传递回调

<Item v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj" :checkTodo="checkTodo" :deleteTodo="deleteTodo"/>

Item组件:
接收回调

props:['todo','checkTodo','deleteTodo']

定义事件

<button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>

定义事件回调

handleDelete(id){
      if (confirm('确定删除吗?')) {
        //通知App组件将对应的todo对象
        this.deleteTodo(id)
      }
    }

效果:
请添加图片描述
请添加图片描述

实现全选与全不选

可以借助已完成和全部做文章,这时需要把全部任务项显示那里改为计算属性形式

      <span>已完成{{doneTodo}}</span> / 全部{{total}}
    isAll(){
      return this.doneTodo === this.total && this.total > 0
    }

实现有两种方式:

  • 一种是与前面一样
    App组件:
    声明回调
    //全选or取消全选
    checkAllTodo(done){
      this.todos.forEach((todo)=>{
        todo.done = done
      })
    }

传递回调

<Footer :todos="todos" :checkAllTodo="checkAllTodo"/>

Footer组件:
接收回调

props:['todos','checkAllTodo']

定义事件

<input type="checkbox" :checked="isAll" @change="checkAll"/>

定义事件回调

  methods: {
    checkAll(e){
    //通知App组件全选or取消全选操作
    this.checkAllTodo(e.target.checked)
    }
  }
  • 另一种是把给勾选框双向绑定计算属性isAll,这时要求isAll只能完整写法
<input type="checkbox" v-model="isAll"/>

isAll完整写法:当然也要借助App里的回调

isAll:{
      get(){
        return this.doneTodo === this.total && this.total > 0
      },
      set(value){
        this.checkAllTodo(value)
      }
    }

效果:
请添加图片描述
请添加图片描述

实现清除已完成任务

与前面一样,借助App的回调
App组件:
声明回调

	//清除所有以完成的todo
    clearAllTodo(){
      this.todos = this.todos.filter((todo) =>{
        return !todo.done
      })
    }

传递回调

<Footer :todos="todos" :checkAllTodo="checkAllTodo" :clearAllTodo="clearAllTodo"/>

Footer组件:
接收回调

props: ['todos', 'checkAllTodo','clearAllTodo']

绑定事件

<button class="btn btn-danger" @click="clearAll">清除已完成任务</button>

定义事件回调

clearAll(){
      this.clearAllTodo()
    }

效果:
在这里插入图片描述

TodoList案例小细节

  • props适用于:

    ​ (1).父组件 ==> 子组件 通信

    ​ (2).子组件 ==> 父组件 通信(要求父先给子一个函数)

  • 使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props是不可以修改的!
    在Item勾选事件我们可以进行v-model绑定

<input type="checkbox" v-model="todo.done"/>

虽然功能也能实现,当是因为官方规定props是不可以修改的,props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。
并且IDEA会进行报错,(“todo”属性的意外突变。)虽然这个报错不会影响程序运行
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/129799.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

c# http请求使用multipart/form-data 方式上传文件及其他参数

这次的需求是请求java那边的一个excel批量上传的接口。但是他们的接口要求是这样的 于是自己写了个方法&#xff1a; 调用&#xff1a; 控制器层 var file this.HttpContext.Request.Files[0];//获取前端传来的文件 var fileName file.FileName; //注意&…

控制RK3568的GPIO

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、设备树中是如何描述引脚的&#xff1f;1.pinctrl子系统2.gpio子系统二、使用步骤总结前言 RK3568的引脚资源还是相当多的&#xff0c;一共有5组GPIO&#x…

数图互通高校房产管理——房屋修缮管理

数图互通房产管理系统在这方面做得比较全面&#xff1b; 实现房屋修缮改造、装修维护、零星维修线上管理&#xff0c;建立机制规范管理&#xff0c;避免私自改扩建。 建筑物立项审批全流程资料和过程管理&#xff0c;建筑物修建施工、维修审批流程管理。整套系统包含了建筑物从…

链下签名实现

什么是签名 比如我们在使用 opensea 的时候&#xff0c;经常会提示我们进行数字签名&#xff0c;如下图&#xff1a; 用户进行 sign 确认&#xff0c;即用自己的私钥对一段数据进行签名&#xff0c;得到一个 signature&#xff0c;其他人可以使用你私钥对应的公钥&#xff0c…

推荐5款Windows桌面效率工具

今天我想分享一些自己比较喜欢的桌面端软件&#xff0c;还请大家包涵指正。如果你曾搜索过 Windows 效率工具推荐&#xff0c;对下文的软件或许有所了解。不过为了凑字数&#xff0c;我还是会再介绍一遍。 1.文件定位——Listary Listary 是我使用频率最高的软件之一&#xf…

Java重点源码回顾——HashMap1.8

1. 概述 在之前的文章中&#xff0c;我们介绍了HashMap1.7的源码&#xff0c;今天我们来看下HashMap1.8的源码。HashMap1.8相比于1.7最大的改变就是改变了1.7中采用数组链表的方式存储键值对&#xff0c;转而由数组链表红黑树的方式来存储键值对。HashMap1.8的底层结构如下图所…

RPC 好,还是 RESTful 好

OSI网络七层模型 RPC服务 RPC架构 同步调用与异步调用 流行的RPC框架 HTTP服务 总之 RPC主要是基于TCP/IP协议的&#xff0c;而HTTP服务主要是基于HTTP协议的&#xff0c;我们都知道HTTP协议是在传输层协议TCP之上的&#xff0c;所以效率来看的话&#xff0c;RPC当然是要更…

【python】py课后作业程序题5「PTA」

py字典合集7-1 Python猜数游戏7-2 jmu-python-分段函数7-3 循环求e的近似值&#xff08;高教社&#xff0c;《Python编程基础及应用》习题6-7&#xff09;7-4 jmu-python-判断是否构成三角形7-5 jmu-python-输入输出-计算字符串中的数7-6 jmu-python-随机生成密码7-7 jmu-pytho…

vscode使用CMake Tool插件构建第一个CMake的helloworld工程

vscode使用CMake Tool插件构建第一个CMake的helloworld工程一、linux环境准备1.1 CMake安装1.2 gcc/g的安装二、vscode 插件安装2.1 C扩展2.2 CMake Tool三、使用CMake构建第一个工程3.1 创建工程目录3.2 使用CMake Tool创建第一个Project3.3 Configure 第一个project四、构建工…

Java中序列化接口Serializable的serialVersionUID的作用

原文网址&#xff1a;Java中序列化接口Serializable的serialVersionUID的作用_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Java中序列化接口Serializable的serialVersionUID的作用。 序列化与反序列化 含义 序列化&#xff1a;将java对象转化为字节序列。反序列化&#xff1a…

【mysql】索引的基本使用

文章目录1. 索引的声明与使用1.1 索引的分类1.2 创建索引1.2.1 创建表的时候创建索引&#xff08;隐式&#xff09;1.2.2 在已经存在的表上创建索引&#xff08;显式&#xff09;1、创建普通索引2、创建唯一索引3、主键索引4、创建单列索引5、创建联合索引6、创建全文索引7、创…

33、基于STM32的计时器(Proteus仿真+程序)

编号&#xff1a;33 基于STM32的计时器 功能描述&#xff1a; 使用proteus 软件设计一个基于STM32的家用计时器&#xff0c;该系统包含多个按键、LED运行灯和时间显示(时间显示是LCD1602) 其功能如下: 1、利用按键实现设置计时时间功能&#xff0c;时间格式:AB:CD:E 例如01:5…

【攻防世界】江苏工匠杯 Web easyphp

打开页面是一个代码审计的题目&#xff0c;是我不太熟悉的东西&#xff0c;但是没关系&#xff0c;我们可以学是吧&#xff0c;以下为源代码 <?php highlight_file(__FILE__); $key1 0; $key2 0;$a $_GET[a]; $b $_GET[b];if(isset($a) && intval($a) > 60…

【ES实战】ES集群节点迁移与缩容

ES集群节点迁移与缩容 文章目录ES集群节点迁移与缩容master节点迁移场景一场景二场景三data节点迁移数据迁移操作1、查询集群原来的配置2、清空节点数据3、检查是否排空数据迁移原则缩容前置检查项master节点迁移 场景一 集群上的master部署情况&#xff0c;一台机器上同时部…

智能化IT运维平台建设方案,基于智和信通运维体系的高敏捷二次开发

随着企业信息进程不断加速&#xff0c;运维人员需要面对越来越复杂的业务和越来越多样化的用户需求&#xff0c;不断扩展的应用需要越来越合理的模式、越来越智能的工具来保障运维能灵活便捷、安全稳定地开展。企业网络规模的不断扩大&#xff0c;从初期的几台服务器发展到庞大…

Python3 | vscode配置环境

vscode版本&#xff1a;1.74.2python版本&#xff1a;3.9.0win10系统 准备工作&#xff0c;在win10系统 1&#xff0c;安装python3&#xff0c;配置环境变量2&#xff0c;安装vscode 接下来&#xff1a;就可以在vscode配置python环境 1&#xff0c;下载和安装python插件 快…

2022年总结以及2023年的计划

2022年总结以及2023年的计划 文章目录2022年总结以及2023年的计划年终复盘投资理财学习方面前端方面&#xff1a;后端方面&#xff1a;数据库&#xff1a;读书&#xff1a;疫情工作爱情新的一年的展望按照每年的惯例&#xff0c;我每年的总结&#xff0c;复盘会在这几天完成。 …

软件测试精准定位BUG小技巧

目录 一、前置知识 二、定位技巧 一、前置知识 1. 熟透系统业务、团队成员情况 2. 熟悉使用F12或抓包工具 3. 了解HTTP/HTTPS协议&#xff0c;能够区分请求URL、请求头、请求体、入参、响应数据、响应码 4. 具备操作常规Linux命令&#xff0c;能否登入服务器查看Log日志&…

通信原理 | 波段的划分

波段(wave band) 在无线电技术中,波段(wave band)这个名词具有两种含义。 电磁波频谱的划分,例如长波、短波、超短波等波段。 发射机、接收机等设备的工作频率范围的划分。若把工作频率范围分成几个部分,这些部分也称为波段,例如三波段收音机等。 波段划分 波段通常是…

Python实现A股股市情感分析,含数据集可直接运行

Python实现A股股市情感分析&#xff0c;含数据集可直接运行 Stock Market Sentiment Analysis: 股市情感分析 完整代码下载地址&#xff1a;Python实现A股股市情感分析 情绪与股市 情绪与股市关系的研究由来已久&#xff0c;情绪是市场的一个重要影响因素已成为共识。 15年…