【Vue组件之TodoList案例】

效果展示:

 源代码:

提取码:rk3qhttp://xn--https-bl8js66z7n7i//pan.baidu.com/s/10UVcXPwb6IGEwsVv13krGQ

**实现静态页面**

 1.把数据放在APP组件内,通过props传给子组件TODO,然后遍历。

 2.添加事件

子组件heard:

定义键盘事件keyup.enter,空字符串***title:‘ ’***,再把input的value用v-model和title双向绑定,方便我们把新添加的事件追加到静态数据todos里。

添加数据到todos有多种方法,可以用props让父组件传一个函数给子组件(heardView)调用并把新定义的事件对象以参数的形式传给父组件(APP),也可以用$emit触发父组件的自定义事件把新定义的数据传过去。这里我用的是props。

<div id="heard">
     <label for="title">ToDoList</label>
     <input type="text" id="title" name="title" placeholder="添加ToDo" required="required"
      autocomplete="off" @keydown.enter="add" v-model="title"/>
</div>
props: ['addtodo',],
    methods: {
        add() {
            if (!this.title) return alert('输入不能为空')
            const todoobj = { id: nanoid(), title: this.title, completed: false }
            this.addtodo(todoobj)
            this.title = ''
        }
    },

上面代码中新添加事件的ID是用nanoid插件生成的。

使用方法:在需要使用nanoid生成ID的组件引入,直接调用nanoid()即可。

import { nanoid } from 'nanoid'

(插件的安装方式:在当前文件下 用 npm install nanoid 如果出现报错,则可能是版本不符,推荐安装3.0版本,命令:npm i nanoid@3。补充:npm view (组件名) versions 可以查看插件的所有版本,npm (组件名) -v,可以查看当前安装插件版本。)

也可以用时间戳的方式生成(例如:+new Date())。

父组件APP:

methods: {
    addtodo(todoobj) {//添加待做事件
      this.todos.unshift(todoobj)
    },
}

3.改变input勾选状态

这个功能也可以用props父组件传函数和$emit触发父组件的自定义事件来实现。还有一种更方便的方法,用v-model绑定props传过来的todos遍历的todo.completed。但是这样就改变了props的值,虽然vue没有监测到,但这是不被允许的。

props方法:

父组件APP:

