目錄
準備:自訂指令介紹
試煉:實作v-mymodel
定義指令
应用实践:4个实用的自定义指令
权限控制
输入限制
内容处理
文件预览
试着自己实现
总结
首頁 web前端 Vue.js 深入了解Vue中的自訂指令

深入了解Vue中的自訂指令

Nov 21, 2022 pm 08:20 PM
vue.js

深入了解Vue中的自訂指令

準備:自訂指令介紹

#除了核心功能預設內建的指令(v-modelv-show等),Vue 也允許註冊自訂指令。注意,在 Vue2.0 中,程式碼重複使用和抽象的主要形式是元件。然而,有的情況下,你仍然需要對普通 DOM 元素進行底層操作,這時候就會用到自訂指令。 【學習影片分享:vue影片教學web前端影片

作為使用Vue的開發者,我們對Vue指令一定不陌生,諸如v-modelv-onv-forv-if等,同時Vue也為開發者提供了自訂指令的api,熟練的使用自訂指令可以極大的提高了我們編寫程式碼的效率,讓我們可以節省時間開心的摸魚~

對於Vue的自訂指令相信很多同學已經有所了解,自訂指令的具體寫法這裡就不細講了,官方文件很詳細。但不知道各位同學有沒有這種感覺,就是這個技術感覺很方便,也不難,我也感覺學會了,就是不知道如何去應用。這篇文檔就是為了解決一些同學的這些問題才寫出來的。

PS:這次要講的自訂指令我們主要使用的是vue2.x的寫法,不過vue3.x不過是幾個鉤子函數有所改變,只要理解每個鉤子函數的意義,兩者的用法差異並不大。

試煉:實作v-mymodel

我的上篇文章說到要自己實作一個v-model指令,這裡使用v-myodel模擬一個簡易版的,順便再領不熟悉的同學熟悉一下自訂指令的步驟和注意事項。

定義指令

首先梳理思路:原生input控制項與元件的實作方式需要區分,input的實現較為簡單,我們先實作一下input的處理。 首先我們先定義一個不做任何操作的指令

Vue.directive('mymodel', {
        //只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
        bind(el, binding, vnode, oldVnode) {
        },
        //被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中),需要父节点dom时使用这个钩子
        inserted(el, binding, vnode, oldVnode) {
        },
        //所在组件的 VNode 更新时调用,**但是可能发生在其子 VNode 更新之前**。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
        update(el, binding, vnode, oldVnode) {
        },
        //指令所在组件的 VNode **及其子 VNode** 全部更新后调用。
        componentUpdated(el, binding, vnode, oldVnode) {
        },
        只调用一次,指令与元素解绑时调用。
        unbind(el, binding, vnode, oldVnode) {
        },
})
登入後複製

上面的註解中詳細的說明了各個鉤子函數的呼叫時機,因為我們是給元件上新增input事件和value綁定,因此我們在bind這個鉤子函數中定義即可。所以我們把其他的先去掉,程式碼變成這樣。

Vue.directive('mymodel', {
        //只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
        bind(el, binding, vnode, oldVnode) { 
        }
})
登入後複製

簡單說一下bind函數的幾個回呼參數,el是指令綁定元件對應的dombinding 是我們的指令本身,包含namevalueexpressionarg等,vnode就是目前綁定元件對應的vnode結點,oldVnode就是vnode更新前的狀態。

接下來我們要做兩件事:

  • 綁定input事件,同步inputvalue值到外部
  • value值綁定,監聽value的變化,更新到inputvalue

這對input原生元件比較容易實作:

//第一步,添加inout事件监听
el.addEventListener('input', (e) => {
   //context是input所在的父组件,这一步是同步数据
   vnode.context[binding.expression] = e.target.value;
})
//监听绑定的变量
vnode.context.$watch(binding.expression, (v) => {
     el.value = v;
})
登入後複製

