关键词:
create-react-app2.1.1重大改变,授权登陆,( ISO8061时间格式;UTC,GMT时间 ) ,动效,对象数组去重,字符集,base64转码,打包去掉.map文件,location, encodeURIComponent,word-wrap, word-break, white-space, text-overflow,onScroll, scrollIntoView,嵌套路由,子路由,滚动平滑css属性, background, proxy,redux-devtools-extension
(一) create-react-app 2.1
默认支持sass和scss
只需安装node-sass即可( yarn add node-sass )默认支持css-modules
scss文件命名需要加上module
比如: login.module.scss
如何开启绝对路径
1.在根目录下新建名为.env后缀的文件
2.设置环境变量: NODE_PATH=src 即可把src目录作为根目录
create-react-app的配置方式是它的webpack配置会自动选取'.env'文件并读取'NODE_PATH'环境变量,然后可用于绝对导入.自定义环境变量在开发和生产过程中都可以使用,因为变量是在构建时嵌入的,而不是运行时嵌入的,所以你的应用程序可以通过'process.env'访问它的环境
https://www.imooc.com/article/37421proxy的修改
1.新版proxy代理只支持字符串模式了,如果是对象需要下载插件
2.http-proxy-middleware
(库地址) https://github.com/chimurai/http-proxy-middleware
(教程) https://blog.csdn.net/weixin_36094484/article/details/82968545如何使用less
1.安装less和less-loader
cnpm install less less-loader --save
2.修改webpack.config.dev.js和webpack.config.prod.js
在create-react-app中使用less
(1) 定义变量
// style files regexes
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;
const lessRegex = /\.less$/; ------------------------------- 添加这两行
const lessModuleRegex = /\.module\.(less)$/; ------------------- 添加这两行
(2)配置module的rules
{
test: lessRegex,
exclude: lessModuleRegex,
use: getStyleLoaders({ importLoaders: 2 }, 'less-loader'),
},
{
test: lessModuleRegex,
use: getStyleLoaders(
{
importLoaders: 2,
modules: true,
getLocalIdent: getCSSModuleLocalIdent,
},
'less-loader'
),
},
- 如何引入antd,并按需加载
1.安装 cnpm install babel-plugin-import ( 用于按需加载组件代码和样式的 babel 插件 )
2.在package.json中
------------或者webpack.config.dev,webpack.config.prod 中
------------或者自己新建.babelrc文件
如何引入antd,并按需加载
(1) 在package.json中添加:
"plugins":[["import", {"libraryName": "antd", "style": "css"}]]
"babel": {
"presets": [
"react-app"
],
"plugins":[["import", {"libraryName": "antd", "style": "css"}]] // 添加插件
},
------------
(2) 在 webpack.config.dev(开发环境)和 webpack.config.prod 中
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
customize: require.resolve(
'babel-preset-react-app/webpack-overrides'
),
plugins: [
[
require.resolve('babel-plugin-named-asset-import'),
{
loaderMap: {
svg: {
ReactComponent: '@svgr/webpack?-prettier,-svgo![path]',
},
},
},
],
// ["import", {"libraryName": "antd","libraryDirectory": "es","style": "css" }] 添加!!!
],
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/
// directory for faster rebuilds.
cacheDirectory: true,
// Don't waste time on Gzipping the cache
cacheCompression: false,
},
},
- 如何修改antd的主题颜色 (这里有个巨坑)
https://blog.csdn.net/qwe502763576/article/details/83242823
- 在package.json中修改 plugin
"plugins": [
[
"import",
{
"libraryName": "antd",
"libraryDirectory": "es",
"style": true ------------------------ 这里把css改为true
}
]
]
- 在webpack.config.dev.js中修改getStyleLoaders()函数
const getStyleLoaders = (cssOptions, preProcessor) => {
const loaders = [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: cssOptions,
},
{
// Options for PostCSS as we reference these options twice
// Adds vendor prefixing based on your specified browser support in
// package.json
loader: require.resolve('postcss-loader'),
options: {
// Necessary for external CSS imports to work
// https://github.com/facebook/create-react-app/issues/2677
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009',
},
stage: 3,
}),
],
},
},
];
if (preProcessor) { ---------------------------------- 主要修改这里
let loader = require.resolve(preProcessor);
if (preProcessor === "less-loader") {
loader = {
loader,
options: {
javascriptEnabled: true, ------------------- 关键配置这里
}
}
loaders.push(loader);
}
}
return loaders;
};
- 新建them.less文件,在them.less中引入@import "~antd/dist/antd.less",再把them.less引入到项目的入口文件index.js中即可
them.less
@import "~antd/dist/antd.less";
@primary-color: #1890ff; // 全局主色
@link-color: #1890ff; // 链接色
@success-color: #52c41a; // 成功色
@warning-color: #faad14; // 警告色
@error-color: #f5222d; // 错误色
@font-size-base: 14px; // 主字号
@heading-color: rgba(0, 0, 0, .85); // 标题色
@text-color: rgba(0, 0, 0, .65); // 主文本色
@text-color-secondary : rgba(0, 0, 0, .45); // 次文本色
@disabled-color : rgba(0, 0, 0, .25); // 失效色
@border-radius-base: 4px; // 组件/浮层圆角
@border-color-base: #d9d9d9; // 边框色
@box-shadow-base: 0 2px 8px rgba(0, 0, 0, .15); // 浮层阴影
- 如何开启cssModules
如何开启cssModules
import React from 'react';
import { Input, Form, Button } from 'antd';
import S from './login.module.scss'; --------------------- 引入
const FormItem = Form.Item;
export default class Login extends React.Component {
render() {
return (
---------------------------------- 写成对象的形式
)
}
}
redux-devtools-extension
import { createStore, combineReducers, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
const totalReducers = {
};
const store = createStore(
combineReducers({
...totalReducers
}),
composeWithDevTools(
applyMiddleware(),
)
);
export default store;
(二) 授权登陆
(教程)http://www.cftea.com/c/2016/11/6703.asp
(猪八戒授权文档)http://open.zbj.com/wiki/getWikiCategoryAll?wikiid=8#header
react-facebook-login 和 react-google-login
responseGoogle = async(response) => {
if (response.error) {
// message.error(response.error, 2)
return;
} else {
try {
let accessToken = response.accessToken;
const params = {
acToken: accessToken,
userType: 'STORE',
}
const res = await carbonLoginApi(googleGet(params)); // 用google获取得token,换取本服务器token
if ( res.status === 200 ) {
const token = res.data.token;
window.localStorage.setItem('token', token);
// const meRes = await carbonLoginApi(profilesGet()); // 请求me接口,看是否需要修改密码
// if ( meRes.status === 200 ) {
// if (res.data.isNeedModifyPassword) {
// console.log('请重新设置密码,')
// }
// }
this.props.history.push('/request')
}
} catch (err) {
message.error(err.message)
}
}
}
(二) ISO8601标准时间格式 ---- UTC时间,GMT时间
--------- ISO 8601的标准格式是:YYYY-MM-DDTHH:mm:ss.sssZ
-----------------------------------------: year
-month
-date
Thour
:minute
:second
.millisecond
Z
(1) utc时间
'2018-10-30T12:53:19.000Z'-------------这样的时间符合iso8601时间标准
T:表示UTC时间,UTC时间又叫世界协调时间
Z:表示时区-----如果没跟任何数字表示0时区( Z:时区,可以是:Z(UFC)、+HH:mm、-HH:mm )
T 也可以用空格表示,但是这两种表示有点不一样,T 其实表示 UTC,而空格会被认为是本地时区(前提是不通过 Z 指定时区)
> new Date('1970-01-01 00:00:00') --------------------- 空格是本地时区
Thu Jan 01 1970 00:00:00 GMT+0800 (CST)
> new Date('1970-01-01T00:00:00') ---------------------- T是utc时间
Thu Jan 01 1970 08:00:00 GMT+0800 (CST)
(2) gmt时间
'Thu Nov 01 2018 08:58:27 GMT+0800 '
GMT+0800 : 表示东八区时区------- new Date()得到的是GTM本地时间
(3) Date对象最重要的几个方法
Date.prototype.valueOf() ------- 使用时间戳时,都用valueOf转成时间戳提交到后端
valueOf方法返回实例对象距离时间零点(1970年1月1日00:00:00 UTC)对应的毫秒数,
该方法等同于getTime方法。
new Date( new Date().valueOf() )
new Date().valueOf -------------------------- 返回距离时间零点的毫秒数
返回:1541035593721
new Date( new Date().valueOf() )------------- 返回对应的GMT时间
返回:Thu Nov 01 2018 09:27:02 GMT+0800
var d = new Date();
d.valueOf() // 1362790014817
d.getTime() // 1362790014817
Date.prototype.toString() ------- toString方法返回一个完整的日期字符串。
var d = new Date(2013, 0, 1);
d.toString()
// "Tue Jan 01 2013 00:00:00 GMT+0800 (CST)"
d
// "Tue Jan 01 2013 00:00:00 GMT+0800 (CST)"
d 和 d.toString()返回结果是一样的,即 new Date()会自动调用toString()方法
( 因为toString是默认的调用方法,所以如果直接读取Date实例,就相当于调用这个方法。 )
Date.prototype.toISOString() ------- 返回对应的ISO8601格式的时间字符串
Date.prototype.toJSON() ------------- toJSON方法返回一个符合 JSON 格式的 ISO 日期字符串
toISOString() 和 toJSON()方法返回值是相等的
var d = new Date(2013, 0, 1);
d.toISOString()
// "2012-12-31T16:00:00.000Z"
d.toJSON()
// "2012-12-31T16:00:00.000Z"
moment.js
上周的开始时间UTC时间
const lastWeekStart = moment().subtract(1,"w").startOf('isoWeek').toDate().toJSON();
上周的结束时间UTC时间
const lastWeekEnd = moment().add(-1,"w").endOf('isoWeek').toDate().toJSON();
上个月的开始时间UTC时间
const lastMonthStart = moment().month(moment().month()-1).startOf('month').utc().format();
上个月的结束时间UTC时间
const lastMonthEnd = moment().month(moment().month()-1).endOf('month').utc().format();
----------
moment().subtract(Number, String); 减法 ---- 返回的是一个moment对象
moment().subtract(Number, String).toDate() ---- 返回get the native Date object,原时间对象
moment().subtract(Number, String).toISOString() ---- 返回ISO8601格式时间字符串
moment().subtract(1, 'days') === moment.add(-1, 'days') 减一天
moment().startOf('isoWeek'); ----- 返回ISO8601格式的moment对象
--- set to the first day of this week according to ISO 8601, 12:00 am
-----------------------------( isBetween )------------------------------------------------
moment().isBetween(moment-like, moment-like);
moment().isBetween(moment-like, moment-like, String);
// where moment-like is Moment|String|Number|Date|Array
// moment-like可以是一个Moment对象,字符串,数字....
moment('2010-10-20').isBetween('2010-01-01', '2012-01-01', 'year'); // false
moment('2010-10-20').isBetween('2009-12-31', '2012-01-01', 'year'); // true
( isBetween )
!!!!!!!!
const todayStart = moment().startOf('day'); -- 返回的是今天的开始时间的moment对象
const todayEnd = moment().endOf('day');
if ( moment(item.lastReplyAt).isBetween(todayStart, todayEnd) ) { -- isBetween
createTime = moment(item.lastReplyAt).format('h:mm a');
} else {
createTime = moment(item.lastReplyAt).format('MM / DD') // 格式化成月/日
}
!!!!!!!!
目录:
- 数组(对象)去重
--- (1) 数组的reduce方法,没重复push,重复不做任何操作
--- (2) lodash库的_.uniqWith(array, _.isEqual);
- word-break 属性
- word-wrap 属性
- white-space 属性
- text-overflow 属性
- Element.scrollIntoView
- 嵌套路由,子路由
https://blog.csdn.net/hsany330/article/details/78114805 - componentWillReceiveProps
https://www.cnblogs.com/gdsblog/p/7348375.html
https://blog.csdn.net/huanghanqian/article/details/80721575 - scrollHeight = scrollTop + clientHeight
https://www.jianshu.com/p/c14f85f109ee
https://www.jb51.net/article/58688.htm
onScroll事件 和 onWheel事件
8.1 scrollIntoView() ------------- 滚动当前元素到浏览器的可视区域
!! scrollIntoView()类似于 window.location.hash
- 滚动平滑css属性
scroll-behavior: smooth; -- 平滑
el.scrollIntoView(); // 等同于el.scrollIntoView(true)
el.scrollIntoView(false);
方法可以接受一个布尔值作为参数。
如果为true,表示元素的顶部与当前区域的可见部分的顶部对齐(前提是当前区域可滚动);
如果为false,表示元素的底部与当前区域的可见部分的尾部对齐(前提是当前区域可滚动)。
如果没有提供该参数,默认为true。
- 伪元素和伪类
https://www.cnblogs.com/m2maomao/p/7744227.html - 正则对象
- background
background-color
background-image
background-image:url()
background-size -----------!!
background-size: cover拉伸图片,有可能一部分会超出
bckground-size: contain缩放图片,有可能一部分会出现空白,无法填充满
http://www.w3school.com.cn/tiy/c.asp?f=css_background-size&p=8
background-position -----------!!
background-position: 第一个参数是水平位置,第二个参数垂直位置,如果规定了一个值,另一个值是50%
background-position: center center
= background-position: center
是一样的
background-position: 50% 50%
= 0%表示左上角,100%表示右下角
http://www.w3school.com.cn/cssref/pr_background-position.asp
background-attachment
background-attachment : ( scroll , fixed )
元素内背景图片是否随元素滚动而移动
https://www.cnblogs.com/rain-null/p/7064136.html
background-repeat
background-origin
background-clip
- 动效(元素底部,从中间向两边组件变长的横线)
html:
animate test
css:
.animate {
position: relative; // 父元素相对定位,!!伪类就当前元素的子元素
display: inline-block;
}
.animate::after { // 伪类相当于当前元素的子元素,只是不在dom中
content:''; // 一定要有内容,否则伪元素不会被撑开
position: absolute;
left:0; // 定位到父元素的底部
bottom:0;
height: 2px;
background: blue;
left: 50%; // left和right都是50%,则伪类被挤压到宽度是0,看不见了
right: 50%;
transition: all 0.5s;
display: inline-block;
}
.animate:hover::after {
content: '';
position: absolute;
height: 2px;
background: blue;
left: 0;
right: 0; // hove的时候,还原div的长度,正好是中间向两边扩散
display: inline-block;
}
- 全局作用域 , 函数作用域 ------------------- 链式作用域
函数内部可以直接读取全局变量
函数外部无法读取函数内部声明的变量 - lodash ----------------- isEqual
_.isEqual(value, other) -------- 深度比较值是否相等
*值得类型可以是 数组,对象,等
*值得类型是对象时:不考虑继承属性(inherited: inherited是继承的意思),只比较自身属性
argument: 需要比较的两个值
return: 返回一个布尔值
- 函数
函数声明时,如果使用表达式赋值给变量的形式,表达式后需要加分号,表示语句的结束。
- 函数名视同变量名,存在函数名提升。(注意:是function关键字声明的函数存在函数名提升,而采用变量赋值声明的函数,不存在函数名提升,而仅仅是提升变量)
- 不能在 ( if ) 或者 ( try catch) 语句中声明函数,因为函数名存在变量提升,注意是function关键字声明的函数
- 函数的
name属性
,length属性
,toString()方法
- length属性返回形参的个数
- 函数的toString返回函数的源码的字符串形式
- 作用域:指变量存在的范围
- 对于var命令来说,局部变量只能在函数内部声明,在其他区块中声明的变量,都是全局变量
- 函数本身也是一个值,也有自己的作用域,和变量一样,
函数的作用域是其声明时所在的作用域,与其运行时的作用域无关
- 函数执行时的作用域,是函数定义时的作用域,而不是调用时的作用域
很容易犯错的一点是,如果函数A调用函数B,却没考虑到函数B不会引用函数A的内部变量。
- 函数内部声明的函数,作用域绑定在函数内部
- 传递方式
1. 传值传递:
函数的参数是原始类型的值( 数字,字符串,布尔值 ),是传值传递,在函数内部修改参数值,不会影响函数外部---------------------------- 原始值的拷贝
2. 传址传递:
函数的参数是复合类型的值 (数组,对象,其他函数),是传址传递,在函数内部修改参数值,会影响函数外部---------------------------------- 原始值的地址
3. 注意:
函数内部修改的不是参数对象的某个属性,而是替换掉整个参数,这时不会影响原始值 - IIFE立即执行函数
function关键字出现在行首,一律解析成语句。所以function关键字出现在行首,认为是函数声明语句,不该以()圆括号结尾。所以function(){}()会报错
(function(){}());
或者(function(){})();
----------------------注意分号是必须的
以圆括号开头,引擎认为圆括号后面跟的是表达式,就不会报错
f();
var f = function (){};
---------------------------------- 等同于
var f;
f();
f = function () {};
(1) word-break 属性
word-break :规定自动换行的处理方法
- word-break: break-all 允许在单词内换行
- word-break: keep-all 只能在半角空格或连字符处换行。
( 文字超出自动换行 ) https://blog.csdn.net/ysynhtt/article/details/44301461
( 文字超出自动换行 ) http://www.cnblogs.com/loya1015/p/5992366.html
中文在div中会自动换行,英文和数字不会,英文没空格时会被认为是一个单词,则不会换行
(2) word-wrap 属性
word-wrap : 允许( 长单词 )或者( url地址 )换行到下一行
- word-wrap: break-word 在长单词或 URL 地址内部进行换行。
对比
word-wrap: break-word ------------------- 整个单词一起被换行
word-break: break-all ---------------------- 单词内换行,单词会被分开
(3) white-space 属性
white-space 设置如何处理元素内的空白
- white-space: nowrap 文本不换行,文本会在同一行上继续,直到遇到 br 标签为止
- white-space: pre-wrap 保留空白符序列,但是正常地进行换行
- white-space: pre-line 合并空白符序列,但是保留换行符
- white-space: inherit 规定应该从父元素继承 white-space 属性的值
herit: 是继承的意思
(4) text-overflow 属性
text-overflow 文本溢出的css
- text-overflow: ellipsis 显示省略符号来代表被修剪的文本。
- text-overflow: string 使用给定的字符串来代表被修剪的文本。
- text-overflow: clip 修剪文本。
clip是修剪得意思
https://blog.csdn.net/lpandeng/article/details/72885811
(显示x行后,超出显示...) https://www.cnblogs.com/like-xcm/p/5849630.html
超出设定大小的div后,文字显示 省略号
html
sfdsdfasfsdfasdf good welllllllllllllllll hao djfksjdkfs fsadfas sdf sdf s df sdf
css
.ellipsis {
width: 100px;
height: 60px;
background: yellow;
word-break: break-all; // 单词内换行,会分开单词
word-wrap: break-word; // 整个单词都会被换行,不会被分开
text-overflow: ellipsis; // 文字溢出,显示省略号
white-space: nowrap; // 不换行
over-flow: hidden; // 这个一定不能忘了,否则不会显示省略号
}
(1) 数组(对象数组去重)
采用数组的reduce方法
Array.reduce((累计变量,当前变量,当前位置,原数组) => {...}, 累计变量初始值);
Array.reduce((cumulate, current, index) => {...}, initial )
第一个参数是:函数,该函数又有4个参数
第二个参数是:累计变量的初始值
返回值: 返回值是最后一次的计算结果!!!
let _arr = [
{id:'1', name:'wang'},
{id:'2', name:'li'},
{id:'3', name:'zhang'},
{id:'4', name:'wu'},
{id:'1', name:'wang'},
];
let _obj = {};
let result = _arr.reduce((cumulate, current) => {
let _radom = _obj[current.id] ? '' : _ojb[current.id] = true && cumulate.push(current);
return cumulate
}, []) // 注意:这里给累计变量的初始值是一个空数组
// result就是去重后的数组
解析:
(1) 在react中,三元表达式的返回值,需要赋给一个变量,不然此处会报错
(2) 计算过程:
_ojb['1']不存在,就给_ojb['1']赋值为true (其他值也可以),并且往空数组中push对象{id:'1', name:'wang'},
...
...
_ojb['1']存在,则不做任何操作 ------------ 则重复项,并没有push到累计变量数组中
最后:返回累积变量数组
--------------------------------------------
lodash
_.uniqWith( 重复项数组, _.isEqual) 返回值就是去重的数组
字符集
javascript使用unicode字符集,javascript内部所有字符都使用unicode表示
base64转码
javascript原生提供两个base64相关方法
- 什么是base64:
base64是一种编码方法,可以将任意值
转换成0~9, A~Z, a~z, +, /
这64
个字符组成的可打印字符 - 作用:
不出现特殊字符,和加密 - 使用场景:
- 文本包含一些不可打印的符号, 则可以使用base64编码,
转成可打印的字符
-
以文本方式转递二进制数据
,可以使用base64编码
btoa():任意值转为 Base64 编码
atob():Base64 编码转为原来的值
这两个字符都不适合非 ASCII的字符
如: btoa('您好')会报错
function b64Encode(str) {
return btoa(encodeURIComponent(str));
}
function b64Decode(str) {
return decodeURIComponent(atob(str));
}
b64Encode('你好') // "JUU0JUJEJUEwJUU1JUE1JUJE"
b64Decode('JUU0JUJEJUEwJUU1JUE1JUJE') // "你好"
var x = '中文';
decodeURIComponent(atob(btoa(encodeURIComponent(x)))) // 输出中文
react-create-app建立的项目把包去掉.map文件
- map文件是帮助我们查看报错的位置的。
- map文件由devtool属性控制,如果不想要map,注释掉就可以,大约webpack.config.prod.js第57行;
一个完整的url地址
http://localhost:8080/a/b/c?a=1&b=2#abc
window.location
( http://localhost:8080/a/b/c?a=1&b=2#abc )
protocol协议:-------- 'http:' 注意包括:
hostname域名:-------- 'localhost'
host域名+端口:------- 'localhost:8080' 包括主机名,":"和端口号
hash:--------------- '#abc' #号开始的url
search:------------- '?a=1&b=2' ?开始的部分
pathname: ------------ '/a/b/c' 当前 URL 的路径部分,注意以 / 开头
origin: -------------- 'http://localhost:8080' 返回url中完整的协议和主机地址部分,包括端口
herf:---------------- 'http://localhost:8080/a/b/c?a=1&b=2#abc' 完整的url
// query:-------------- 'a=1&b=2' window.location中没有query属性
proxy
create-react-app中设置proxy
https://segmentfault.com/q/1010000008508440/a-1020000008516740
"proxy": "http://image.baidu.com"
getData = async() => {
const res = await axios.
get('/channel/listjson?pn=0&rn=30&tag1=明星&tag2=全部&ie=utf8')
.then(res => console.log(res))
}
说明:
(1) 上面访问'/channel/listjson?pn=0&rn=30...'将被代理到下面的地址:
---------- "http://image.baidu.com/channel/listjson?pn=0&rn=30..."
(2) 所以在浏览器看来访问的是'/channel/listjson?pn=0&rn=30...' 所以不会有跨域问题
------------
interceptor
axios中的拦截器
You can intercept requests or responses before they are handled by then or catch.
你可以在请求或者响应的中,在then和catch方法前拦截请求
实例:
import axios from 'axios';
import { message } from 'antd';
const isDev = window.location.origin === '............';
const isLocalhost = window.location.origin === '.........................';
export const hostname = isDev || isLocalhost ? '................' : '........................' ;
const _axios = axios.create({
baseURL: hostname,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
});
_axios.interceptors.request.use(request => { // 请求拦截
const {token} = localStorage;
if (token) {
request.headers.token = token;
}
return request;
}, error => Promise.reject(error) )
_axios.interceptors.response.use(response => { // 响应拦截
return response;
}, error => {
if (error.response) {
switch(error.response.status) {
case 401:
{
message.config({
maxCount: 1,
});
message.error('Login expired, please login again');
window.location.href = '#/login';
break;
}
case 500:
{
message.error('Network Error');
break;
}
default:
break;
}
}
return Promise.reject(error)
})
export default _axios;