vue3 自定义事件传参、v-model实现父子组件互相通信的todoList案例实现

本文介绍了一个使用Vue.js、Vite和Bootstrap构建的待办事项管理应用。项目涉及组件化开发,包括待办事项输入、列表展示和状态筛选按钮。通过初始化项目、设置项目结构和编写源码,实现了添加、显示和过滤任务的功能。项目结构清晰,代码组织有序,适合初学者学习Vue.js应用开发。
摘要由CSDN通过智能技术生成


一、使用的工具

二、项目结构

在这里插入图片描述

三、使用步骤

1. 初始化项目

  • 在终端定位到需要创建项目的目录输入npm init vite-app todoList
  • npm install less -D安装less
  • 导入bootstrap

2.项目源码

  • index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <link rel="icon" href="/favicon.ico" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vite App</title>
</head>
<body>
  <div id="app"></div>
  <script type="module" src="/src/main.js"></script>
</body>
</html>

  • App.vue
<template>
  <div>
    <h1>App根组件</h1>
    <hr />
    <todoInput @add="taskActive"></todoInput>
    <todoList :taskList="taskList"></todoList>
    <todoButton v-model:active="activeBtnIndex"></todoButton>
  </div>
</template>

<script>
import todoList from './components/to-do-list/todoList.vue'
import todoInput from './components/to-do-input/todoInput.vue'
import todoButton from './components/to-do-button/todoButton.vue'
export default {
  name: 'App',
  data() {
    return {
      list: [
        { id: 1, listName: '吃饭', state: false },
        { id: 2, listName: '睡觉', state: false },
        { id: 3, listName: '打游戏', state: false }
      ],
      //下一个任务的Id
      taskId: 4,
      // 控制按钮的状态
      activeBtnIndex: 0
    }
  },
  methods: {
    //添加任务
    taskActive(taskContent) {
      this.list.push({
        id: this.taskId,
        listName: taskContent,
        state: false
      })
      this.taskId++
    }
  },
  computed: {
    //返回筛选后的结果
    taskList() {
      switch (this.activeBtnIndex) {
        case 0:
          return this.list
        case 1:
          return this.list.filter(x => x.state)
        case 2:
          return this.list.filter(x => !x.state)
      }
    }
  },
  components: {
    todoList,
    todoInput,
    todoButton
  }
}
</script>

  • main.js
import { createApp } from 'vue'
import App from './App.vue'
import './index.css'
//全局导入bootstrap
import './assets/css/bootstrap.min.css'
createApp(App).mount('#app')


  • index.css
#app {
margin-top: 10px;
}

  • todoButtton.vue
<template>
  <div class="button-container mt-3">
    <div class="btn-group">
      <button type="button" class="btn" :class="active === 0 ? 'btn-primary' : 'btn-secondary'" @click="onBtnClick(0)">全部</button>
      <button type="button" class="btn" :class="active === 1 ? 'btn-primary' : 'btn-secondary'" @click="onBtnClick(1)">已完成</button>
      <button type="button" class="btn" :class="active === 2 ? 'btn-primary' : 'btn-secondary'" @click="onBtnClick(2)">未完成</button>
    </div>
  </div>
</template>

<script>
export default {
  name: 'todoButton',
  props: {
    active: {
      type: Number,
      required: true,
      // 默认激活索引值为 0 的按钮(全部:0,已完成:1,未完成:2)
      defalut: 0
    }
  },
  emits: ['update:active'],
  methods: {
    //传输按钮的index值给App组件
    onBtnClick(index) {
      if (index === this.active) return
      this.$emit('update:active', index)
    }
  }
}
</script>

<style lang="less" scoped>
.button-container {
  width: 400px;
  text-align: center;
}
</style>


  • todoInput.vue
<template>
  <div>
    <form @submit.prevent="addTask">
      <div class="form-row align-items-center">
        <div class="col-auto">
          <div class="input-group mb-2">
            <div class="input-group-prepend">
              <div class="input-group-text">任务</div>
            </div>
            <input type="text" class="form-control" id="inlineFormInputGroup" placeholder="输入你将要完成的任务" v-model.trim="taskContent" />
          </div>
        </div>
        <div class="col-auto">
          <button type="submit" class="btn btn-primary mb-2">提交</button>
        </div>
      </div>
    </form>
  </div>
</template>

<script>
export default {
  name: 'todoInput',
  data() {
    return { taskContent: '' }
  },
  emits: ['add'],
  methods: {
    //传输需要添加的任务给App组件
    addTask() {
      if (!this.taskContent) return alert('输入的内容不能为空!')
      this.$emit('add', this.taskContent)
      this.taskContent = ''
    }
  }
}
</script>

<style lang="less" scoped></style>

  • todoList.vue
  <template>
    <div>
      <ul class="list-group">
        <li class="list-group-item d-flex justify-content-between align-items-center" v-for="item in taskList" :key="item.id">
          <input type="checkbox" :id="item.id" v-model="item.state" />
          <label :for="item.id" :class="item.state ? 'del' : ''">{{ item.listName }}</label>
          <span class="badge badge-success badge-pill" v-if="item.state">已完成</span>
          <span class="badge badge-warning badge-pill" v-else>未完成</span>
        </li>
      </ul>
    </div>
  </template>

  <script>
  export default {
    props: ['taskList'],
    name: 'todoList'
  }
  </script>

  <style lang="less" scoped>
  li {
    width: 400px;
  }
  .del {
    text-decoration: line-through;
    font-style: italic;
    color: gray;
  }
  </style>

四、项目效果

在这里插入图片描述

五、项目地址

todoList

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值