用于存储数据,这个对象用来存储状态,数据的,state是Vuex中唯一的数据源,因此其他所有获取数据的方式都是从state中获取的数据,提交,修改也是将数据提交,修改state中对应的数据;
computed: {
count () {
return this.$store.state.count
}
}
辅助函数mapState
辅助函数mapState可以再不影响功能的前提下减少写的代码量
import { mapState } from ‘vuex’
computed: {
…mapState({
count2:state => state.count
})
}
通过展开运算符直接将state中的count属性取出来,之后通过count2可以使用了,假如我们命名的计算属性名和state中的对象名是完全相同的,比如下例
import { mapState } from ‘vuex’
computed: {
…mapState({
count:state => state.count
})
}
计算属性中的属性名和state中的属性名都是count,那么就可以再简写一步
import { mapState } from ‘vuex’
computed: {
…mapState([‘count’])
}
getters
有时候需要从state中获取的数据是需要经过转换过滤的,那么就可以将过滤的逻辑写在getters中
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: ‘…’, done: true },
{ id: 2, text: ‘…’, done: false }
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
}
}
})
获取数据的时候就不再是从state中获取了,就可以直接从getters中获取筛选后的数据
computed: {
count () {
return this.$store.getters.doneTodos
}
}
辅助函数mapGetters
用法和mapState基本一致,下例是计算属性的属性名和getters中的某各属性名完全相同时可以直接写
import { mapGetters } from ‘vuex’
export default {
// …
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
…mapGetters([
‘doneTodosCount’,
‘anotherGetter’,
// …
])
}
}
上面是最简写的方式,将store中的getter映射到了计算属性
mutations
修改数据,只能包含同步操作的。更改Vuex的store中数据的唯一方法,就是提交mutation,使用方式接近事件
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 获取state中的count,并且自增1
state.count++
}
}
})
使用这个mutation并不是直接调用函数,而是通过store.commit调用,比如
//调用store中的中的mutatins,increment
this.$store.commit(‘increment’)
假如有多个参数,那么
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state,num) {
state.count += num
}
}
})
使用的时候就需要多传入一个或者多个参数
//调用store中的中的mutatins,increment
this.$store.commit(‘increment’,10)
辅助函数mapMutations
使用其实是差不多的
import { mapMutations } from ‘vuex’
export default {
// …
computed: {
// 使用对象展开运算符将 mapMutations中的指定事件获取到
…mapMutations([
‘doneTodosCount’,
‘anotherGetter’,
// …
])
}
}
**
Actions
异步操作。因为mutations仅仅是同步操作,如果有时候是异步操作的,那么就可以使用actions,另外注意,actions并不是直接修改store中的数据,而是通过mutations提交的
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
//在actions中调用mutations提交数据到state中
context.commit(‘increment’)
}
}
})
在组件中使用actions和mutations类似,区别在于:mutations通过commit提交,而actions通过dispatch调用
this.$store.dispatch(‘increment’)
还有一个区别就是Actions可以包含任意异步代码,而mutations则不行
actions: {
incrementAsync ({ commit }) {
//通过解构获取到context中的commit对象,并直接通过commit调用mutations中的对应事件
setTimeout(() => {
commit(‘increment’)
}, 1000)
}
}
辅助函数mapActions
使用方式还是差不多
import { mapActions } from ‘vuex’
export default {
// …
computed: {
// 使用对象展开运算符将 mapActions中的指定事件获取到
…mapActions([
‘doneTodosCount’,
‘anotherGetter’,
// …
])
}
}
modules
开发大型项目时,store对象就会变得非常臃肿,为了解决这个问题,Vuex允许将store分割成多个模块,每个模块可以拥有自己的state,getters,mutations,actions,甚至可以再对子模块进行更进一步的分割
const moduleB = {
state: { … },
mutations: { … },
actions: { … }
}
import moduleA from ‘xxx’
import moduleB from ‘xxx’
const store = new Vuex.Store({
modules: {
moduleA,
moduleB
}
})
moduleA内部
export default {
state: { … },
mutations: { … },
actions: { … },
getters: { … }
}
moduleB内部
const state = {};
const mutations = {};
const getters = {};
const actions = {};
export default {
state,
mutations,
actions,
getters
}
模块做的就是分割,方便对于store仓库的管理,使用的方式分割和不分割是完全一致的,该怎么用;
简介
简单的说,Vue Router是Vue官方推出的路由管理器,它和Vue深度集成,可以很好的管理路由
安装与使用
初始化项目时会有选择是否安装Vue-router,如果初始化时未安装,那么之后再安装需要输入命令
//当然,如果方便的话使用cnpm代替npm
npm install vue-router
//全局使用的话必须通过Vue.use()安装
import Vue form ‘vue’;
import VueRouter from ‘vue-router’;
Vue.use(VueRouter)
起步
首先得明确,路由的使用离不开:输入和输出,无论是通过使用方法还是通过组件,都是要告诉Vue,需要跳转的路径是哪一个,之后路径对应的组件将有一个输出的位置,或者说路径对应的组件要有一个显示的位置,,下面是一个简单的示例
Hello App!
Go to Foo
Go to Bar
// 0. 如果使用模块化机制编程,导入Vue和VueRouter,要调用 Vue.use(VueRouter)
// 1. 定义 (路由) 组件。
// 可以从其他文件 import 进来
const Foo = { template: ‘
const Bar = { template: ‘
// 2. 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
const routes = [
{ path: ‘/foo’, component: Foo },
{ path: ‘/bar’, component: Bar }
]
// 3. 创建 router 实例,然后传 routes
配置
const router = new VueRouter({
routes // (缩写) 相当于 routes: routes
})
点击之后,将显示属性to中的路径,路径对应的组件就是下面定义的组件
动态路由
我们经常需要把某种匹配到的所有路由,全部映射到同一个组件中(比如:user组件,针对不同的ID,虽然加载的是同一个组件,但是内容却是不一样的),因此可以在vue-router的路由路径中使用“动态路由参数”(在路径中以冒号开头)来达到这个效果
var router = new VueRouter({
routers:[
{
//动态路径参数,以冒号开头
path:‘/user/:id’,
component:User
}
]
})
这样当路径匹配到的是:/user/具体的id,可以在组件User中获取到具体的id的值,之后向服务器请求当前id的具体内容,注意的是,如果切换不同id值,比如路径:/user/1 和 /user/2 这两个路径都会调用组件User,此时变化的仅仅是路由的参数,而组件是不会被销毁再创建的,因此也就代表组件的生命周期钩子函数不会被再次调用;如果想要有响应式的变化操作,可以使用导航守卫(此功能下面讲)
嵌套路由(敲黑板,重点)
实际的项目开发的应用界面,通常由多层嵌套的组件组合而成。同样的,URL中各段动态路径也按某种结构对应嵌套的各层组件。
举个后台的列子:实际开发中,登录页,注册页,主页等这是最顶层路由,在主页上有一个侧边导航栏,有一个侧边导航栏对应内容显示区域,这个时候的内容的跳转实际上就在对应的是在主页上进行子路由的跳转;
div id=‘app’>
var router = new VueRouter({
routers:[
{
//动态路径参数,以冒号开头
path:‘/user/:id’,
component:User,
children:[
{
path:‘/userMsg’,
component:() => import(‘@/views/Home/users/UserManager.vue’)
},
{
path:‘/userLog’,
component:() => import(‘@/views/Home/users/UserLog.vue’)
}
]
}
]
})
示例的代码是最高级的顶层出口,这个渲染的是最顶层路由匹配到的组件,同样的,假如被渲染的组件内同样包含自己的那么在路由配置中需要添加children属性来指定子路由的匹配;
换句话说,比如下例中的User组件中也包含了一个,当路由匹配到的路径是/userMsg和/userLog时,那么这两个组件的内容就会被渲染到User组件中的里;
编程式导航
先说一下,这个标签是vue官方提供的一个组件,其本质是标签,在这个标签上有一个属性to,当用户点击标签时,这个组件会在内部使用router.push()这个方法
router.push()
当使用router.push()的时候,这个方法会向history栈添加一个新纪录,因此当点击浏览器的后退按钮时,则回到之前的URL
//将路由路径跳转到/home,是一种简写
router.push('home);
//等同于上一种,将路由路径跳转到/home
router.push({path:‘home’});
//命名路由,params是post传参方式
router.push({ name: ‘user’, params: { userId: ‘123’ }});
// 带查询参数,变成 /register?plan=private,query是get的传参方式
router.push({ path: ‘register’, query: { plan: ‘private’ }})
router.replace()
用法和push()几乎一样,唯一的不同点就是它不会向history添加新纪录,而是跟它的方法名一样,替换掉当前的history记录,如果要在router-link上使用则需要加上replace属性;
**
router.go(n)
参数n是一个整数,意思是在当前的history记录中向前或者后退多少步
//返回上一个界面
router.go(-1)
//进入下一个界面
router.go(1)
命名路由
有时候,通过一个名称来标识一个路由显得更方便些,可以通过方法进行路由地址进行跳转或者通过
const router = new VueRouter({
routes: [
{
path: ‘/user/:userId’,
name: ‘user’,
component: User
}
]
})
//通过参数重的name属性进行关联,当点击router-link的时候,根据name属性的值匹配到User组件,params是参数,会将123传递给动态路由
User
//等同于的方式
router.push({ name: ‘user’, params: { userId: 123 }})
这两种方式都会将路由路径导航到/user/123
命名视图
有时候在一个界面里,也就是同级中会有多个渲染的出口,也就是由多个同级的,这个时候就需要命名视图了,如果没有命名,那么router-view将默认命名为default
比如,在首页里,有两个输出的router-view,分别加载了不同的组件,这个时候就需要通过给视图命名,来告诉vue,哪个组件对应哪个router-view了
const router = new VueRouter({
routes: [
{
path: ‘/’,
components: {
//因为上面有3个router-view,因此在这个路由地址打开的时候,需要对三个router-view,分别渲染指定的组件
default: Foo,
a: Bar,
b: Baz
}
}
]
})
注意,这里是components,而不是component。
重定向和别名
重定向
重定向的意思就是比如,当路径导航到/a时,vue会自动把路径/a **替换 **成/b,然后回去匹配路径/b,而不再是/a;
举个后台例子,侧边导航栏中有一个下拉菜单,每个主菜单下都有几个副菜单,现在要求是,点击主菜单的时候,自动显示的是主菜单下第一个子菜单对应的组件,这种时候就需要用到重定向了
const router = new VueRouter({
routes: [
{ path: ‘/a’, redirect: ‘/b’ }
]
})
//当然,重定向也可以是一个命名路由
const router = new VueRouter({
routes: [
{ path: ‘/a’, redirect: {name:'foo} }
]
})
//甚至是一个方法
const router = new VueRouter({
routes: [
{ path: ‘/a’, redirect: to => {
// 方法接收 目标路由 作为参数
// return 重定向的 字符串路径/路径对象
}}
]
})
别名
最后
推荐一些系统学习的途径和方法。
每个Web开发人员必备,很权威很齐全的Web开发文档。作为学习辞典使用,可以查询到每个概念、方法、属性的详细解释,注意使用英文关键字搜索。里面的一些 HTML,CSS,HTTP 技术教程也相当不错。
HTML 和 CSS: