Vue2 —— 学习(七)

news2024/12/22 12:02:48

目录

一、TodoList 案例(第一版)

(一)组件化编码流程

1.实现静态组件

2.显示动态数据 

(二)增加元素

 (三)多选框状态确定

(四)删除元素

(五)统计勾上的数据 

(六)全部勾上/取消

(七)清除完成的任务

二、总结:

(一)组件化的编码流程:

1.先拆分组件

2.实现动态组件:

(二)props 适用于

1.父组件到子组件传递数据(一层层太麻烦)

2.子组件到父组件传递数据

(三)v-model 不能绑定 props 传过来的值

(四)props 传过来的东西如果是对象

三、代码部分

(一)App.vue 

(二)MyFooter.vue 

(三)Header.vue

(四)MyItem.vue

(五)MyList.vue

(七)Main.js


一、TodoList 案例(第一版)

实现一个自定义添加项的列表 新添加的项在最上面 可以删除项 并能全选 

(一)组件化编码流程

1.实现静态组件

在我们要完成的成品页面中,抽取组件,使用组件实现静态页面

我们拆出来四个组件 先实现这四个静态组件 只考虑样式 不包含数据和动态的交互

拆分组件把四个新建四个组件到文件夹里面 然后 命名 在 App 中引入

先拆样式再拆结构,看 Html 结构都是属于哪一部分的 然后分别剪切 复制到对应的组件中,并在剪切初写上对应的组件标签

然后再拆 css 把对应的 css 结构截取出来 然会放到对应的组件中 

2.显示动态数据 

数据类型 数组对象 不能光写名字 还要有 id 什么的

数据谁用就给谁 我们给 List 

兄弟组件之间传数据 不太方便 后面会学但是我们先用一种基础的办法

所以我们把数据先把数据写到 App 中

组件间通信

(二)增加元素

父亲给儿子传:直接用 props 进行传数据就行

儿子给父亲传数据:父亲得先给儿子一个自己的函数,然后传给儿子 儿子在自己里面调用就实现了儿子给父亲传数据

兄弟间传数据:目前还办不到

先在 app 中 因为是header 想往 app 中添加数据 所以要在 app 中写个函数传给 header

<div class="todo-wrap">
        <MyHeader :addTodo="addTodo" />
        <MyList :todos="todos"/>
        <MyFooter />
      </div>
