vue实战2知识点回顾
项目背景
该项目是第二个vue实战项目,第一个是跟着gitbook上的vue学习课程一起来的。这个项目呢是跟着从github上找的vue项目一起来的。源项目地址是 https://github.com/liangxiaojuan/vue-todos。
在这个项目中分了好几个阶段来完成:
阶段 | 描述 | 完成度 |
---|---|---|
step1 | 项目需求分析 | 100% |
step2 | 组件撰写、数据模拟和功能初步实现 | 95% |
step3 | css样式化实现,和源项目不同,这里没有用less来实现 | 95% |
step4 | 组件间数据共享实现 | 100% |
step5 | 部分问题解决 | 90% |
step6 | 项目回顾 | 100% |
step7 | 添加github预览项目功能 | 100% |
项目预览
注:这里预览地址采用的是GitHub Pages,而不是GitHub & BitBucket HTML Preview。
项目需求
- 查询所有待办事项,待办单项
- 新增,修改待办事项
- 删除,锁定待办事项
- 新增,修改,删除待办单项
- 未完成的待办单项的计数
箭头函数
api中有不少这样的写法,这个呢实际上是箭头函数表达式的语法。
export const editTodo = params => {
return axios.post(`/todo/editTodo`, params).then(res => res.data)
}
export const editRecord = params => {
return axios.post(`/todo/editRecord`, params).then(res => res.data)
}
箭头函数的语法如下:很明显上面的写法符合单一参数时,园括号是可选的,这里就是没有写。
(参数1, 参数2, …, 参数N) => { 函数声明 }
(参数1, 参数2, …, 参数N) => 表达式(单一)
//相当于:(参数1, 参数2, …, 参数N) =>{ return 表达式; }
// 当只有一个参数时,圆括号是可选的:
(单一参数) => {函数声明}
单一参数 => {函数声明}
// 没有参数的函数应该写成一对圆括号。
() => {函数声明}
所以结合箭头函数的语法来看:
addRecord({id: ID, text: this.text}) 等价于这个:
{id: ID, text: this.text} => {
return axios.post(`/todo/editRecord`, {
id: ID,
text:
// 箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。
// 在ECMAScript 3/5中,通过将this值分配给封闭的变量,可以解决this问题。
this.text}).then(res => res.data)
}
axios
axios是基于Promise的http库,用在浏览器和node.js中。axios常用的是get和post请求。get请求呢可以理解为向服务器发送索取数据的请求,post请求则是向服务器提交数据的请求。get请求中的数据是附在url后面,数据都是明文可见的,所以相对于post请求 没有那么安全。
Promise
Promise就是用来进行异步处理的,替代以前JS的异步处理方式(回调函数)。Promise迷你书
Promise方法链,.then()实际上返回的也是一个Promise对象。而Promise构造函数中resolve和reject参数是默认的,resolve代表着success后调用.then()。
new Promise((resolve, reject) => {
setTimeout(() => {
resolve([200, {
todo: todo
}])
}, 200).then(res => {
let {
id,
title,
count,
isDelete,
locked,
record
} = res.data.todo
...
).then(...)
Vue Router
动态路由匹配: 动态路径参数 以冒号开头。
**嵌套路由: 在 VueRouter 的参数中使用 children 配置。
命名路由: 可以在创建 Router 实例的时候,在 routes 配置中给某个路由设置名称。这样更容易找到该路由。
export default new Router({
routes: [
{
path: '/', // 访问路径
name: 'Layouts', // 路径名
component: Layouts, // 访问的组件,即访问‘/’,它会加载 Layouts 组件所有的内容。
children: [{
path: '/todo/:id',
name: 'todo',
component: todo
}]
}
]
})
编程式导航: 导航到指定的 URL,这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。
//等价于 声明式: <router-link :to="...">
this.$router.push({name: 'todo', params: {id: id}})
Vuex
vuex的核心就是store。store可以看作是一个仓库,里面包含着应用中大部分的state。
- vuex的状态存储是响应式的。若store中的state发生了变化,那么相应的组件也会相应地得到高效更新。
- store中的state不能直接更改,必须通过mutations。
下面的这段代码,vuex主要包含如下字段:state、mutations、getters和actions。
Vue.use(Vuex)
// 创建初始应用全局状态变量
const state = {
todoList: [], // 指我们的待办事项列表数据
menuOpen: false // 移动端的时候菜单是否开启
}
// 定义所需的 mutations
const mutations = {
EDITTODE (state, data) { // 定义名为 EDITTODE函数用作改变todoList的值
state.todoList = data
},
MENUOPEN (state) { // 定义名为 MENUOPEN函数用作改变menuOpen的值
state.menuOpen = !state.menuOpen
}
}
// 创建 store 实例并且导出
export default new Vuex.Store({
actions,
getters,
state,
mutations
})
state不用多说,包含应用全局状态变量。
提交 mutations是更改state的唯一方法,比如:
commit('EDITTODE', res.data.todos)
// type: EDITTODE
// state作为第一参数,data作为mutations的载荷,是可选参数
EDITTODE (state, data) {
state.todoList = data
},
gettters呢是从store中的state中派生出来的内容。比如下面的这段代码中要获取state中的todoList变量,直接调用getTodoList接口即可。
// 调用方式
this.$store.getters.getTodoList
export const getTodoList = state => {
// 派生状态todoList
return state.todoList
}
actions类似于mutations,差异在于:
- 它提交的是mutation,而不是直接变更状态。
- actions可以包含任意异步操作。
// 调用方式
this.$store.dispatch('getTodo').then(
export const getTodo = ({commit}) => {
return new Promise((resolve) => {
getTodoList().then(res => {
commit('EDITTODE', res.data.todos)
resolve()
})
})
}
Mock
下面这段代码是利用Mock框架生成的模拟的数据。具体的语法可以参考wiki: https://github.com/nuysoft/Mock/wiki
Mock.mock({ // 根据数据模板生成模拟数据。
id: Mock.Random.guid(), // 随机生成一个 GUID
title: Mock.Random.first(), // 随机生成一个常见的英文名。
isDelete: false, // 是否删除
locked: Mock.Random.boolean(), // 随机锁定
record: COUNT.map(() => { // 代办单项列表的数据
return {
text: Mock.Random.cparagraph(2), // 随机内容
isDelete: false, // 是否删除
checked: Mock.Random.boolean() // 是否完成
}
})
})
光有Mock生成的数据还是无法工作的,需要想办法和axios关联起来,所以axios-mock-adapter 就来了。
下面部分的代码就有模拟get和post请求的。具体的语法可以参考npm对应包里面的注释。
get和post请求的回复 reply函数,它的参数格式是这样的:[status, data, headers],reply允许返回一个promise对象。
let mock = new MockAdapter(axios)
// 对应 axios.get(`/todo/listId`, { params: params})
mock.onGet('/todo/listId').reply(config => {
let {
id
} = config.params
// id 是传进来的值
// todo 是根据id和现有的Todos数据匹配,找出id相等的数据,在进行返回
let todo = Todos.find(todo => {
return id && todo.id === id
})
// todo.count (等待完成数目)等于 todo.record(代办事项列表下面未被选择的数据
todo.count = todo.record.filter((data) => {
return data.checked === false
}).length
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve([200, {
todo: todo
}])
}, 200)
})
})
// 对应 axios.post(`/todo/editTodo`, params).then(res => res.data)
mock.onPost('/todo/editTodo').reply(config => {
let {
todo
} = JSON.parse(config.data)
Todos.some((t, index) => {
if (t.id === todo.id) {
t.title = todo.title
t.locked = todo.locked
t.isDelete = todo.isDelete
return true
}
})
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve([200])
}, 200)
})
})