這裡解釋一下上面的程式碼,vnode.context是什麼呢,他就是我們指令所在元件的上下文環境,可以理解就是指令綁定的值所在的元件實例。不熟悉vnode結構的同學建議先看一下官方的文檔,不過文檔描述的比較簡單,不是很全面,所以最好在控制台log一下vnode的物件看一下它具體的結構,這很有助於我們封裝自訂指令,對理解Vue原理也很有幫助。

我們可以透過context[binding.expression]來取得v-model上到綁定的值,同樣可以修改它。上面的程式碼中我們首先透過在新增的input事件中操作vnode.context[binding.expression] = e.target.value同步inputvalue值到外部(context),與使用@input新增事件監聽效果是一樣的;然後我們需要做第二件事,做value值的綁定,監聽value的變化,同步值的變更到inputvalue上,我們想到我們可以使用Vue實例上的額$ watch方法監聽值的變化,而context就是那個Vue實例,binding.expression就是我們想要監聽的屬性,如果我們這樣寫

参考vue实战视频讲解:进入学习

<input v-mymodel=&#39;message&#39;/>
登入後複製

那么binding.expression就是字符串&#39;message&#39;。所以我们想下面的代码这样监听绑定的响应式数据。

//监听绑定的变量
vnode.context.$watch(binding.expression, (v) => {
     el.value = v;
})
登入後複製

至此,inputv-mymodel的处理就完成了(当然input组件还有typecheckbox,radio,select等类型都需要去特别处理,这里就不再一一处理了,感兴趣的同学可以自己尝试去完善一下),但是对于非原生控件的组件,我们要特殊处理。 因此我们完善代码如下:

Vue.directive(&#39;mymodel&#39;, {
        //只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
        bind(el, binding, vnode, oldVnode) {
           //原生input组件的处理
           if(vnode.tag===&#39;input&#39;){
                //第一步,添加inout事件监听
                el.addEventListener(&#39;input&#39;, (e) => {
                   //context是input所在的父组件,这一步是同步数据
                   vnode.context[binding.expression] = e.target.value;
                })
                //监听绑定的变量
                vnode.context.$watch(binding.expression, (v) => {
                     el.value = v;
                })
           }else{//组件

           }
        }
})
登入後複製

接下来我们要处理的是自定义组件的逻辑,

//vnode的结构可以参见文档。不过我觉得最直观的方法就是直接在控制台打印处理
let {
    componentInstance,
    componentOptions,
    context
} = vnode;
const {
   _props
} = componentInstance;
//处理model选项
if (!componentOptions.Ctor.extendOptions.model) {
  componentOptions.Ctor.extendOptions.model = {
        value: &#39;value&#39;,
        event: &#39;input&#39;
  }
}
let modelValue = componentOptions.Ctor.extendOptions.model.value;
let modelEvent = componentOptions.Ctor.extendOptions.model.event;
//属性绑定,这里直接修改了属性,没有想到更好的办法,友好的意见希望可以提出
_props[modelValue] = binding.value;
context.$watch(binding.expression, (v) => {
     _props[modelValue] = v;
})
//添加事件处理函数,做数据同步
componentInstance.$on(modelEvent, (v) => {
     context[binding.expression] = v;
})
登入後複製

声明一下,上面的实现不是vue源码的实现方式,vue源码中实现v-model更加复杂一点,是结合自定义指令、模板编译等去实现的,因为我们是应用级别的封装,所以采用了上述的方式实现。

实现此v-mymodel需要同学去多了解一下VnodeComponentAPI,就像之前说的,最简单的方法就是直接在控制台中直接打印出vnode对象,组件的vnode上有Component的实例componentInstance

接下来简单说一下上面的代码,首先我们可以在componentOptions.Ctor.extendOptions上找到model的定义,如果没有的话需要设置默认值valueinput,然后分别对想原生input的处理一样,分别监听binding.expression的变化和modelEvent事件即可。

需要注意的是,我们上面的代码直接给_prop做了赋值操作,这实际上是不符合规范的,但是我目前没有找到更好的方法去实现,有好思路的同学可以在评论区留言指教。

