开始第一步
components文件夹里新建五个vue文件
- header.vue//头部组件 也就是图中的jtodo这个几个字
- footer.vue//底部组件,就是下面的 ‘written by 懒人漫游’
- todo.vue // 整个todo应用
- tabs.vue //列表,这个是循环出来的
- item.vue //按钮的功能
App.vue:注册组件
注意:由于只是演示代码,所以是在app里注册,正确的应该是通过路由注册,写在 router/index.js这个文件里
子组件注册:这个写在todo.vue里
正式开始写代码
先来todo.vue
<section class="real-app">
<input
type="text"
class="add-input"
autofocus="autofocus"
placeholder="接下来做什么"
@keyup.enter="addTodo"
>
<Item/>
<Tabs/>
</section>
<script>
import Item from './item.vue'
import Tabs from './tabs.vue'
import '../assets/styles/todo.styl'
let id = 0
export default {
data() {
return {
todos:{
id:0,
content:'this is todo',
completed:false
},
filter:"all"
}
},
components: {
Item,
Tabs
},
computed:{
filteredTodos(){
},
},
methods: {
addTodo(e){
},
deleteTodo(id){
},
toggleFilter(state){
},
clearAllCompleted(){
}
},
}
</script>
autofocus="autofocus" 一进来自动选中输入框
@keyup.enter="addTodo" 等同与v-on:key="addTodo"
.enter是修饰符,注意是 '.enter' !,监听键盘事件,回车是enter,
现在来写item.vue
<div :class="['todo-item',todo.completed ? 'completed' :'' ]">
<input
type="checkbox"
class="toggle"
v-model="todo.completed"
>
<label> {{todo.content}}</label>
<button class="destroy" @click="deletetodo"> </button>
</div>
<script>
export default {
props: {
todo: {
type: Object,
required: true
}
},
methods : {
deletetodo(){
}
}
}
</script>
:class="['todo-item',todo.completed ? 'completed' :'' ]" class的动态写法
v-model="todo.completed" //双向数据绑定
<label> {{todo.content}}</label>// 就是你写入的todo的内容
<button class="destroy" @click="deletetodo"> </button>//后面删除按钮
props:通过 Prop 向子组件传递数据,todo相对于item.vue来说是父组件,所以用props来传递数据
$emit 方法并传入事件的名字,来向父级组件触发一个事件
@click="deletetodo"是简写,deletetodo事件函数名
<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>
<!-- 缩写 -->
<a @click="doSomething">...</a>
现在来写tabs.vue
<div class="helper">
<span class="left">2 items left</span>
<span class="tabs">
<span
v-for="state in states"
:key="state"
:class="[state,filter === state ? 'actived' :'']"
@click="toggleFilter(state)"
>
{{state}}
</span>
</span>
<span class="clear" @click="clearAllCompleted()">
Clear completed
</span>
</div>
<script>
export default {
props:{
filter:{
type:String,
required:true,
},
todos: {
type:Array,
required: true,
}
},
data(){
return {
states:['all','active','completed']
}
},
methods:{
toggleFilter(state){
},
clearAllCompleted(){
}
}
}
</script>
这个组件主要就是
:class="[state,filter === state ? 'actived' :'']"能不能看懂
给class设置两个类名,如果filter === state,class ="state actived"
否则就是class ="state",这个和jquery一样,动态添加'active'
v-for="state in states"
:key="state"
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用 “就地复用” 策略。如果数据项的顺序被改变,Vue将不是移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。这个类似 Vue 1.x 的 track-by="$index" 。
这个默认的模式是有效的,但是只适用于不依赖子组件状态或临时 DOM 状态(例如:表单输入值)的列表渲染输出。
:key 总的来说就是,可以提高性能
当你写完的时候,页面是这个样子(css部分请到时候查看源码)
开始第二步:实现业务逻辑
todo.vue
<script>
import Item from './item.vue'
import Tabs from './tabs.vue'
import '../assets/styles/todo.styl'
let id = 0
export default {
data() {
return {
todos:[],
filter:"all"
}
},
components: {
Item,
Tabs
},
computed:{
filteredTodos(){
if (this.filter === 'all'){
return this.todos
}
const completed = this.filter === 'completed'
return this.todos.filter(todo => completed ===todo.completed)
},
},
methods: {
addTodo(e){
if(e.target.value==''){
alert("你什么都没有添加!")
}
else{
this.todos.unshift({
id:id++,
content: e.target.value.trim(),
completed:false
}),
e.target.value =''
}
},
deleteTodo(id){
// console.log(todo => todo.id ===id);
this.todos.splice(this.todos.findIndex(todo => todo.id ===id),1)
},
toggleFilter(state){
this.filter =state
},
clearAllCompleted(){
this.todos = this.todos.filter(todo => !todo.completed)
}
},
}
</script>
- data()里的todos要改成空数组,在增加的时候,添加进去就可以了
- 改写<Item/> <Tabs/>
<Item
:todo="todo"
v-for="todo in filteredTodos"
:key="todo.id"
@del="deleteTodo"
></Item>
<Tabs
:filter="filter"
:todos="todos"
@toggle="toggleFilter"
@clearAll="clearAllCompleted"
></Tabs>
@del="deleteTodo"是子组件传过来的,写在父组件的好处是方便解耦。
实现addTodo(e),在todo列表的最上面添加todo,id从0开始,每次添加,id++,内容就是每次input输入的值然后去掉空格,完了之后要把input的内容清空,所以是e.target.value =''
删除deleteTodo(id),找到对应的下标,删除一个
切换状态toggleFilter(state) :
this.filter =state
- 清除完成的clearAllCompleted():
this.todos = this.todos.filter(todo => !todo.completed)
然后实现items.vue的业务逻辑
methods : {
deletetodo(){
this.$emit("del",this.todo.id);
}
}
最后是tabs.vue的
computed: {
unFinishedTodoLength() { //计算left的items的长度
return (this.todos.filter(todo => !todo.completed).length)
}
},
data() {
return {
states: ['all', 'active', 'completed']
}
},
methods: {
toggleFilter(state) {
this.$emit('toggle', state)
},
clearAllCompleted() {
this.$emit('clearAll')
}
}
把html部分改写下,动态显示未完成的数字显示
<span class="left">{{unFinishedTodoLength}} items left</span>
写完todo应用之后对组件注册,事件处理函数,vue的相关指令,父子组件的通信有了进一步的了解,对vue使用有了更多的经验