Vue.js的todolist案例(之一)添加&勾选&删除等
饮水思源:https://www.bilibili.com/video/BV1Zy4y1K7SH?p=70
①划分组件,使用组件实现静态页面的效果。
MyHeader.vue:
<template> template> <script> export default { name: 'MyHeader', } script> <style scoped> style>
②把组件导入App。假设已经有非组件的静态页面。
App.vue:
<template> <div> <input type="text" placeholder="输入任务,按回车确认" /> <ul> <li> <label> <input type="checkbox" /> <span>xxxsspan> label> <button>删除button> li> <li> <label> <input type="checkbox" /> <span>xxxsspan> label> <button>删除button> li> ul> <div> <label> <input type="checkbox" /> label> <span> <span>已完成0span> / 全部2 span> <button>清楚已完成项目button> div> div> template> <script> // import MyHeader from './components/MyHeader.vue' // import MyFooter from './components/MyFooter.vue' // import MyList from './components/MyList.vue' // import MyItem from './components/MyItem.vue' export default { name: 'App', components: { } } script> <style> style>
③在维持静态页面正常显示的情况下,把html和css分发到各个.vue文件中去。
App.vue:
<template> <div> <MyHeader /> <MyList /> <MyFooter /> div> template> <script> import MyHeader from './components/MyHeader.vue' import MyList from './components/MyList.vue' import MyFooter from './components/MyFooter.vue' // import MyItem from './components/MyItem.vue' export default { name: 'App', components: { MyHeader, MyList, MyFooter, } } script> <style> style>
④安装nanoid(一个用于生成id的库)
cnpm i nanoid
⑤动态展示数据,暂时把数据放在MyList(初始化列表,内存List转化为页面List)
MyList.vue:
<template> <ul> <MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj" /> ul> template> <script> import MyItem from './MyItem.vue' export default { name: 'MyList', components: { MyItem, }, data() { return { todos: [ {id: '001', title: '吃饭', done: true}, {id: '002', title: '喝水', done: false}, {id: '003', title: '睡觉', done: true}, ], } }, } script> <style scoped> style>
MyItem.vue:
<template> <li> <label> <input type="checkbox" :checked="todo.done"/> <span>{{todo.title}}span> label> <button>删除button> li> template> <script> export default { name: 'MyItem', props: ['todo'] } script> <style scoped> style>
⑥动态添加列表元素。
通过MyHeader.vue添加元素,但是有个问题,组件之间是兄弟关系,而不是父子关系,已知的知识没法传递数据。
MyHeader.vue:
<template> <input type="text" placeholder="输入任务,按回车确认" @keyup.enter="addItem"/> template> <script> import {nanoid} from 'nanoid' export default { name: 'MyHeader', methods: { addItem(e) { const todoObj = { id: nanoid(), title: e.target.value, done: false, } console.log(todoObj) }, }, } script> <style scoped> style>
解决办法:子组件向父组件传递——把List放在App(父)上,App(父)给MyHeader(子)传递一个向List添加元素的方法,MyHeader调用给方法实现传递。App(父)再通过MyList的props向其传递列表。
修改MyList.vue(感觉props有点类似于java中的构造器参数):
<template> <ul> <MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj" /> ul> template> <script> import MyItem from './MyItem.vue' export default { name: 'MyList', components: { MyItem, }, props: ['todos'], } script> <style scoped> style>
修改MyHeader.vue:
<template> <input type="text" placeholder="输入任务,按回车确认" @keyup.enter="addItem"/> template> <script> import {nanoid} from 'nanoid' export default { name: 'MyHeader', props: ['appAddItem'], methods: { addItem(e) { const todoObj = { id: nanoid(), title: e.target.value, done: false, } this.appAddItem(todoObj) }, }, } script> <style scoped> style>
修改App.vue:
<template> <div> <MyHeader :appAddItem="appAddItem" /> <MyList :todos="todos" /> <MyFooter /> div> template> <script> import MyHeader from './components/MyHeader.vue' import MyList from './components/MyList.vue' import MyFooter from './components/MyFooter.vue' export default { name: 'App', data() { return { todos: [ {id: '001', title: '吃饭', done: true}, {id: '002', title: '喝水', done: false}, {id: '003', title: '睡觉', done: true}, ], } }, methods: { appAddItem(x) { this.todos.unshift(x); } }, components: { MyHeader, MyList, MyFooter, } } script> <style> style>
⑦勾选后改变数据
MyItem.vue办法一:
<template> <li> <label> <input type="checkbox" :checked="todo.done" @click="handleClick(todo)" /> <span>{{todo.title}}span> label> <button>删除button> li> template> <script> export default { name: 'MyItem', props: ['todo'], methods: { handleClick(todo) { todo.done = !todo.done }, }, } script> <style scoped> style>
办法二:
<template> <li> <label> <input type="checkbox" v-model="todo.done" /> <span>{{todo.title}}span> label> <button>删除button> li> template> <script> export default { name: 'MyItem', props: ['todo'], } script> <style scoped> style>
教程貌似不太建议上面的两种方法(修改了props,违反原则?)。而采用,父向子传递方法的办法。
⑧实现删除
从MyItem.vue开始实现(用css实现视觉效果):
<template> <li> <label> <input type="checkbox" v-model="todo.done" /> <span>{{todo.title}}span> label> <button @click="handleRemove(todo.id)">删除button> li> template> <script> export default { name: 'MyItem', props: ['todo', 'appRemoveTodo'], methods: { handleRemove(id) { // console.log(id); this.appRemoveTodo(id) } }, } script> <style scoped> li:hover { background-color: aquamarine; } li button { display: none; } li:hover button { display: block; } style>
途经MyList.vue传递方法:
<template> <ul> <MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj" :appRemoveTodo="appRemoveTodo"/> ul> template> <script> import MyItem from './MyItem.vue' export default { name: 'MyList', components: { MyItem, }, props: ['todos', 'appRemoveTodo'], } script> <style scoped> style>
通过App实现这个方法,修改todos:
<template> <div> <MyHeader :appAddItem="appAddItem" /> <MyList :todos="todos" :appRemoveTodo="appRemoveTodo" /> <MyFooter /> div> template> <script> import MyHeader from './components/MyHeader.vue' import MyList from './components/MyList.vue' import MyFooter from './components/MyFooter.vue' export default { name: 'App', data() { return { todos: [ {id: '001', title: '吃饭', done: true}, {id: '002', title: '喝水', done: false}, {id: '003', title: '睡觉', done: true}, ], } }, methods: { appAddItem(x) { this.todos.unshift(x); }, appRemoveTodo(todoId) { this.todos = this.todos.filter(todo => todo.id !== todoId); }, }, components: { MyHeader, MyList, MyFooter, } } script> <style> style>