最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

js實現(xiàn)ctrl+v粘貼上傳圖片(兼容chrome、firefox、ie11)

 更新時間:2021年08月20日 10:20:21   作者:djuny  
這篇文章主要為大家詳細介紹了js實現(xiàn)ctrl+v粘貼上傳圖片,兼容chrome,firefox,ie11,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

我們或多或少都使用過各式各樣的富文本編輯器,其中有一個很方便功能,復(fù)制一張圖片然后粘貼進文本框,這張圖片就被上傳了,那么這個方便的功能是如何實現(xiàn)的呢?

原理分析

提取操作:復(fù)制=>粘貼=>上傳
在這個操作過程中,我們需要做的就是:監(jiān)聽粘貼事件=>獲取剪貼板里的內(nèi)容=>發(fā)請求上傳
為方便理解下文,需要先明白幾點:

  • 我們只能上傳網(wǎng)頁圖(在網(wǎng)頁上右鍵圖片,然后復(fù)制)和截圖(截圖工具截的圖片,eg:qq截圖),不能粘貼上傳系統(tǒng)里的圖片(從桌面上、硬盤里復(fù)制),他們是存在完全不同的地方的。
  • 截圖工具截的圖與在網(wǎng)頁點擊右鍵復(fù)制的圖是有些不同的,因此處理方式也不一樣。
  • 知悉paste event這個事件:當進行粘貼(右鍵paste/ctrl+v)操作時,該動作將觸發(fā)名為'paste'的剪貼板事件,這個事件的觸發(fā)是在剪貼板里的數(shù)據(jù)插入到目標元素之前。如果目標元素(光標所在位置)是可編輯的元素(eg:設(shè)置了contenteditable屬性的div。textarea并不行。),粘貼動作將把剪貼板里的數(shù)據(jù),以最合適的格式,插入到目標元素里;如果目標元素不可編輯,則不會插入數(shù)據(jù),但依然觸發(fā)paste event。數(shù)據(jù)在粘貼的過程中是只讀的。此段是翻譯于w3.org_the-paste-action。
  • 可惜的是,經(jīng)過試驗,發(fā)現(xiàn)chrome(當前最新版)、firefox(當前最新版)、ie11對paste事件的實現(xiàn)并不是完全按照w3c來的,各自也有區(qū)別(w3c的paste標準也因此只是草案階段)。

test代碼及截圖如下:

chrome:

<textarea ></textarea> 
<div contenteditable style="width: 100px;height: 100px; border:1px solid"> 
</div> 
<script> 
document.addEventListener('paste', function (event) { 
  console.log(event) 
})
</script>

  1. event有clipboardData屬性,且clipboardData有item屬性,clipboardData.item中的元素(對象)有type和kind屬性;
  2. 無論在哪進行粘貼,均可觸發(fā)paste事件;
  3. 在div(未特殊聲明時,本文div均指設(shè)置了contenteditable屬性的div) 里粘貼截圖,不顯示圖片。img.src為base64編碼字符串;
  4. 在div里粘貼網(wǎng)頁圖片,直接顯示圖片,img.src為圖片地址。

firefox:

  1. event有clipboardData屬性,clipboardData沒有item屬性;
  2. 只有在textarea里或者可編輯的div(里才粘貼才觸發(fā)paste事件;
  3. 在div里粘貼截圖,直接顯示圖片,img.src為base64編碼字符串;
  4. 在div里粘貼網(wǎng)頁圖片,表現(xiàn)同chrome。

ie11:(不截圖了,可自行試驗,其他瀏覽器同理<( ̄▽ ̄)/,因為懶...)

  • event沒有clipboardData屬性;
  • 只在可編輯的div中粘貼才觸發(fā)paste事件;
  • 在div里粘貼截圖,直接顯示圖片,img.src為base64編碼字符串;
  • 在div里粘貼網(wǎng)頁圖片,表現(xiàn)同chrome。

監(jiān)聽了paste事件,也知道了表現(xiàn)形式,接下來就是如何獲取數(shù)據(jù)了:
chrome有特定的方法,利用clipboardData.items、getAsFile()、new FileReader()等api可以在paste回調(diào)函數(shù)里獲取到剪貼板里圖片的base64編碼字符串(無論是截圖粘貼的還是網(wǎng)頁圖片復(fù)制粘貼的),ie11,firefox沒有這樣的api,不過依然有辦法可以獲取,因為數(shù)據(jù)已經(jīng)表現(xiàn)在img的src里了,對于截圖粘貼的,直接取img的src屬性值(base64),對于網(wǎng)頁粘貼的,則把地址傳給后臺,然后根據(jù)地址down下來,存在自己的服務(wù)器,最后把新地址返回來交給前端展示就ok了。為了保持一致性便于管理,統(tǒng)一將所有情況(截圖、網(wǎng)頁)中的img的src屬性替換為自己存儲的地址。因此可以得到以下核心代碼(注釋很全哦~~):

html展示:

<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
body {
  display: -webkit-flex; 
  display: flex;    
  -webkit-justify-content: center;
  justify-content: center;
}
#tar_box {
  width: 500px;
  height: 500px;
  border: 1px solid red;
}
</style>

前端js處理邏輯:

document.addEventListener('paste', function (event) {
  console.log(event)
  var isChrome = false;
  if ( event.clipboardData || event.originalEvent ) {
    //not for ie11  某些chrome版本使用的是event.originalEvent
    var clipboardData = (event.clipboardData || event.originalEvent.clipboardData);
    if ( clipboardData.items ) {
      // for chrome
      var  items = clipboardData.items,
        len = items.length,
        blob = null;
      isChrome = true;
      //items.length比較有意思,初步判斷是根據(jù)mime類型來的,即有幾種mime類型,長度就是幾(待驗證)
      //如果粘貼純文本,那么len=1,如果粘貼網(wǎng)頁圖片,len=2, items[0].type = 'text/plain', items[1].type = 'image/*'
      //如果使用截圖工具粘貼圖片,len=1, items[0].type = 'image/png'
      //如果粘貼純文本+HTML,len=2, items[0].type = 'text/plain', items[1].type = 'text/html'
      // console.log('len:' + len);
      // console.log(items[0]);
      // console.log(items[1]);
      // console.log( 'items[0] kind:', items[0].kind );
      // console.log( 'items[0] MIME type:', items[0].type );
      // console.log( 'items[1] kind:', items[1].kind );
      // console.log( 'items[1] MIME type:', items[1].type );

      //阻止默認行為即不讓剪貼板內(nèi)容在div中顯示出來
      event.preventDefault();

      //在items里找粘貼的image,據(jù)上面分析,需要循環(huán)  
      for (var i = 0; i < len; i++) {
        if (items[i].type.indexOf("image") !== -1) {
          // console.log(items[i]);
          // console.log( typeof (items[i]));

          //getAsFile() 此方法只是living standard firefox ie11 并不支持        
          blob = items[i].getAsFile();
        }
      }
      if ( blob !== null ) {
        var reader = new FileReader();
        reader.onload = function (event) {
          // event.target.result 即為圖片的Base64編碼字符串
          var base64_str = event.target.result
          //可以在這里寫上傳邏輯 直接將base64編碼的字符串上傳(可以嘗試傳入blob對象,看看后臺程序能否解析)
          uploadImgFromPaste(base64_str, 'paste', isChrome);
        }
        reader.readAsDataURL(blob); 
      }
    } else {
      //for firefox
      setTimeout(function () {
        //設(shè)置setTimeout的原因是為了保證圖片先插入到div里,然后去獲取值
        var imgList = document.querySelectorAll('#tar_box img'),
          len = imgList.length,
          src_str = '',
          i;
        for ( i = 0; i < len; i ++ ) {
          if ( imgList[i].className !== 'my_img' ) {
            //如果是截圖那么src_str就是base64 如果是復(fù)制的其他網(wǎng)頁圖片那么src_str就是此圖片在別人服務(wù)器的地址
            src_str = imgList[i].src;
          }
        }
        uploadImgFromPaste(src_str, 'paste', isChrome);
      }, 1);
    }
  } else {
    //for ie11
    setTimeout(function () {
      var imgList = document.querySelectorAll('#tar_box img'),
        len = imgList.length,
        src_str = '',
        i;
      for ( i = 0; i < len; i ++ ) {
        if ( imgList[i].className !== 'my_img' ) {
          src_str = imgList[i].src;
        }
      }
      uploadImgFromPaste(src_str, 'paste', isChrome);
    }, 1);
  }
})