methods: {
    addTodo(todoObj) {
      this.todos.unshift(todoObj);
    },

然后在 Header 中 再写一个函数 把数据传回来

 <div class="todo-header">
    <input type="text" placeholder="请输入你的任务名称,按回车键确认"   @keyup.enter="add"/>
  </div>
 methods: {
    add(e) {
      const todoObj = { id: nanoid(), title: e.target.value, done: false };
      this.addTodo(todoObj);
    },
  },

 (三)多选框状态确定

app 中 

 <div class="todo-wrap">
        <MyHeader :addTodo="addTodo" />
        <MyList :todos="todos" :checkTodo="checkTodo"/>
        <MyFooter />
      </div>
 checkTodo(id){
      this.todos.forEach((todo)=>{
        if(todo.id === id) todo.done = !todo.done
      })
    }

MyList 中

<MyItem
      v-for="todoObj in todos"
      :key="todoObj.id"
      :todo="todoObj"
      :checkTodo="checkTodo"
    />
 props: ["todos", "checkTodo"],

 MyItem 中

   <input
        type="checkbox"
        :checked="todo.done"
        @change="handleCheck(todo.id)"
      />
 methods: {
    handleCheck(id) {
      this.checkTodo(id);
    },
  },

用 v-model 也能修改 多选框 但是不建议使用

还是 app 中写函数然后一步步引入比较好

(四)删除元素

confirm 函数是根据用户的交互来输出 布尔值是真还是假

弹个窗 确认时才会弹窗

app 文件中

 handleDelete(id) {
      if (confirm("确定删除吗")) {
        this.deleteTodo(id);
      }
    },

item 文件中

handleDelete(id) {
      if (confirm("确定删除吗")) {
        this.deleteTodo(id);
      }
    },

然后把 app 中的方法通过使用props 方法 传到 item 中即可

(五)统计勾上的数据 

模板代码

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

 写在 计算函数中 返回的就是最后的 return 值 里面再加一个判断 todo.done 看是否勾上 只统计勾上的项进行计数

computed:{
    doneTotal(){
     return this.todos.reduce((pre,todo)=>pre + (todo.done ? 1 : 0),0)
    }
  }

(六)全部勾上/取消

看是否还有项如果没有项就不显示这个删除框 v-show=“total”

我们能使用 v-model 的双向绑定方式来进行绑定 能显示最开始的状态,在这个isAll 函数内部写上,如果勾上就所有都全选 ,如果取消就所有都取消

<template>
  <div class="todo-footer" v-show="total">
    <label>
      <input type="checkbox" v-model="isAll" />
    </label>
    <span>
      <span>已完成{{ doneTotal }}</span> / 全部{{ total }}</span
    >
    <button class="btn btn-danger">清除已完成任务</button>
  </div>
</template>

然后在 app 里写上一个函数 用来给所有的选项都勾上或者都取消

然后用 props 连接 

checkAllTodo(done) {
      this.todos.forEach((todo) => {
        todo.done = done;
      });
    },

(七)清除完成的任务

app 中的函数

    clearAllTodo() {
      this.todos = this.todos.filter((todo) => {
        return !todo.done;
      });
    },

footer 中的函数 先用props 引入 然后在 button 中写点击事件 使用 clearAll 方法 在其中直接调用 app 中的清除已选项的函数就行了

    clearAll() {
      this.clearAllTodo();
    },

二、总结:

(一)组件化的编码流程:

1.先拆分组件

按功能拆,命名不能和 html 中的标签冲突,实现静态界面不考虑交互

2.实现动态组件:

考虑好数据的存放位置,看数据是被一个组件用还是被一些组件用

只有一个组件用这个数据就放在它自身就行

一些组件在用,就放到他们共同的父组件上(状态提升)状态就是我们数据改变引起了页面的变化就是状态的改变

(二)props 适用于

两种情况

1.父组件到子组件传递数据(一层层太麻烦)

在父组件中  :传递的数据名 

然后直接在子组件中用 props 接收即可

2.子组件到父组件传递数据

父组件要先给子组件传递一个函数(用 props)

子组件在合适的时候调用函数 通过传参的形式把数据传过去

(三)v-model 不能绑定 props 传过来的值

v-model 是双向的,如果绑定就说明我们的输入和勾选的行为都会影响 props 传进来的值,这就不符合我们所理解的规则了 (props 不可修改)

(四)props 传过来的东西如果是对象

里面属性能修改而且不报错 但是我们不推荐这么做

三、代码部分

(一)App.vue 

<template>
  <div id="root">
    <div class="todo-container">
      <div class="todo-wrap">
        <MyHeader :addTodo="addTodo" />
        <MyList
          :todos="todos"
          :checkTodo="checkTodo"
          :deleteTodo="deleteTodo"
        />
        <MyFooter
          :todos="todos"
          :checkAllTodo="checkAllTodo"
          :clearAllTodo="clearAllTodo"
        />
      </div>
    </div>
  </div>
</template>
<script>
import MyHeader from "./components/MyHeader.vue";
import MyFooter from "./components/MyFooter.vue";
import MyList from "./components/MyList.vue";
export default {
  name: "app",
  components: {
    MyHeader,
    MyFooter,
    MyList,
  },
  data() {
    return {
      todos: [
        { id: "001", title: "吃饭", done: true },
        { id: "002", title: "喝水", done: false },
        { id: "003", title: "玩游戏", done: true },
      ],
    };
  },
  methods: {
    addTodo(todoObj) {
      this.todos.unshift(todoObj);
    },
    checkTodo(id) {
      this.todos.forEach((todo) => {
        if (todo.id === id) todo.done = !todo.done;
      });
    },
    deleteTodo(id) {
      this.todos = this.todos.filter((todo) => {
        return todo.id !== id;
      });
    },
    checkAllTodo(done) {
      this.todos.forEach((todo) => {
        todo.done = done;
      });
    },
    clearAllTodo() {
      this.todos = this.todos.filter((todo) => {
        return !todo.done;
      });
    },
  },
};
</script>

<style>
/*base*/
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>

(二)MyFooter.vue 

<template>
  <div class="todo-footer" v-show="total">
    <label>
      <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: "MyFooter",
  props: ["todos", "checkAllTodo", "clearAllTodo"],
  computed: {
    total() {
      return this.todos.length;
    },
    doneTotal() {
      return this.todos.reduce((pre, todo) => pre + (todo.done ? 1 : 0), 0);
    },
    isAll: {
      get() {
        return this.doneTotal === this.total && this.total > 0;
      },
      set(value) {
        this.checkAllTodo(value);
      },
    },
  },
  methods: {
    checkAll(e) {
      console.log(e.target.checked);
      this.checkAllTodo(e.target.checked);
    },
    clearAll() {
      this.clearAllTodo();
    },
  },
};
</script>

<style scoped>
/*footer*/
.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>

(三)Header.vue

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

<script>
import { nanoid } from "nanoid";
export default {
  name: "MyHeader",
  props: ["addTodo"],
  methods: {
    add(e) {
      const todoObj = { id: nanoid(), title: e.target.value, done: false };
      this.addTodo(todoObj);
    },
  },
};
</script>

<style scoped>
/*header*/
.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);
}
</style>

(四)MyItem.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",
  props: ["todo", "checkTodo", "deleteTodo"],
  mounted() {
    console.log(this.todo);
  },
  methods: {
    handleCheck(id) {
      this.checkTodo(id);
    },
    handleDelete(id) {
      if (confirm("确定删除吗")) {
        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>

(五)MyList.vue

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

<script>
import MyItem from "./MyItem.vue";
export default {
  name: "MyList",
  components: {
    MyItem,
  },
  props: ["todos", "checkTodo","deleteTodo"],
};
</script>

<style scoped>
/*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>

(七)Main.js

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
  el: '#app',
  render: h => h(App),

})

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

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

相关文章

Boost电感的作用

Boost电感在Boost升压电路中起着关键的作用。Boost电路是一种DC-DC电源转换器&#xff0c;其主要功能是将低电压直流&#xff08;DC&#xff09;信号转换为高电压直流&#xff08;DC&#xff09;信号。Boost电感在这个过程中起着平滑电流、储存能量和提高电路效率的作用。 具体…

【yolo数据集合并方法】

yolo数据集合并方法 1.数据集容2.数据集合并 1.数据集容 包含训练集、验证集和测试集。 每一个数据集中包含图像文件夹和标签文件夹。 yaml文件中定义了配置参数&#xff0c;包括目标识别的class类别&#xff1a; 2.数据集合并 需要修改labels文件夹下txt文件class信息&…

Vision Pro 零基础教程:1.机器视觉概述

文章目录 机器视觉简介机器视觉的发展历史机器视觉的结构组成机器视觉的应用工业相机分类1. 按传感器类型分类&#xff1a;2. 按分辨率分类&#xff1a;3. 按扫描方式分类&#xff1a;4. 按输出信号类型分类&#xff1a;5. 按应用领域分类&#xff1a;6. 按接口类型分类&#x…

TLS v1.3 导致JetBrains IDE jdk.internal.net.http.common CPU占用高

开发环境 GoLand版本&#xff1a;2022.3.4 问题原因 JDK 中的 TLS v1.3 实现引起 解决办法 使用 SOCKS 代理代替HTTP代理 禁用 Space 和 Code With Me 插件 禁用 TLS v1.3&#xff0c;参考&#xff1a;https://stackoverflow.com/questions/54485755/java-11-httpclient-…

IEDA 的各种常用插件汇总

目录 IEDA 的各种常用插件汇总1、 Alibaba Java Coding Guidelines2、Translation3、Rainbow Brackets4、MyBatisX5、MyBatis Log Free6、Lombok7、Gitee IEDA 的各种常用插件汇总 1、 Alibaba Java Coding Guidelines 作用&#xff1a;阿里巴巴代码规范检查插件&#xff0c;…

Spring-dataSource事务案例分析-使用事务嵌套时,一个我们容易忽略的地方

场景如下&#xff1a; A_Bean 中的方法a()中调用B_Bean的b();方法都开启了事务&#xff0c;使用的默认的事务传递机制&#xff08;即&#xff1a;属于同一事务&#xff09;&#xff1b; 如下两种场景会存在较大的差异&#xff1a; 在b()方法中出现了异常&#xff0c;在b()中进…

只用键盘的技巧

技巧一&#xff1a;将常用软件固定在任务栏使用winnum/winT(shift)打开 技巧二&#xff1a;winX快捷键&#xff08;显示快捷键的快捷键&#xff09; ALT F4    关闭当前应用程序 技巧三&#xff1a;使用好Chrome快键键 ctrl h&#xff1b;历史纪录。 ctrl shift esc&am…

致远互联FE协作办公平台 editflow_manager.jsp 存在SQL注入漏洞

0x01 免责声明 请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;作者不为此承担任何责任。工具来自网络&#xff0c;安全性自测&#xff0c;如有侵权请联系删…

多ip证书实现多个ip地址https加密

在互联网快速发展的现在&#xff0c;很多用户会使用由正规数字证书颁发机构颁发的数字证书&#xff0c;其中IP数字证书就是只有公网IP地址网站的用户用来维护网站安全的手段。由于域名网站比较方便记忆&#xff0c;只有公网IP地址的网站是很少的&#xff0c;相应的IP数字证书产…

PlistEdit Pro for Mac激活版:强大的Plist文件编辑工具

PlistEdit Pro for Mac是一款专为Mac用户设计的强大Plist文件编辑工具。Plist文件是苹果公司开发的一种XML文件格式&#xff0c;用于存储应用程序的配置信息和数据。这款软件为用户提供了直观、易用的界面&#xff0c;使编辑和管理Plist文件变得轻松简单。 PlistEdit Pro for M…

Mybatis-plus中的分页操作

Mybatis-plus中的分页操作 1.导入Mybatis-plus依赖2.创建mybatis配置类3.参数 1.导入Mybatis-plus依赖 因为是一个springboot项目&#xff0c;其中的pom.xml文件内容如下&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns&q…

深入理解JVM中的G1垃圾收集器原理、过程和参数配置

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! 在Java虚拟机&#xff08;JVM&#xff09;中&#xff0c;垃圾收集&#xff08;GC&#xff09;是一个自动管理内存的过程&#xff…

【kubeEdge】离线部署

部署 kubeEdge 在线部署 在线方式部署直接执行以下命令&#xff0c;会联网下载需要的安装文件执行安装 $ keadm init --advertise-address{ip} --kubeedge-version{version} --kube-config{config_path}&#xff0c; 离线部署 离线准备工作 所有下载操作均在可以联网的机…

2024年在Vim中开发vue2+java

neovim 0.5刚出来的时代&#xff0c;那时刚有lua插件我很狂热。每天沉迷于打造自己的IDE之中。写过一堆相关的博客&#xff0c;也录过一些视频教程。后来发现neovim的接口和插件更新的很快&#xff0c;导致配置文件要不定期的修改&#xff0c;才能保证新版本的插件的适配。我也…

近端安全互联样例使用指导

样例介绍 本样例基于rk3568开发板&#xff0c;通过封装openharmony安全子系统deviceauth组件提供的能力&#xff0c;实现了一组可用于设备间快速建立可信认证和连接的接口&#xff0c;通过预先定义关系网&#xff0c;在设备初始化阶段完成端端设备间的认证&#xff0c;构建安全…

探索设计模式的魅力:融合AI大模型与函数式编程、开启智能编程新纪元

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 ✨欢迎加入探索AI大模型与函数式编程模式融合之旅✨ 在编程世界的广阔疆域里&#xff0c;两大…

mamba->jamba

1 mamba解决什么问题 Transformer的问题&#xff0c;其计算复杂度与序列长度的平方成正比&#xff0c;导致在处理长序列时效率低下。 Transformer 的注意力创建一个矩阵&#xff0c;将每个 token 与之前的每个 token 进行比较。矩阵中的权重由 token 对之间的相关性决定。 长度…

B树(B-tree)

B树(B-tree) B树(B-tree)是一种自平衡的多路查找树&#xff0c;主要用于磁盘或其他直接存取的辅助存储设备 B树能够保持数据有序&#xff0c;并允许在对数时间内完成查找、插入及删除等操作 这种数据结构常被应用在数据库和文件系统的实现上 B树的特点包括&#xff1a; B树为…

EelasticSearch是什么?及EelasticSearch的安装

一、概述 Elasticsearch 是一个基于 Apache Lucene 构建的开源分布式搜索引擎和分析引擎。它专为云计算环境设计&#xff0c;提供了一个分布式的、高可用的实时分析和搜索平台。Elasticsearch 可以处理大量数据&#xff0c;并且具备横向扩展能力&#xff0c;能够通过增加更多的…

如何获取手机root权限?

获取手机的 root 权限通常是指在 Android 设备上获取超级用户权限&#xff0c;这样用户就可以访问和修改系统文件、安装定制的 ROM、管理应用权限等。然而&#xff0c;需要注意的是&#xff0c;获取 root 权限可能会导致手机失去保修、安全性降低以及使系统变得不稳定。在获取 …