第四篇主要讲常用的js库.主要偏向于JavaScript的库和前端库,Nodejs的库在第十篇
jquery jquery是目前使用最广泛的js函数库,在使用JavaScript的网站中,93%使用了jquery,成为了开发者必学的技能
jquery的优势有两个,首先它基本是一个DOM操作工具,可以使操作DOM对象变得异常简单,其次它统一 了不同浏览器的api接口,使得代码能够在所有现代浏览器运行,开发者不用担心浏览器之间的差异了
加载jquery可以使用CDN或者本地获取
1 2 3 4 5 6 7 8 9 <script type = "text/javascript" src = "//code.jquery.com/jquery-1.11.0.min.js" > </script > <script > window .jQuery || document .write( '<script src ="js/jquery-1.11.0.min.js" type ="text/javascript" > </script > ' ); </script >
jquery的基本思想是“先选中某些网页元素,在对其进行某种处理(find something,do something)”
与DOM属性相关的方法 addClass、removeClass、toggleClass
addClass用于添加一个类,removeClass用于移除一个类,toggleClass用于折叠一个类,也就是无就添加,有就移除
1 2 3 $('li' ).addClass('special' ) $('li' ).removeClass('special' ) $('li' ).toggleClass('special' )
css方法
css方法用于获取或者改变css的属性
1 2 3 4 $("h1" ).css('fontSize' ) $("h1" ).css({ 'padding-left' ,'20px' })
prop、attr、removeProp、removeAttr方法
attr方法读写网页元素的属性,如a元素的href属性,img的src属性
prop方法读写DOM元素的属性,如nodeName,nodeType、tagName
removeProp方法移除某个DOM属性
removeAttr方法移除某个HTML属性
1 2 $("a" ).prop("oldValue" ,1234 ).removeProp('oldValue' ) $("a" ).removeAttr("title" )
data方法
用于在一个DOM对象上存储数据
1 2 $("body" ).data("foo" ,52 ); $("body" ).data("foo" )
与DOM相关的方法 Append、appendTo方法
用于将参数插入当前元素的尾部
用法
1 2 3 $('div' ).append("<p>World</p>" ) ("<p>World</p>" ).appendTo("div" )
prepend、prependTo方法
将参数中的元素变成当前元素的第一个子元素
1 2 3 $("p" ).prepend("hello" ) $("<p></p>" ).prependTo("div" )
After、insertAfter方法
将参数中的元素插在当前元素的后面
1 2 3 $("div" ).after("<p></p>" ) $("<p></p>" ).insertAfter("div" )
before、insertBefore方法
将参数中的元素插入到当前元素的前面
1 2 3 $("div" ).before("<p></p>" ) $("<p></p>" ).insertbefore("div" )
wrap、wrapAll、unwrap、wrapInner方法
wrap方法将参数中的元素变成当前元素的父元素
unwrap方法移除当前元素的父元素
wrapAll方法为结果集的所有元素,添加一个共同的父元素
wrapInner方法为当前元素的所有子元素添加一个父元素
1 2 3 4 $("p" ).wrap("<div></div>" ) $("p" ).unwrap() $("p" ).wrapAll("<div></div>" ) $("p" ).wrapInner('<strong></strong>' )
clone方法
clone方法克隆当前元素
1 var clones = $('li' ).clone();
remove、detach、replaceWith方法
remove方法移除并返回一个元素,取消该元素上所有事件的绑定
detach方法移除并返回一个元素,但不取消该元素上所有事件的绑定
replaceWith用参数中的元素替换并返回当前元素,取消当前元素的所有事件的绑定
1 2 3 $('p' ).remove() $('p' ).detach() $('p' ).replaceWith('<div></div>' )
遍历方法 first方法返回结果集的第一个成员,last方法返回结果集的最后一个成员
1 2 3 $("div p" ).first(); $("div p" ).last();
next方法紧邻的下一个同级元素,prev方法紧邻的上一个同级元素
1 2 $("h2" ).next(); $("h2" ).prev();
siblings方法返回当前元素的所有同级元素,也可以设置参数来过滤对同胞元素的搜索,nextAll方法返回当前元素其后的所有同级元素,prevAll返回当前元素前面的所有同级元素
1 2 3 4 $("h2" ).siblings("p" ) $("h2" ).nextAll("p" ) $("h2" ).prevAll("p" )
parent方法返回当前元素的父元素,parents方法返回当前元素的所有上级元素,也可以指定元素类型进行筛选,parentsUntil方法返回介于两个给定元素之间的所有祖先元素
1 2 3 $("span" ).parent() $("span" ).parents("ul" ) $("span" ).parentsUntil("div" )
closest方法返回当前元素、以及当前元素的所有上级元素之中第一个符合条件的元素
find方法返回当前元素的所有符合条件的下级元素
1 $("span" ).closest("ul" ).css({"color" :"red" })
filter方法用于过滤结果集,他可以接受多种类型的参数,只返回与参数一致的结果,
not方法返回,与filter方法相反
1 2 $("p" ).filter(".url" ) $("p" ).not(".url" )
has方法与filter方法作用相同,但是只过滤出子元素符号条件的元素
is方法判断当前jquery对象是否符合指定的表达式
hasClass方法判断当前对象所匹配的元素是否含有指定的css类名
1 2 $('.object' ).is("expression" ) $('.object' ).hasClass("className" )
获取子元素是父元素的第几个子元素
1 2 3 4 5 6 $(function ( ) { $(".demo ul li" ).click(function ( ) { var index=$(".demo ul li" ).index(this ); console .log(index); }) })
获取第几个子元素
children方法获取该元素下的直接子集元素
find方法获取该元素下的所有子集元素
1 2 3 $('#test' ).children().eq(1 ).css({'display' :'inline-block' }) $('#test' ).find('select' ).eq(2 ).val();
each方法用于遍历指定的对象和数组,并以对象的每个属性或者数组的每个成员作为上下文来遍历执行指定的函数,上下文是指通过this指针引用该元素
map方法用于处理当前的Jquery对象匹配的所有元素,并将结果封装为新的数组。
1 2 3 $("li" ).each(function ( ) { alert($(this )) })
网络请求 $.ajax()方法:执行异步AJAX请求,该方法常用于其他方法不能完成的请求
$.get()方法:使用AJAX的HTTP GET请求从服务器加载数据
$.getJSON()方法:使用HTTP GET请求从服务器加载JSON编码数据
$.getScript()方法:
$.load方法:从服务器加载数据,并把返回的数据放入被选元素中
$.post()方法:使用AJAX的HTTP POST请求从服务器加载数据
1 2 3 $.ajax({url :"demo_test.txt" ,success :function (result ) { $("#div1" ).html(result); }})
使用this 动画 jquery提供简单的动画效果,但整体不如css强大
jquery提供以下动画效果:
show:显示当前元素
hide:隐藏当前元素
toggle:显示或隐藏当前元素
fadeIn:将当前元素的不透明度逐渐提升到100%
fadeOut:将当前元素的不透明度逐渐降为0%
fadeToggle:以逐渐透明或逐渐不透明的方式折叠显示当前元素
slideDown:以从上向下滑入的方式显示当前元素
slideDown只能显示被jquery隐藏的元素或者css设置为display:none的元素,使用overflow:hidden隐藏的元素不能被展示
slideUp:以从下向上滑出的方式隐藏当前元素
sildeToggle:以垂直滑入或滑出的方式折叠显示当前元素
这些方法可以不带参数使用,也可以使用毫秒或者预定义的关键字或自定义的关键字。预定义的关键字也可以进行修改。
1 2 3 4 5 6 7 8 9 10 11 12 13 $('.hidden' ).show(); $('.hidden' ).show(300 ); $('.hidden' ).show('slow' ); jQuery.fx.speeds.fast = 50 ; jQuery.fx.speeds.slow = 3000 ; jQuery.fx.speeds.normal = 1000 ; jQuery.fx.speeds.blazing = 30 ; $('.hidden' ).show('blazing' );
stop、delay方法
stop方法表示立即停止执行当前的动画,delay方法接受一个时间参数,表示暂停多少秒之后执行
1 2 3 4 $('#stop' ).click(function ( ) { $(".block" ).stop(); }) $("#foo" ).slideUp(300 ).delay(800 ).fadeIn(400 )
animate
除了上面这些,jquery可以使用animate自己写动画效果。
animate接受三个参数,第一个参数是一个对象,表示动画结束时的css属性的值,第二个参数是动画持续的毫秒数。写css属性时,如果带有连字号,则需要使用骆驼拼写法改写;第三个参数表示动画结束时的回调函数
1 2 3 4 5 6 7 8 9 10 $('div' ).animate({ left:'+=50' ; opacity:0.25 ; fontSize:'12px' }, 300 , function ( ) { console .log('done!' ); } )
事件处理 on方法
on方法是jquery事件绑定的统一接口,事件绑定的那些简便方法都是on方法的简写形式,
on方法接受两个参数,第一个是事件名称,第二个是回调函数
1 2 3 $('li' ).on('click' ,function (e ) { console .log($(this ),text()); })
为li元素绑定click事件的回调函数
trigger方法
trigger方法用于触发回调函数,它的参数就是事件的名称
1 $('li' ).trigger('click' )
off方法
off方法用来移除事件的回调函数
插件 jquery的其他应用 获取浏览器语言
1 2 3 4 5 6 7 8 9 10 11 12 13 14 var type= navigator.appName;if (type == "Netscape" ){ var lang = navigator.language; }else { var lang = navigator.userlanguage; }; var lang = lang.substr(0 ,2 );if (lang == "zh" ){ window .location.replace('url' ) }else if (lang == "en" ){ window .location.replace('url' ) }else { window .location.replace('url' ) }
获取浏览器类型
loash.js Array _.chunk:将一个数组拆分成多个size长度的区块,并用这些区块组成一个新数组
_.compact:去掉原数组中所有的假值元素,创建一个新数组
_.concat:将所有参数组合,创建一个新数组,
_.difference:返回过滤后的新数组,去除重复值
_.differenceBy:
_.drop:去除数组中的前n个元素
_.dropRight:去除数组尾部的n个元素
_.dropRightWhile:
_.union: 创建一个按顺序排列的唯一值的数组, 可以合并数组。
.unionWith: 这个方法类似[` .union](https://www.lodashjs.com/docs/lodash.unionWith#union), 除了它接受一个
comparator调用比较
arrays`数组的每一个元素。
.unionBy: 这个方法类似[` .union](https://www.lodashjs.com/docs/lodash.unionBy#union) ,除了它接受一个
iteratee(迭代函数),调用每一个数组(
array`)的每个元素以产生唯一性计算的标准。
_.uniq(array):创建一个去重之后的数组副本
_.uniqBy(array):创建一个去重之后的数组副本
_.uniqWith(array):创建一个去重之后的数组副本
_.zip():创建一个分组元素的数组,数组的第一个元素包含所有给定数组的第一个元素,数组的第二个元素包含所有给定数组的第二个元素,以此类推。
.zipWith():这个方法类似于[` .zip](https://www.lodashjs.com/docs/lodash.zipWith#zip),不同之处在于它接受一个
iteratee`(迭代函数),来 指定分组的值应该如何被组合。 该iteratee调用每个组的元素
_.zipObject():
_.zipObjectDeep():
.unzip():这个方法类似于[` .zip`](https://www.lodashjs.com/docs/lodash.unzip#zip),除了它接收分组元素的数组,并且创建一个数组,分组元素到打包前的结构。
.unzipWith():此方法类似于[` .unzip](https://www.lodashjs.com/docs/lodash.unzipWith#unzip),除了它接受一个
iteratee`指定重组值应该如何被组合。iteratee 调用时会传入每个分组的值
_.fromPairs():接受数组,返回一个由键值对构成的对象
_.tail():返回数组中去除第一个元素之后的数组
_.pull():移除数组array
中所有和给定值相等的元素
_.pullAll():与pull方法功能相同,只是这个方法接收一个数组
_.pullAllBy(): 与pull方法功能相同,区别是这个方法接受一个 iteratee
(迭代函数) 调用 array
和 values
的每个值以产生一个值,通过产生的值进行了比较。
.pullAllWith():这个方法类似于[` .pullAll](https://www.lodashjs.com/docs/lodash.pullAllWith#pullAll),区别是这个方法接受
comparator调用
array中的元素和
values`比较。
_.pullAt():根据索引 indexes
,移除array
中对应的元素,并返回被移除元素的数组。
_.intersection():创建唯一值的数组,这个数组包含所有给定数组都包含的元素
_.intersectionBy(): 类似于intersection, 区别是它接受一个 iteratee
调用每一个arrays
的每个值以产生一个值,通过产生的值进行了比较
_.intersectionWith():类似于intersection, 区别是它接受一个 comparator
调用比较arrays
中的元素。结果值是从第一数组中选择
_.take(): 创建一个数组切片,从array
数组的起始元素开始提取n
个元素
_.takeRight(): 创建一个数组切片,从array
数组的最后一个元素开始提取n
个元素
_.takeRightWhile(): 从array
数组的最后一个元素开始提取元素,直到 predicate
返回假值
_.takeWhile(): 从array
数组的起始元素开始提取元素,,直到 predicate
返回假值
_.xor(): 创建一个给定数组唯一值的数组
_.xorBy(): 除了它接受 iteratee
(迭代器),这个迭代器 调用每一个 arrays
(数组)的每一个值,以生成比较的新值
.xorWith(): 该方法是像[` .xor](https://www.lodashjs.com/docs/lodash.xorWith#xor),除了它接受一个
comparator` ,以调用比较数组的元素
Object _.assign:返回一个对象
_.at:返回所选中对象属性组成的数组
_.findKey:返回满足value条件的key
_.findLastKey:
_.pick:返回一个从object中选中的属性的对象
_.pickBy:返回一个从object中判断为真的属性的对象
_.omit:与pick返回结果相反
_.omitBy:与pickBy返回结果相反
_.invert:返回一个原对象key-value倒置的对象
_.invertBy:返回一个原对象key-value倒置的对象,与invert不同的是value是一个数组
_.values:返回一个object可枚举属性组成的数组
_.valuesln:返回一个object自身和继承的可枚举属性组成的数组
_.toPairs: 创建一个object
对象自身可枚举属性的键值对数组
_.toPairsIn: 创建一个object
对象自身和继承的可枚举属性的键值对数组。
_.mapKeys: 创建一个对象,这个对象的value与object
对象相同, 只修改对象中的key
_.mapValues: 创建一个对象,这个对象的key与object
对象相同,值是通过 iteratee
运行 object
中每个自身可枚举属性名字符串产生的
_.merge: 返回对象的浅拷贝对象,对象自身和继承的可枚举属性到 object
目标对象。
_.mergeWith: 与merge函数功能相同,并且它接受一个 customizer
,调用以产生目标对象和来源对象属性的合并值。如果customizer
返回 undefined
,将会由合并处理方法代替
String _.camelCase:转换字符串为下驼峰写法
_.capitalize:返回首字母为大写、其他字母为小写的字符串
_.upperCase(): 转换字符串string
为 空格 分隔的大写单词
_.upperFirst(): 转换字符串string的首字母为大写
_.lowerCase(): 转换字符串string
以空格分开单词,并转换为小写
_.lowerFirst(): 转换字符串string的首字母为小写
_.snakeCase():转换字符串为snakecase
_.startCase(): 转换字符串为start case
_.startWith: 返回布尔值,是否以该首字母开头
_.toLower:转换整个字符串的字符为小写
_.toUpper:转换整个字符串的字符为大写
_.trim:从字符串中移除前面和后面的空格或指定的字符串
_.trimEnd:移除字符串后面的空格或者指定字符串
_.trimStart: 移除字符串前面的空格或者指定字符串
_.pad(): 如果string
字符串长度小于 length
则从左侧和右侧填充字符。 如果没法平均分配,则截断超出的长度
_.padEnd(): 如果string
字符串长度小于 length
则在右侧填充字符。 如果超出length
长度则截断超出的部分
_.padStart():如果string
字符串长度小于 length
则在左侧填充字符。 如果超出length
长度则截断超出的部分
_.truncate(): 截断string
字符串,如果字符串超出了限定的最大值。 被截断的字符串后面会以 omission 代替,omission 默认是 “…”
常用函数 Math _.ceil:向上取整数
_.floor:向下取整数
_.max:取数组中的最大值
_.maxBy:
_.min:取数组中的最小值
_.minBy
_.mean:计算数组中的平均值
_.meanBy
_.divide:除
Number _.clamp:返回限制在上下限之间的值
_.inRange:返回布尔值,判断是否在上下限之间
_.random:产生一个上下限之间的数,可以指定是否为浮点数
1 2 3 _.clamp(-10 ,-5 ,5 ) _.inRange(3 ,2 ,4 ) _.random(0 ,5 )
fullpage.js 安装
Velocity.js Momentjs momentjs是js日期处理类库,js原生对date对象处理比较好,但是对时间戳处理不友好,所以moment在这方面比原生的时间处理函数更强大。
安装
1 npm install moment --save
引入
1 import moment from 'moment'
日期格式化
1 2 3 4 5 moment().format('MMMM Do YYYY, h:mm:ss a' ); moment().format('dddd' ); moment().format("MMM Do YY" ); moment().format('YYYY [escaped] YYYY' ); moment().format();
获取时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 moment().format('X' ) moment().unix() moment().format('x' ) moment().valueOf() moment().get('year' ) moment().get('11' ) moment().get('25' ) moment().day() (0 ~6 , 0 : 周日, 6 : 周六) moment().weekday() (0 ~6 , 0 : 周日, 6 : 周六) moment().isoWeekday() (1 ~7 , 1 : 周一, 7 : 周日) moment().get('day' ) mment().get('weekday' ) moment().get('isoWeekday' ) moment().toArray() moment().toObject() moment().seconds() moment().get('seconds' ) moment().minutes() moment().get('minutes' ) moment().hours() moment().get('hours' )
获取相对时间
1 2 3 4 5 6 7 8 9 10 11 moment("20111031" , "YYYYMMDD" ).fromNow(); moment("20120620" , "YYYYMMDD" ).fromNow(); moment().startOf('day' ).fromNow(); moment().startOf('day' ) moment().startOf('week' ) moment().startOf('isoWeek' ) moment().startOf('month' ) moment().endOf('day' ).fromNow(); moment().endOf('day' ) moment().startOf('hour' ).fromNow();
日历时间
1 2 3 4 5 6 7 8 9 10 moment().subtract(10 , 'days' ).calendar(); moment().subtract(6 , 'days' ).calendar(); moment().subtract(3 , 'days' ).calendar(); moment().subtract(1 , 'days' ).calendar(); moment().calendar(); moment().add(1 , 'days' ).calendar(); moment().add(3 , 'days' ).calendar(); moment().add(10 , 'days' ).calendar();
获取当前月总天数
比较时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 let start_date = moment().subtract(1 , 'weeks' )let end_date = moment()end_date.diff(start_date) end_date.diff(start_date, 'months' ) end_date.diff(start_date, 'weeks' ) end_date.diff(start_date, 'days' ) start_date.diff(end_date, 'days' ) end_date.isBefore(start_date); end_date.isAfter(start_date); end_date.isSame(start_date); end_date.isSameOrBefore(start_date); end_date.isSameOrAfter(start_date); moment().isBetween(moment-like, moment-like); moment().isLeapYear(); moment.isMoment(end_date); moment.isDate(end_date);
转为js原生时间对象
1 2 let m = moment()let nativeDate1 = m.toDate()
设置时间
1 2 3 4 5 6 7 8 moment().set('year' , 2019 ) moment().set('month' , 11 ) moment().set('date' , 15 ) moment().set('weekday' , 0 ) moment().set('isoWeekday' , 1 ) moment().set('hours' , 12 ) moment().set('minutes' , 30 ) moment().set('seconds' , 30 )
https://segmentfault.com/a/1190000015240911
date-fns 像lodash一样的操作日期
安装
1 2 3 npm install date-fns --save # or with yarn yarn add date-fns
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import { compareAsc, format } from 'date-fns' format(new Date (2014 , 1 , 11 ), 'yyyy-MM-dd' ) const dates = [ new Date (1995 , 6 , 2 ), new Date (1987 , 1 , 11 ), new Date (1989 , 6 , 10 ), ] dates.sort(compareAsc)
dayjs 由于momentjs不再维护,因此寻找别的js时间库进行时间操作。
dayjs对时间的操作
bigNumberjs bignumber.js是一个用于数学计算的库,支持任意精度
clone()
config()
maximum()、minimum()
random([])
实例方法:
plus():加法。minus():减法
.times():乘法 div():除法。.idiv():除法,只返回整数
.mod():取模/取余。.pow():指数运算 .sqrt():开平方
.comparedTo():比较大小
.dp() 精度调整
.integerValue():取整
.sd():有效数字
.toFixed():返回字符串,截取小数点后位数
.toFormat():数字格式化
.toNumber():转换为js基础数值类型
slidev 在线ppt制作
shell.js Shelljs是Node.js下的脚本语言解析器,具有丰富且强大的底层操作(Windows/Linux/OS X)权限。Shelljs本质就是基于node的一层命令封装插件,让前端开发者可以不依赖linux也不依赖类似于cmder的转换工具,而是直接在我们最熟悉不过的javascript代码中编写shell命令实现功能。
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var shell = require ('shelljs' );if (shell.exec('npm run build' ).code !== 0 ) { shell.echo('Error: Git commit failed' ); shell.exit(1 ); } shell.cp ('-r' , './dist/*' , '../../Rychou' ); shell.cd('../../Rychou' ); shell.exec('git add .' ); shell.exec("git commit -m 'autocommit'" ) shell.exec('git push' )
Robotjs自动化库 控制鼠标移动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var robot = require ("robotjs" );robot.setMouseDelay(2 ); var twoPI = Math .PI * 2.0 ;var screenSize = robot.getScreenSize();var height = (screenSize.height / 2 ) - 10 ;var width = screenSize.width;for (var x = 0 ; x < width; x++){ y = height * Math .sin((twoPI * x) / width) + height; robot.moveMouse(x, y); }
控制键盘输入
1 2 3 4 5 6 7 8 var robot = require ("robotjs" );robot.typeString("Hello World" ); robot.keyTap("enter" );
获取屏幕数据
1 2 3 4 5 6 7 8 9 var robot = require ("robotjs" );var mouse = robot.getMousePos();var hex = robot.getPixelColor(mouse.x, mouse.y);console .log("#" + hex + " at x:" + mouse.x + " y:" + mouse.y);
js-导出读取xlsx包 sheetjs
https://github.com/SheetJS/sheetjs
安装
读取本地文件
1 2 3 4 5 6 7 8 9 10 function readWorkbookFromLocalFile (file, callback ) { var reader = new FileReader(); reader.onload = function (e ) { var data = e.target.result; var workbook = XLSX.read(data, {type : 'binary' }); if (callback) callback(workbook); }; reader.readAsBinaryString(file); }
读取网络文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function readWorkbookFromRemoteFile (url, callback ) { var xhr = new XMLHttpRequest(); xhr.open('get' , url, true ); xhr.responseType = 'arraybuffer' ; xhr.onload = function (e ) { if (xhr.status == 200 ) { var data = new Uint8Array (xhr.response) var workbook = XLSX.read(data, {type : 'array' }); if (callback) callback(workbook); } }; xhr.send(); }
通过上述代码获取到workbook对象
workbook对象中的SheetNames
里面保存了所有的sheet名字,然后Sheets
则保存了每个sheet的具体内容(我们称之为Sheet Object
)。每一个sheet
是通过类似A1
这样的键值保存每个单元格的内容,我们称之为单元格对象(Cell Object
)
Sheet Object
表示一张表格,只要不是!
开头的都表示普通cell
,否则,表示一些特殊含义,具体如下:
!ref:表示此sheet所有单元格的范围,如A1到F8
[!merges]
:存放一些单元格合并信息,是一个数组,每个数组由包含s
和e
构成的对象组成,s
表示开始,e
表示结束,r
表示行,c
表示列;
每一个单元格是一个对象(Cell Object
),主要有t
、v
、r
、h
、w
等字段
t:表示内容类型,s
表示string类型,n
表示number类型,b
表示boolean类型,d
表示date类型,等等
v:表示原始值;
f:表示公式,如B2+B3
;
h:HTML内容
w:格式化后的内容
r:富文本内容rich text
读取workbook对象
1 2 3 4 5 6 7 8 9 10 11 function outputWorkbook (workbook ) { var sheetNames = workbook.SheetNames; sheetNames.forEach(name => { var worksheet = workbook.Sheets[name]; for (var key in worksheet) { console .log(key, key[0 ] === '!' ? worksheet[key] : worksheet[key].v); } }); }
XLSX.utils.sheet_to_csv
:生成CSV格式
XLSX.utils.sheet_to_txt
:生成纯文本格式
XLSX.utils.sheet_to_html
:生成HTML格式
XLSX.utils.sheet_to_json
:输出JSON格式
导出xlsx文件
使用插件官方提供的工具类
aoa_to_sheet
: 这个工具类最强大也最实用了,将一个二维数组转成sheet,会自动处理number、string、boolean、date等类型数据;
table_to_sheet
: 将一个table dom
直接转成sheet,会自动识别colspan
和rowspan
并将其转成对应的单元格合并;
json_to_sheet
: 将一个由对象组成的数组转成sheet;
处理单元格合并
1 2 3 4 5 6 7 8 9 10 11 12 var aoa = [ ['主要信息' , null , null , '其它信息' ], ['姓名' , '性别' , '年龄' , '注册时间' ], ['张三' , '男' , 18 , new Date ()], ['李四' , '女' , 22 , new Date ()] ]; var sheet = XLSX.utils.aoa_to_sheet(aoa);sheet['!merges' ] = [ {s : {r : 0 , c : 0 }, e : {r : 0 , c : 2 }} ]; openDownloadDialog(sheet2blob(sheet), '单元格合并示例.xlsx' );
http://blog.haoji.me/js-excel.html#dao-chu-excel
marked.js marked.js可以将md解析为html
1 <script type ="text/javascript" src ="https://cdn.jsdelivr.net/npm/marked/marked.min.js" > </script >
使用
1 2 let md = `### h3` let table = marked(md);
Showdown.js Markdown转 html
1 2 3 4 5 6 7 8 9 10 11 <script src ="/showdown-1.9.0/dist/showdown.min.js" > </script > <script type ="text/javascript" > var content = $('#text' ).text(); var converter = new showdown.Converter(); var htmlcontent = converter.makeHtml(content); $("#article" ).html(htmlcontent); </script > <body > <p id ="text" > </p > <p id ="article" > </p > </body >
docsearchjs 首先在Algolia申请一个api。
在Vue中可以使用docsearchjs,配合Algolia使用
1 yarn add -D docsearch.js
在组件中使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <template> <input type="text" class="search-input" id="search_input" placeholder="" /> </template> <script> import 'docsearch.js/dist/cdn/docsearch.min.css' import docsearch from 'docsearch.js' export default { mounted () { docsearch({ apiKey: 'feb33c2506cdece7f0267859a856767a' IndexName: '', inputSelector: '#search_input', algoliaOptions: { 'fetchFilters': ['version: v2_0'] }, debug: false }) } } </script>
还有组件we-vue可以使用
hedron.js FormatJS 是一个模块化的 JavaScript 国际化库。可用于格式化数值、日期等显示,使用 i18n 工业标准,提供一些常用的模板和组件库。
已经有很多包内置formatjs,比如react-intl
react-intl npm 包文件可以通过设置package.json 文件的main的方式可以为commnjs, ES6, UMD dev, UMD prod这几个版本,但无论是使用那个版本的React Intl, 它们都提供相同的命名导出如下:
shepherd.js 引导用户进行网站教程
安装
1 2 <link rel ="stylesheet" href ="shepherd.js/dist/css/shepherd.css" /> <script src ="shepherd.js/dist/js/shepherd.min.js" > </script >
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 const tour = new Shepherd.Tour({ defaultStepOptions: { cancelIcon: { enabled: true }, classes: 'class-1 class-2' , scrollTo: { behavior : 'smooth' , block : 'center' } } }); tour.addStep({ title: 'Creating a Shepherd Tour' , text: `Creating a Shepherd tour is easy. too!\ Just create a \`Tour\` instance, and add as many steps as you want.` , attachTo: { element: '.hero-example' , on: 'bottom' }, buttons: [ { action() { return this .back(); }, classes: 'shepherd-button-secondary' , text: 'Back' }, { action() { return this .next(); }, text: 'Next' } ], id: 'creating' }); tour.start();
react-shepherd 安装
1 npm install --save react-shepherd
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import React, { Component, useContext } from 'react' import { ShepherdTour, ShepherdTourContext } from 'react-shepherd' import newSteps from './steps' const tourOptions = { defaultStepOptions: { cancelIcon: { enabled: true } }, useModalOverlay: true }; function Button() { const tour = useContext(ShepherdTourContext); return ( <button className="button dark" onClick={tour.start}> Start Tour </button> ); } class App extends Component { render() { return ( <div> <ShepherdTour steps={newSteps} tourOptions={tourOptions}> <Button /> </ShepherdTour> </div> ); } }
peer.js 简化使用WebRTC
https://www.cnblogs.com/yjmyzz/p/peerjs-tutorial.html
这是mozilla开发者官网上的一张图, 大致描述了webrtc的处理过程:
A通过STUN服务器,收集自己的网络信息
A创建Offer SDP,通过Signal Channel(信令服务器)给到B
B做出回应生成Answer SDP,通过Signal Channel给到A
B通过STUN收集自己的网络信息,通过Signal Channel给到A
注:如果A,B之间无法直接穿透(即:无法建立点对点的P2P直连),将通过TURN服务器中转。
要创建一个真正的webrtc应用还是有些小复杂的,特别是SDP交换(createOffer及createAnswer)、网络候选信息收集(ICE candidate),这些都需要开发人员对webrtc的机制有足够的了解,对webrtc初学者来讲有一定的开发门槛。
而peerjs开源项目简化了webrtc的开发过程,把SDP交换、ICE candidate这些偏底层的细节都做了封装,开发人员只需要关注应用本身就行了。 peerjs的核心对象Peer,它有几个常用方法:
peer.connect 创建点对点的连接
peer.call 向另1个peer端发起音视频实时通信
peer.on 对各种事件的监控回调
peer.disconnect 断开连接
peer.reconnect 重新连接
peer.destroy 销毁对象
另外还有二个重要对象DataConnection、MediaConnection,其中:
DataConnection用于收发数据(对应于webrtc中的DataChannel),它的所有方法中有一个重要的send方法,用于向另一个peer端发送数据;
MediaConnection用于处理媒体流,它有一个重要的stream属性,表示关联的媒体流。
更多细节可查阅peerjs的api在线文档 (注:peerjs的所有api只有一页,估计15分钟左右就全部看一圈)
peerjs的服务端(即信令服务器)很简单,只需要下面这段nodejs代码即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 var fs = require ('fs' );var PeerServer = require ('peer' ).PeerServer; var options = { key: fs.readFileSync('key/server.key' ), cert: fs.readFileSync('key/server.crt' ) } var server = PeerServer({ port: 9000 , ssl: options, path:"/" });
文本聊天
主要流程:
Jack和Rose先连接到PeerJs服务器
Rose指定要建立p2p连接的对方名称(即:Jack),然后发送消息
Jack在自己的页面上,可以实时收到Rose发送过来的文字,并回复
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 var txtSelfId = document .querySelector("input#txtSelfId" );var txtTargetId = document .querySelector("input#txtTargetId" );var txtMsg = document .querySelector("input#txtMsg" );var tdBox = document .querySelector("td#tdBox" );var btnRegister = document .querySelector("button#btnRegister" );var btnSend = document .querySelector("button#btnSend" ); let peer = null ;let conn = null ; hashCode = function (str ) { var hash = 0 ; if (str.length == 0 ) return hash; for (i = 0 ; i < str.length; i++) { char = str.charCodeAt(i); hash = ((hash << 5 ) - hash) + char; hash = hash & hash; } return hash; } sendMessage = function (message ) { conn.send(JSON .stringify(message)); console .log(message); tdBox.innerHTML = tdBox.innerHTML += "<div class='align_left'>" + message.from + " : " + message.body + "</div>" ; } window .onload = function ( ) { let connOption = { host : 'localhost' , port : 9000 , path : '/' , debug : 3 }; btnRegister.onclick = function ( ) { if (!peer) { if (txtSelfId.value.length == 0 ) { alert("please input your name" ); txtSelfId.focus(); return ; } peer = new Peer(hashCode(txtSelfId.value), connOption); peer.on('open' , function (id ) { tdBox.innerHTML = tdBox.innerHTML += "<div class='align_right'>system : register success " + id + "</div>" ; }); peer.on('connection' , (conn) => { conn.on('data' , (data) => { var msg = JSON .parse(data); tdBox.innerHTML = tdBox.innerHTML += "<div class='align_right'>" + msg.from + " : " + msg.body + "</div>" ; if (txtTargetId.value.length == 0 ) { txtTargetId.value = msg.from; } }); }); } } btnSend.onclick = function ( ) { var message = { "from" : txtSelfId.value, "to" : txtTargetId.value, "body" : txtMsg.value }; if (!conn) { if (txtTargetId.value.length == 0 ) { alert("please input target name" ); txtTargetId.focus(); return ; } if (txtMsg.value.length == 0 ) { alert("please input message" ); txtMsg.focus(); return ; } conn = peer.connect(hashCode(txtTargetId.value)); conn.on('open' , () => { sendMessage(message); }); } if (conn.open) { sendMessage(message); } } }
如果两端的浏览器如果不在一个网段,需要配置stun或turn服务器,参考下面的配置
1 2 3 4 5 6 var peer = new Peer({ config: {'iceServers' : [ { url : 'stun:stun.l.google.com:19302' }, { url : 'turn:homeo@turn.bistri.com:80' , credential : 'homeo' } ]} });
视频通话
在1个页面上输入”张三“并点击register,同时允许使用摄像头,然后在另1个页面输入”李四“,也点击register,并允许使用摄像头,然后把摄像头切换到另1个,这样2个页面看到的本地视频就不一样了(相当于2个端各自的视频流)。然后在”李四”的页面上,target name这里输入”张三”,并点击call按钮发起视频通话,此时”张三”的页面上会马上收到邀请确认
”张三“选择Accept同意后,二端就相互建立连接,开始实时视频通话
注:首次运行时,浏览器会弹出类似下图的提示框询问是否同意启用摄像头/麦克风(出于安全隐私考虑),如果手一抖选择了不允许,就算刷新页面,也不会再弹出提示框。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 btnCall.onclick = function ( ) { if (txtTargetId.value.length == 0 ) { alert("please input target name" ); txtTargetId.focus(); return ; } sendMessage(txtSelfId.value, txtTargetId.value, "call" ); } function sendMessage (from, to, action ) { var message = { "from" : from , "to" : to, "action" : action }; if (!localConn) { localConn = peer.connect(hashCode(to)); localConn.on('open' , () => { localConn.send(JSON .stringify(message)); console .log(message); }); } if (localConn.open){ localConn.send(JSON .stringify(message)); console .log(message); } } btnRegister.onclick = function ( ) { if (!peer) { if (txtSelfId.value.length == 0 ) { alert("please input your name" ); txtSelfId.focus(); return ; } peer = new Peer(hashCode(txtSelfId.value), connOption); peer.on('open' , function (id ) { console .log("register success. " + id); }); peer.on('call' , function (call ) { call.answer(localStream); }); peer.on('connection' , (conn) => { conn.on('data' , (data) => { var msg = JSON .parse(data); console .log(msg); if (msg.action === "call" ) { lblFrom.innerText = msg.from; txtTargetId.value = msg.from; $("#dialog-confirm" ).dialog({ resizable: false , height: "auto" , width: 400 , modal: true , buttons: { "Accept" : function ( ) { $(this ).dialog("close" ); sendMessage(msg.to, msg.from, "accept" ); }, Cancel: function ( ) { $(this ).dialog("close" ); } } }); } if (msg.action === "accept" ) { console .log("accept call => " + JSON .stringify(msg)); var call = peer.call(hashCode(msg.from), localStream); call.on('stream' , function (stream ) { console .log('received remote stream' ); remoteVideo.srcObject = stream; sendMessage(msg.to, msg.from, "accept-ok" ); }); } if (msg.action === "accept-ok" ) { console .log("accept-ok call => " + JSON .stringify(msg)); var call = peer.call(hashCode(msg.from), localStream); call.on('stream' , function (stream ) { console .log('received remote stream' ); remoteVideo.srcObject = stream; }); } }); }); } }
白板共享
send方法不仅仅可以用来发送文字消息,同样也可以发送其它内容,每次在canvas上的的涂鸦,本质上就是调用canvas的api在一系列的坐标点上连续画线。只要把1个页面上画线经过的坐标点发送到另1个页面上,再还原出来就可以了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 window .onload = function ( ) { if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { console .log('webrtc is not supported!' ); alert("webrtc is not supported!" ); return ; } let connOption = { host : 'localhost' , port : 9000 , path : '/' , debug : 3 }; context = demoCanvas.getContext('2d' ); demoCanvas.onmousedown = function (e ) { e.preventDefault(); context.strokeStyle='#00f' ; context.beginPath(); started = true ; buffer.push({ "x" : e.offsetX, "y" : e.offsetY }); } demoCanvas.onmousemove = function (e ) { if (started) { context.lineTo(e.offsetX, e.offsetY); context.stroke(); buffer.push({ "x" : e.offsetX, "y" : e.offsetY }); } } demoCanvas.onmouseup = function (e ) { if (started) { started = false ; sendData(txtSelfId.value, txtTargetId.value, buffer); buffer = []; } } btnRegister.onclick = function ( ) { if (!peer) { if (txtSelfId.value.length == 0 ) { alert("please input your name" ); txtSelfId.focus(); return ; } peer = new Peer(hashCode(txtSelfId.value), connOption); peer.on('open' , function (id ) { console .log("register success. " + id); }); peer.on('connection' , (conn) => { conn.on('data' , (data) => { let msg = JSON .parse(data); console .log(msg); txtTargetId.value = msg.from; context.strokeStyle='#f00' ; context.beginPath(); context.moveTo(msg.data[0 ].x,msg.data[0 ].y); for (const pos in msg.data) { context.lineTo(msg.data[pos].x,msg.data[pos].y); } context.stroke(); }); }); } } btnShare.onclick = function ( ) { if (txtTargetId.value.length == 0 ) { alert("please input target name" ); txtTargetId.focus(); return ; } } start(); } function sendData (from, to, data ) { if (from .length == 0 || to.length == 0 || data.length == 0 ) { return ; } let message = { "from" : from , "to" : to, "data" : data }; if (!localConn) { localConn = peer.connect(hashCode(to)); localConn.on('open' , () => { localConn.send(JSON .stringify(message)); console .log(message); }); } if (localConn.open) { localConn.send(JSON .stringify(message)); console .log(message); } }
发送文件
在2个浏览器页面上,分别register2个用户,然后在其中1个页面上,输入对方的名字,然后选择一张图片,另1个页面将会收到传过来的图片。
核心仍然利用的是DataConnection的send方法,只不过发送的内容里包含了图片对应的blob对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 btnRegister.onclick = function ( ) { if (!peer) { if (txtSelfId.value.length == 0 ) { alert("please input your name" ); txtSelfId.focus(); return ; } peer = new Peer(hashCode(txtSelfId.value), connOption); peer.on('open' , function (id ) { console .log("register success. " + id); lblStatus.innerHTML = "scoket open" }); peer.on('connection' , (conn) => { conn.on('data' , (data) => { console .log("receive remote data" ); lblStatus.innerHTML = "receive data from " + data.from; txtTargetId.value = data.from if (data.filetype.includes('image' )) { lblStatus.innerHTML = data.filename + "(" + data.filetype + ") from:" + data.from const bytes = new Uint8Array (data.file) img.src = 'data:image/png;base64,' + encode(bytes) } }); }); } } inputFile.onchange = function (event ) { if (txtTargetId.value.length == 0 ) { alert("please input target name" ); txtTargetId.focus(); return ; } const file = event.target.files[0 ] const blob = new Blob(event.target.files, { type : file.type }); img.src = window .URL.createObjectURL(file); sendFile(txtSelfId.value, txtTargetId.value, blob, file.name, file.type); } function sendFile (from, to, blob, fileName, fileType ) { var message = { "from" : from , "to" : to, "file" : blob, "filename" : fileName, "filetype" : fileType }; if (!localConn) { localConn = peer.connect(hashCode(to)); localConn.on('open' , () => { localConn.send(message); console .log('onopen sendfile' ); }); } localConn.send(message); console .log('send file' ); }
video.js HTTP stream 是各家自己定义的http流,应用于国内点播视频网站。
HLS 是苹果公司实现的基于 HTTP 的流媒体传输协议,全称 HTTP Live Streaming,可支持流媒体的直播和点播,主要应用在 iOS 系统,为 iOS 设备(如 iPhone、iPad)提供音视频直播和点播方案。
RTMP 是实时消息传输协议,Real Time Messaging Protocol,是 Adobe Systems 公司为 Flash 播放器和服务器之间音频、视频和数据传输开发的开放协议。协议基于 TCP,是一个协议族,包括 RTMP 基本协议及 RTMPT/RTMPS/RTMPE 等多种变种。RTMP 是一种设计用来进行实时数据通信的网络协议,主要用来在 Flash/AIR 平台和支持RTMP协议的流媒体/交互服务器之间进行音视频和数据通信。
HTTP用于点播,本质上还是文件分发,实时性差。
HLS支持点播和直播 ,HLS的延迟在10秒以上。
RTMP本质上是流协议,主要的优势是:实时性高(实时性一般在3秒之内)、稳定性高。主要用于直播 应用,对实时性有一定要求。
RTMP协议一般传输的是flv,f4v格式流,RTSP协议一般传输的是ts,mp4格式的流。HTTP没有特定的流。
video.js有两种初始化方式,一种是在video的html标签之中,一种是使用js来进行初始化。两种都需先引入video.js和video-js.css
在html标签中初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <link href ="//vjs.zencdn.net/7.3.0/video-js.min.css" rel ="stylesheet" > <script src ="//vjs.zencdn.net/7.3.0/video.min.js" > </script > <video id ="my-player" class ="video-js" controls preload ="auto" poster ="//vjs.zencdn.net/v/oceans.png" width ="600" height ="400" data-setup ='{}' > <source src ="//vjs.zencdn.net/v/oceans.mp4" type ="video/mp4" > </source > <source src ="//vjs.zencdn.net/v/oceans.webm" type ="video/webm" > </source > <source src ="//vjs.zencdn.net/v/oceans.ogv" type ="video/ogg" > </source > <p class ="vjs-no-js" > To view this video please enable JavaScript, and consider upgrading to a web browser that <a href ="https://videojs.com/html5-video-support/" target ="_blank" > supports HTML5 video </a > </p > </video >
在js中初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 <video id ="myVideo" class ="video-js vjs-big-play-centered vjs-fluid" > <p class ="vjs-no-js" > To view this video please enable JavaScript, and consider upgrading to a web browser that <a href ="https://videojs.com/html5-video-support/" target ="_blank" > supports HTML5 video </a > </p > </video > <script > var player = videojs(document .getElementById('myVideo' ), { controls: true , poster: 'xxx' , preload: 'auto' , autoplay: false , fluid: true , language: 'zh-CN' , muted: false , inactivityTimeout: false , controlBar: { /* 设置控制条里面组件的相关属性及显示与否 'currentTimeDisplay' :true , 'timeDivider' :true , 'durationDisplay' :true , 'remainingTimeDisplay' :false , volumePanel: { inline: false , } */ children: [ {name: 'playToggle' }, {name: 'currentTimeDisplay' }, {name: 'progressControl' }, {name: 'durationDisplay' }, { name: 'playbackRateMenuButton' , 'playbackRates' : [0.5 , 1 , 1.5 , 2 , 2.5 ] }, { name: 'volumePanel' , inline: false , }, {name: 'FullscreenToggle' } ] }, sources:[ { src: '//vjs.zencdn.net/v/oceans.mp4' , type: 'video/mp4' , poster: '//vjs.zencdn.net/v/oceans.png' } ] }, function () { console .log('视频可以播放了' ,this ); }); </script >
controlBar组件说明
playToggle
, //播放暂停按钮
volumeMenuButton
,//音量控制
currentTimeDisplay
,//当前播放时间
timeDivider
, // ‘/‘ 分隔符
durationDisplay
, //总时间
progressControl
, //点播流时,播放进度条,seek控制
liveDisplay
, //直播流时,显示LIVE
remainingTimeDisplay
, //当前播放时间
playbackRateMenuButton
, //播放速率,当前只有html5模式下才支持设置播放速率
fullscreenToggle
//全屏控制
currentTimeDisplay
,timeDivider
,durationDisplay
是相对于 remainingTimeDisplay
的另一套组件,后者只显示当前播放时间,前者还显示总时间。若要显示成前者这种模式,即 ‘当前时间/总时间’,可以在初始化播放器选项中配置
动态切换视频
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <script > var data = { src: 'xxx.mp4' , type: 'video/mp4' }; var player = videojs('myVideo' , {...}); player.pause(); player.src(data); player.load(data); player.posterImage.setSrc('xxx.jpg' ); player.play(); </script >
设置语言
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <script src ="//example.com/path/to/lang/es.js" > </script > <script src ="//example.com/path/to/lang/zh-CN.js" > </script > <script src ="//example.com/path/to/lang/zh-TW.js" > </script > <script > var player = videojs('myVideo' , { language: 'zh-CN' }); /* 动态切换语言 使用这种方式进行动态切换不会立即生效,必须有所操作后才会生效。如播放按钮,必须点击一次播放按钮后播放按钮的提示文字才会改变 */ </script >
vue开发
1 2 3 4 5 6 7 8 9 import Video from 'video.js' /* 不能直接引入js,否则会报错:videojs is not defined import 'video.js/dist/lang/zh-CN.js' */ import video_zhCN from 'video.js/dist/lang/zh-CN.json' import video_en from 'video.js/dist/lang/en.json' import 'video.js/dist/video-js.css' Video.addLanguage('zh-CN', video_zhCN); Video.addLanguage('en', video_en);
pace.js PDF.js wiki.js axios Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
其基本的特性是
从浏览器中创建 XMLHttpRequests
从 node.js 创建 http 请求
支持 Promise API
拦截请求和响应
转换请求数据和响应数据
取消请求
自动转换 JSON 数据
客户端支持防御 XSRF
responseType: 设置表示服务器响应的数据类型,可以是 ‘arraybuffer’, ‘blob’, ‘document’, ‘json’, ‘text’, ‘stream’, 默认是json
拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 axios.interceptors.request.use(function (config ) { return config; }, function (error ) { return Promise .reject(error); }); axios.interceptors.response.use(function (response ) { return response; }, function (error ) { return Promise .reject(error); }); const myInterceptor = axios.interceptors.request.use(function ( ) {});axios.interceptors.request.eject(myInterceptor);
全局配置
1 2 3 axios.defaults.baseURL = 'https://api.example.com' ; axios.defaults.headers.common['Authorization' ] = AUTH_TOKEN; axios.defaults.headers.post['Content-Type' ] = 'application/x-www-form-urlencoded' ;
错误处理
1 2 3 4 5 axios.get('/user/12345' , { validateStatus: function (status ) { return status < 500 ; } })
取消请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const CancelToken = axios.CancelToken;const source = CancelToken.source();axios.get('/user/12345' , { cancelToken: source.token }).catch(function (thrown ) { if (axios.isCancel(thrown)) { console .log('Request canceled' , thrown.message); } else { } }); axios.post('/user/12345' , { name: 'new name' }, { cancelToken: source.token }) source.cancel('Operation canceled by the user.' );
moxios 基于axios的mock包
安装
1 npm install moxios --save-dev
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 import axios from 'axios' import moxios from 'moxios' import sinon from 'sinon' import { equal } from 'assert' describe('mocking axios requests' , function ( ) { describe('across entire suite' , function ( ) { beforeEach(function ( ) { moxios.install() }) afterEach(function ( ) { moxios.uninstall() }) it('specify response for a specific request' , function (done ) { let input = document .querySelector('.UserList__Filter__Input' ) let button = document .querySelector('.UserList__Filter__Button' ) input.value = 'flintstone' button.click() moxios.wait(function ( ) { let request = moxios.requests.mostRecent() request.respondWith({ status: 200 , response: [ { id : 1 , firstName : 'Fred' , lastName : 'Flintstone' }, { id : 2 , firstName : 'Wilma' , lastName : 'Flintstone' } ] }) .then(function ( ) { let list = document .querySelector('.UserList__Data' ) equal(list.rows.length, 2 ) equal(list.rows[0 ].cells[0 ].innerHTML, 'Fred' ) equal(list.rows[1 ].cells[0 ].innerHTML, 'Wilma' ) done() }) }) }) it('stub response for any matching request URL' , function (done ) { moxios.stubRequest('/say/hello' , { status: 200 , responseText: 'hello' }) moxios.stubRequest(/say.*/ , {}) let onFulfilled = sinon.spy() axios.get('/say/hello' ).then(onFulfilled) moxios.wait(function ( ) { equal(onFulfilled.getCall(0 ).args[0 ].data, 'hello' ) done() }) }) }) it('just for a single spec' , function (done ) { moxios.withMock(function ( ) { let onFulfilled = sinon.spy() axios.get('/users/12345' ).then(onFulfilled) moxios.wait(function ( ) { let request = moxios.requests.mostRecent() request.respondWith({ status: 200 , response: { id: 12345 , firstName : 'Fred' , lastName : 'Flintstone' } }) .then(function ( ) { equal(onFulfilled.called, true ) done() }) }) }) }) it('Should reject the request' , function (done ) { const errorResp = { status: 400 , response: { message : 'invalid data' } } moxios.wait(function ( ) { let request = moxios.requests.mostRecent() request.reject(errorResp) }) .catch(function (err ) { equal(err.status, errorResp.status) equal(err.response.message, errorResp.response.message) done() }) }) })
https://blog.csdn.net/yellow757/article/details/107484717