Vue2-TodoList案例

news2024/12/22 18:33:17

TodoList案例

    • 组件化编码流程(通用)
    • 整体思路
      • 1、分析结构
      • 2、拆html和css
      • 3、初始化列表
      • 4、实现添加列表功能
      • 5、实现勾选功能
      • 6、实现删除功能
      • 7、实现底部统计功能
      • 8、实现全选框的交互
        • (1)每个todo控制全选框
        • (2)全选框控制todo全选或者取消全选:使用点击事件实现。
        • (3)全选框控制todo全选或者取消全选:使用v-model实现。
      • 9、点击右下角按钮删除全部已完成任务
    • 案例完整代码展示
      • 1、App.vue
      • 2、TodolistHeader.vue
      • 3、TodolistList.vue
      • 4、TodolistItem.vue
      • 5、TodolistFooter.vue
    • 三、总结

组件化编码流程(通用)

  1. 实现静态组件:抽取组件,使用组件实现静态页面效果

  2. 展示动态数据:

    ①数据的类型、名称是什么?

    ②数据保存在哪个组件?

  3. 交互——从绑定事件监听开始

整体思路

TodoList类似于我们手机里的待办事项或者备忘录

请添加图片描述

1、分析结构

确定组件名称TodolistHeader,TodolistList,TodolistItem,TodolistFooter(下文会简写成Header、List、Item、Footer)和个数,还有嵌套关系(TodolistList里面包含TodolistItem,TodolistList和TodolistHello\TodolistFooter为兄弟组件),然后引入相应的组件。

  • 一个命名问题:此处命名不直接用Header、Footer等简单的命名是因为这些命名本身在标签具有特殊的含义(类似于关键字),并且Vue推荐我们使用多单词命名。为了达到和Vue开发者工具里的名字一样,这里使用的“大驼峰”命名(在驼峰命名的基础上首字母大写)。

请添加图片描述

请添加图片描述

2、拆html和css

一般的项目是写好html和css的,我们要把他们拆到相应的组件里,可以先全部放到App.vue中,然后打开开发者工具,观察他们的结构,分别放到对应的组件里面,style标签中加上scoped属性(保证当前样式只在当前组件中使用,防止样式名字不能重复使用)

3、初始化列表

在List中定义一个数组todos存储每个item为对象,然后在List的标签中写<Item></Item>并用v-for遍历数组中的每个对象生成结构,且通过自定义属性todo把每个对象传给子组件Item

在Item中使用props配置项接收(实现父子组件通信),然后input框里的checked绑定todo.done(可以初始化页面)

props配置项不熟悉的可以点击此处复习props

4、实现添加列表功能

上一步我们是在List中定义了todos数组,而用户的输入是在Header中,也就是说我们要在Header中收集数据,然后传给List,但是兄弟组件如何通信?全局事件总线、消息订阅与发布、Vuex都可以,但是现在还没学。

之前我们学的props配置项,可以实现父组件给子组件传数据(父组件里写子组件标签并配置属性,子组件使用props接收),现在我们想实现兄弟组件HeaderList的通信,可以借助App这个共同的父亲。

(1)把List中的数据todos定义在App里,然后传给List一份(通过props接收,由于是直接传到vc上,模板不会报错)。
(2)在App组件中定义一个函数,函数里面写个参数

	addTodo(x) {
            //借助这个函数,拿到Header中用户输入的东西
            this.todos.unshift(x);
       }

(3)把这个函数传给HeaderHeaderprops接收一下,然后在Header中调用这个函数,把用户的输入传给这个函数

const todoObj = { id: nanoid(), title: this.title, done: false };
this.addTodo(todoObj);

(4)由于addTodo是定义在App上的,所以App就直接拿到了函数的参数,然后就可以直接添加在todos中,这样的话todos改变,模板重新解析,传给Listtodos也改变,List模板重新解析,v-for一遍历,页面就多了一个。

5、实现勾选功能

选中:done=true,不选中:done=false。思路:简单来说就是让App拿到要修改的数据的id,找到这个数据然后把done属性取反。