function uploadImgFromPaste (file, type, isChrome) {
  var formData = new FormData();
  formData.append('image', file);
  formData.append('submission-type', type);

  var xhr = new XMLHttpRequest();
  xhr.open('POST', '/upload_image_by_paste');
  xhr.onload = function () {
    if ( xhr.readyState === 4 ) {
      if ( xhr.status === 200 ) {
        var data = JSON.parse( xhr.responseText ),
          tarBox = document.getElementById('tar_box');
        if ( isChrome ) {
          var img = document.createElement('img');
          img.className = 'my_img';
          img.src = data.store_path;
          tarBox.appendChild(img);
        } else {
          var imgList = document.querySelectorAll('#tar_box img'),
            len = imgList.length,
            i;
          for ( i = 0; i < len; i ++) {
            if ( imgList[i].className !== 'my_img' ) {
              imgList[i].className = 'my_img';
              imgList[i].src = data.store_path;
            }
          }
        }

      } else {
        console.log( xhr.statusText );
      }
    };
  };
  xhr.onerror = function (e) {
    console.log( xhr.statusText );
  }
  xhr.send(formData);
}

用express.js搭的簡易后臺的接收邏輯:

router.post('/', upload.array(), function (req, res, next) {
//1.獲取客戶端傳來的src_str字符串=>判斷是base64還是普通地址=>獲取圖片類型后綴(jpg/png etc)
//=>如果是base64替換掉"前綴"("data:image\/png;base64," etc)
//2.base64 轉(zhuǎn)為 buffer對象 普通地址則先down下來
//3.寫入硬盤(后續(xù)可以將地址存入數(shù)據(jù)庫)
//4.返回picture地址
var src_str = req.body.image,
  timestamp = new Date().getTime();
if ( src_str.match(/^data:image\/png;base64,|^data:image\/jpg;base64,|^data:image\/jpg;base64,|^data:image\/bmp;base64,/) ) {
  //處理截圖 src_str為base64字符串
  var pic_suffix = src_str.split(';',1)[0].split('/',2)[1],
    base64 = src_str.replace(/^data:image\/png;base64,|^data:image\/jpg;base64,|^data:image\/jpg;base64,|^data:image\/bmp;base64,/, ''),
    buf = new Buffer(base64, 'base64'),
    store_path = 'public/images/test_' + timestamp + '.' + pic_suffix;

  fs.writeFile(store_path, buf, function (err) {
    if (err) {
      throw err;
    } else {
      res.json({'store_path': store_path});
    }
  });
} else {// 處理非chrome的網(wǎng)頁圖片 src_str為圖片地址
  var temp_array = src_str.split('.'),
    pic_suffix = temp_array[temp_array.length - 1],
    store_path = 'public/images/test_' + timestamp + '.' + pic_suffix,
    wstream = fs.createWriteStream(store_path);

  request(src_str).pipe(wstream);
  wstream.on('finish', function (err) {
    if( err ) {
      throw err;
    } else {
      res.json({"store_path": store_path});
    }
  });
}
});

需要node環(huán)境:安裝node=>npm intall=>node app.js)

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助。

