整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          用原生Javascript制作一個隨機移動的圖片動畫

          eb Animation API 介紹

          當我們談及網頁動畫時,自然聯想到的是 CSS3 動畫、JS 動畫、SVG 動畫 等技術以及 jQuery.animate() 等動畫封裝庫,根據實際動畫內容設計去選擇不同的實現方式,然而,每個現行的動畫技術都存在一定的缺點,如 CSS3動畫必須通過JS去獲取動態改變的值,一個動畫效果分散在css文件和js文件里不好維護,setInterval 的時間往往是不精確的而且還會卡頓,引入額外的動畫封裝庫也并非對性能敏感的業務適用。

          Web Animation API 的歷史也應該有幾年了,但是每當做動畫效果時,筆者就是依賴各種庫,很少想著去原生實現,最終造成了我們的項目各種依賴庫,體積也不斷變大,性能如何也不得而知,作為前端開發的我們多么希望原生的JS去支持通用的動畫解決方案, Web Animation API 可能就是一個不錯的解決方案。

          W3C 提出 Web Animation API(簡稱 WAAPI)正緣于此,它致力于集合 CSS3 動畫的性能、JavaScript 的靈活、動畫庫的豐富等各家所長,將盡可能多的動畫控制由原生瀏覽器實現,并添加許多 CSS 不具備的變量、控制以及或調的選項。它為我們提供了一種通用語言來描述DOM元素的動畫,主要方法有:Animation,KeyframeEffect,AnimationEvent,DocumentTimeline,EffectTiming。關于這個API的詳細介紹,可以參照MDN的這篇文檔,鏈接地址:https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API。

          使用Web Animations API,我們可以將交互式動畫從樣式表移動到JavaScript,將表示與行為分開。我們不再需要依賴DOM的技術,例如編寫CSS屬性作用于元素以控制方向。為了構建自定義動畫庫和創建交互式動畫,Web Animations API可能是完成工作的完美工具,你無需借助第三方動畫庫,就可以輕松實現一個效果不錯的動畫。

          為了讓大家對這個API有個清晰的認識,筆者在接下來的系列文章里,用五六個例子讓大家理解這個API,今天筆者將用此API實現一個隨機移動的圖片開始進行介紹,比如用這個效果我們可以制作一個隨機飄浮移動的廣告位,游戲里隨機走動的怪物等等,本例中的特點就是為了體現Web Animation API的靈活性和強大性,我沒有引用任何第三方類庫,比如(JQ)以及也沒有使用setTimeout和requestAnimationFrame()函數。

          本篇文章預計時間 5 分鐘

          動畫效果

          開始前,我們先來看看完成后的動畫效果,示例如下效果:

          頁面布局

          無論圖片怎么隨機移動,我們都希望在指定的容器里,而不是漫無邊際,首先我們在html頁面定義容器:

          <div id="container">
          </div>
          

          接下來定義容器的樣式:

          body {
           margin: 0;
          }
          div#container {
           height:500px;
           width:100%;
           background: #C6CEF7;
          }
          #target {
           position: absolute;
           filter: drop-shadow(-12px 12px 7px rgba(0,0,0,0.5));
          }
          

          腳本部分

          獲取容器

          var container = document.getElementById("container");
          

          加載動畫

          為了更加直觀性,我選擇一個走動的gif圖片,由于圖片的加載需要一些時間,為了不破壞動畫的連貫性,確保圖片加載完了我們在執行動畫,相關代碼如下:

          var target = document.createElement("img");
          target.id = "target";
          target.onload = function() {
           floatHead();
          }
          target.src = "walk.gif";
          container.appendChild(target);
          

          大家都看到了,onload部分我們加載了floatHead()函數,接下來我們來進行相關實現,此函數主要包含以下功能:創建一個隨機位置,計算移動時間,封裝移動動畫。

          隨機位置

          我們利用Math.floor函數實現了其隨機位置的變化,示例代碼如下:

          function makeNewPosition() {
           var containerVspace = container.offsetHeight - target.offsetHeight,
           containerHspace = container.offsetWidth - target.offsetWidth,
           newX = Math.floor(Math.random() * containerVspace),
           newY = Math.floor(Math.random() * containerHspace);
           return [newX, newY];
          }
          

          這里的隨機位置,我們返回了一個數組,描述的是圖片相對容器的位置,即top,left。這里你需要理解offsetHeight,offsetWidth,可理解為div的可視高度或寬度,樣式的height或Width+上下padding或左右padding+上下border-width或左右border-width。

          計算時間

          動畫是有時間屬性的,我們進行位置的移動,需要花多久時間,假設運動速度為0.1個單位/毫秒。這個函數包含兩個數組:prev為當前目標的原始X和Y位置,next為移動目標的位置。此函數沒有進行進行精確的距離計算,只是判斷了x和y軸上移動的距離大小用最大的距離除以速度,示例代碼如下:

          function velocity(prev, next) { 
           var x = Math.abs(prev[1] - next[1]),
           y = Math.abs(prev[0] - next[0]),
           larger = x > y ? x : y,
           speedModifier = 0.1,
           time = Math.ceil(larger / speedModifier);
           return time; 
          }
          

          封裝移動動畫

          接下來是我們Web Animations API的核心部分,我們使用其核心API在加上上述我們完成的兩個函數讓其動起來,示例代碼如下:

          function floatHead() {
           var newPos = makeNewPosition(),
           oldTop = target.offsetTop,
           oldLeft = target.offsetLeft,
           target.animate([
           { top: oldTop+"px", left: oldLeft+"px" },
           { top: newPos[0]+"px", left: newPos[1]+"px" }
           ], {
           duration: velocity([oldTop, oldLeft],newPos),
           fill: "forwards"
           }).onfinish = function() {
           floatHead();
           }
          }
          

          該Animation的animate函數有兩個參數,一個是KeyframeEffects數組和AnimationEffectTimingPropertiesoptions 的對象。基本上,第一個參數映射到您將放入CSS中的內容@keyframes,你可以想象成css中的@keyframes內容,比如以下代碼:

          @keyframes emphasis {
           0% {
           transform: scale(1); 
           opacity: 1; 
           }
           30% {
           transform: scale(.5); 
           opacity: .5; 
           }
           78.75% {
           transform: scale(.667); 
           opacity: .667; 
           }
           100% {
           transform: scale(.6);
           opacity: .6; 
           }
          }
          

          你可以將“{}”里的信息順序依次放到一個數組里;第二個參數是時間控制 timing,包括有 duration 持續時間、iterations 執行次數、direction 動畫方向、easing 緩動函數等屬性。比如以下代碼:

          #toAnimate {
           animation: emphasis 700ms ease-in-out 10ms infinite alternate forwards;
          }
          

          你還可能注意到我們使用了onfinish事件完成了floatHead函數的反復調用,其是Animation的屬性,監聽動畫完成事件,如果動畫完成繼續執行floatHead(),相當不斷的遞歸調用。

          最終完成的代碼

          <!DOCTYPE html>
          <html lang="en">
          <head>
           <style>
           body {
           margin: 0;
           }
           div#container {
           height:500px;
           width:100%;
           background: #C6CEF7;
           }
           #target {
           position: absolute;
           filter: drop-shadow(-12px 12px 7px rgba(0,0,0,0.5));
           }
           </style>
           <meta charset="UTF-8">
           <title>前端達人示例展示——圖片隨機移動</title>
          </head>
          <body>
          <div id="container"></div>
          <script>
           function makeNewPosition() {
           var containerVspace = container.offsetHeight - target.offsetHeight,
           containerHspace = container.offsetWidth - target.offsetWidth,
           newX = Math.floor(Math.random() * containerVspace),
           newY = Math.floor(Math.random() * containerHspace);
           return [newX, newY];
           }
           function velocity(prev, next) {
           var x = Math.abs(prev[1] - next[1]),
           y = Math.abs(prev[0] - next[0]),
           larger = x > y ? x : y,
           speedModifier = 0.2,
           time = Math.ceil(larger / speedModifier);
           return time;
           }
           function floatHead() {
           var newPos = makeNewPosition(),
           oldTop = target.offsetTop,
           oldLeft = target.offsetLeft;
           target.animate([
           { top: oldTop+"px", left: oldLeft+"px" },
           { top: newPos[0]+"px", left: newPos[1]+"px" }
           ], {
           duration: velocity([oldTop, oldLeft],newPos),
           fill: 'forwards'
           }).onfinish = function() {
           floatHead();
           }
           }
           var container = document.getElementById("container"),
           target = document.createElement("img");
           target.id = "target";
           target.onload = function() {
           floatHead();
           }
           target.src = "walk.gif";
           target.width="200";
           container.appendChild(target);
          </script>
          </body>
          </html>
          

          兼容情況

          最后聊聊你關心的各瀏覽器兼容問題,如下所示顯示了各個瀏覽器的兼容情況:

          看來好多都是部分支持,沒有完全支持,筆者也親自測試了下,在pc端最新版的谷歌瀏覽器和Firefox是沒有任何問題的可以完美運行,筆者的safari還是運行不起來,在iPhone XS Max無法運行。

          作為一名前端開發者,在移動端大行其道怎么能容忍在手機端沒有效果,為了在現代瀏覽器廠商還沒完全跟進到位的時候搶先用上 WAAPI(Web Animation API簡稱),我們可以選擇引入針對 Web Animation API 的 Polyfill 庫 [https://github.com/web-animations/web-animations-js],從而在 IE/Firefox/Safari 等瀏覽器上體驗到 WAAPI 的精彩。

          因此我們只需要文件里引入以下js,就可以完美體驗:

          <script src="https://cdn.jsdelivr.net/web-animations/latest/web-animations.min.js"></script>
          

          移動端瀏覽器,Android 5.0 以上的 Android Browser 和 Chrome for Android 本身就已經支持 WAAPI 了,加上 Polyfill 之后,筆者的手機終于可以看到運行效果了,微信里的QQ內核瀏覽器也能完美運行,pc端的safari也可以完美運行。可以說是全平臺支持了,有了這個庫你可以放心大膽的使用了。

          小節

          好了今天的代碼擼完了,js代碼還不到50行(注:為了在手機端運行,引入了web-animations.min.js),您可以點擊"https://www.qianduandaren.com/demo/walk/"行預覽,筆者親測在iPhone XS Max運行良好,其他手機沒有,有待親們的測試,歡迎到留言區告知。下一篇文章我們用不到20行的原生js代碼純手工擼一個漂亮的時鐘,敬請期待。

          更多精彩內容,請微信關注“前端達人”公眾號

          在美化博客園的時候,遇到了一個問題:博客背景圖片只支持一張圖片,看到有道友說可以用API隨機圖片。

          于是就有了這篇文章。

          本文主要整理了一些隨機圖片API,希望對你有幫助。

          • 歲月小筑 https://img.xjh.me
          • 愛壁紙API api.isoyu.com
          • 保羅API https://api.paugram.com/help/wallpaper
          • 墨天逸 http://api.mtyqx.cn
          • 聽風過畔 https://api.osgz.com
          • 如詩API https://api.likepoems.com
          • Unsplash https://source.unsplash.com/
          • 小歪API https://api.ixiaowai.cn
          • 櫻花API http://www.dmoe.cc/
          • 櫻道 https://img.r10086.com/
          • EEEDOG https://www.eee.dog/tech/rand-pic-api.html
          • 東方Project https://img.paulzzh.tech/
          • 動漫星空 https://api.dongmanxingkong.com/suijitupian.html
          • 隨機生成圖片大全:https://www.fang1688.cn/study-code/103.html
          • 隨機美圖API:https://cdn.seovx.com/
          • 二次元:http://www.dmoe.cc/random.php
          • 二次元:https://api.mz-moe.cn/img.php

          分享是一種快樂,開心是一種態度!

          JavaScript 開發者,我們經常忘記并不是所有人都像我們一樣了解 JavaScript,這被稱為知識的詛咒:當我們精通某個內容的時候,我們就不記得自己作為新人的時候有多么困惑。我們總是對其他人的能力估計過高,因此我們覺得,自己寫的類庫需要一些 JavaScript 代碼去初始化和配置也很正常。然而,一些用戶卻在使用過程中大費周折,他們瘋狂地從文檔中復制粘貼例子并隨機組合這些代碼,直到它們生效為止。

          • JavaScript(JS)中如何檢查一個對象(Object)是否包含指定的鍵(屬性)

          你或許會想:“所有寫 HTML 和 CSS 的人都會 JavaScript,對吧?”

          你錯了。來看看我的調查結果吧,這是我所知道的唯一相關數據了。

          根據投票結果來看,每兩個寫 HTML 和 CSS 的人中,就有一個對 JavaScript 沒有好感。 這是個值得讓人深思的數據結果。

          舉個例子,以下的代碼用來初始化一個 jQuery UI 自動完成庫。

          toml<div class="ui-widget">
              <label for="tags">Tags: </label>
              <input id="tags">
          </div>
          
          toml$( function() {
              var availableTags = [
                  "ActionScript",
                  "AppleScript",
                  "Asp",
                  "BASIC",
                  "C"
              ];
              $( "#tags" ).autocomplete({
                  source: availableTags
              });
          } );
          

          你覺得這很簡單,甚至覺得即使那些根本不會 JavaScript 的人也會覺得簡單,對吧?

          錯!非程序員在文檔中看到這個例子的時候,腦子里會閃過各種問題:“我該把這段代碼放哪兒呢?”“這些花括號、冒號和方括號都是什么意思?”“我要用這些嗎?”“如果我的元素沒有 ID 怎么辦?”等等。所以即使這段極其簡短的代碼也要求人們了解對象字面量、數組、變量、字符串、如何獲取 DOM 元素的引用、事件、 DOM 樹何時構建完畢等等更多知識。這些對于程序員來說微不足道的事情,對于不會 JavaScript 、只會寫 HTML 的人來說都是一場艱難的攻堅戰。

          • JavaScript(JS)中怎么遍歷數組?一文講解 JS 遍歷數組的方法

          現在來看一下 HTML5 中的等效聲明性代碼:

          html<div class="ui-widget">
              <label for="tags">Tags: </label>
              <input id="tags" list="languages">
              <datalist id="languages">
                  <option>ActionScript</option>
                  <option>AppleScript</option>
                  <option>Asp</option>
                  <option>BASIC</option>
                  <option>C</option>
              </datalist>
              </div>
          

          這不僅讓寫 HTML 的人看得更清楚更明白,也對程序員來說更為簡單。我們看到所有的內容都同時被設置好,不必關心什么時候初始化、如何獲取元素的引用以及如何設置每個內容,無需知道哪個函數是用來初始化或者它需要什么參數。在更高級的使用情況中,還會添加一個 JavaScript API 來允許動態創建屬性和元素。這遵循了一條最基本的 API 設計原則:讓簡單的內容變得更簡單,讓復雜的內容得以簡單實現。

          • REST API 設計規范:最佳實踐和示例

          這給我們上了一堂關于 HTML API 的重要一課:HTML API 不光要給那些了解 JavaScript 但水平有限的人帶來福音,還要讓我們程序員在普通的工作中也要不惜犧牲程序的靈活性來換取更高的表述性。然而不知道為什么,我們在寫自己的類庫的時卻總忘記這些原則。

          那么什么是 HTML API 呢?根據維基百科的定義,API(也就是應用程序接口)是“用于構建應用程序軟件的一組子程序定義、協議和工具”。在 HTML API 中,定義和協議就是 HTML ,工具在 HTML 中配置。HTML API 通常由可用于現有 HTML 內容的類和屬性模式組成。通過 Web 組件,甚至可以像玩游戲一般自定義元素名稱和 Shadow DOM,HTML API 甚至能擁有完整的內部結構,并且對頁面其余部分隱藏實現細節。但是這并不是一篇關于 Web 組件的文章,Web 組件給予了 HTML API 設計者更多的能力和選擇,但是良好的(HTML)API 設計原則都是可以舉一反三的。

          HTML API 加強了設計師和工程師之間的合作,減輕工程師肩上的工作負擔,還能讓設計師創造更具還原度的原型。在類庫中引入 HTML API 不僅讓社區更具包容性,最終還能造福程序員。

          并不是每個類庫都需要 HTML API。 HTML API 在使用了 UI 元素的類庫中非常有用,比如 galleries、drag-and-drop、accordions、tabs、carousels 等等。經驗表明,如果一個非程序員不能理解該類庫的功能,它就不需要 HTML API。比如,那些簡化代碼或者幫助管理代碼的庫就不需要 HTML API。那 MVC 框架或者 DOM 助手之類的庫又怎會需要 HTML API 呢?

          目前為止,我們只討論了 HTML API 的定義、功能和用處,文章剩下的部分是關于如何設計一個好的 HTML API。

          初始化選擇器

          在 JavaScript API 中,初始化是被類庫的用戶嚴格控制的:因為他們必須手動調用函數或者創建對象,精確地控制著其運行的時間和基礎。在 HTML API 中,我們要幫用戶選擇,同時也要確保不會妨礙那些仍然使用 JavaScript 的用戶,因為他們可能希望得到完全控制。

          最常見的兼容兩種使用場景的辦法是:只有匹配到給定選擇器(通常是一個特定的類)時才會自動初始化。Awesomplete 就是采用的這種方法,只選取具有 class="awesomplete" 的 input 元素進行初始化。

          有時候,簡化自動初始化比做顯式選擇初始化更重要。當你的類庫需要運行在眾多元素之上時,避免手動給每個元素單獨添加類比顯式選擇初始化更加重要。比如,Prism 自動高亮任何包含 language-xxx 類的 <code> 元素(HTML5 的說明中建議指定代碼段的語言)及其包含languate-xxx 類的元素內部的 <code> 元素。這是因為 Prism 可能會用在一個有著成千上萬代碼段的博客系統中,回過頭去給每一個元素添加類將會是一項非常巨大的工程。

          在可以自由地使用 init 選擇器的情況下,最好的做法是允許選擇是否自動化。比如,Stretchy 默認自動調整每個 <input><select><textarea>的尺寸,但是也允許通過 data-stretchy-filter 屬性自定義指定其他元素為 init 選擇器。Prism 支持 <script> 元素的 data-manual 屬性來完全取消自動初始化。良好的實踐應該允許 HTML 和 JavaScript 都能設置這個選項,來適應 HTML 和 JavaScript 兩種類庫的用戶。

          最小化初始標記

          那么,對于 init 選擇器的每個元素,你的類庫都需要有一個封包、三個內部的按鈕和兩個相鄰的 div 該怎么辦呢?小問題,自己生成就好了。但是這種瑣碎的工作更適合機器,而不是人。不要期望每個使用類庫的人都同時使用了模板系統:許多人還在使用手動添加標記,他們會發現這樣建造系統太過復雜。因此,我們應該讓他們更輕松些。

          這種做法也最小化了錯誤風險:如果一個用戶僅僅引入了用來初始化的類卻沒有引入所有需要的標記怎么辦?如果不需要添加額外的標記,就不會產生錯誤。

          這條規則中有一個例外:優雅地退化并漸進地增強。比如,即使單個具有 data- * 屬性的元素并在 data-* 中添加所有選項就可以實現,在嵌入推文的時候也還是會涉及很多標記。這樣做是為了在 JavaScript 加載和運行之前推文就可讀。一個良好的經驗法則就是捫心自問“即使在沒有 JavaScript ,多余的標記能否給終端用戶帶來好處?”如果是,那么就引入;如果不是,那就要用類庫生成。

          便于用戶使用還是讓用戶自定義也是一組經典的矛盾:自動生成所有的標記會易于用戶使用,讓用戶自定義又顯得更加靈活。在你需要的時候,靈活性如雪中送炭,在不需要的時候卻適得其反,因為你不得不手動設置所有的參數。為了平衡這兩種需要,你可以生成那些需要但不存在的標記。比如,假設你需要給所有的 .foo 元素外層添加一個 .foo-container 元素。首先,通過element.closest(".foo-container") 檢查 .foo 元素的父元素或者任何的祖先元素(這樣最好了)是否含有 foo-container 類,如果有的話,你就不用生成新的元素,直接使用就可以了。

          設置

          通常,設置應該通過在恰當的元素上使用 data-* 屬性來實現。如果你的類庫中添加了成千上萬的屬性,然后你希望給它們添加命名空間來避免和其他類庫混淆,比如這樣 data-foo-*(foo 是基于類庫名字的一到三個字母長度的前綴)。如果名字顯得太長,你可以使用 foo-*,但你要知道,這種方式會打破 HTML 驗證并且會使得一些勤奮的 HTML 作者因此而棄用你的類庫。理想情況下,只要代碼不會太臃腫,以上兩種情況都應該支持。目前還沒有完美的解決辦法,因此在 WHATWG 中展開了一場如火如荼的討論:是否應該讓自定義的屬性前綴合法化。

          盡可能地遵從 HTML 的慣例。比如,你使用了一個屬性來做布爾類型的設置,當該屬性出現時無論其值如何都被視為 true,若不出現則被視為 false,不要期望可以用 data-foo="true" 或者 data-foo="false" 來代替。

          你也可以使用類進行布爾值設置。一般情況下它的語法和布爾屬性類似:類存在的時候是 true 不出現的時候就是 false。如果你想反過來設置,那就用一個 no- 前綴(比如,no-line-number)。但是要記住,類名可不像屬性一樣只有 data-*,因此這種方式很可能會和用戶現存的類名沖突,因此你可以考慮一下在類名中使用 foo- 這樣的前綴來避免沖突。但也有可能在后期的維護中發現這些類并未被 CSS 使用所以誤刪,這又是另一個隱患。

          當你需要設置一組相關的布爾值時,使用空格區分會比使用多個分隔符的方式好很多。

          html<!-- 第一種-->
          <div data-permissions="read add edit delete save logout"> 
          
          html<!-- 第二種-->
          <div data-read data-add data-edit data-delete data-save data-logout">
          
          html <!-- 第三種-->
           <div class="read add edit delete save logout">
          

          比如,第一種當時就比后面兩種好得多,因為后者可能會造成很多的沖突。你還可以使用 ~= 屬性選擇器來定位單個元素,比如 element.matches("[data-permissions~=read]") 可以檢查該元素是否有 read 權限。

          如果設置內容的類型是數組(array)或者對象(object) ,那么你就可以使用 data-* 屬性來關聯到另一個元素。比如, HTML5 中的自動完成:因為自動完成需要一個建議列表,你可以使用 data-* 屬性并通過 ID 聯系到包含建議內容的 <datalist> 元素。

          HTML 有一個慣例很讓人頭痛:在 HTML 中,用屬性聯系到另一個元素通常是靠引用其 ID 實現的(試想一下 <label for="...">)。然而,這種方法相當受限制:如果能夠允許使用選擇器或者甚至允許嵌套將更為方便,其效果將會極大地依賴于你的使用情況。要記住,穩定性重要,但實用性更加重要。

          即使有些設置內容不能在 HTML 中指定也沒關系。在 JavaScript 中以函數為設置值的部分被稱作“高級自定義”。試想一下 Awesomplete:所有數字、布爾值、字符串和對象都可以通過 data-* 屬性(listminCharsmaxItemsautoFirst)設置,所有的函數設置只能通過 JavaScript 使用(filtersortitemreplacedata),這樣會寫 JavaScript 函數來配置類庫的人就可以使用 JavaScript API 了。

          正則表達式(regex)處在灰色地帶:通常只有程序員才知道正則表達式(甚至程序員在使用的時候也會有問題!);那么,乍看之下,在 HTML API 中引入正則表達式類型的設置并沒有意義。然而,HTML5 確實引入了這樣的設置(<input pattern="regex">),并且我覺得很成功,因為非程序員能在正則詞典中找到他們的用例并復制粘貼。

          繼承

          如果你的 UI 庫在每個頁面只會調用一兩次,繼承可能不是很重要。然而,如果要應用于多個元素,通過類或者屬性給每個元素做相同的配置將會非常令人頭疼。咱要記住并不是每個人都用了構建系統,尤其是非程序員。在這些情況下,定義能夠從祖先元素繼承設置將會變得非常有用,那樣多個實例就可以被批量設置了。

          還拿 Smashing Magazine 中使用的時下流行的語法高亮類庫 —— Prism 來舉例。高亮語句是通過 language-xxx 形式的類來配置的。如你所見,這違反了我們在前文中談過的規則,但這只是一種主觀決策,因為 HTML5 手冊中建議如此。在有許多代碼段的頁面上(想象一下,在博客文章中使用內聯 <code> 元素的頻率!),在每個 <code> 元素中指定代碼語句將會非常煩人。為了減輕這種痛苦,Prism 支持繼承這些類:如果一個 <code> 元素自己沒有 language-xxx 類,那么將會使用其最近的祖先元素的 language-xxx 類。這使得用戶可以設置全局的代碼語句(通過在 <body> 或者 <html> 元素上設置類)或者設置區塊的代碼語句,并且可以在擁有不同語句的元素或者區塊上重寫設置。

          現在 CSS 變量已經被所有的瀏覽器支持,它們可以用于以下設置:他們默認可以被繼承,并且可以以內聯的方式通過 style 屬性設置,也可以通過 CSS 或者 JavaScript 設置。在代碼中,你可以通過getComputedStyle(element).getPropertyValue("--variablename") 獲取它們。除了瀏覽器支持,其主要的劣勢就是開發者們還沒習慣使用它們,但是那已經發生改變了。并且,你不能像監視元素和屬性的一般通過 MutationObserver 來監視其改變。

          全局設置

          大多數 UI 類庫都有兩組設置:定義每個組件表現形式的設置和定義整個類庫表現形式的全局設置。目前為止,我們主要討論了前者,你現在可能好奇全局設置該在設置在哪里。

          進行全局設置的一個好地方就引入類庫的 <script> 元素。你可以通過 document.currentScript 獲取該元素,這有著非常好的瀏覽器支持。好處就是,這對于設置的作用域非常清楚,因此它們的名字可以起的更短(比如 data-filter 而不是 data-stretchy-filter)。

          然而,你不能只在 <script> 元素中進行設置,因為一些用戶可能會在 CMS 中使用你的類庫,而 CMS 中不允許用戶自定義 <script> 元素。你也可以在 <html><body> 元素或者甚至任何地方設置,只要你清楚地聲明了屬性值重復的時候哪個會生效。

          文檔

          那么,你已經掌握了如何在類庫中設置一個漂亮的聲明性的 API,那自然很好,然而,如果你所有的文檔都寫得只有會 JavaScript 的用戶才看得懂,那么就只有很少人能使用了。我記得曾經看過一個很酷的類庫,基于 URL 并通過切換元素的 HTML 屬性來切換元素的表現形式。然而,這漂亮的 HTML API 并不能被其目標人群所使用,因為整篇文檔中都充滿了 JavaScript 引用。最開始的例子開頭就是“這和 location.href.match(/foo/)等價”。非程序員哪能看懂這個呀?

          同時要記得許多人并不會任何編程語言而不僅僅是 JavaScript。你希望用戶能夠讀懂并理解的文中的模型、視圖、控制器或者其他軟件工程觀念,但結果無非是讓他們感到迷惑。

          當然,你應該在文檔中寫 API 里 JavaScript 的內容,你可以寫在“高級使用”部分。然而,如果你在文檔一開頭就引用 JavaScript 對象和函數或者軟件工程的觀念,那么你實質上就是在告訴非程序員這個類庫不是給他們用的,因此你就排除了一大批潛在用戶。不幸的是,大部分的 HTML API 類庫文檔都受這些問題困擾著,因為 HTML API 經常被視為是程序員的捷徑,而并不是給非程序員使用的。慶幸的是,這種狀況在未來可以有改變。

          Web 組件

          在不遠的未來,Web 組件百分之百將會徹底改變 HTML API。<template> 元素將會允許作者提供惰性加載的腳本。自定義元素將使得用戶可以像原生的 HTML 一樣使用更多優雅的 init 標記。引入 HTML 也將使得作者能夠僅引入一個文件來替代三個樣式表、五個腳本和十個模板(如果瀏覽器能夠同時獲取并且不再認為 ES6 模塊是一種競爭技術)。Shadow DOM 使得類庫可以將復雜的 DOM 結構適當壓縮并且不會影響用戶自己的標記。

          然而除了 <template>,瀏覽器對其他三個特征的支持目前受限。因此他們需要更高的聚合度,以此來減少對類庫的影響。這將會是我們在未來一段時間里需要不斷關注的東西。

          • 源于:https://www.smashingmagazine.com/2017/02/designing-html-apis/

          主站蜘蛛池模板: 日韩av片无码一区二区不卡电影| 亚洲大尺度无码无码专线一区| 久久中文字幕无码一区二区| 国产在线精品一区二区三区不卡 | 成人精品视频一区二区三区尤物| 九九久久99综合一区二区| 国产午夜福利精品一区二区三区 | 国产乱码精品一区二区三区四川人| 性色A码一区二区三区天美传媒| 国产精品视频一区二区三区无码| 中文字幕精品无码一区二区三区 | 伊人久久一区二区三区无码| 国产精品综合AV一区二区国产馆| 亚洲欧美国产国产综合一区| 精品成人一区二区三区免费视频| 四虎在线观看一区二区| 亚洲一区二区高清| 久久久久人妻精品一区蜜桃| 国产精品日韩欧美一区二区三区 | 中文字幕在线观看一区二区| 国产一区二区三区乱码网站| 午夜视频久久久久一区| 无码人妻精品一区二区在线视频 | 国模无码一区二区三区不卡| 免费无码VA一区二区三区| 波霸影院一区二区| 天堂一区二区三区精品| 日本一区二区在线| 八戒久久精品一区二区三区 | 一级特黄性色生活片一区二区 | 日本一区二区免费看| 国产精品一区二区三区久久 | 中文无码AV一区二区三区| 国产在线精品一区在线观看| 欧洲精品码一区二区三区| 国产伦精品一区二区三区在线观看| 暖暖免费高清日本一区二区三区 | 狠狠综合久久AV一区二区三区 | 国产精品va无码一区二区| 精品国产一区二区三区久久蜜臀 | 亚洲一区二区精品视频|