一、添加columnDetail 页面
首页有专栏列表(ColumnList组件),专栏列表中有很多专栏,然后点击某个专栏就进入专栏详情页(ColumnDetail组件),专栏详情页中有很多文章,点击某个文章就进入文章详情页()这样子
数据我们是设计成什么样子呢,如下
testData是专栏数据,testPosts是文章数据,就是每个专栏里面都对应着它们相对应的文章们,它们是怎么联系起来的呢也就是说怎么知道这个文章是哪个专栏里的呢?通过文章中的columnId=专栏中的id,则说明这个文章是这个专栏的。
那url中参数怎么与专栏和文章联系起来呢,我们之前做路由跳转的时候跳转到columnDetail专栏详情页的时候不是做了动态路由嘛,通过加:id,到时候url中我们通过在url的column/后加2,那么它就会跳转到query中id为2的数据页面中。所以我们url中这个参数我们让它等于专栏的id,即url中这个参数是2时,则让它是id为2的专栏。
所以当url中该参数为2时,则找出专栏中id为2的数据,因为专栏详情页中需要展示出该专栏下的文章,所以还需要获取这个专栏下的文章们,而专栏和文章是以专栏id(和url那个id其实是相等了) = 文章columnId,即过滤出columnId等于2的即可找出这个专栏下的文章了
如下
数据获取到了,然后专栏详情页中不是有文章们嘛,就建个PostList组件,专门放该专栏详情页下的文章列表
二、vuex
1、什么是状态管理工具
我们现在有3个页面了,分别是首页、登录页、专栏详情页,这三个页面中都有一些共同的数据需要获取和处理,现在我们的做法是把这些共用的数据都保存在一个全局的js对象中
全局对象的弊端:
·数据不是响应式的
·数据修改无法追踪
·不符合组件开发的原则
状态管理工具的基本原则:
·一个类似object 的全局数据结构 - 称为store (里面的数据是不能随便更改的,只能通过action修改)
·只能调用一些特殊的方法来实现数据修改(所以store中的数据变化是可追溯可控制的)
2、vuex 简介 和 安装
单向数据流理念,state决定了view长什么样,view上可以通过actions方法修改state
但是,当多个组件共享状态时,单向数据流就容易被破坏。
vuex的核心是store,store就像一个仓库,store包含应用中大多数状态(state)
vuex的特点:
·状态存储是响应式的
·不能直接改变store中的状态,唯一途径就是显式地提交(commit) mutation
安装vuex:npm install vuex --save
3、vuex 整合当前应用
创建一个store.ts如下
然后我们需要把这个store和vue联合起来,去main.ts,如下即把store和整个应用整合到了一起
接下来看看在组件中怎么拿到数据,在home.vue中举个例子,如下
我们哪里要用就引入vuex的useStore,然后通过 useStore() 就可以拿到vuex中的store了
如下发现没有自动补全,我们可以引入store的GlobalDataProps
当做泛型传入进去后就可以出现自动补全了
由于vuex的状态存储是响应式的,从store实例中读取状态最简单的方法是在计算属性中返回某个状态,如下
第二个任务就是修改数据
我们希望登录以后,vuex数据发生变化,然后触发页面上的变化。登录后就把vuex中当前登录人的信息从未登录变成登录,从某某人变成当前人这样子
然后到App.vue中引入vuex,然后 useStore() 拿到vuex中的store,然后在computed中通过store.state.user拿到store中的user信息
到login.vue中,我们希望它登录后跳转到首页去,并且尝试修改,注意修改一定要用commit。
如下,commit就会去触发store中的mutations,commit('login') 即触发mutations中的login函数,如下这个login函数中就会去修改store中的user信息
如此,去登录,发现登录成功后就跳转到了首页了
4、使用vuex getters
前面我们知道了怎么给整个页面添加vuex store,同时知道了怎么在vue组件中获取store的数据,以及怎么触发mutation,从而引起应用的更新。
接下来我们了解getter,有时候我们需要从store的state中派生出一些状态,比如说我们对专栏们进行过滤,找出id大于2的有多少专栏,我们就需要这样:store.state.columns.filter(c=>c.id>2).length,通过这么一长串逻辑就拿到了有多少专栏id大于2
假如我们在多个页面当中都要使用的话,就需要反复重复这么长的代码,就比较麻烦
vuex就允许我们在store中定义一个叫getter的东西,可以认为是store的一个计算属性,就和计算属性一样,getter返回值会根据它的依赖被缓存起来,且当它依赖值发生改变才会重新计算。
如下,接下来我们使用getter,就直接通过store.getters.biggerColumnsLen就可以拿到id大于2的专栏数量了
我们来到专栏详情页,我们想通过getters,查询具体是哪个column
如下是还没用getters的
这里和之前的区别就是,我们需要传入一个称为currentId的值,因为这个值是在页面上才能拿到的,所以你在页面拿到后,你得传入到getters中,然后拿currentId做上面的这些操作
在getters中我们可以让它返回一个函数来实现给getters传参,它在你对store里的数组进行查询的时候非常有用,如下
三、添加新建文章页面
每个column专栏都有一个作者(有columnId,id等),它们两个是一对一的关系,这个作者信息和当前这个用户登录信息使用的是同一个数据结构,所以我们在新建文章的时候,可以从当前登录用户的信息中拿到这个columnId,然后创建定义的文章
就是你创建文章,你得知道这个文章是谁写的?(这里有点?)
views中新建一个CreatePost.vue即新建文章页面,新建文章中也是用的validate-input
然后到router.ts中加入新建文章的页面路径,并且在新建文章按钮中把a标签变成router-link标签,:to指向/create,这样点击新建文章时就会跳转到新建文章页面
应该让validateInput支持textarea,添加一个属性让它判断要显示哪个节点就好
如下,设置一个类型是input或者textarea,然后props中接入一个tag,这个tag就是要展示input还是textarea,然后input标签中就通过v-if来判断是input类型还是textarea类型框
然后新建文章这里,我们传入tag=textarea,这样子在新建文章页面
如果要创建文章,我们就需要拿到用户信息的columnId,所以我们给我们的数据结构做一些修改
如下:在mutations中定义createPost,接收newPost即新建的文章,把传过来的新建的文章追加到state的posts中
如下:新建文章点击提交按钮后,触发onFormSubmit事件,从当前用户中获取columnId做当前新建文章的columnId,然后新建newPost对象,这个对象中放置这个新建文章的信息,然后commit调用vuex的mutation,把当前新建文章追加到state中的posts中,并且往router中push如下路径
四、vue router 添加路由守卫
1、 前置守卫
接下来谈谈不同路由的权限问题,有些路由有某些特定权限才能使用,比如新建文章页面只有在用户登录以后才可以使用,如果用户未登录,直接访问新建页面的话,一般会重定向到另外一个路由,比如说此时重定向到login页面去登录;比如说登录和注册页面,在未登录的时候就可以访问,如果已经登录,此时去访问这两个页面一般会重定向到首页去。
由于我们整体应用是SPA,即所说的单页面,那我们的路由使用了vue-router,我们就去看看vue-router怎么完成这个任务,就是这个导航守卫
现在我们就来注册一个全局前置守卫,判断一下加入用户是否登录,如果没有登录,那么就让页面跳转到login页面,如上,注册守卫其实很简单,我们需要在router的实例上拿到beforeEach方法,
beforeEach方法就是当一个导航触发的时候,这个beforeEach要全局前置守卫,就按照创建顺序调用,守卫是一步一个解析执行,此时导航的所有守卫resolve完之前一直处于等待中
to就是即将到达的路由,from是正在离开的路由,next是一个function
从首页到新建文章页,可以看到to即将到达的路由变成/create,from当前路由是首页
但是此时我们发现,已经点击新建文章按钮了,却没有跳转到新建文章页面,这是因为最后一个参数next在作祟
next是一个function,我们一定要调用该方法来resolve这个钩子,让这个路由继续前进到下一个钩子,此时我们就直接让它next()继续前进不要停在这里即可到新建文章页面
如果为false则不能跳转了
然后我们来完成,当没有登录的时候就跳转到登录页面去
如下,如果不是跳转到登录页,并且当前没有登录,即当前没有登录还想跳到非登录页就让它重定向回登录页得先登录再去其他页面
此时如果没有登录,那么到首页就会重定向到登录页,或者到新建文章页也会重定向回登录页
这个功能是实现了,但是这不是我们最终想要的结果,因为有些页面即使没有登录也是可以访问的,只有特定的页面才需要登录后才能访问,所以我们还需要再把这个功能进化一下
2、使用元信息完成权限管理
现在路由可以被这个守卫操控,在跳转之前进行对应的检查,但是现在我们的规则是眉毛胡子一起抓,用一个规则把所有页面都拒之门外。
第一种是home和columndetail这两个页面是无论有没有登录都是可以访问的;第二种是create页面是只有登录的用户才可以访问的;第三种是login这个页面,用户登录以后他访问就会直接跳转到首页;所以有三种对应的路由,又代表了三种不同的行为,也就是说我们需要在特定种类的路由上面添加独特的信息进行区分,看文档如下
要知道怎么在路由上添加元信息,即在路由上添加meta: { xx: xx }
路由元信息,也就是说我们在定义路由的时候可以配置一个叫meta的字段,这个就是这个元信息,这个meta字段下面我们可以使用Object形式写出来我们所需要的一些额外的信息
这时候我们就在create页面上面添加一个元信息,添加完了后我们需要到beforeEach中访问这个信息,如下
我们访问create可以看到打印出了requiredLogin:true,既然我们能拿到这个信息,后面的判断就可以做了
我们只需要用meta中的信息判断该路由是否登录就可以了
如下create页面是只有登录的用户才可以访问的
登录用户访问登录页面就会跳转到首页