我们先在App组件里定义一个函数,用来接收当前操作对象的id,然后函数里的逻辑是找到这个id,然后done属性取反(记住,数据源在哪里,修改数据的方法就写在哪里

changeTodo(id) {
            this.todos.forEach((todo) => {
                if (todo.id === id) todo.done = !todo.done;
            })
        }

然后把changeTodo这个函数通过标签和props传给List,再传给Item
然后在Item组件里定义一个函数handleChange,用来获取当前操作的多选框的id

handleChange(id) {
            // 不能像下面这样直接修改props的数据,数据源在哪里,我们就去哪里改
            // 如下代码也能实现功能,但是不建议这么写,理由就是不能直接改props传来的东西
            // this.todo.done = !this.todo.done;   
            //不报错是因为,改的不是整个对象(对象的地址),地址没变就不会报错

            //通知App要修改的数据的id是哪个
            this.changeTodo(id);
        }

handleChange函数通过点击事件来触发,实参就是当前input节点的todo的id

<input type="checkbox" :checked="todo.done" @click="handleChange(todo.id)" />

当然,这个勾选功能不用这么绕来绕去也可以实现,比如我直接在handleChange

this.todo.done = !this.todo.done;   

又或者我用v-model,一行代码就搞定了,不用在App再定义函数,然后传来传去

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

但是不建议这么写,理由就是不能直接改props传来的东西,记住,数据源在哪里,修改数据的方法就配置在哪里,千万记住props是只读的,如果改它,就会改源数据,这样所有用到数据的组件都会受到影响。

6、实现删除功能

和上面的类似,也是需要传递函数,不能动props。
首先App定义一个删除函数

deleteTodo(id) {
            this.todos = this.todos.filter((todo) => {
                return todo.id !== id;
            })
            // this.todos = this.todos.filter(todo => todo.id !== id);
        }

把这个函数传给List,再传给Item
Item中的按钮来个点击事件

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

把当前input的这个id传给App,调用App中的deleteTodo函数让App去操作

handleDelete(id) {
    if (confirm('确定要删除吗?'))  //点确定是true,取消是false
        this.deleteTodo(id);
}

7、实现底部统计功能

(1)App中的todos数据传给Footer一份
(2)全部比较简单,直接插值语法读数组todos的长度就行。已完成这里可以用计算属性

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

(3)计算属性这里有多种实现方式:

写法1:forEach遍历

let count = 0;
this.todos.forEach(todo => {
    if (todo.done) count++;
});
return count;

写法2:for of遍历

let count = 0;
//for in 拿到的是数组的索引,for of才能拿到元素
for (let todo of this.todos) {
    if (todo.done === true)
        count++;
}
return count;

写法3:filter过滤

let count = this.todos.filter(todo => todo.done)
return count.length;

写法4:ES6的reduce

  • 对reduce不熟悉的可以点击此处复习reduce(点击目录里的数组核心方法即可)
const count = this.todos.reduce((pre, todo) => {
    return pre + (todo.done ? 1 : 0)
}, 0);
return count;
//return this.todos.reduce((pre, todo) => pre + (todo.done ? 1 : 0), 0);

8、实现全选框的交互

(1)每个todo控制全选框

当已完成和全部相等且不等于0时,勾选全选框,写在计算属性中

<input type="checkbox" :checked="isAll" " />
isAll(){
  return this.total === this.doneTotal && this.total !== 0;
  }

如果全部是0个,就隐藏Footer(用v-show实现)

(2)全选框控制todo全选或者取消全选:使用点击事件实现。

App中定义一个函数,用来接收Footer中全选框的状态值,然后把每个数据的done值都改成和全选框的状态值一样(选择or不选择)

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

Footer的全选框中,加入点击事件并定义一个函数

<input type="checkbox" :checked="isAll" @click="handleCheckAll" />

在函数中调用App中的函数,把状态传过去

handleCheckAll(e) {
            // this.checkAllTodos(!this.isAll);  
            this.checkAllTodos(e.target.checked);  //直接拿dom的值比较合适
        },

(3)全选框控制todo全选或者取消全选:使用v-model实现。

第一步一样,在App中定义一个函数,用来接收Footer中全选框的状态值,然后把每个数据的done值都改成和全选框的状态值一样(选择or不选择)

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

在Footer的全选框中,加入v-model(没有value绑定的是checked)绑定isAll计算属性

<input type="checkbox" v-model="isAll" />

isAll中加入setter,把每个更新的值传给App中的函数。这样就不用再另外定义methods了,只用计算属性就能搞定:item影响全选框(getter读isAll)全选框影响item(setter改isAll)两种情况

isAll: {
            get() {
                return this.total === this.doneTotal && this.total !== 0;
            },
            set(val) {
                this.checkAllTodos(val);
            }
        },

9、点击右下角按钮删除全部已完成任务

App中定义一个方法并传给Footer

//5.删除已完成任务
clearAllTodo() {
      this.todos = this.todos.filter((todo) => {
        return !todo.done
      })
    },

Footer中调用这个方法

<button class="btn btn-danger" @click="clearAll">清除已完成任务</button>
clearAll() {
      this.clearAllTodo()//点击调用App里边的方法,把所有true删掉
    },

案例完整代码展示

1、App.vue

<template>
  <div id="root">
    <div class="todo-container">
      <div class="todo-wrap">
        <TodolistHeader :addTodo="addTodo" />
        <TodolistList
          :todos="todos"
          :changeTodo="changeTodo"
          :deleteTodo="deleteTodo"
        />
        <TodolistFooter
          :todos="todos"
          :checkAllTodo="checkAllTodo"
          :clearAllTodo="clearAllTodo"
        />
      </div>
    </div>
  </div>
</template>

<script>
import TodolistHeader from './components/TodolistHeader.vue'
import TodolistFooter from './components/TodolistFooter.vue'
import TodolistList from './components/TodolistList.vue'
export default {
  name: 'App',
  components: { TodolistHeader, TodolistFooter, TodolistList },
  data() {
    return {
      todos: [
        //通过App把todos传给List
        //id不用数值是因为数值是有尽头的,而字符串没有尽头
        { id: '001', title: '吃饭', done: true },
        { id: '002', title: '睡觉', done: true },
        { id: '003', title: '打豆豆', done: true },
      ],
    }
  },
  //记住,数据源在哪里,修改数据的方法就配置在哪里
  //最好不要在任何子组件中修改父组件的数据
  methods: {
    //1.添加一个todo
    addTodo(todoObj) {
      //借助这个函数,拿到Header中用户输入的东西
      this.todos.unshift(todoObj)
    },
    //2.勾选or取消勾选一个todo
    changeTodo(id) {
      this.todos.forEach((todo) => {
        if (todo.id === id) todo.done = !todo.done
      })
    },
    //3.删除一个todo
    deleteTodo(id) {
      this.todos = this.todos.filter((todo) => {
        return todo.id !== id
      })
    },
    //4.全选or取消全选,其他子框同步
    checkAllTodo(done) {
      this.todos.forEach((todo) => {
        todo.done = done
      })
    },
    //5.删除已完成任务
    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>

2、TodolistHeader.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: 'TodolistHeader',
  data() {
    return {
      title: '',
    }
  },
  props: ['addTodo'],
  methods: {
    // 输入内容按回车添加一个事件
    add() {
      //1.校验数据
      if (!this.title.trim()) return alert('输入不能为空')
      //2.将用户的输入包装成一个todo对象
      const todoObj = { id: nanoid(), title: this.title, done: false }
      //3.借助App里的函数,把用户的输入从Header传给App里面的todos 然后再通过App把todos传给List,用这种捷径(借助App)就巧妙地实现了Header和List的兄弟组件通信
      this.addTodo(todoObj)
      this.title = '' //4.输入完回车输入框变为空
    },
  },
}
</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>

3、TodolistList.vue

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

<script>
import TodolistItem from './TodolistItem.vue'
export default {
  name: 'TodolistList',
  components: { TodolistItem },
  props: ['todos', 'changeTodo', '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>

4、TodolistItem.vue

<template>
  <li>
    <label>
      <input
        type="checkbox"
        :checked="todo.done"
        @change="handleChange(todo.id)"
      />
      <!-- 如下代码也能实现功能,但是不建议这么写,理由就是不能直接改props传来的东西 -->
      <!-- <input type="checkbox" v-model="todo.done" /> -->
      <span>{{ todo.title }}</span>
    </label>
    <button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
  </li>
</template>

<script>
export default {
  name: 'TodolistItem',
  //声明接收todo对象
  props: ['todo', 'changeTodo', 'deleteTodo'],
  methods: {
    handleChange(id) {
      // 不能像下面这样直接修改props的数据,数据源在哪里,我们就去哪里改
      // 如下代码也能实现功能,但是不建议这么写,理由就是不能直接改props传来的东西
      // this.todo.done = !this.todo.done;
      //不报错是因为,改的不是整个对象(对象的地址),地址没变就不会报错

      //通知App要修改的数据的id是哪个
      this.changeTodo(id)
    },
    handleDelete(id) {
      //confirm点确定是true,取消是false
      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>

5、TodolistFooter.vue

<template>
  <!-- 这里total如果显示是0(false)就隐藏(v-show)-->
  <div class="todo-footer" v-show="total">
    <label>
      <input type="checkbox" :checked="isAll" @change="checkAll" />
    </label>
    <span>
      <span>已完成{{ doneTotal }}</span> / 全部{{ total }}
    </span>
    <button class="btn btn-danger" @click="clearAll">清除已完成任务</button>
  </div>
</template>

<script>
export default {
  name: 'TodolistFooter',
  props: ['todos', 'checkAllTodo', 'clearAllTodo'],
  computed: {
    total() {
      return this.todos.length
    },
    doneTotal() {
      return this.todos.reduce(
        (pre, current) => pre + (current.done ? 1 : 0),
        0
      )
    },
    isAll() {
      return this.doneTotal === this.total && this.total > 0
    },
  },
  methods: {
    checkAll(e) {
      this.checkAllTodo(e.target.checked)
    },
    clearAll() {
      this.clearAllTodo() //点击调用App里边的方法,把所有为true的删掉
    },
  },
}
</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>

三、总结

1.组件化编码流程:
(1)拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。
(2)实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:

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

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

2.props适用于:
(1).父组件 ==> 子组件 通信
(2).子组件 ==> 父组件 通信(要求父先给子一个函数)

3.使用v-model时要切记
v-model绑定的值不能是props传过来的值,因为props是不可以修改的!

4.关于props
props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。

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

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

相关文章

第7章 C控制语句:分支和跳转

本章介绍以下内容&#xff1a; 关键字&#xff1a;if、else、switch、continue、break、case、default、goto 运算符&#xff1a;&&、||、?: 函数&#xff1a;getchar()、putchar()、ctype.h系列 如何使用if和if else语句&#xff0c;如何嵌套它们 在更复杂的测试表达…

SpringBoot的配置文件(properties与yml)

文章目录 1. 配置文件的作用2. 配置文件格式3. 配置文件的使用方法3.1. properties配置文件3.1.1. 基本语法和使用3.1.2. properties优缺点分析 3.2. yml配置文件3.2.1. 基本语法与使用3.2.2. yml中单双引号问题3.2.3. yml配置不同类型的数据类型及null3.2.4. 配置对象3.2.5. 配…

百日筑基篇——Linux中文本工具应用(Linux入门六)

百日筑基篇——Linux中文本工具应用&#xff08;Linux入门六&#xff09; 文章目录 前言一、文本搜索工具 **grep**二、流式文本处理工具 **sed**三、文本处理工具 **awk**总结 前言 在Linux中&#xff0c;通常会使用一些工具来处理文本以获得所需的内容。而Linux中的文本处理…

python编程小游戏 五子棋,python编程小游戏简单的

大家好&#xff0c;本文将围绕python编程小游戏如何停止展开说明&#xff0c;python编程小游戏日语教程是一个很多人都想弄明白的事情&#xff0c;想搞清楚python编程小游戏超级玛丽需要先了解以下几个事情。 今天分享一个有趣的Python游戏库freegames&#xff0c;它里面包含经…

前端新手学习路线

文章目录 前端学习路线&#xff01;特点符号表大纲前言 - 学编程需要的特质一、前端入门⭐️ 开发工具浏览器编辑器文档笔记 ⭐️ HTML⭐️ CSS⭐️ JavaScript✅ ES6 特性 二、巩固基础前端基础知识计算机基础✅ 算法和数据结构✅ 计算机网络✅ 操作系统 软件开发基础✅ 设计模…

Kafka 入门到起飞 - 什么是 HW 和 LEO?何时更新HW和LEO呢?

上文我们已经学到&#xff0c; 一个Topic&#xff08;主题&#xff09;会有多个Partition&#xff08;分区&#xff09;为了保证高可用&#xff0c;每个分区有多个Replication&#xff08;副本&#xff09;副本分为Leader 和 Follower 两个角色&#xff0c;Follower 从Leader同…

【数据结构】实现顺序表

目录 一.介绍顺序表二.实现顺序表1.创建多文件2.顺序表的存储方式3.函数的声明4.初始化顺序表5.清理顺序表6.打印顺序表7.扩容8.尾插8.尾删9.头插10.头删11.查找12.修改13.在pos位置插入13.在pos位置删除 三.全部代码1.SeqList.h2.SeqList.c3.Test.c 一.介绍顺序表 顺序表是用…

【佳佳怪文献分享】使用点云从半监督到全监督房间布局估计

标题&#xff1a;From Semi-supervised to Omni-supervised Room Layout Estimation Using Point Cloud 作者&#xff1a;Huan-ang Gao, Beiwen Tian, Pengfei Li, Xiaoxue Chen, Hao Zhao, Guyue Zhou , Yurong Chen and Hongbin Zha 来源&#xff1a;2023 IEEE Internation…

Android系统-线程-消息处理机制

引言&#xff1a; Android应用消息处理机制是怎么样的呢&#xff1f; 跟Native&#xff0c;Linux底层都有些什么关系呢&#xff1f; 概念与理解&#xff1a; Android应用程序是通过消息来驱动的。 1&#xff09;应用程序的每一个线程在启动的时候&#xff0c;都可以首先在内…

Swagger-ui在idea中的使用

1.添加依赖 <!--添加swagger2相关概念--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency><!--添加swagger-ui相关功能--><de…

【贪心+堆】CF1701 D

Problem - 1701D - Codeforces 题意&#xff1a; 思路&#xff1a; 手推样例可知&#xff1a; 一开始想的是&#xff0c;把这些区间按右端点排序&#xff0c;然根据排序后的贪心 事实上不是这样的&#xff0c;而是要把有可能的区间扔进堆里&#xff1a; 感觉这种带堆的贪心&…

【TI-CCS笔记】工程编译配置 bin文件的编译和生成 各种架构的Post-build配置汇总

【TI-CCS笔记】工程编译配置 bin文件的编译和生成 各种架构的Post-build配置汇总 TI编译器分类 在CCS按照目录下 有个名为${CG_TOOL_ROOT}的目录 其下就是当前工程的编译器 存放目录为&#xff1a; C:\ti\ccs1240\ccs\tools\compiler按类型分为五种&#xff1a; ti-cgt-arm…

J‘meter 连接 MySQL 数据库脚本

1、创建线程组 2、创建 JDBC Connection Configuration 3、创建 JDBC Request 4、最终创建的目录 5、重点来了 5.1 在百度中下载个 MySQL-connector-Java-8.0.28.jar&#xff0c;放在 jmeter 的 bin 目录下 5.2 在测试计划中&#xff0c;将 jar 包添加到脚本中 5.3 输入参…

如何查看mysql中各个表的数据大小

1.SHOW VARIABLES LIKE datadir; 这会显示 MySQL 数据目录的路径。在这个路径下&#xff0c;你可以找到每个数据库的文件夹&#xff0c;每个数据库文件夹中会包含各个表的 .ibd 文件。 2.进入对应的目录 3.进入对应的db&#xff0c;例如我自己的db为test 4.如果我们想以M为单…

在Gazebo中添加悬浮模型后,利用键盘控制其移动方法

前段时间写了文章&#xff0c;通过修改sdf、urdf模型的方法&#xff0c;在Gazebo中添加悬浮模型方法 / Gazebo中模型如何不因重力下落&#xff1a;在Gazebo中添加悬浮模型方法 / Gazebo中模型如何不因重力下落&#xff1a;修改sdf、urdf模型_sagima_sdu的博客-CSDN博客 今天讲…

2401. 最长优雅子数组;1111. 有效括号的嵌套深度;2134. 最少交换次数来组合所有的 1 II

2401. 最长优雅子数组 核心思想&#xff1a;滑动窗口。如何知道当前值与以前的值是否and为0很重要&#xff0c;这是这道题目的关键&#xff0c;and操作会把1变成0&#xff0c;但是不会把0变成1&#xff0c;所以当前值x要和前面的值两两and为0意味着&#xff0c;你要使前面的值…

Vim的插件管理器之Vundle

1、安装Vundle插件管理器 Vim可以安装插件&#xff0c;但是需要手动安装比较麻烦&#xff0c;Vim本身没有提供插件管理器&#xff0c;所以会有很多的第三方的插件管理器&#xff0c;有一个vim的插件叫做 “vim-easymotion”&#xff0c;在它的github的安装说明里有列出对于不同…

比ChatGPT更强的星火大模型V2版本发布!

初体验 测试PPT生成 结果&#xff1a; 达到了我的预期&#xff0c;只需要微调就可以直接交付&#xff0c;这点比ChatGPT要强很多. 测试文档问答 结果&#xff1a; 这点很新颖&#xff0c;现在类似这种文档问答的AI平台收费都贵的离谱&#xff0c;星火不但免费支持而且效果也…

vue项目报错:node:internal/modules/cjs/loader:1080

运行项目报错&#xff1a; 原因&#xff1a; 看划线的地方&#xff0c;中文乱码导致找不见模块了 解决方案 将路径上的中文改为英文即可&#xff0c;项目命名最好只有英文、下划线&#xff08;_&#xff09;、数字、横杠&#xff08;-&#xff09;等英文符号组成

MATLAB图形窗口固定

起因是上次作图的时候写了&#xff1a; clc clear close all 这三个典型的刷新语句 清空工作区、命令行并且关闭图窗 就导致每次我把图窗拉到合适的位置观察&#xff0c;再一次点击运行都会重新刷新在出生点&#xff08;x&#xff09; 所以想把图窗固定在某个位置 显然更…