待办事项处理

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>待办事项</title>
</head>
<body>
  <div id="app">
    <todo-header>
      <!-- 2.6 之前 -->
      <div
        style="font-size: 18px; color: #f00; font-weight: 700;"
        slot="title"
      >这是自定义的主标题</div>
      <!-- 2.6 中使用 v-slot 指令,它需要在 template 标签中使用 -->
      <!-- <template v-slot:subtitle>
        <div>这是自定义的副标题</div>
      </template> -->
      <template #subtitle>
        <div>这是自定义的副标题</div>
      </template>
    </todo-header>
    <todo-input v-on:add="addTodoItem"></todo-input>
    <!-- <todo-list list="传递给子组件的数据"></todo-list> -->
    <todo-list v-bind:list="todos"></todo-list>
  </div>

  <script src="./libs/vue/vue.js"></script>
  <script>
    // 创建全局变量,用于保存 event-bus 中的对象
    const bus = new Vue()

    // 创建 TodoHeader 选项
    const todoHeaderOption = {
      template: `
        <div class="header">
          <slot name="title">
            <h2 class="title">待办事项</h2>
          </slot>
          <slot name="subtitle">
            <h3 class="subtitle">ToDoList...</h3>
          </slot>
        </div>
      `,
    }

    // 创建 TodoInput 选项
    const todoInputOption = {
      template: `
        <div class="input">
          <input
            class="input-todo"
            type="text"
            placeholder="请输入新待办事项"
            ref="inputRef"
            v-model.trim="inputValue"
            @keydown.enter="handleAdd"
          />
          <button @click="handleAdd">添加</button>
        </div>
      `,
      data() {
        return {
          inputValue: ''
        }
      },
      methods: {
        handleAdd() {
          // 文本框自动获得焦点
          this.$refs.inputRef.focus()
          // 没有输入内容,则结束不添加
          if (this.inputValue.length === 0) {
            return
          }
          // 触发在父组件中定义的 add 事件
          this.$emit('add', this.inputValue)
          // 清空文本框
          this.inputValue = ''
        }
      },
    }

    // 创建 TodoItem 选项
    const todoItemOption = {
      template: `
        <li class="list-item">
          <input type="checkbox" v-model="item.completed">
          {{item.id}} - {{item.title}} - {{item.completed ? '已': '未'}}完成 -
          <button @click="handleModify">修改</button>
          <button @click="handleRemove">删除</button>
        </li>
      `,
      props: {
        item: Object
      },
      methods: {
        handleModify() {
          this.item.completed = !this.item.completed
        },
        // 处理删除
        handleRemove() {
          // 触发 bus 对象上绑定的 'remove' 事件
          bus.$emit('remove', this.item.id)
        }
      }
    }

    // 创建 TodoList 选项
    const todoListOption = {
      template: `
        <div>
          <ul class="list" v-if="list.length">
            <todo-item v-for="todo in list" :key="todo.id" :item="todo"></todo-item>
          </ul>
          <div v-else>待办事项为空,请添加新待办事项!</div>

          <div>
            共有{{ total }}项待办事项,
            已完成{{ completedCount }}项,
            未完成{{ total - completedCount }}</div>
        </div>
      `,
      components: { // 局部组件注册
        'todo-item': todoItemOption,
      },
      // props: ['list'], // 利用数组声明当前组件可以从父组件中接收哪些名称的属性
      props: { // 利用对象声明可接收属性及进行属性验证
        list: {
          type: Array,
          required: true,
        }
      },
      computed: { // 计算属性
        total() { // 所有待办事项总项数
          return this.list.length
        },
        completedCount() { // 已完成的待办事项
          return this.list.reduce((sum, todo) => todo.completed ? sum + 1 : sum, 0)
        }
      }
    }

    // 注册组件
    Vue.component('todo-header', todoHeaderOption)

    // 创建根实例,TodoApp 组件
    const vm = new Vue({
      el: '#app',
      data() {
        return {
          // 所有待办事项
          todos: Array(3).fill(null).map((_, index) => ({
            id: index + 1,
            title: '待办事项' + (index + 1),
            completed: Math.random() > 0.5
          }))
        }
      },
      components: { // 局部组件注册(子组件)
        'todo-input': todoInputOption,
        'todo-list': todoListOption,
      },
      methods: {
        // 向 todos 数组中添加新待办事项
        addTodoItem(title) {
          this.todos.push({
            id: Math.random(),
            title,
            completed: false,
          })
        },
        // 删除 todos 数组中 id 对应的待办事项
        removeTodoItem(id) {
          this.todos = this.todos.filter(todo => todo.id !== id)
        }
      },
      // 实例创建后自动执行
      created() {
        // 绑定自定义事件,用于接收数据
        bus.$on('remove', this.removeTodoItem)
      },
    })
  </script>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值