一区二区日本_久久久久久久国产精品_无码国模国产在线观看_久久99深爱久久99精品_亚洲一区二区三区四区五区午夜_日本在线观看一区二区

如何解決 iframe 無法觸發 clickOutside,iframeclickoutside

前言

在公司的一次小組分享會上,組長給我們分享了一個他在項目中遇到的一個問題。愛掏網 - it200.com在一個嵌入 iframe 的系統中,當我們點擊按鈕展開 Dropdown 展開后,再去點擊 iframe 發現無法觸發 Dropdown 的 clickOutside 事件,導致 Dropdown 無法關閉。愛掏網 - it200.com

查看在線示例

為什么無法觸發 clickOutside

目前大多數的 UI 組件庫,例如 Element、Ant Design、iView 等都是通過鼠標事件來處理, 下面這段是 iView 中的 clickOutside 代碼,iView 直接給 Document 綁定了 click 事件,當 click 事件觸發時候,判斷點擊目標是否包含在綁定元素中,如果不是就執行綁定的函數。愛掏網 - it200.com

bind (el, binding, vnode) {
  function documentHandler (e) {
    if (el.contains(e.target)) {
      return false;
    }
    if (binding.expression) {
      binding.value(e);
    }
  }
  el.__vueClickOutside__ = documentHandler;
  document.addEventListener('click', documentHandler);
}
復制代碼

但 iframe 中加載的是一個相對獨立的 Document,如果直接在父頁面中給 Document 綁定 click 事件,點擊 iframe 并不會觸發該事件。愛掏網 - it200.com

知道問題出現在哪里,接下來我們來思考怎么解決?

給 iframe 的 body 元素綁定事件

我們可以通過一些特殊的方式給 iframe 綁定上事件,但這種做法不優雅,而且也是存在問題的。愛掏網 - it200.com我們來想想一下這樣一個場景,左邊是一個側邊欄(導航欄),上面是一個 Header 里面有一些 Dropdown 或是 Select 組件,下面是一個頁面區域。愛掏網 - it200.com

但這些頁面有的是嵌入 iframe,有些是當前系統的頁面。愛掏網 - it200.com如果使用這種方法,我們在切換路由的時候就要不斷的去判斷這個頁面是否包含 iframe,然后重新綁定/解綁事件。愛掏網 - it200.com而且如果 iframe 和當前系統不是同域(大多數情況都不是同域的),那么這種做法是無效的。愛掏網 - it200.com

添加遮罩層

我們可以通過給 iframe 添加一個透明遮罩層,點擊 Dropdown 的時候顯示透明遮罩層,點擊 Dropdown 之外的區域或遮罩層,就派發 clickOutside 事件并關閉遮罩層,這樣雖然可以觸發 clickOutside 事件,但存在一個問題,如果用戶點擊的區域正好是 iframe 頁面中的某個按鈕,那么第一次點擊是不會生效的,這種做法對于交互不是很友好。愛掏網 - it200.com

監聽 focusin 與 focusout 事件

其實我們可以換一種思路,為什么一定要用鼠標事件來做這件事呢?focusin 與 focusout 事件就很適合處理當前這種情況。愛掏網 - it200.com

當我們點擊綁定的元素之外時就觸發 focusout 事件,這時我們可以添加一個定時器,延時調用我們綁定的函數。愛掏網 - it200.com而當我們點擊綁定元素例如 Dropdown 會觸發 focusin 事件,這時候我們判斷目標是否包含在綁定元素中,如果包含在綁定元素中就清除定時器。愛掏網 - it200.com

不過使用 focusin 與 focusout 事件需要解決一個問題,那就是要將綁定的元素變成 focusable 元素,那么怎么將元素變成 focusable 元素呢?我們通過將元素的 tabindex 屬性置為 -1 , 該元素就變成 focusable 的元素。愛掏網 - it200.com

需要注意的是,元素變成 focusable 元素之后,當它獲取焦點的時候,瀏覽器會給它加上默認的高亮樣式,如果你不需要這種樣式可以將 outline 屬性設置為 none。愛掏網 - it200.com

不過這種方法雖然很棒,但是也會存在一些問題,瀏覽器兼容性,下面是 MDN 給出的瀏覽器兼容情況,從圖中可以看出 Firefox 低版本不支持這個事件,所以你需要去權衡你的項目是否支持低版本的 Firefox 瀏覽器。愛掏網 - it200.com

使用 focus-outside 庫

focus-outside?正是為了解決上述問題所創建的倉庫,代碼不到 200 行。愛掏網 - it200.com使用起來也非常方便,它只有兩個方法,bind 與 unbind,不依賴其他第三方庫,并且支持為多個元素綁定同一個函數。愛掏網 - it200.com

為什么要給多個元素綁定同一個函數,這么做是為了兼容 Element 與 Ant Design,因為 Element 與 Ant Design 會將 Dropdown 插入 body 元素中,它的按鈕和容器是分離的,當我們點擊按鈕顯示 Dropdown,當我們點擊 Dropdown 區域,這時候按鈕會失去焦點觸發 focusout 事件。愛掏網 - it200.com事實上我們并不希望這時關閉 Dropdown,所以我將它們視為同一個綁定源。愛掏網 - it200.com

這里說明下 Element 與 Ant Design 為什么要將彈出層放在 body 元素中,因為如果直接將 Dropdown 掛載在父元素下,會受到父元素樣式的影響。愛掏網 - it200.com比如當父元素有 overflow: hidden,Dropdown 就有可能被隱藏掉。愛掏網 - it200.com

簡單使用

// import { bind, unbidn } from 'focus-outside'
// 建議使用下面這種別名,防止和你的函數命名沖突了。愛掏網 - it200.com
import { bind: focusBind, unbind: focusUnbind } from 'focus-outside'

