1. 程式人生 > 其它 >js常用工程類函式 | 下載連結 | 自定義下載內容

js常用工程類函式 | 下載連結 | 自定義下載內容

原文:https://mp.weixin.qq.com/s/4LEVIHOsAyRIkNkg0lDQ-g

1. 下載一個excel文件

同時適用於word,ppt等瀏覽器不會預設執行預覽的文件,也可以用於下載後端介面返回的流資料,見3

//下載一個連結
functiondownload(link,name){
if(!name){
name=link.slice(link.lastIndexOf('/')+1)
}
leteleLink=document.createElement('a')
eleLink.download=name
eleLink.style.display='none'
eleLink.href=link
document.body.appendChild(eleLink)
eleLink.click()
document.body.removeChild(eleLink)
}
//下載excel
download('http://111.229.14.189/file/1.xlsx')
複製程式碼

2. 在瀏覽器中自定義下載一些內容


場景:我想下載一些DOM內容,我想下載一個JSON檔案

/**
*瀏覽器下載靜態檔案
*@param{String}name檔名
*@param{String}content檔案內容
*/
functiondownloadFile(name,content){
if(typeofname=='undefined'){
thrownewError('Thefirstparameternameisamust')
}
if(typeofcontent=='undefined'){
thrownewError('Thesecondparametercontentisamust')
}
if(!(contentinstanceofBlob)){
content=newBlob([content])
}
constlink=URL.createObjectURL(content)
download(link,name)
}
//下載一個連結
functiondownload(link,name){
if(!name){//如果沒有提供名字,從給的Link中擷取最後一坨
name=link.slice(link.lastIndexOf('/')+1)
}
leteleLink=document.createElement('a')
eleLink.download=name
eleLink.style.display='none'
eleLink.href=link
document.body.appendChild(eleLink)
eleLink.click()
document.body.removeChild(eleLink)
}
複製程式碼

使用方式:

downloadFile('1.txt','lalalallalalla')
downloadFile('1.json',JSON.stringify({name:'hahahha'}))
複製程式碼

3. 下載後端返回的流


資料是後端以介面的形式返回的,呼叫1中的download方法進行下載

download('http://111.229.14.189/gk-api/util/download?file=1.jpg')
download('http://111.229.14.189/gk-api/util/download?file=1.mp4')

複製程式碼

4. 提供一個圖片連結,點選下載


圖片、pdf等檔案,瀏覽器會預設執行預覽,不能呼叫download方法進行下載,需要先把圖片、pdf等檔案轉成blob,再呼叫download方法進行下載,轉換的方式是使用axios請求對應的連結


//可以用來下載瀏覽器會預設預覽的檔案型別,例如mp4,jpg等
importaxiosfrom'axios'
//提供一個link,完成檔案下載,link可以是http://xxx.com/xxx.xls
functiondownloadByLink(link,fileName){
axios.request({
url:link,
responseType:'blob'//關鍵程式碼,讓axios把響應改成blob
}).then(res=>{
constlink=URL.createObjectURL(res.data)
download(link,fileName)
})

}
複製程式碼

注意:會有同源策略的限制,需要配置轉發

6 防抖


在一定時間間隔內,多次呼叫一個方法,只會執行一次.這個方法的實現是從Lodash庫中copy的

/**
*
*@param{*}func要進行debouce的函式
*@param{*}wait等待時間,預設500ms
*@param{*}immediate是否立即執行
*/
exportfunctiondebounce(func,wait=500,immediate=false){
vartimeout
returnfunction(){
varcontext=this
varargs=arguments

if(timeout)clearTimeout(timeout)
if(immediate){
//如果已經執行過,不再執行
varcallNow=!timeout
timeout=setTimeout(function(){
timeout=null
},wait)
if(callNow)func.apply(context,args)
}else{
timeout=setTimeout(function(){
func.apply(context,args)
},wait)
}
}
}
複製程式碼

使用方式:

<!DOCTYPEhtml>
<htmllang="en">
<head>
<metacharset="UTF-8"/>
<metahttp-equiv="X-UA-Compatible"content="IE=edge"/>
<metaname="viewport"content="width=device-width,initial-scale=1.0"/>
<title>Document</title>
</head>
<body>
<inputid="input"/>
<script>
functiononInput(){
console.log('1111')
}
constdebounceOnInput=debounce(onInput)
document
.getElementById('input')
.addEventListener('input',debounceOnInput)//在Input中輸入,多次呼叫只會在呼叫結束之後,等待500ms觸發一次
</script>
</body>
</html>

複製程式碼

如果第三個引數immediate傳true,則會立即執行一次呼叫,後續的呼叫不會在執行,可以自己在程式碼中試一下

7 節流


多次呼叫方法,按照一定的時間間隔執行這個方法的實現也是從Lodash庫中copy的

/**
*節流,多次觸發,間隔時間段執行
*@param{Function}func
*@param{Int}wait
*@param{Object}options
*/
exportfunctionthrottle(func,wait=500,options){
//container.onmousemove=throttle(getUserAction,1000);
vartimeout,context,args
varprevious=0
if(!options)options={leading:false,trailing:true}

varlater=function(){
previous=options.leading===false?0:newDate().getTime()
timeout=null
func.apply(context,args)
if(!timeout)context=args=null
}

varthrottled=function(){
varnow=newDate().getTime()
if(!previous&&options.leading===false)previous=now
varremaining=wait-(now-previous)
context=this
args=arguments
if(remaining<=0||remaining>wait){
if(timeout){
clearTimeout(timeout)
timeout=null
}
previous=now
func.apply(context,args)
if(!timeout)context=args=null
}elseif(!timeout&&options.trailing!==false){
timeout=setTimeout(later,remaining)
}
}
returnthrottled
}
複製程式碼

第三個引數還有點複雜,options

  • leading,函式在每個等待時延的開始被呼叫,預設值為false
  • trailing,函式在每個等待時延的結束被呼叫,預設值是true

可以根據不同的值來設定不同的效果:

  • leading-false,trailing-true:預設情況,即在延時結束後才會呼叫函式
  • leading-true,trailing-true:在延時開始時就呼叫,延時結束後也會呼叫
  • leading-true, trailing-false:只在延時開始時呼叫

例子:

<!DOCTYPEhtml>
<htmllang="en">
<head>
<metacharset="UTF-8"/>
<metahttp-equiv="X-UA-Compatible"content="IE=edge"/>
<metaname="viewport"content="width=device-width,initial-scale=1.0"/>
<title>Document</title>
</head>
<body>
<inputid="input"/>
<script>
functiononInput(){
console.log('1111')
}
constthrottleOnInput=throttle(onInput)
document
.getElementById('input')
.addEventListener('input',throttleOnInput)//在Input中輸入,每隔500ms執行一次程式碼
</script>
</body>
</html>

複製程式碼

8. cleanObject


去除物件中value為空(null,undefined,'')的屬性,舉個栗子:

letres=cleanObject({
name:'',
pageSize:10,
page:1
})
console.log("res",res)//輸入{page:1,pageSize:10}name為空字串,屬性刪掉
複製程式碼

使用場景是:後端列表查詢介面,某個欄位前端不傳,後端就不根據那個欄位篩選,例如name不傳的話,就只根據pagepageSize篩選,但是前端查詢引數的時候(vue或者react)中,往往會這樣定義


exportdefault{
data(){
return{
query:{
name:'',
pageSize:10,
page:1
}
}
}
}


const[query,setQuery]=useState({name:'',page:1,pageSize:10})
複製程式碼

給後端傳送資料的時候,要判斷某個屬性是不是空字串,然後給後端拼引數,這塊邏輯抽離出來就是cleanObject,程式碼實現如下

exportconstisFalsy=(value)=>(value===0?false:!value);

exportconstisVoid=(value)=>
value===undefined||value===null||value==="";

exportconstcleanObject=(object)=>{
//Object.assign({},object)
if(!object){
return{};
}
constresult={...object};
Object.keys(result).forEach((key)=>{
constvalue=result[key];
if(isVoid(value)){
deleteresult[key];
}
});
returnresult;
};

複製程式碼
letres=cleanObject({
name:'',
pageSize:10,
page:1
})
console.log("res",res)//輸入{page:1,pageSize:10}
複製程式碼