随着做到的项目记录一下前端技术上的坑点和注意点。文章的Vue指的是vue2.x,React是指React hooks,也有可能谈到jquery。欢迎指正和讨论
首先,我觉得项目中比较重要的部分,不是一些高端用法,先应该搞清楚网络这块东西。vue一般会使用axios来处理请求,而react这边可以用axios。由于之前项目中使用的框架是umijs,使用的是umi-request(基于fetch封装),偶尔会使用fetch(某些封装不能满足业务需求情况)。
具体可查看umi-request文档
也可以看更底层的fetch
基于fetch的设计只有在请求没发出去和没接收回来的情况下才会reject,但凡有个状态码404,500都行,也算resolve,只是设置 resolve 返回值的ok属性为false。另外就是 “源/域” 的概念(Origin的翻译问题),在项目中很重要。
一般的跨域操作是需要前后端一起实现的,但前端可以利用 <script>
src属性不受限制来用jsonp来绕过跨域,但只限于GET请求。
<script>
$.getJSON("https://www.runoob.com/try/ajax/jsonp.php?jsoncallback=?", function(data) {
var html = '<ul>';
for(var i = 0; i < data.length; i++)
{
html += '<li>' + data[i] + '</li>';
}
html += '</ul>';
$('#divCustomers').html(html);
});
</script>
上图是菜鸟jsonp例子
一般实现跨域,需要后端规范是否允许请求,带有请求参数的接口,浏览器会在请求前自动加入一个OPTION类型的接口来获取后端是否允许跨域,在发起请求本体。
在一些业务复杂的场景下,比如需要从本应用跳转到外部页面,在跳转回来之类的就会比较复杂,前端发起请求时需要带上cookies,headers之类的。详见跨域
接着讲讲请求封装,一般项目中会封一个request.js来减少发起请求的重复代码。一般会限制请求的timeout,携带的请求头,错误处理等,具体可以看上面umi-request的文档,与axios格式类似。
一个完整的前端请求逻辑应该包括:组件的loading,成功时数据显示,错误是信息抛出,结束loading。
接下来是和以上相关的几个常见业务或者功能:
-
文件上传下载:需要注意content-type,用来告诉后端用什么类型接收数据,返回时也能告诉浏览器如何处理数据。
一般会约定application/json;charset:utf-8;
作为默认接口参数类型,不同架构不同接口会不一样,比如pdf格式如果希望浏览器能够直接开启预览可以返回application/pdf;
类型,关于文件的下载可以参考这篇文章文件下载整理但如果是在使用axios(0.21.0版本)的时候设置类型需要注意这块儿代码:
// Add headers to the request if ('setRequestHeader' in request) { utils.forEach(requestHeaders, function setRequestHeader(val, key) { if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') { // Remove Content-Type if data is undefined delete requestHeaders[key]; } else { // Otherwise add header to the request request.setRequestHeader(key, val); } }); }
意思是在data参数为空的时候,想要设置content-type是无效的。可以设置一个无意义的data参数绕过这个判断。
(这里**一下csdn,我这文章写了三天,我撤回的时候直接给我撤到了一天前的代码找不回来了,心态直接爆炸,千万别在csdn用线上的编辑器写长文章,稀烂,所以这段可能写的粗糙,因为写第二遍没耐心了)
-
无感登录:比如当用户的token过期了,访问接口的时候会产生401错误,接口没有拿到相应的数据,渲染会出现问题导致页面不显示,又或者刚进入页面同时发起了很多请求。
大概思路是维护一个请求数组,在第一次登录失效时将后续的请求全部存入等待登录token获取到再重新发起请求:
// 标记 let flag = false; // 重试队列,每一项将是一个待执行的函数形式 let requestList = []; // respone拦截器==>对响应做处理 service.interceptors.response.use( response => { // 成功请求到数据 return response.data; }, error => { // 响应错误处理 if (error.response.status === 401) { // 登录出错 return new Promise((re) => { const config = error.config; if (!flag) { flag = true; // 登录请求 login().then((res) => { config.headers["token"] = res.token; requestList.forEach((cb) => cb(res.token)); // 传入token requestList = []; // 清空 re(service.request(config)); return service.request(config); }).catch(err => { ... }) } else { return new Promise((re) => { // 放入队列 requestList.push((token) => { config.headers["token"] = token; re(service(config)); }); }); } }); } else { ... } return Promise.reject(error); } );
-
等我想起来再补充
接下来要说一下组件的使用。
如果时jquery,直接引用组件的cdn即可,怕他突然无了可以下载下来放本地,但这样做和cdn的思维有点背道而驰了,思考.jpg
现在大多使用npm或者yarn来搭建项目,操作组件。
一般情况下,组件的安装应该不存在疑问,一旦有问题,那就是不好解决的问题。
- npm install 出错:和同事使用相同版本的nodejs和npm;EPERM: operation not permitted, unlink…提示使用管理员权限安装,这个提示是不正确的,其实是因为网络问题导致install失败,建议删除整个node_modules, 清除npm缓存再重新install,如果删除比较慢的话,推荐使用rimraf;使用不同registry比如使用cnpm;换yarn;还是不行建议直接拿同事成功的node_modules。通常yarn比npm问题少。还有些奇奇怪怪的情况,比如电脑没有管理员权限情况下安装的nodejs是会有奇奇怪怪问题的,建议重装nodejs。
- 组件版本问题:注意package.json中组件版本前的
^
,~
,升级的时候避免困惑,再用element-ui/vant之类的组件库的时候注意有些属性在某个版本以上才会有,怎么写都不生效的时候注意一下。package-lock.json
这个很重要,项目统一。 - 编写组件封装并发布的时候,制定相应的依赖项目的规则,比如小版本 / 修订号patch修复bug,中版本 / 次版本号minor功能升级,大版本 / 主版本号major大升级一般不向下兼容的。另外,如果是还未开源的组件库,或者是公司内部组件库,在publish的时候记得通知使用者版本更新。需要发布组件可以看下这个:语义化版本号。
- 插件升级变化:比如
Prettier,Eslint,babel
这些插件,低版本的使用方式大多是在package.json
中直接配置,而新版本支持在项目根目录使用独立配置文件的方式运行。比如eslintrc.js
,babel.config.js
。 - 说到eslint,就要说到项目团队代码规范和代码审查的问题,一般前端会有
eslint
,stylelint
这种代码格式插件和工具,团队使用同一个配置,让代码看起来统一一些,像是一个人写的一样。稍微好一点公司内会有相应的代码审查功能,或者需要代码风格评审、code review
。如果是eslint
需要添加env
来让他对使用的作用域不再报错,或者对es6
语法不再报错等,可以看eslint官网。