// 如果你是使用 CDN 引入的,應該這樣使用
// 
// const { bind: focusBind, unbind: focusUnbind } = FocusOutside

const elm = document.querySelector('#dorpdown-button')
// 綁定函數
focusBind(elm, callback)

function callback () {
  console.log('您點擊了 dropdown 按鈕外面的區域')
  // 清除綁定
  focusUnbind(elm, callback)
}
復制代碼

查看在線示例

注意

前面說到過元素變成 focusable 元素后,當它獲取焦點瀏覽器會給它加上高亮樣式,如果你不希望看到和這個樣式,你需要將這個元素的 CSS 屬性 outline 設置為 none。愛掏網 - it200.comfocsout-outside 0.5.0 版本中新增 className 參數,為每個綁定的元素添加 focus-outside 默認類名,你要可以通過傳遞 className 參數自定義類名,當執行 unbind 函數時候會將類名從元素上刪除 。愛掏網 - it200.com



// js
const elm = document.querySelector('#focus-ele')
// 默認類名是 focus-outside
focusBind(elm, callback, 'my-focus-name')

// css
// 如果你需要覆蓋所有的默認樣式,可以在這段代碼放在全局 CSS 中。愛掏網 - it200.com
.my-focus-name {
  outline: none;
}
復制代碼

在 Vue 中使用

// outside.js
export default {
  bind (el, binding) {
    focusBind(el, binding.value)
  },

  unbind (el, binding) {
    focusUnbind(el, binding.value)
  }
}

// xx.vue
復制代碼

查看在線示例

在 Element 中使用


      下拉菜單
    
    黃金糕獅子頭螺螄粉雙皮奶蚵仔煎復制代碼

查看在線示例

在 Ant Design 中使用

import { Menu, Dropdown, Icon, Button } = antd
import { bind: focusBind, unbind: focusUnbind } = 'focus-outside'

function getItems () {
  return [1,2,3,4].map(item => {
    return {item} st menu item 
  })
}

class MyMenu extends React.Component {
  constructor (props) {
    super(props)
    this.menuElm = null
  }

  render () {
    return ({getItems()})
  }

  componentDidMount () {
    this.menuElm = ReactDOM.findDOMNode(this.refs.menu)
    if (this.menuElm && this.props.outside) focusBind(this.menuElm, this.props.outside)
  }

  componentWillUnmount () {
    if (this.menuElm && this.props.outside) focusUnbind(this.menuElm, this.props.outside)
  }
}

class MyDropdown extends React.Component {
  constructor (props) {
    super(props)
    this.dropdownElm = null
  }

  state = {
    visible: false
  }

  render () {
    const menu = ()
    return (
      
      
    )
  }

  componentDidMount () {
    this.dropdownElm = ReactDOM.findDOMNode(this.refs.divRef)
    if (this.dropdownElm) focusBind(this.dropdownElm, this.handleOutside)
  }

  componentWillUnmount () {
    if (this.dropdownElm) focusUnbind(this.dropdownElm, this.handleOutside)
  }

  handleOutside = () => {
    this.setState({ visible: false })
  }

  handleClick = () => {
    this.setState({ visible: !this.state.visible })
  }
}

ReactDOM.render(
  ,
  document.getElementById('container')
)
復制代碼

查看在線示例

總結

iframe 元素無法觸發鼠標事件,如果在嵌入 iframe 的系統中觸發 clickOutside, 更好的做法是使用 focusin 與 focusout 事件,將 HTML 屬性 tabindex 設置為 -1 可以將元素變成 focusable 元素。愛掏網 - it200.com瀏覽器會給 focusable 元素加上默認的高亮樣式,如果你不需要這種樣式,可以將 CSS 屬性 outline 設置為 none。愛掏網 - it200.com

相關鏈接

  • MDN focusin
  • MDN focusout
  • focus-outside
  • 說說 tabindex 的那些事兒
  • HTML tabindex 屬性與 web 網頁鍵盤無障礙訪問




原文發布時間為:2024年07月02日

作者:掘金

本文來源:掘金?如需轉載請聯系原作者
聲明:所有內容來自互聯網搜索結果,不保證100%準確性,僅供參考。如若本站內容侵犯了原著者的合法權益,可聯系我們進行處理。
發表評論
更多 網友評論0 條評論)
暫無評論

返回頂部

主站蜘蛛池模板: 欧美无乱码久久久免费午夜一区 | 日韩在线视频精品 | 四虎影| 国产成人精品一区二区 | 亚洲一区二区三区视频 | 成人av一区| 久久久久久国产精品免费免费 | 中文字幕欧美一区 | 国内精品一区二区三区 | 91欧美激情一区二区三区成人 | 天天欧美 | 日日夜夜草 | 天天艹天天干天天 | 国产不卡一区在线观看 | 亚洲交性| 狠狠躁18三区二区一区 | 6080亚洲精品一区二区 | 午夜av电影 | 国产黄色小视频在线观看 | 色免费看 | 成人精品国产一区二区4080 | 精精精精xxxx免费视频 | 91欧美精品 | 欧美日韩一卡二卡 | 国产亚洲欧美日韩精品一区二区三区 | 国产成人在线视频 | 特黄毛片视频 | 亚洲在线一区 | 亚洲精品在线视频 | 91亚洲国产成人精品一区二三 | 91 在线| 国产人成精品一区二区三 | 久久综合一区 | 中文字幕伊人 | 在线日韩 | 中文字幕亚洲一区二区三区 | 国产精品一区二区av | 免费黄色片视频 | 99re在线| 女女百合av大片一区二区三区九县 | 日韩精品中文字幕一区二区三区 |