相關(guān)文章

  • 紅黑樹的插入詳解及Javascript實現(xiàn)方法示例

    紅黑樹的插入詳解及Javascript實現(xiàn)方法示例

    這篇文章主要給大家介紹了關(guān)于紅黑樹的插入的相關(guān)資料,以及Javascript實現(xiàn)的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起看看吧。
    2018-03-03
  • JS Promise axios 請求結(jié)果后面的.then() 是什么意思

    JS Promise axios 請求結(jié)果后面的.then() 是什么意思

    本文主要介紹了JS Promise axios 請求結(jié)果后面的 .then() 是什么意思,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • JS vs TS二分法博弈對比分析

    JS vs TS二分法博弈對比分析

    這篇文章主要介紹了JS vs TS二分法博弈對比分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01
  • 網(wǎng)頁爬蟲之cookie自動獲取及過期自動更新的實現(xiàn)方法

    網(wǎng)頁爬蟲之cookie自動獲取及過期自動更新的實現(xiàn)方法

    這篇文章主要介紹了網(wǎng)頁爬蟲之cookie自動獲取及過期自動更新的實現(xiàn)方法,需要的朋友可以參考下
    2018-03-03
  • JSON的parse()方法介紹

    JSON的parse()方法介紹

    今天小編就為大家分享一篇關(guān)于JSON的parse()方法介紹,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • JS實現(xiàn)獲取進今年第幾天是周幾的方法分析

    JS實現(xiàn)獲取進今年第幾天是周幾的方法分析

    這篇文章主要介紹了JS實現(xiàn)獲取進今年第幾天是周幾的方法,結(jié)合實例形式對比分析了JavaScript進行日期與天數(shù)運算相關(guān)操作技巧與注意事項,需要的朋友可以參考下
    2018-06-06
  • 利用JavaScript緩存遠程竊取Wi-Fi密碼的思路詳解

    利用JavaScript緩存遠程竊取Wi-Fi密碼的思路詳解

    這篇文章主要介紹了利用JavaScript緩存遠程竊取Wi-Fi密碼的方法,本文通過實例代碼相結(jié)合的形式給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-11-11
  • Javascript在IE或Firefox下獲取鼠標位置的代碼

    Javascript在IE或Firefox下獲取鼠標位置的代碼

    由于Firefox和IE等瀏覽器之間對JS解釋的方式不一樣,F(xiàn)irefox下面獲取鼠標位置不能夠直接使用clientX來獲取。網(wǎng)上說的一般都是觸發(fā)mousemove事件才行。我這里有兩段代碼,思路都一樣,就是風格不同。
    2009-12-12
  • 兩種JavaScript的AES加密方式(可與Java相互加解密)

    兩種JavaScript的AES加密方式(可與Java相互加解密)

    這篇文章主要介紹了兩種JavaScript的AES加密方式(可與Java相互加解密) 的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-08-08
  • javascript 發(fā)布-訂閱模式 實例詳解

    javascript 發(fā)布-訂閱模式 實例詳解

    這篇文章主要介紹了javascript 發(fā)布-訂閱模式,結(jié)合實例形式詳細分析了javascript發(fā)布-訂閱模式基本功能、原理、實現(xiàn)方法與相關(guān)使用技巧,需要的朋友可以參考下
    2023-06-06

最新評論

图片| 新源县| 辽阳县| 清原| 黑河市| 长寿区| 镇远县| 平陆县| 平顶山市| 贵溪市| 余干县| 潼南县| 荥阳市| 海盐县| 文安县| 香河县| 海南省| 福建省| 洛浦县| 景宁| 稷山县| 蒙山县| 德清县| 泊头市| 门源| 连山| 崇义县| 江门市| 都匀市| 丰原市| 高密市| 定陶县| 吴桥县| 赤峰市| 察哈| 磴口县| 霍城县| 南乐县| 黔南| 桓仁| 华亭县|