前言
系列文章目录:
老师的课件笔记,不含视频 https://www.aliyundrive.com/s/B8sDe5u56BU
1. 组件化编码流程(通用)
- 实现静态组件:抽取组件,使用组件实现静态页面效果
- 展示动态数据:
- 数据的类型、名称是什么?
- 数据保存在哪个组件?
- 交互——从绑定事件监听开始
2. 页面组件的划分
3. 静态页面代码
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>React App</title> <link rel="stylesheet" href="index.css"> </head> <body> <div id="root"> <div class="todo-container"> <div class="todo-wrap"> <div class="todo-header"> <input type="text" placeholder="请输入你的任务名称,按回车键确认"/> </div> <ul class="todo-main"> <li> <label> <input type="checkbox"/> <span>xxxxx</span> </label> <button class="btn btn-danger" style="display:none">删除</button> </li> <li> <label> <input type="checkbox"/> <span>yyyy</span> </label> <button class="btn btn-danger" style="display:none">删除</button> </li> </ul> <div class="todo-footer"> <label> <input type="checkbox"/> </label> <span> <span>已完成0</span> / 全部2 </span> <button class="btn btn-danger">清除已完成任务</button> </div> </div> </div> </div> </body> </html>
/*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; } /*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); } /*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; } /*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; } /*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; }
4. 静态页面组件化拆分
App.vue
<template> <div class="todo-container"> <div class="todo-wrap"> <TodoAddTask></TodoAddTask> <TodoList></TodoList> <TodoSituation></TodoSituation> </div> </div> </template> <script> // 导入子组件 import TodoAddTask from './components/TodoAddTask.vue' import TodoList from './components/TodoList.vue' import TodoSituation from './components/TodoSituation.vue' export default { name: 'App', components: { TodoAddTask, TodoList, TodoSituation } } </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>
TodoAddTask.vue
<template> <div class="todo-header"> <input type="text" placeholder="请输入你的任务名称,按回车键确认" /> </div> </template> <script> export default { name: 'TodoAddTask' } </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>
TodoList.vue
<template> <ul class="todo-main"> <TodoItem></TodoItem> <TodoItem></TodoItem> <TodoItem></TodoItem> </ul> </template> <script> // 导入子组件 import TodoItem from './TodoItem.vue' export default { name: 'TodoList', components: {TodoItem} } </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>
TodoItem.vue
<template> <li> <label> <input type="checkbox" /> <span>xxxxx</span> </label> <button class="btn btn-danger" style="display:none">删除</button> </li> </template> <script> export default { name: 'TodoItem' } </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; } </style>
TodoSituation.vue
<template> <div class="todo-footer"> <label> <input type="checkbox" /> </label> <span> <span>已完成0</span> / 全部2 </span> <button class="btn btn-danger">清除已完成任务</button> </div> </template> <script> export default { name: 'TodoSituation' } </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>
5. 初始化数据列表
TodoList.vue
<template> <ul class="todo-main"> <TodoItem v-for="todo in todos" :key="todo.id" :todoObj="todo" ></TodoItem> </ul> </template> <script> // 导入子组件 import TodoItem from './TodoItem.vue' export default { name: 'TodoList', components: {TodoItem}, data() { return { todos: [ {id: '001', todo: '吃饭', done: true}, {id: '002', todo: '睡觉', done: false}, {id: '003', todo: '打豆豆', done: true} ] } }, } </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>
TodoItem.vue
<template> <li> <label> <!-- 使用v-bind绑定checked属性,true则有这个属性,false无这个属性 --> <input type="checkbox" :checked="todoObj.done"/> <span>{{todoObj.todo}}</span> </label> <button class="btn btn-danger" style="display:none">删除</button> </li> </template> <script> export default { name: 'TodoItem', props: ['todoObj'] } </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; } </style>