<Todo :todos="todos" :changechecked="changechecked" @removeTodo="removeTodo"></Todo>
changechecked(id) {//改变表单勾选状态
      //方法1.获取点击的ID把它的complete值取反
      this.todos.forEach(todo => {
        if (todo.id == id) {
          todo.completed = !todo.completed
        }
      })

子组件todo:

<ol id="todolist">
    <li v-for="todo in todos" :key="todo.id"><!--改变勾选状态放法1-->
         <input type="checkbox" @click="change(todo.id)" :checked="todo.completed" />
         <!-- <input type="checkbox" v-model="todo.completed" /> -->
         <span>{{todo.title}}</span>
         <button class="btn btn-danger" @click="delTodo(todo.id)">删除</button>
    </li>
</ol>
change(id) {//通过调用props传递的函数把ID给父组件
            this.changechecked(id)
},

4.删除事件:

这里也可以使用 props或者$emit,本次演示$emit。通过绑定自定义事件收到子组件传来的发生点击事件 `(<li>)`的ID并筛选出去。

父组件APP:

<Todo :todos="todos" :changechecked="changechecked" @removeTodo="removeTodo"></Todo>


<Done :todos="todos" @removeDone="removeTodo"></Done>

待做事件和已完成都有删除功能,所以自定义事件可以重复使用。

removeTodo(id) {
      this.todos = this.todos.filter(todo => {
        return todo.id != id;
      })
},

动态数据:待做事件,已完成事件切换与计数

1.计数功能:

遍历todos得到done的值,当值为真时已完成事件数量加1,反之待做事件数量加1。方法有很多,这里演示计算属性的方法。补充:通过计算得到的值,一般不做修改,所以这里我只写了getter().

computed: {
    num: {//通过循环得到当前值的checked,计算得出待做事件todos的数量
      get() {
        return this.todos.reduce((total, item) => {
          return total+(item.completed?0:1)
        },0)
      }
    },
    newnum: {//通过循环得到当前值的checked,计算得出已做事件dones的数量
      get() {
        return this.todos.reduce((total, item) => {
          return total + (item.completed ? 1 : 0)
        }, 0)
      },
    }

2.todo,done动态切换:

因为在实现静态页面3.改变input状态里,我们把发生点击事件的 `<li>里面的input状态取反了,这样我们就可以拿到props传过来的todos,然后用计算属性遍历得到我们想要的input状态的事件数组。`

待做事件Todo:

注意:从props拿到的todos并没有直接使用,而是用计算属性筛选之后得到的newMSg去遍历。

props: ['todos'],
<ul id="donelist">
     <li v-for="done in newMsg" :key="done.id">
     <input type="checkbox" v-model='done.completed'/>
            <span>{{done.title}}</span>
            <button class="btn btn-danger" @click="deldo(done.id)">删除</button>
     </li>
</ul>
computed: {
        newMsg: {
            get() {//通过计算父组件用props传来的数据,把checked为false的筛选出去
              return    this.todos.filter(todo => {
                    return todo.completed == true
                })

            },
        }
    }

已做事件Done;

同上

本地存储

父组件APP:

利用监视属性来对todos进行深度监视,只要todos发生改变就把handler(newval)中的newval保存到本地。

watch: {
    todos: {
      deep: true,
      handler(val) {
        localStorage.setItem('Todos',JSON.stringify(val))
      }
    }
  },

拿到本地存储的数据:

export default {
  name: 'App',
  data() {
    return {
      todos: JSON.parse(localStorage.getItem('Todos'))||[]

    }
  },

因为todos默认为空,所以JSON.stringify(val)为null,又因为JSON.parse(null)==null,所以要在JSON.parse(localStorage.getItem('Todos'))为空时把todos赋为【】空数组。

Vue3中做一个Todo List的例子,我们可以使用Vuex管理状态,Vuetify作为UI库,并结合Element Plus提供一些常用组件。下面是基本步骤: 1. **项目初始化**: 使用`vue create todo-app`创建一个新的Vue3项目。 2. **安装依赖**: 安装Vue Router、Vuex、Element Plus等必要库: ``` npm install vuex vuetify @element-plus/vue ``` 3. **创建store**: 在`src/store/index.js`中设置初始状态和mutation,比如: ```js import Vue from 'vue' import Vuex from 'vuex' const state = { todos: [], } const mutations = { addTodo(state, text) { state.todos.push({ text, completed: false }); }, }; export default new Vuex.Store({ state, mutations, }); ``` 4. **TodoList组件**: - 创建`components/TodoList.vue`,监听输入事件添加任务并保存到本地存储(例如使用浏览器的localStorage): ```html <template> <v-card> <v-textarea v-model="newTodo" @input="addTodoToLocalStorage" placeholder="添加新的待办事项..." ></v-textarea> <v-list> <v-list-item v-for="(todo, index) in todos" :key="index" :class="{ done: todo.completed }" > <v-list-tile-content> <v-icon @click="toggleTodo(index)">done</v-icon> {{ todo.text }} </v-list-tile-content> </v-list-item> </v-list> </v-card> </template> <script> import { mapState } from "vuex"; export default { computed: { ...mapState(["todos"]), }, methods: { addTodoToLocalStorage(text) { localStorage.setItem('todos', JSON.stringify(this.todos)); this.addTodo(text); }, toggleTodo(index) { // 根据索引修改todo的completed状态 } }, data() { return { newTodo: '', }; }, }; </script> ``` 5. **兄弟组件**: 如果有其他兄弟组件想访问Todo List的状态,可以通过Vue实例的$store来获取,或者使用provide/inject方式传递数据。 6. **路由配置**: 在`src/router/index.js`中配置路由,让TodoList组件成为可导航的页面。 注意:这只是一个基础示例,实际应用中可能还需要处理错误情况,如localStorage的读取异常,以及更复杂的列表操作(如删除、排序)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值