1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        原生 popover 終于要來(lái)了!

        共 5197字,需瀏覽 11分鐘

         ·

        2023-06-14 20:31

        提到 popover,相信大家都很熟悉,沒(méi)錯(cuò),就是組件庫(kù)里經(jīng)常見(jiàn)到的懸浮層(或者叫“氣泡卡片”),比如 Ant Design

        0618f0d7b2a4d4bb0597a14bc1610adf.webpimage-20230504191034134

        現(xiàn)在,這個(gè)好用的特性終于要在Chrome 114上正式支持了~下面花幾分鐘快速了解一下吧

        一、popover 屬性

        其實(shí)這個(gè)名稱以前叫做popup,后來(lái)才更改成了popover??。

        popover是一個(gè)全局屬性。給任意元素添加popover以后,它就變成了一個(gè)懸浮層。

              
              <div?popover>我是懸浮層div>

        popover有兩個(gè)值,分別是

        • auto:自動(dòng)(默認(rèn)值)。也就是瀏覽器默認(rèn)行為,比如點(diǎn)擊懸浮層外面會(huì)關(guān)閉懸浮層,按鍵盤Esc鍵也會(huì)關(guān)閉懸浮層
        • manual:手動(dòng)。也就是沒(méi)有前面的默認(rèn)行為,所有操作必須由開(kāi)發(fā)者手動(dòng)控制。
              
              <div?popover>我是懸浮層div>
        <div?popover="auto">我是懸浮層div>
        <div?popover="manual">我是懸浮層div>

        懸浮層默認(rèn)是隱藏的,也不能通過(guò)屬性設(shè)置默認(rèn)顯示。那么,如何打開(kāi)一個(gè)懸浮層呢?

        二、控制懸浮層的方式

        控制懸浮層有兩種方式,分別是 聲明式命令式

        首先來(lái)看聲明式,經(jīng)常寫原生HTML的應(yīng)該會(huì)很喜歡這種方式,無(wú)需 JS 介入就可以實(shí)現(xiàn)懸浮層的打開(kāi)和關(guān)閉,如下

              
              <button?popovertarget="pop1">打開(kāi)?auto?懸浮層button>
        <div?id="pop1"?popover>我是?auto?懸浮層div>

        只需要通過(guò)popovertarget屬性將目標(biāo)懸浮層的id屬性和按鈕相關(guān)聯(lián)就行了(注意,只能是ID),效果如下

        8fa2f90620bde52c9bae6ff3506b7b50.webpKapture 2023-05-04 at 19.52.20

        還可以通過(guò)popovertargetaction屬性來(lái)設(shè)置點(diǎn)擊行為,有三個(gè)值,分別是

        • show:打開(kāi)。
        • hide:關(guān)閉。
        • toggle:切換(默認(rèn)值)。如果懸浮層是關(guān)閉的就打開(kāi),反正亦然
              
              <button?popovertarget="pop1"?popovertargetaction="show">打開(kāi)?auto?懸浮層button>
        <button?popovertarget="pop1"?popovertargetaction="hide">關(guān)閉?auto?懸浮層button>
        <button?popovertarget="pop1"?popovertargetaction="toggle">切換?auto?懸浮層button>
        <div?id="pop1"?popover>我是?auto?懸浮層div>

        效果如下

        bbb7674de6638600e4d5516430f9a58f.webpKapture 2023-05-04 at 19.59.38

        現(xiàn)在回過(guò)頭來(lái)看看兩種popover的區(qū)別

              
              <button?popovertarget="pop1">切換?auto?懸浮層button>
        <button?popovertarget="pop2">切換?manual?懸浮層button>
        <div?id="pop1"?popover>我是?auto?懸浮層div>
        <div?id="pop2"?popover="manual">我是?manual?懸浮層div>

        效果如下

        df38de992a5943970ad6a3ad5bd0b44c.webp

        Kapture 2023-05-06 at 11.00.49

        可以看到,auto懸浮層點(diǎn)擊空白會(huì)自動(dòng)關(guān)閉(還可以通過(guò)Esc鍵關(guān)閉),而manual懸浮層只能手動(dòng)去關(guān)閉。當(dāng)然大部分情況下auto可以滿足需求。

        三、命令式方式

        所謂“命令式”,其實(shí)就是一套JS API,需要在 JS中主動(dòng)去調(diào)用。

        那么,有了聲明式為啥還要命令式呢?答案是,更靈活。

        比如,前面的聲明式,只適用于click場(chǎng)景,如果需要hover也能打開(kāi)懸浮層,這種方式就不行了。像這種情況,就可以采用命令式方式了。

        先看語(yǔ)法,很簡(jiǎn)單,就是 3 個(gè)方法

              
              popoverEl.showPopover();?//?打開(kāi)
        popoverEl.hidePopover();?//?關(guān)閉
        popoverEl.togglePopover(force)?//?切換,可傳參數(shù),強(qiáng)制設(shè)置為?true?或者?false

        需要注意的是,這 3 個(gè)方式僅適用于懸浮層,也就是必須有popover屬性,如果是普通元素,會(huì)直接報(bào)錯(cuò),如下

        e379bbcb5e03b860464d813f3addc338.webpimage-20230506111347549

        還有一種情況,如果一個(gè)本來(lái)已經(jīng)打開(kāi)的懸浮層,再次調(diào)用showPopover(),也會(huì)報(bào)錯(cuò),反之亦然

        ac9f96eb64a10c5b886f227a937d6529.webpimage-20230506112322476

        因此,在使用 JS 控制時(shí),推薦使用manual懸浮層,便于精準(zhǔn)控制。

        下面來(lái)看一個(gè)hover控制的例子

              
              <button?id="button">hover?打開(kāi)懸浮層button>
        <div?id="pop"?popover="manual">我是?hover?懸浮層div>

        然后是相關(guān)JS

              
              button.addEventListener('mouseenter',?()?=>?{
        ??pop.showPopover()
        })
        button.addEventListener('mouseleave',?()?=>?{
        ??pop.hidePopover()
        })

        效果如下

        959edcef46e28878737c2fcbf5d3525e.webpKapture 2023-05-06 at 11.26.08

        四、判斷懸浮層的打開(kāi)狀態(tài)

        首先,從HTML結(jié)構(gòu)上來(lái)看,打開(kāi)和關(guān)閉沒(méi)有任何屬性變化,這個(gè)和details不一樣(details會(huì)添加open屬性)。為此,CSS 還專門出了一個(gè)偽類:open用于標(biāo)識(shí)懸浮層的打開(kāi)狀態(tài)

        目前還不穩(wěn)定,后續(xù)可能會(huì)更變?yōu)?code style="font-size:14px;background-color:rgba(27,31,35,.05);font-family:'Operator Mono', Consolas, Monaco, Menlo, monospace;color:rgb(150,84,181);">:popover-open

              
              div
        ??/*?打開(kāi)樣式?*/
        }

        通過(guò)這個(gè)偽類,我們可以很輕松的給懸浮層添加過(guò)渡動(dòng)畫

              
              [popover]{
        ??display:?block;?/*默認(rèn)是display:none,不會(huì)有動(dòng)畫*/
        ??visibility:?hidden;
        ??opacity:?0;
        ??transform:?scale(.6);
        ??transition:?.3s;
        }
        [popover]:open{
        ??visibility:?visible;
        ??transform:?scale(1);
        ??opacity:?1;
        }

        效果如下

        06cf30d62d4f6d0f92dbcb8321a7bdbf.webpKapture 2023-05-06 at 14.31.03

        除了 CSS 方式,JS 也能判斷懸浮層的狀態(tài),但是并不是自己想象的那樣。

        起初,我以為有一個(gè)屬性可以直接獲取到懸浮層的狀態(tài),發(fā)現(xiàn)并不行,如下

              
              popoverEl.open?//?undefined

        那如何獲取呢?

        其實(shí)可以借助前面 CSS 的方式,只要匹配的:open偽類不就可以了嗎,需要用到matches方法

        https://developer.mozilla.org/en-US/docs/Web/API/Element/matches

        這樣就能隨時(shí)獲取到懸浮層的打開(kāi)狀態(tài)了

              
              popoverEl.matches(':open')

        另外,還可以通過(guò)事件監(jiān)聽(tīng)的方式來(lái)獲取,需要用到新的事件toggle,這是一個(gè)專門針對(duì)popover新推出的事件,使用方式如下

              
              popoverEl.addEventListener("toggle",?(event)?=>?{
        ??if?(event.newState?===?"open")?{
        ????console.log("打開(kāi)狀態(tài)");
        ??}?else?{
        ????console.log("關(guān)閉狀態(tài)");
        ??}
        });

        五、popover 的頂層特性

        前面說(shuō)了那么多,好像并沒(méi)有什么很厲害的地方,隨便一個(gè) div 都可以模擬,而且現(xiàn)在的組件庫(kù)不是也實(shí)現(xiàn)的好好的嗎?到底有什么優(yōu)勢(shì)呢?

        打開(kāi)控制臺(tái)可以看到,popover上有一個(gè)很特殊的標(biāo)識(shí)

        a4ae3ed6afad546b6897aa24740c143e.webpimage-20230506145148101

        這個(gè)就是頂層 top-layer !也就是層級(jí)是最高的,高于頁(yè)面上的一切。

        這也是懸浮層的意義所在,本身就應(yīng)該是懸浮在最上面。下面是示意圖

        8a94052a82e4f95b33bb61d63145759c.webpimage-20230506145624083

        這樣的好處就是無(wú)論在 HTML中的任何位置,都無(wú)需擔(dān)心懸浮層被遮擋的情況,也無(wú)需將懸浮層移動(dòng)的最外層body上。

        這個(gè)特性和dialog是一樣的,有興趣的可以參考之前這篇文章:你可能不知道的dialog彈窗

        以上完整代碼可以查看以下任意鏈接:

        • popover (juejin.cn) [1]
        • popover (codepen.io) [2]
        • popover (runjs.work) [3]

        如果瀏覽器不支持,會(huì)有下面提示

        e4f521386b7b5ce9994871e1602008be.webpimage-20230506163742550

        這個(gè)是用@supports實(shí)現(xiàn)的

              
              @supports?selector([popover]:open)?{
        ????.no-support{
        ????????display:?none?!important;
        ????}
        }

        六、兼容性和總結(jié)

        看一下兼容性,目前只有Chrome 114+支持,內(nèi)部項(xiàng)目可以嘗鮮一下,如果是Electron應(yīng)用,那就大膽使用吧

        68fd40bc9d113a767004f3872cb83818.webpimage-20230506151107934

        下面來(lái)總結(jié)一下本文要點(diǎn):

        1. popover是一個(gè)全局屬性。給任意元素添加popover以后,它就變成了一個(gè)懸浮層。
        2. popover屬性有兩個(gè)值,默認(rèn)是auto自動(dòng)模式,支持默認(rèn)行為,比如點(diǎn)擊空白關(guān)閉,鍵盤Esc關(guān)閉
        3. popover屬性還支持manual手動(dòng)模式,也就是沒(méi)有以上默認(rèn)行為
        4. 控制popover有兩種方式,分別是聲明式和命令式
        5. 聲明式是指通過(guò)HTML屬性來(lái)實(shí)現(xiàn)點(diǎn)擊交互
        6. 可以通過(guò)popovertarget屬性將懸浮層的id和按鈕相關(guān)聯(lián),這樣就能通過(guò)按鈕打開(kāi)懸浮層了
        7. 還可以通過(guò)popovertargetaction屬性來(lái)設(shè)置點(diǎn)擊行為,有show、hide、toggle3種方式
        8. 命令式是指通過(guò) JS API來(lái)實(shí)現(xiàn)對(duì)懸浮層的控制,相比聲明式而言更加靈活
        9. 控制懸浮層的方法有showPopover、hidePopover、togglePopover
        10. CSS偽類:open可以區(qū)分懸浮層的打開(kāi)狀態(tài)
        11. JS 可以通過(guò)matches(':open')來(lái)獲取懸浮層的打開(kāi)狀態(tài)
        12. JS 還可以通過(guò)監(jiān)聽(tīng)toggle事件來(lái)獲取懸浮層的打開(kāi)狀態(tài),方式是event.newState
        13. 相比傳統(tǒng)實(shí)現(xiàn),原生popover最大的優(yōu)勢(shì)是支持頂層特性

        最近正在對(duì)xy-ui[4]進(jìn)行升級(jí)改造,里面的 popover 組件就使用到了這一特性,不過(guò)也對(duì)不支持的瀏覽器做了兼容,有興趣的可以去體驗(yàn)一下。

        https://xy-ui.codelabo.cn/components/popover

        b3416ea0ab65dfcc61eb5da879de5b1e.webpimage-20230506191435391

        最后,如果覺(jué)得還不錯(cuò),對(duì)你有幫助的話,歡迎點(diǎn)贊、收藏、轉(zhuǎn)發(fā)???

        參考資料

        [1]

        popover (juejin.cn): https://code.juejin.cn/pen/7229985240335269943

        [2]

        popover (codepen.io): https://codepen.io/xboxyan/pen/MWPrRod

        [3]

        popover (runjs.work): https://runjs.work/projects/d38b9c37b0d04897

        [4]

        xy-ui: https://github.com/XboxYan/xy-ui


        瀏覽 89
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            免费黄网在线观看 | 日韩无打码| 三级天天操 | 三上悠亚被淫辱の教室下载 | 国产精品成人一区二区网站软件 | 国产做受 入口 | 玖玖玖玖玖玖玖玖 | 久操免费视频 | 午夜成人无码精品免费 | 无套内谢少妇毛片 |