下面?是完整的源码:

应用实践:4个实用的自定义指令

上文我们通过封装v-mymodel为各位同学展示了如何封装和使用自定义指令,接下来我把自己在生产实践中使用自定义指令的一些经验分享给大家,通过实例,我相信各位同学能够更深刻的理解如何在在应用中封装自己的指令,提高效率。

权限控制

下面我们定义一个v-permission指令用于全平台的权限控制

  • role:角色控制;
  • currentUser:当前登录人判断;当前用户是否是业务数据中的创建人或者负责人
  • bussinessStatus:业务状态判断;
  • every:与操作;
  • some:或操作;

示例代码

//定义权限类型
const permissionType = {
    ROLE: &#39;role&#39;,
    CURRENTUSER:&#39;currentUser&#39;,
    BUSSINESSSTATUS: &#39;bussinessStatus&#39;,
    MIX_EVERY: &#39;every&#39;,
    MIX_SOME: &#39;some&#39;
}
export default {
    //只调用一次,指令第一次绑定到元素时调用
    bind: function () {
    },
    //当前vdom插入到真实dom时,因为是对dom的样式操作,在这里操作
    inserted: function (el, binding) {
        let show = false;
        show=processingType(binding.arg,binding.value); 
        el.style.display = `${show ? &#39;inline-block&#39; : &#39;none&#39;}`
    },
    //所在组件的VNode更新时调用,状态更新后需要更新显示状态
    update: function (el, binding) {
        //避免无效的模板更新
        if(binding.value===binding.oldValue) return;
        let show = false;
        show=processingType(binding.arg,binding.value); 
        el.style.display = `${show ? &#39;inline-block&#39; : &#39;none&#39;}`
    },
    //指令所在组件的 VNode 及其子 VNode 全部更新后
    componentUpdated: function (el, binding) {
    },
    unbind: function () {
    },
}
//处理不同类型的权限控制
function processingType(type,value){
    let values=[];
    switch (type) {
        case permissionType.ROLE:
            return permissionByRole(value);
        case permissionType.CURRENTUSER:
            return permissionCreater(value);
        case permissionType.BUSSINESSSTATUS:
            return permissionBusinessStatus(value);
        case permissionType.MIX_EVERY:
            for(let type in value){
                values.push(processingType(type,value[type]))
            }
            return values.every(v=>{
                return v;
            })
        case permissionType.MIX_SOME:
            for(let type in value){
                values.push(processingType(type,value[type]))
            }
            return values.some(v=>{
                return v;
            })
        default:
            return false;
    }
}
//业务状态判断
function permissionBusinessStatus(bindingValue){
   return bindingValue.status==bindingValue.value;
}
//当前用户?
function permissionCreater(bindingValue){
    const userInfo = JSON.parse(sessionStorage.CDTPcookie);
    // console.log(userInfo.userInfo.id,bindingValue)
    if(bindingValue instanceof Array){
        return bindingValue.some(v=>{
            return userInfo.userInfo.id==v;
        })
    }
    return userInfo.userInfo.id==bindingValue;
}
//角色控制
export function permissionByRole(bindingValue) {
    //这里也可以是store里的用户信息
    const userInfo = JSON.parse(sessionStorage.userInfo);  
    let roles = []
    if (userInfo) {
        roles = userInfo.roleList
    }
    let show = false;
    if (bindingValue instanceof Array) {
        return roles.some(role => {//多角色处理
            return bindingValue.some(item => {
                return role.roleCode === item
            })
        })
    } else if (typeof bindingValue == &#39;string&#39;) {
        show = roles.some(role => {
            return role.roleCode === bindingValue;
        })
    }
    return show;
}
登入後複製

简单说一下上面?指令的定义思路和使用方法。整体思路就是通过processingType处理权限逻辑,使用el.style.display控制组件显示或隐藏。我在这里从日常应用中提取了一些通用的processingType中的权限处理方式,方便大家理解也供大家参考。

