今年國慶假期終于可以憋在家里了不用出門了,不用出去看后腦了,真的是一種享受。這么好的光陰怎么浪費,睡覺、吃飯、打豆豆這怎么可能(耍多了也煩),完全不符合我們程序員的作風,趕緊起來把文章寫完。
這篇文章比較基礎,在國慶期間的業余時間寫的,這幾天又完善了下,力求把更多的前端所涉及到的關于文件上傳的各種場景和應用都涵蓋了,若有疏漏和問題還請留言斧正和補充。
以下是本文所涉及到的知識點,break or continue ?
原理很簡單,就是根據 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結尾。
每一個表單項又由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 會自動保存文件到系統臨時目錄下,也可以指定保存的文件路徑。
然后在后續中間件內得到已保存的文件的信息,再做二次處理。
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 <==
雖然這些字符不是大問題,但是當你想要以某種方式解析文本,并且不希望就它們是否存在進行編碼時,這有時候會產生干擾。
幸運的是,有幾種方法可以輕松刪除回車符。這有三個選擇:
你可能會在安裝時遇到麻煩,但 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 -e “s/^M//” before.txt > after.txt
一件需要注意的重要的事情是,請不要輸入你看到的字符。你必須按下 Ctrl+V 后跟 Ctrl+M 來輸入 ^M。s 是替換命令。斜杠將我們要查找的文本(Ctrl + M)和要替換的文本(這里為空)分開。
你甚至可以使用 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 語句
優點
短板
適用場景
Demo
<style>
.demo {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
<body>
<div class="demo">這是一段很長的文本</div>
</body>
示例圖片
核心 CSS 語句
優點
短板
適用場景
Demo
<style>
.demo {
display: -webkit-box;
overflow: hidden;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
</style>
<body>
<div class='demo'>這是一段很長的文本</div>
</body>
示例圖片
優點
短板
適用場景
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 語句
優點
短板
適用場景
Demo
<style>
.demo {
overflow: hidden;
max-height: 40px;
line-height: 20px;
}
</style>
<body>
<div class='demo'>這是一段很長的文本</div>
</body>
示例圖片
核心 CSS 語句
優點
短板
適用場景
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>
示例圖片
核心 CSS 語句
優點
短板
適用場景
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 盒子高度(或最大高度)要保持一致
凡重復的,讓它單一;凡復雜的,讓它簡單。
每次都要搞一坨代碼,太麻煩。這時候你需要考慮將文本截斷的能力,封裝成一個可隨時調用的自定義容器組件。市面上很多 UI 組件庫,都提供了同類組件的封裝,如基于 Vue 的 ViewUI Pro,或面向小程序提供組件化解決能力的 MinUI。
轉載鏈接:https://segmentfault.com/a/1190000020920000
*請認真填寫需求信息,我們會在24小時內與您取得聯系。