在尝试了解了React和Vue之后,还是选择了Vue作为开发前端web的单页应用的框架,主要是vue相对来说还简单容易理解一些。通过断断续续的两周学习和准备,现在基本对vue的开发有了一个比较深入的认识。Vue最核心的魅力就在于双向绑定,可以让我们专注于数据,而不用管dom。之所这样说,是因为,只要数据改变了,页面就实时的调整改变了,这也之前使用jquery进行dom操作完全是两个概念。我觉得jquery是对原生js操作dom进行了封装改进的库,但是Vue是把操作dom又进行了更高级的封装,结合后端所谓的模版引擎的理念而发展的一种新的框架,总之,很神奇。
下面记录下在学习工程中遇到的问题。
1.关于npm的命令
npm -i vue -D = npm install vue -save-dev
最初在看的时候,有-s有-D,有-save等等,其实用的是缩写而已。
参考这个链接,说的更清晰。
2.关于axios的使用
(1)关于post请求收不到参数
可以看到几乎所有关于axios封装的例子中,都会使用qs.stringify对传入的json格式对象进行处理,如果不处理,你会发现,后台接口接收不到参数,为什么?!
因为axios自己内部会对参数是对象的请求修改Content-type=json/text,不管你是否已经手工设置过Content-type。
参考这个链接,说明比较清晰。
这里关于Content-type,正常情况下,我们post表单或者默认的ajax请求,content-type=application/x-www-form-urlencoded,这样会让请求的参数放到formDate里,后端通过request.getParameter就能取到对应的参数。但是像jons/text格式的,tomcat不会进行特殊处理,你在过滤器里,必须通过getStream流的方式才能获取。
(2)关于首次请求的时候,会发两次请求
SPA单页应用是完全的前后端分离开发,一般情况下,跨域问题是不可避免的要面对的。我们一般通过后端的CROS即允许不同源的请求访问方式来解决跨域问题,但是有时候还是会发现,明明发送了一次请求,为什么调试显示是两次?
这是因为ajax的跨域请求,如果请求的header中有自定义的内容,那么会先自动发起OPTIONS请求去探测后端是否允许跨域请求,探测成功了会再发送正常的POST请求(注:只要探测成功,那么后续在同一个session下就不会再探测,即后面所有请求就只发一次正常的)。
贴一段关于后台过滤器中CROS设置的代码如下:
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse rep = (HttpServletResponse) response;
rep.setHeader("Access-Control-Allow-Origin", "*");// cors解决跨域
if ("OPTIONS".equals(req.getMethod()))
{
rep.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS");
rep.setHeader("Access-Control-Max-Age", "3600");
rep.setHeader("Access-Control-Allow-Headers",
"Content-Type,Access-Control-Allow-Headers,
Authorization,
X-Requested-With
,token");
// 针对post请求的options请求,直接返回访问成功即可
chain.doFilter(req, rep);
}
上述代码,注意rep.setHeader中的内容,这个是允许请求方写入的header的字段名,如果不在这几个范围内,则不允许跨域请求。
(3)在axios封装的http.js中使用其他组件
一般情况,在http.js中会对response进行拦截预处理,如果出错了,会直接路由到出错的页面,同时进行提示。
关于提示,我最初想用Layer.js,但是官方的Layer.js并不支持vue里直接使用,然后找到通过npm -i lyaer-vue的组件,但是发现一个问题,那就是layer只能在VUE初始化之后,在其他自己写的组件中使用,但是再自己封装的http.js中不能使用。
最后放弃layer-vue,选择了vuxUI的Toast。
使用方式为在http.js中import Vue fomr 'vue'
用的时候,直接Vue.$vux.toat.show{}即可,不可以用this代替Vue,因为此时在https里还没有this。其实就是执行先后顺序的问题吧,这一点也不是太确定。
3.关于全局,关于import/export
最初写jsp、jquery的时候,前端的js之间耦合度很高,只要页面引入了这个js,就能直接用变量,某种程度上可以说,任何变量和方法都能使全局的变量和方法。但是在模块化开发中不是这样,在学习了两周后,我被js的模块化开发震撼了,模块化开可以说是颠覆性的改变,让js变的更优雅,更有面向对象的思想。
之前,只要页面引入了这个js,就可以使用这个js中的function和变量,但是现在,js是通过import的方式引入,引入的js中必须有export将相关对象或者变量暴露出来,你才可以用,这种方式,可以让模块更加紧凑,更加能体现高内聚低耦合的理念。
那么这就有一个问题,以前,我在一个页面引入js后,其他引入的相关js之间都是互相可见的,只要先后顺序对,相关参数、方法都能随便调用。但是现在,你在一个js中想使用方法,就必须通过import,不然不能用,那像一些工具方法,如何声明全局的对象呢?
这里提供两种方法,一种是挂在Vue.prototype上,这样,就可以像使用Vue的属性一样在组件中使用了,但是请注意,这种方式有一个问题,那就是不能在自己写的js中使用,哪怕你引入Vue,使用Vue.$youtool这样的方式也不行。
另外一种方式,也是我觉得比较好用的方式,那就是挂载在window上,在mian.js中,直接把全局的方法或者变量挂载window上,例如:
import Vue from 'vue'
import App from './App'
import router from './router'
import FastClick from 'fastclick'
import commTool from './utils/commTool'
import config from './utils/config'
import apis from './utils/api'
import {TransferDom, ToastPlugin, LoadingPlugin, Flexbox, FlexboxItem} from 'vux'
import './assets/amaze-ui/css/amazeui.min.css'
//挂在全局对象和方法
window.ctool = commTool;
window.capis = apis;
window.cconfig = config;
使用的时候,在任何地方都可以直接ctool.xxx这样去用
4.关于vue-router的传参及刷新丢参问题
使用params和query的区别在于,query不会丢参,你刷新也不会丢。param则会在页面刷新后丢参,解决方式是在定义路由的时候,给path机上参数的声明。
还有一种方式,就是设置pors=true,也可以直接传参,在子组件中使用pros:声明下参数名,然后就可以像使用data里的数据一样使用传过来的参数了,注意:这种方式,如果刷新页面,参数一样会丢。
5.关于页面刷新
页面的刷新,会同时走子组件和父组件的所有生命周期。
6.关于在beforRouterEnter
这个钩子函数太神奇了,他能让你还在from页面的时候,就提前请求to页面的数据,在数据成功获取后,页面路由才会跳转到to页面,这种方式在用户体验上会非常好,能避免跳转到页面后因为要等待请求结果而出现的白屏效果。
最初的时候,我遇到一个很棘手的问题,那就是在这个钩子函数中不能使用this对象,那全局的https我怎么办?通过验证发现可以在组件中单独import axios方式进行请求时可行的。但是我总不能在所有页面都这样做,那太愚蠢了。最后发现可以把https挂在window上,这样就可以在任何地方进行使用了。
注:有网友说,可以把请求的方法写到method中,然后在next(vm=>fun())方式去调用,这是不行的,因为你会发现这根本没什么意义,还是会先进入到组件渲染完才进行请求,因为next中vm调用的方法会在mounted之后回调执行,具体可以看官网山如下的流程说明:
先记录到这里,后面再继续完善。