6.4 渲染列表的 DOM 结构
- 通过 v-for 指令,循环渲染列表的 DOM 结构:
- 通过 v-if 和 v-else 指令,按需渲染 badge 效果:
<template> <div> <ul class="list-group"> <!-- 列表组 --> <li class="list-group-item d-flex justify-content-between align-items-center" v-for="item in list" :key="item.id" > <!-- 复选框 --> <div class="custom-control custom-checkbox"> <input type="checkbox" class="custom-control-input" :id="item.id" > <label class="custom-control-label" :for="item.id">{{item.task}}</label> </div> <!-- 徽标 --> <span class="badge badge-success badge-pill" v-if="item.done">完成</span> <span class="badge badge-warning badge-pill" v-else>未完成</span> </li> </ul> </div> </template>
3.通过 v-model 指令,双向绑定任务的完成状态:
<template> <div> <ul class="list-group"> <!-- 列表组 --> <li class="list-group-item d-flex justify-content-between align-items-center" v-for="item in list" :key="item.id" > <!-- 复选框 --> <div class="custom-control custom-checkbox"> <!-- list 接收的是父组件传递过来的数组的引用 --> <!-- 在子组件修改,父组件中数组中的元素的值会跟着改变 --> <input type="checkbox" class="custom-control-input" :id="item.id" v-model="item.done" > <label class="custom-control-label" :for="item.id">{{item.task}}</label> </div> <!-- 徽标 --> <span class="badge badge-success badge-pill" v-if="item.done">完成</span> <span class="badge badge-warning badge-pill" v-else>未完成</span> </li> </ul> </div> </template>
4.通过 v-bind 属性绑定,动态切换元素的 class 类名:
<style lang="less" scoped> .list-group { width: 400px; } .delete { text-decoration: line-through; color: gray; font-style: italic; } </style>
<!-- 复选框 --> <div class="custom-control custom-checkbox"> <!-- list 接收的是父组件传递过来的数组的引用 --> <!-- 在子组件修改,父组件中数组中的元素的值会跟着改变 --> <input type="checkbox" class="custom-control-input" :id="item.id" v-model="item.done" > <label class="custom-control-label" :class="item.done ? 'delete' : ''" :for="item.id" >{{item.task}}</label> </div>
7. 封装 todo-input 组件
7.1 创建并注册 TodoInput 组件
1.在 src/components/todo-input/ 目录下新建 TodoInput.vue 组件:
<template> <div> <h1>TodoInput</h1> </div> </template> <script> export default { name: 'TodoInput' } </script> <style lang="less" scoped> </style>
2.在 App.vue 组件中导入并注册 TodoInput.vue 组件:
<template> <div> <h1>App 组件</h1> <hr> <!-- 使用TodoInput组件 --> <todo-input></todo-input> <!-- 使用TodoList组件 --> <todo-list :list="todolist"></todo-list> </div> </template> <script> import TodoList from './components/todo-list/TodoList.vue' import TodoInput from './components/todo-input/TodoInput.vue' export default { name: 'App', data() { return { // 任务列表的数据 todolist: [ { id: 1, task: '周一早晨9点开会', done: false }, { id: 2, task: '周一晚上8点聚餐', done: false }, { id: 3, task: '准备周三上午的演讲稿', done: true }, ] } }, components: { TodoList, TodoInput } } </script> <style lang="less" scoped> </style>
7.2 基于 bootstrap 渲染组件结构
1.根据 bootstrap 提供的 inline-forms(https://v4.bootcss.com/docs/components/forms/#in
line-forms)渲染 TodoInput 组件的基本结构。
2.在 TodoInput 组件中渲染如下的 DOM 结构:
<template> <div> <form class="form-inline"> <div class="input-group mb-2 mr-sm-2"> <div class="input-group-prepend"> <div class="input-group-text">任务</div> </div> <input type="text" class="form-control" placeholder="请输入任务信息"> </div> <button type="submit" class="btn btn-primary mb-2">添加新任务</button> </form> </div> </template> <script> export default { name: 'TodoInput' } </script> <style lang="less" scoped> </style>
7.3 通过自定义事件向外传递数据
1.在 TodoList 组件的 data 中声明如下的数据:
<script> export default { name: 'TodoInput', data() { return { taskname: '' } } } </script>
2.为 input 输入框进行 v-model 的双向数据绑定:
<input type="text" class="form-control" placeholder="请输入任务信息" v-model.trim="taskname" >
3.监听 form 表单的 submit 事件,阻止默认提交行为并指定事件处理函数:
<form class="form-inline" @submit.prevent="onFormSubmit">
4.在 methods 中声明 onFormSubmit 事件处理函数如下:
methods: { // 表单提交的事件处理函数 onFormSubmit() { // 1. 判断任务名称是否为空 if (!this.taskname) return alert('任务名称不能为空!') // 2. 触发自定义的 add 事件,并向外界传递数据 // 3. 清空文本框 } }
5.声明自定义事件如下:
emits: ['add'],
6.进一步完善 onFormSubmit 事件处理函数如下:
emits: ['add'], methods: { // 表单提交的事件处理函数 onFormSubmit() { // 1. 判断任务名称是否为空 if (!this.taskname) return alert('任务名称不能为空!') // 2. 触发自定义的 add 事件,并向外界传递数据 this.$emit( 'add', this.taskname ) // 3. 清空文本框 this.taskname = '' } }