这几天参加了腾讯课堂的IMWeb训练营加薪课程,学习了Vue的相关知识,现在我来谈谈这几天的收获吧。。。
前言
Vue是一个现在比较流行的基于MVVM的渐进式框架,作者是尤雨溪大大!何谓渐进式?就是说Vue.js的核心库只关注视图层,也就是ViewModel这一层,这样Vue.js的核心库就会很小,然后如果你还需要其他功能,再根据功能需求加上不同的功能就是。在它官网首页有一句话已经很好地介绍了vue,“数据驱动的组件,为现代化的 Web 界面而生”, 其核心思想就是响应的数据绑定和组合的试图组件。
现在前端比较流行的MVVM框架有三个,Angular,React,Vue,我为什么要选择Vue来学习呢?其一,相对于其他两个来说,Vue体积小,比较轻量;其二就是Vue的学习曲线比较平缓,没有另外两个陡峭,学习Angular要对typeScript有所了解,而React就更不用说了,全家桶。。。所有我想都没有想,就是他了,Vue!!!刚好准备学习Vue的时候,看到了腾讯课堂的十天前端加薪Vue课程,我就立即报名了。
回归正题,现在我来谈一下这次的个人作业,根据这几天的课程老师的讲解,做一个todolist,来看一下最终运行效果图。。。
核心代码
这个页面的样式我是参考了todoMVC网站的样式。当然这个作业重点是Vue部分,所以代码HTML部分就不贴出来了,下面是这个作业的核心代码
var store = {
save(key, value) {
localStorage.setItem(key, JSON.stringify(value));
},
fetch(key) {
return JSON.parse(localStorage.getItem(key)) || [];
}
};
var list = store.fetch('newTodoClass');
var vm = new Vue({
el: "#todoapp",
data: {
list: list,
todo: '',
edtorTodos: '',
beforeTitle: '',
visibility: 'all'
},
watch: {
list: {
handler() {
store.save('newTodoClass', this.list);
},
deep: true
}
},
methods: {
addTodo() {
this.list.push({
title: this.todo,
isChecked: false
});
this.todo = '';
},
deleteTodo(todo) {
var index = this.list.indexOf(todo);
this.list.splice(index, 1);
},
edtorTodo(todo) {
this.edtorTodos = todo;
this.beforeTitle = todo.title;
},
edtorTodoed(todo) {
this.edtorTodos = '';
},
cancelTodo(todo) {
todo.title = this.beforeTitle;
this.edtorTodos = '';
}
},
directives: {
"focus": {
update(el, binding) {
if (binding.value) {
el.focus();
}
}
}
},
computed: {
completed() {
return this.list.filter(function(item) {
return !item.isChecked;
}).length;
},
filteredList() {
var filter = {
all(list) {
return list
},
finished(list) {
return list.filter(function(item) {
return item.isChecked
})
},
unfinished(list) {
return list.filter(function(item) {
return !item.isChecked
})
}
}
return filter[this.visibility] ? filter[this.visibility](list) : list
}
}
});
function watchHashChange() {
var hash = window.location.hash.slice(1);
vm.visibility = hash;
};
watchHashChange();
window.addEventListener('hashchange', watchHashChange);
功能实现思路
我来大致讲解一下这个功能的实现吧,html部分会通过vue的v-for指令渲染todos列表,这个列表相对应的内容已经在js代码中定义的list数组中存储了。
如何增加一条新的任务呢?
我们可以来理清一下思路:
- 首先我们需要通过在最上面的输入框里面输入文本,列表内容
然后再按下回车键,或者这个输入框失去焦点时,就会在下面的todos列表中加入一行任务,状态默认是未完成的,这个状态是通过data数据里的isChecked来控制的。这部分的功能可以在Vue的实例中增加一个methods的属性,所以的方法都放在这里面。 - 然后我们在methods属性增加一个addTodo的方法,可以通过v-on来绑定时间。这个方法作用就是当函数触发时,我们会向list数组中插入一条数据,也就是一个对象,然后把输入框清空,注意这个push方法不是我们所熟知的js数组中的push方法,除了push,还有很多方法都是这样的,虽然名字和方法是类似的,但是vue的push方法是已经重写了的,希望大家不要搞混!
addTodo() {
this.list.push({
title: this.todo,
isChecked: false
});
this.todo = '';
}
title对应的值是通过v-model来绑定到输入框的,这就是双向数据绑定。
删除任务
删除一条任务也就是类似的道理了,直接定义一个delete方法,传入的参数是对应的那个任务item,找到这条任务在list对应的索引值,然后从数组中删除。
双击修改任务
另外一个功能就是双击任务,可以改变任务名称,也就是title的值,通过@dblclick绑定edtorTodo事件,定义了一个edtorTodos来记录修改的状态,在todo列表的父元素上绑定一个editing的class,通过这个class来改变任务列表和相对应的修改这个title的输入框的隐藏与显示,也是通过v-model绑定了item.title才能修改相对应任务的名称。
之后就是如果在修改的时候不想修改了,应该如何取消?
1. 定义一个beforeTitle,在修改之前把这个任务列表的title值赋给 beforeTitle;
2. 然后通过@keyup.esc绑定cancelTodo事件,把beforeTitle的值又传回给任务列表的title,并退出编辑;
而显示还有多少个任务未完成是通过Vue的计算属性completed来动态计算出list数组个每个项目里isChecked为false的项目个数,这个应该很简单,相信大家都能明白。
按钮控制不同状态任务列表的显示
然后我们怎么实现在点击对应的按钮后,显示对应状态的任务列表呢?比如点击未完成时,任务列表就只会渲染出isChecked为false的item,这个可以用到hash值
- 我们可以给window对象通过addEventListener绑定一个 hashchange事件,回调函数就是获得这个hash值,然后把这个hash值赋给Vue实例中的visibility属性,这个visibility默认是全部显示的。
- 通过一个计算属性filteredList来根据visibility的值动态返回不同的状态的list,然后html中v-for指令就不是直接渲染list了,而是通过这个filteredList筛选出来的list,如果在输错hash值的情况下,我们可以判断hash不存在的情况下,全都返回hash值为all的结果,这样就达到了我们想要的效果了。
实现上诉所说的功能之后,这个todos应该完成的差不多了,现在就差临门一脚,我们要怎么实现在刷新页面之后,这个todos的列表还在呢?换句话说,我们怎么把这个list存储下来呢?谈到存储,相信大家第一时间会想到locaStorage,下面我们就来实现这个功能
- 我们定义一个store的对象,里面有两个方法save和fetch,也就是通过 locaStorage.setItem设置存储和 locaStorage.getItem读取存储,这个大家应该都懂,就不多说了。
- 我们把list就不设置死了,把获取的本地存储的值赋给list,这样list就能在刷新页面后依然能取到之前的存储下来的list数组,那么我们应该在什么时候把list存储下来呢?如果在上面的各个有改动list的方法中,都去设置store的存储方法,未免比较繁杂,有没有一个属性可能让我们监听到list的变化呢?Vue中提供了一个watch的属性,用过浏览器开发者工具js断点调试的应该知道有个watch的东西吧,这个就是差不多的作用。
- 我们在Vue实例中定义一个watch的属性,监听list数据的变化,其中如果自定义一个监听函数,虽然可以监听到list表层的变化,但是对于list数组各个项里的数据变化就监听不到了,所以我们还需在watch中定义一个deep的属性,把它设置为true,这样就可以了。
最后的最后
这几天一直都比较上心,早上起不来的时候想起来还要签到,逼着自己爬起来。。。九点开始看课程的录播视频,然后跟着老师的思路自己敲一遍代码,目前来看,大致还是能听懂的,而这篇博文就是这几天的成果了,希望之后自己能更上一层楼,到时候毕业设计就可以用Vue实现了,想一想就有点小激动呢。。。加油,努力!!!梦想会实现的,技术会提升的,工作会找到的!