ly2011 / blog

前端学习笔记
https://ly2011.github.io/blog
122 stars 12 forks source link

利用剪切板JS API优化输入框的粘贴体验 #72

Open ly2011 opened 6 years ago

ly2011 commented 6 years ago

利用剪切板JS API优化输入框的粘贴体验

JS改变剪贴板内容

我们可以利用Clipboard API改变剪切板内容,从而提高输入框粘贴信息的交互体验。

一段简易的处理代码 下面这段JavaScript代码实现的是针对输入框的的粘贴处理(IE9+支持)。然后演示了邮箱,手机号剪切板数据的简单过滤处理,其他场景大家可以自行补充。

/**
@description 表单输入框粘贴体验优化,出处https://www.zhangxinxu.com/wordpress/?p=8003
@author zhangxinxu
*/
Array.from(document.querySelectorAll('input, textarea')).forEach(ele => {
  ele.addEventListener('paste', function (event) {
    // 输入框类型
    const type = this.getAttribute('type') || this.type
    // 剪贴板数据对象
    const clipboardData = event.clipboardData || window.clipboardData
    // 粘贴内容
    let paste = ''
    // 剪贴板对象可以获取
    if (!clipboardData) {
      return
    }
    // 获取选中的文本内容
    let userSelection, textSelected = ''
    if (window.getSelection) {
      // 现代浏览器
      // 直接window.getSelection().toString() 对于IE的输入框无效
      textSelected = this.value.slice(ele.selectionStart, ele.selectionEnd)
    } else if (document.selection) {
      // 旧IE浏览器
      textSelected = document.selection.createRange().text
    }
    // 只有输入框没有数据,或全选状态才处理
    if (this.value.trim() === '' || textSelected === this.value) {
      // 阻止冒泡和默认粘贴行为
      event.preventDefault()
      event.stopPropagation()
      // 获取粘贴数据
      paste = clipboardData.getData('text') || ''
      // 进行如下处理
      // 除非是password,其他都过滤前后空格
      if (type !== 'password') {
        paste = paste.trim()
      }
      // 邮箱处理,可能会使用#代替@避免被爬虫抓取
      if(type === 'email') {
        paste = paste.replace('#', '@')
      } else if (type === 'tel') {
        // 手机号处理
        paste = paste.replace(/^\+86/, '')
        // 如果此时剩余所有数字正好11位
        if(paste.match(/\d/g) && paste.match(/\d/g).length === 11) {
          paste =paste.replace(/\D/g, '')
        }
      }
      this.value = paste
    }
  })

  ele.addEventListener('drop', function(event) {
    // 输入框类型
    const type = this.getAttribute('type') || this.type
    // 获取拖拽文本内容
    let text = event.dataTransfer.getData('text')
    if (type !== 'password') {
      text = text.trim()
    }
    if (type === 'tel') {
      // 手机号处理
      text = text.replace(/^\+86/, '')
      if (this.value === '' && text.match(/\d/g) && text.match(/\d/g).length === 11) {
        // 阻止冒泡和默认粘贴行为
        event.preventDefault()
        event.stopPropagation()
        this.value = text.replace(/\D/g, '')
        this.select()
      }
    }
  })
})

例如,复制demo页面手机输入框后面的手机号码,然后粘贴到输入框中,会看到中间的短横线自动被过滤了。 default

其它 上面代码对剪切板内容的处理比较简单,就是过滤前后空格,邮箱#替换成@,手机号11位标准格式化。大家可以根据实际需求进行更好的处理,例如,XSS过滤可以直接在剪切板中进行等。

拖拽输入优化 当我们拖拽文本进入输入框的时候,也可以做类似的优化,效果如下GIF:

相关JavaScript代码如下:

input.addEventListener('drop', function (event) {
  // 获取拖拽文本内容
  var text = event.dataTransfer.getData('text');
  if (this.value == '' && text.match(/\d/g) && text.match(/\d/g).length == 11) {
    event.preventDefault();
    input.value = text.replace(/\D/g, '');
    input.select();
  }
});

copy与剪切板

基于剪切板JS API可以做的事情不仅仅是粘贴,复制的时候也可以做些事情,例如,我可以在我的网站页面上绑定一个copy事件,当你复制文章内容的时候,自动在剪切板文字后面加上一段版权声明。

代码示意:

document.addEventListener('copy', function (event) {
  var clipboardData = event.clipboardData || window.clipboardData;
  if (!clipboardData) { return; }
  var text = window.getSelection().toString();
  if (text) {
    event.preventDefault();
    clipboardData.setData('text/plain', text + '\n\n鑫空间版权所有');
  }
});

复制demo页面任意一段文字,然后粘贴到输入框中,可以看到粘贴内容最后附有“鑫空间版权所有”这样的信息,如下截图: default

MaleWxt commented 3 years ago

不好意思,冒昧请假一下,我比较新手,想问一下,我在复制别的页面内容的时候,想要在粘贴前过滤一下style这些信息,只想保留一下文字,文字换行,还有图片这些,应该怎么处理!谢谢!