整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          手把手教你前端的各種文件上傳攻略和大文件斷點續傳



          在前面

          今年國慶假期終于可以憋在家里了不用出門了,不用出去看后腦了,真的是一種享受。這么好的光陰怎么浪費,睡覺、吃飯、打豆豆這怎么可能(耍多了也煩),完全不符合我們程序員的作風,趕緊起來把文章寫完。

          這篇文章比較基礎,在國慶期間的業余時間寫的,這幾天又完善了下,力求把更多的前端所涉及到的關于文件上傳的各種場景和應用都涵蓋了,若有疏漏和問題還請留言斧正和補充。

          自測讀不讀

          以下是本文所涉及到的知識點,break or continue ?

          • 文件上傳原理
          • 最原始的文件上傳
          • 使用 koa2 作為服務端寫一個文件上傳接口
          • 單文件上傳和上傳進度
          • 多文件上傳和上傳進度
          • 拖拽上傳
          • 剪貼板上傳
          • 大文件上傳之分片上傳
          • 大文件上傳之斷點續傳
          • node 端文件上傳

          原理概述

          原理很簡單,就是根據 http 協議的規范和定義,完成請求消息體的封裝和消息體的解析,然后將二進制內容保存到文件。

          我們都知道如果要上傳一個文件,需要把 form 標簽的enctype設置為multipart/form-data,同時method必須為post方法。

          那么multipart/form-data表示什么呢?

          multipart互聯網上的混合資源,就是資源由多種元素組成,form-data表示可以使用HTML Forms 和 POST 方法上傳文件,具體的定義可以參考RFC 7578。

          multipart/form-data 結構

          看下 http 請求的消息體



          • 請求頭:

          Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryDCntfiXcSkPhS4PN 表示本次請求要上傳文件,其中boundary表示分隔符,如果要上傳多個表單項,就要使用boundary分割,每個表單項由———XXX開始,以———XXX結尾。

          • 消息體- Form Data 部分

          每一個表單項又由Content-Type和Content-Disposition組成。

          Content-Disposition: form-data 為固定值,表示一個表單元素,name 表示表單元素的 名稱,回車換行后面就是name的值,如果是上傳文件就是文件的二進制內容。

          Content-Type:表示當前的內容的 MIME 類型,是圖片還是文本還是二進制數據。

          解析

          客戶端發送請求到服務器后,服務器會收到請求的消息體,然后對消息體進行解析,解析出哪是普通表單哪些是附件。

          可能大家馬上能想到通過正則或者字符串處理分割出內容,不過這樣是行不通的,二進制buffer轉化為string,對字符串進行截取后,其索引和字符串是不一致的,所以結果就不會正確,除非上傳的就是字符串。

          不過一般情況下不需要自行解析,目前已經有很成熟的三方庫可以使用。

          至于如何解析,這個也會占用很大篇幅,后面的文章在詳細說。

          最原始的文件上傳

          使用 form 表單上傳文件

          在 ie時代,如果實現一個無刷新的文件上傳那可是費老勁了,大部分都是用 iframe 來實現局部刷新或者使用 flash 插件來搞定,在那個時代 ie 就是最好用的瀏覽器(別無選擇)。

          DEMO



          這種方式上傳文件,不需要 js ,而且沒有兼容問題,所有瀏覽器都支持,就是體驗很差,導致頁面刷新,頁面其他數據丟失。

          HTML

           <form method="post" action="http://localhost:8100" enctype="multipart/form-data">
          
                  選擇文件:
                      <input type="file" name="f1"/> input 必須設置 name 屬性,否則數據無法發送<br/>
          <br/>
                      標題:<input type="text" name="title"/><br/><br/><br/>
          
                  <button type="submit" id="btn-0">上 傳</button>
          
          </form>
          
          復制代碼

          文件上傳接口

          服務端文件的保存基于現有的庫koa-body結合 koa2實現服務端文件的保存和數據的返回。

          在項目開發中,文件上傳本身和業務無關,代碼基本上都可通用。

          在這里我們使用koa-body庫來實現解析和文件的保存。

          koa-body 會自動保存文件到系統臨時目錄下,也可以指定保存的文件路徑。



          然后在后續中間件內得到已保存的文件的信息,再做二次處理。

          • ctx.request.files.f1 得到文件信息,f1為input file 標簽的 name
          • 獲得文件的擴展名,重命名文件

          NODE

          /**
           * 服務入口
           */
          var http = require('http');
          var koaStatic = require('koa-static');
          var path = require('path');
          var koaBody = require('koa-body');//文件保存庫
          var fs = require('fs');
          var Koa = require('koa2');
          
          var app = new Koa();
          var port = process.env.PORT || '8100';
          
          var uploadHost= `http://localhost:${port}/uploads/`;
          
          app.use(koaBody({
              formidable: {
                  //設置文件的默認保存目錄,不設置則保存在系統臨時目錄下  os
                  uploadDir: path.resolve(__dirname, '../static/uploads')
              },
              multipart: true // 開啟文件上傳,默認是關閉
          }));
          
          //開啟靜態文件訪問
          app.use(koaStatic(
              path.resolve(__dirname, '../static') 
          ));
          
          //文件二次處理,修改名稱
          app.use((ctx) => {
              var file = ctx.request.files.f1;//得道文件對象
              var path = file.path;
              var fname = file.name;//原文件名稱
              var nextPath = path+fname;
              if(file.size>0 && path){
                  //得到擴展名
                  var extArr = fname.split('.');
                  var ext = extArr[extArr.length-1];
                  var nextPath = path+'.'+ext;
                  //重命名文件
                  fs.renameSync(path, nextPath);
              }
              //以 json 形式輸出上傳文件地址
              ctx.body = `{
                  "fileUrl":"${uploadHost}${nextPath.slice(nextPath.lastIndexOf('/')+1)}"
              }`;
          });
          
          /**
           * http server
           */
          var server = http.createServer(app.callback());
          server.listen(port);
          console.log('demo1 server start ......   ');
          復制代碼

          CODE

          https://github.com/Bigerfe/fe-learn-code/

          回車字符(Ctrl+M)讓你緊張時,別擔心。有幾種簡單的方法消除它們。

          -- Sandra Henry-stocker(作者)

          當回車字符(Ctrl+M)讓你緊張時,別擔心。有幾種簡單的方法消除它們。

          “回車”字符可以往回追溯很長一段時間 —— 早在打字機上就有一個機械裝置或杠桿將承載紙滾筒的機架移到右邊,以便可以重新在左側輸入字母。他們在 Windows 上的文本文件上保留了它,但從未在 Linux 系統上使用過。當你嘗試在 Linux 上處理在 Windows 上創建的文件時,這種不兼容性有時會導致問題,但這是一個非常容易解決的問題。

          如果你使用 od( 八進制轉儲(octal dump))命令查看文件,那么回車(也用 Ctrl+M 代表)字符將顯示為八進制的 15。字符 CRLF 通常用于表示 Windows 文本文件中的一行結束的回車符和換行符序列。那些注意看八進制轉儲的會看到 \r\n。相比之下,Linux 文本僅以換行符結束。

          這有一個 od 輸出的示例,高亮顯示了行中的 CRLF 字符,以及它的八進制。

          $ od -bc testfile.txt
          0000000 124 150 151 163 040 151 163 040 141 040 164 145 163 164 040 146
           T h i s i s a t e s t f
          0000020 151 154 145 040 146 162 157 155 040 127 151 156 144 157 167 163
           i l e f r o m W i n d o w s
          0000040 056 015 012 111 164 047 163 040 144 151 146 146 145 162 145 156 <==
           . \r \n I t ' s d i f f e r e n <==
          0000060 164 040 164 150 141 156 040 141 040 125 156 151 170 040 164 145
           t t h a n a U n i x t e
          0000100 170 164 040 146 151 154 145 015 012 167 157 165 154 144 040 142 <==
           x t f i l e \r \n w o u l d b <==
          

          雖然這些字符不是大問題,但是當你想要以某種方式解析文本,并且不希望就它們是否存在進行編碼時,這有時候會產生干擾。

          3 種從文本中刪除回車符的方法

          幸運的是,有幾種方法可以輕松刪除回車符。這有三個選擇:

          dos2unix

          你可能會在安裝時遇到麻煩,但 dos2unix 可能是將 Windows 文本轉換為 Unix/Linux 文本的最簡單方法。一個命令帶上一個參數就行了。不需要第二個文件名。該文件會被直接更改。

          $ dos2unix testfile.txt
          dos2unix: converting file testfile.txt to Unix format...
          

          你應該會發現文件長度減少,具體取決于它包含的行數。包含 100 行的文件可能會縮小 99 個字符,因為只有最后一行不會以 CRLF 字符結尾。

          之前:

          -rw-rw-r-- 1 shs shs 121 Sep 14 19:11 testfile.txt
          

          之后:

          -rw-rw-r-- 1 shs shs 118 Sep 14 19:12 testfile.txt
          

          如果你需要轉換大量文件,不用每次修復一個。相反,將它們全部放在一個目錄中并運行如下命令:

          $ find . -type f -exec dos2unix {} \;
          

          在此命令中,我們使用 find 查找常規文件,然后運行 dos2unix 命令一次轉換一個。命令中的 {} 將被替換為文件名。運行時,你應該處于包含文件的目錄中。此命令可能會損壞其他類型的文件,例如除了文本文件外在上下文中包含八進制 15 的文件(如,鏡像文件中的字節)。

          sed

          你還可以使用流編輯器 sed 來刪除回車符。但是,你必須提供第二個文件名。以下是例子:

          $ sed -e “s/^M//” before.txt > after.txt
          

          一件需要注意的重要的事情是,請不要輸入你看到的字符。你必須按下 Ctrl+V 后跟 Ctrl+M 來輸入 ^M。s 是替換命令。斜杠將我們要查找的文本(Ctrl + M)和要替換的文本(這里為空)分開。

          vi

          你甚至可以使用 vi 刪除回車符(Ctrl+M),但這里假設你沒有打開數百個文件,或許也在做一些其他的修改。你可以鍵入 : 進入命令行,然后輸入下面的字符串。與 sed 一樣,命令中 ^M 需要通過 Ctrl+V 輸入 ^,然后 Ctrl+M 插入 M。%s 是替換操作,斜杠再次將我們要刪除的字符和我們想要替換它的文本(空)分開。 g(全局)意味在所有行上執行。

          :%s/^M//g
          

          總結

          dos2unix 命令可能是最容易記住的,也是從文本中刪除回車的最可靠的方法。其他選擇使用起來有點困難,但它們提供相同的基本功能。


          via: https://www.networkworld.com/article/3438857/how-to-remove-carriage-returns-from-text-files-on-linux.html

          作者: Sandra Henry-Stocker 選題: lujun9972 譯者: geekpi 校對: wxy

          本文由 LCTT 原創編譯, Linux中國 榮譽推出

          點擊“了解更多”可訪問文內鏈接



          載鏈接:https://segmentfault.com/a/1190000020920000

          前言

          在我們的日常開發工作中,文本溢出截斷省略是很常見的一種需考慮的業務場景細節。看上去 “稀松平常” ,但在實現上卻有不同的區分,是單行截斷還是多行截斷?多行的截斷判斷是基于行數還是基于高度?這些問題之下,都有哪些實現方案?他們之間的差異性和場景適應性又是如何?凡事就怕較真,較真必有成長。本文試圖通過編碼實踐,給出一些答案。

          先來點基礎的,單行文本溢出省略

          核心 CSS 語句

          • overflow: hidden;(文字長度超出限定寬度,則隱藏超出的內容)
          • white-space: nowrap;(設置文字在一行顯示,不能換行)
          • text-overflow: ellipsis;(規定當文本溢出時,顯示省略符號來代表被修剪的文本)

          優點

          • 無兼容問題
          • 響應式截斷
          • 文本溢出范圍才顯示省略號,否則不顯示省略號
          • 省略號位置顯示剛好

          短板

          • 只支持單行文本截斷

          適用場景

          • 適用于單行文本溢出顯示省略號的情況

          Demo

          <style>
              .demo {
                  white-space: nowrap;
                  overflow: hidden;
                  text-overflow: ellipsis;
              }
          </style>
          <body>
              <div class="demo">這是一段很長的文本</div>
          </body>

          示例圖片

          進階一下,多行文本溢出省略(按行數)

          ○ 純 CSS 實現方案

          核心 CSS 語句

          • -webkit-line-clamp: 2;(用來限制在一個塊元素顯示的文本的行數,2 表示最多顯示 2 行。 為了實現該效果,它需要組合其他的 WebKit 屬性)
          • display: -webkit-box;(和1結合使用,將對象作為彈性伸縮盒子模型顯示 )
          • -webkit-box-orient: vertical;(和 1 結合使用 ,設置或檢索伸縮盒對象的子元素的排列方式 )
          • overflow: hidden;(文本溢出限定的寬度就隱藏內容)
          • text-overflow: ellipsis;(多行文本的情況下,用省略號“…”隱藏溢出范圍的文本)

          優點

          • 響應式截斷
          • 文本溢出范圍才顯示省略號,否則不顯示省略號
          • 省略號顯示位置剛好

          短板

          • 兼容性一般: -webkit-line-clamp 屬性只有 WebKit 內核的瀏覽器才支持

          適用場景

          • 多適用于移動端頁面,因為移動設備瀏覽器更多是基于 WebKit 內核

          Demo

          <style>
              .demo {
                    display: -webkit-box;
                  overflow: hidden;
                  -webkit-line-clamp: 2;
                  -webkit-box-orient: vertical;
              }
          </style>
          
          <body>
              <div class='demo'>這是一段很長的文本</div>
          </body>

          示例圖片

          ○ 基于 JavaScript 的實現方案

          優點

          • 無兼容問題
          • 響應式截斷
          • 文本溢出范圍才顯示省略號,否則不顯示省略號

          短板

          • 需要 JS 實現,背離展示和行為相分離原則
          • 文本為中英文混合時,省略號顯示位置略有偏差

          適用場景

          • 適用于響應式截斷,多行文本溢出省略的情況

          Demo

          當前僅適用于文本為中文,若文本中有英文,可自行修改

          <script type="text/javascript">
              const text = '這是一段很長的文本';
              const totalTextLen = text.length;
              const formatStr = () => {
                  const ele = document.getElementsByClassName('demo')[0];
                  const lineNum = 2;
                  const baseWidth = window.getComputedStyle(ele).width;
                  const baseFontSize = window.getComputedStyle(ele).fontSize;
                  const lineWidth = +baseWidth.slice(0, -2);
          
                  // 所計算的strNum為元素內部一行可容納的字數(不區分中英文)
                  const strNum = Math.floor(lineWidth / +baseFontSize.slice(0, -2));
          
                  let content = '';
                  
                    // 多行可容納總字數
                  const totalStrNum = Math.floor(strNum * lineNum);
          
                  const lastIndex = totalStrNum - totalTextLen;
          
                  if (totalTextLen > totalStrNum) {
                      content = text.slice(0, lastIndex - 3).concat('...');
                  } else {
                      content = text;
                  }
                  ele.innerHTML = content;
              }
              
              formatStr();
              
                  window.onresize = () => {
                  formatStr();
              };
          </script>
          
          <body>
              <div class='demo'></div>
          </body>

          示例圖片

          再進階一步,多行文本溢出省略(按高度)

          ○ 多行文本溢出不顯示省略號

          核心 CSS 語句

          • overflow: hidden;(文本溢出限定的寬度就隱藏內容)
          • line-height: 20px;(結合元素高度,高度固定的情況下,設定行高, 控制顯示行數)
          • max-height: 40px;(設定當前元素最大高度)

          優點

          • 無兼容問題
          • 響應式截斷

          短板

          • 單純截斷文字, 不展示省略號,觀感上較為生硬

          適用場景

          • 適用于文本溢出不需要顯示省略號的情況

          Demo

          <style>
              .demo {
                  overflow: hidden;
                  max-height: 40px;
                  line-height: 20px;
              }
          </style>
          
          <body>
              <div class='demo'>這是一段很長的文本</div>
          </body>
          

          示例圖片

          ○ 偽元素 + 定位實現多行省略

          核心 CSS 語句

          • position: relative; (為偽元素絕對定位)
          • overflow: hidden; (文本溢出限定的寬度就隱藏內容)
          • position: absolute;(給省略號絕對定位)
          • line-height: 20px; (結合元素高度,高度固定的情況下,設定行高, 控制顯示行數)
          • height: 40px; (設定當前元素高度)
          • ::after {} (設置省略號樣式)

          優點

          • 無兼容問題
          • 響應式截斷

          短板

          • 無法識別文字的長短,無論文本是否溢出范圍, 一直顯示省略號
          • 省略號顯示可能不會剛剛好,有時會遮住一半文字

          適用場景

          • 適用于對省略效果要求較低,文本一定會溢出元素的情況

          Demo

          <style>
              .demo {
                  position: relative;
                  line-height: 20px;
                  height: 40px;
                  overflow: hidden;
              }
              .demo::after {
                  content: "...";
                  position: absolute;
                  bottom: 0;
                  right: 0;
                  padding: 0 20px 0 10px;
              }
          </style>
          
          <body>
              <div class='demo'>這是一段很長的文本</div>
          </body>

          示例圖片

          ○ 利用 Float 特性,純 CSS 實現多行省略

          核心 CSS 語句

          • line-height: 20px;(結合元素高度,高度固定的情況下,設定行高, 控制顯示行數)
          • overflow: hidden;(文本溢出限定的寬度就隱藏內容)
          • float: right/left;(利用元素浮動的特性實現)
          • position: relative;(根據自身位置移動省略號位置, 實現文本溢出顯示省略號效果)
          • word-break: break-all;(使一個單詞能夠在換行時進行拆分)

          優點

          • 無兼容問題
          • 響應式截斷
          • 文本溢出范圍才顯示省略號,否則不顯示省略號

          短板

          • 省略號顯示可能不會剛剛好,有時會遮住一半文字

          適用場景

          • 適用于對省略效果要求較低,多行文本響應式截斷的情況

          Demo

          <style>
              .demo {
                  background: #099;
                  max-height: 40px;
                  line-height: 20px;
                  overflow: hidden;
              }
              .demo::before{
                  float: left;
                  content:'';
                  width: 20px;
                  height: 40px;
              }
          
              .demo .text {
                  float: right;
                  width: 100%;
                  margin-left: -20px;
                  word-break: break-all;
              }
              .demo::after{
                  float:right;
                  content:'...';
                  width: 20px;
                  height: 20px;
                  position: relative;
                  left:100%;
                  transform: translate(-100%,-100%);
              }
          </style>
          
          <body>
              <div class='demo'>這是一段很長的文本</div>
          </body>

          示例圖片

          原理講解

          有 A、B、C 三個盒子,A 左浮動,B、C 右浮動。設置 A 盒子的高度與 B 盒子高度(或最大高度)要保持一致

          1. 當的 B 盒子高度低于 A 盒子,C 盒子仍會處于 B 盒子右下方。
          2. 如果 B 盒子文本過多,高度超過了 A 盒子,則 C 盒子不會停留在右下方,而是掉到了 A 盒子下。
          3. 接下來對 C 盒子進行相對定位,將 C 盒子位置向右側移動 100%,并向左上方向拉回一個 C 盒子的寬高(不然會看不到喲)。這樣在文本未溢出時不會看到 C 盒子,在文本溢出時,顯示 C 盒子。

          收,大道歸簡,能力封裝

          凡重復的,讓它單一;凡復雜的,讓它簡單。

          每次都要搞一坨代碼,太麻煩。這時候你需要考慮將文本截斷的能力,封裝成一個可隨時調用的自定義容器組件。市面上很多 UI 組件庫,都提供了同類組件的封裝,如基于 Vue 的 ViewUI Pro,或面向小程序提供組件化解決能力的 MinUI。


          轉載鏈接:https://segmentfault.com/a/1190000020920000


          主站蜘蛛池模板: 爆乳无码AV一区二区三区 | 制服丝袜一区二区三区| 精品在线一区二区| 无码少妇精品一区二区免费动态| 亚洲熟妇成人精品一区| 亚洲国产精品第一区二区三区| 久久久老熟女一区二区三区| 国产亚洲福利精品一区二区 | 国产一区二区在线观看麻豆| 亚洲电影一区二区| 变态调教一区二区三区| 日本一区二三区好的精华液 | 成人区人妻精品一区二区不卡网站| 蜜臀AV无码一区二区三区| 无码精品人妻一区二区三区中| 三上悠亚国产精品一区| 中文字幕在线观看一区二区三区| 精品国产福利在线观看一区| 精品免费国产一区二区三区| 亚洲欧美成人一区二区三区| 麻豆一区二区免费播放网站| 交换国产精品视频一区| 乱码精品一区二区三区| 亚洲美女一区二区三区| 亚洲AV无码片一区二区三区| 日韩一区二区视频| 无码视频免费一区二三区| 2018高清国产一区二区三区| 中文字幕在线不卡一区二区| 成人精品视频一区二区| 无码人妻一区二区三区免费视频 | 蜜臀AV一区二区| 麻豆国产一区二区在线观看| 亚洲性无码一区二区三区| 无码人妻aⅴ一区二区三区| 精品一区二区三区在线视频观看| 一区二区高清视频在线观看| 一区二区三区观看| 久久99精品一区二区三区| 蜜臀AV一区二区| 精品一区二区高清在线观看|