下面逐一说一下权限指令各个类型的使用方法:

//角色权限
<component v-permission:role=&#39;leader&#39;></component>
//判断当前登录人
<component v-permission:currentUser=&#39;orderInfo.createUser&#39;></component>
//判断业务状态
<component v-permission:bussinessStatus=&#39;{status:orderStatus.RUNNING,value:orderInfo.status}&#39;></component>
//角色是leader或者是当前订单的创建者,有权限
<component v-permission:some="{role:&#39;leader&#39;,currentUser:&#39;orderInfo.createUser&#39;}"></component>
//角色是leader并且是当前订单的创建者,有权限
<component v-permission:every="{role:&#39;leader&#39;,currentUser:&#39;orderInfo.createUser&#39;}"></component>
登入後複製

输入限制

v-input 输入框限制,限制数字、保留n位小数点等。

export default {
    inserted: function (el, binding, vnode) {
        el.addEventListener(&#39;input&#39;, function (e) {
            if (binding.arg == &#39;toFixed&#39;) {
                //限制输入n位小数点
                toFiexd(e.target, vnode, binding.value)
            } else {
                //限制数字输入
                Integer(e.target, vnode)
            }
        })
    },
}
function toFiexd(target, vnode, v) {
    console.log(v);
    let ln = 2;
    if (v) {
        ln = v;
    }
    var regStrs = [
        [&#39;^0(\\d+)$&#39;, &#39;$1&#39;], //禁止录入整数部分两位以上,但首位为0
        [&#39;[^\\d\\.]+$&#39;, &#39;&#39;], //禁止录入任何非数字和点
        [&#39;\\.(\\d?)\\.+&#39;, &#39;.$1&#39;], //禁止录入两个以上的点
        [&#39;^(\\d+\\.\\d{&#39; + ln + &#39;}).+&#39;, &#39;$1&#39;] //禁止录入小数点后两位以上
    ];
    for (var i = 0; i < regStrs.length; i++) {
        var reg = new RegExp(regStrs[i][0]);
        target.value = target.value.replace(reg, regStrs[i][1]);
    }
    //对于封装的像el-input组件,因为其需要通过input事件同步状态
    if(vnode.componentInstance){
      vnode.componentInstance.$listeners.input(target.value)
    }
}
function Integer(target, vnode) {
    let valueStr = target.value
    if (valueStr.length == 1) {
        //第一个数字不为0
        valueStr = valueStr.replace(/[^0-9]/g, "");
    } else {
        //只能输入正整数
        valueStr = valueStr.replace(/\D/g, "");
    }
    target.value = valueStr;
    if(vnode.componentInstance){
      vnode.componentInstance.$listeners.input(target.value)
    }
}
登入後複製

这里需要特别注意的是下面这行代码

vnode.componentInstance.$listeners.input(target.value)
登入後複製

我们为什么需要添加这一句呢,我们明明已经为target.value做了赋值。
实际上这一句代码相当于指令作用组件内部的$emit(&#39;input&#39;,target.value),这是因为如果我们是在antd或者elementui中的输入框组件上添加我们定义的v-input指令,直接为target.value赋值是不能生效的,修改的只是原生input控件value值,并没有修改自定义组件的value,还需要通过触发input事件去同步组件状态,修改value值。(这里不了解为什么需要触发input事件区同步状态的同学了解一下v-model的语法糖原理即可理解, 使用方法:

<!-- 限制输入两位小数数字 -->
<input v-input:toFixed="2"/>
<!-- 限制输入正整数 -->
<el-input v-input:integer/>
登入後複製

内容处理

我们也可以通过自定义指令做对内容到处理,比如

  • 空值处理

  • 数字千分数逗号分割

export default {
    bind:function(){
    },
    inserted:function(el,binding){
        dealContent(el,binding)
    },
    update:function(el,binding){
        dealContent(el,binding)
    },
    componentUpdated:function(){
    },
    unbind:function(){
    },
}
function dealContent(el,binding){
   const {arg}=binding;
   if(arg==&#39;empty&#39;){
       if(!el.textContent){//空值显示
            el.textContent=binding.value||&#39;暂无数据&#39;;
        }
   }else if(arg==&#39;money&#39;){//金额千分位逗号分割,如10000000显示为100,000,00
        if (binding.value) {
            el.textContent = dealMoney(binding.value);
        }else {
            el.textContent = dealMoney(el.textContent);
        }
   }
}
登入後複製

千分位分割代码:

//金额处理
export function dealMoney(money, places = 2) {
    const zero = `0.00`;
    if (isNaN(money) || money === &#39;&#39;) return zero;
    if (money && money != null) {
        money = `${money}`;
        let left = money.split(&#39;.&#39;)[0]; // 小数点左边部分
        let right = money.split(&#39;.&#39;)[1]; // 小数点右边
        // 保留places位小数点,当长度没有到places时,用0补足。
        right = right ? (right.length >= places ? &#39;.&#39; + right.substr(0, places) : &#39;.&#39; + right + &#39;0&#39;.repeat(places - right.length)) : (&#39;.&#39; + &#39;0&#39;.repeat(places));
        var temp = left.split(&#39;&#39;).reverse().join(&#39;&#39;).match(/(\d{1,3})/g); // 分割反向转为字符串然后最多3个,最少1个,将匹配的值放进数组返回
        return (Number(money) < 0 ? &#39;-&#39; : &#39;&#39;) + temp.join(&#39;,&#39;).split(&#39;&#39;).reverse().join(&#39;&#39;) + right; // 补齐正负号和货币符号,数组转为字符串,通过逗号分隔,再分割(包含逗号也分割)反向转为字符串变回原来的顺序
    } else if (money === 0) {
        return zero;
    } else {
        return zero;
    }
}
登入後複製

使用方法:

<span v-content:empty="&#39;无&#39;">{{message}}</span>
<!-- 金额千分位逗号分割 -->
<span v-content:money>100000</span>
登入後複製

文件预览

v-preview方便的实现文件预览功能

  • 预览图片;

  • 预览文件;

  • 其他预览类业务功能

import {isOffic,isPdf,isImage} from &#39;@/utils/base&#39;
import {previewWithOffice} from &#39;@/utils/fileUtils.js&#39;
export default {
    inserted:function(el,binding){
        el.onclick=function(e){
            let params = binding.value
            if(isOffic(params.name)){
                e.preventDefault()
                e.stopPropagation()
                previewWithOffice(params.url)//使用office在线预览打开
            }else if(isPdf(params.name) || isImage(params.name)){
                e.preventDefault()
                e.stopPropagation()
                if(params.url){//直接打开url
                    previewFile(params)
                }
            }
        }
    },
    //指令所在组件的 VNode 及其子 VNode 全部更新后
    componentUpdated: function (el, binding) {
        el.onclick=function(e){
            let params = binding.value
            if(isOffic(params.name)){
                //使用插件预览Office文件
                e.preventDefault()
                e.stopPropagation()
                previewWithOffice(params.url)
            }else if(isPdf(params.name) || isImage(params.name)){
               //预览图片和pdf等能直接打开的文件
                e.preventDefault()
                e.stopPropagation()
                previewFile(params)
            }
        }
    },
    unbind(el){
       el.onclick=null;
    }
}
//预览图片和pdf等能直接打开的文件
function previewFile(params) {
    let a = document.createElement("a");
    a.download = params.name
    a.href = params.url;
    a.target = "_blank";
    a.click();
    a = null;
}
登入後複製

使用方法:

<!-- 预览图片 -->
<image :src=&#39;url&#39; v-preview="{name:file.name,url:file.url}"></image>
<!-- 预览文件 -->
<span v-preview="{name:file.name,url:file.url}">{{file.name}}</span>
登入後複製

试着自己实现

各位同学可以试着自己实现一个v-loading的加载中的指令,通过设置一个bool值来设置容器的加载状态。 如有疑问可以在评论区留言。

总结

本文主要讲了如下几件事:

  • vue自定义指令介绍
  • 实现一个v-model
  • 通用的自定义指令使用技巧

(学习视频分享:web前端开发编程基础视频

以上是深入了解Vue中的自訂指令的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1665
14
CakePHP 教程
1424
52
Laravel 教程
1322
25
PHP教程
1270
29
C# 教程
1249
24
深入探討vite是怎麼解析.env檔的 深入探討vite是怎麼解析.env檔的 Jan 24, 2023 am 05:30 AM

使用vue框架開發前端專案時,我們部署的時候都會部署多套環境,往往開發、測試以及線上環境呼叫的介面網域都是不一樣的。如何能做到區分呢?那就是使用環境變數和模式。

圖文詳解如何在Vue專案中整合Ace程式碼編輯器 圖文詳解如何在Vue專案中整合Ace程式碼編輯器 Apr 24, 2023 am 10:52 AM

Ace 是一個用 JavaScript 寫的可嵌入程式碼編輯器。它與 Sublime、Vim 和 TextMate 等原生編輯器的功能和效能相符。它可以很容易地嵌入到任何網頁和 JavaScript 應用程式中。 Ace 被維護為Cloud9 IDE的主要編輯器 ,並且是 Mozilla Skywriter (Bespin) 專案的繼承者。

vue中組件化和模組化有什麼區別 vue中組件化和模組化有什麼區別 Dec 15, 2022 pm 12:54 PM

組件化和模組化的區別:模組化是從程式碼邏輯的角度進行劃分的;方便程式碼分層開發,確保每個每個功能模組的職能一致。元件化是從UI介面的角度進行規劃;前端的元件化,方便UI元件的重複使用。

探討如何在Vue3中撰寫單元測試 探討如何在Vue3中撰寫單元測試 Apr 25, 2023 pm 07:41 PM

在當今前端開發中,Vue.js 已經成為了一個非常流行的框架。隨著 Vue.js 的不斷發展,單元測試變得越來越重要。今天,我們將探討如何在 Vue.js 3 中編寫單元測試,並提供一些最佳實踐和常見的問題及解決方案。

聊聊vue3怎麼使用高德地圖api 聊聊vue3怎麼使用高德地圖api Mar 09, 2023 pm 07:22 PM

在我們使用高德地圖的時候,官方給我們推薦了很多案例,demo,但是這些案例都是使用原生方法接入,並沒有提供vue或者react 的demo,vue2的接入網上也很多人都有寫過,以下這篇文章就來看看vue3怎麼使用常用的高德地圖api,希望對大家有幫助!

怎麼查詢目前vue的版本 怎麼查詢目前vue的版本 Dec 19, 2022 pm 04:55 PM

查詢目前vue版本的兩種方法:1、在cmd控制台內,執行「npm list vue」指令查詢版本,輸出結果就是vue的版本號資訊;2、在專案中找到並開啟package.json文件,查找「dependencies」項目即可看到vue的版本資訊。

Vue中JSX語法和模板語法的簡單比較(優劣勢分析) Vue中JSX語法和模板語法的簡單比較(優劣勢分析) Mar 23, 2023 pm 07:53 PM

在Vue.js中,開發人員可以使用兩種不同的語法來建立使用者介面:JSX語法和範本語法。這兩種文法各有優劣,以下就來探討它們的差異和優劣勢。

淺析vue怎麼實現檔案切片上傳 淺析vue怎麼實現檔案切片上傳 Mar 24, 2023 pm 07:40 PM

在實際開發專案過程中有時候需要上傳比較大的文件,然後呢,上傳的時候相對來說就會慢一些,so,後台可能會要求前端進行文件切片上傳,很簡單哈,就是把比如說1個G的檔案流切割成若干個小的檔案流,然後分別請求介面傳遞這個小的檔案流。

See all articles