Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 久久久久久国产a免费观看黄色大片 ,久操国产视频,久久久久免费精品国产

          整合營(yíng)銷(xiāo)服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢(xún)熱線(xiàn):

          用原生Javascript制作一個(gè)隨機(jī)移動(dòng)的圖片動(dòng)畫(huà)

          eb Animation API 介紹

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

          Web Animation API 的歷史也應(yīng)該有幾年了,但是每當(dāng)做動(dòng)畫(huà)效果時(shí),筆者就是依賴(lài)各種庫(kù),很少想著去原生實(shí)現(xiàn),最終造成了我們的項(xiàng)目各種依賴(lài)庫(kù),體積也不斷變大,性能如何也不得而知,作為前端開(kāi)發(fā)的我們多么希望原生的JS去支持通用的動(dòng)畫(huà)解決方案, Web Animation API 可能就是一個(gè)不錯(cuò)的解決方案。

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

          使用Web Animations API,我們可以將交互式動(dòng)畫(huà)從樣式表移動(dòng)到JavaScript,將表示與行為分開(kāi)。我們不再需要依賴(lài)DOM的技術(shù),例如編寫(xiě)CSS屬性作用于元素以控制方向。為了構(gòu)建自定義動(dòng)畫(huà)庫(kù)和創(chuàng)建交互式動(dòng)畫(huà),Web Animations API可能是完成工作的完美工具,你無(wú)需借助第三方動(dòng)畫(huà)庫(kù),就可以輕松實(shí)現(xiàn)一個(gè)效果不錯(cuò)的動(dòng)畫(huà)。

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

          本篇文章預(yù)計(jì)時(shí)間 5 分鐘

          動(dòng)畫(huà)效果

          開(kāi)始前,我們先來(lái)看看完成后的動(dòng)畫(huà)效果,示例如下效果:

          頁(yè)面布局

          無(wú)論圖片怎么隨機(jī)移動(dòng),我們都希望在指定的容器里,而不是漫無(wú)邊際,首先我們?cè)趆tml頁(yè)面定義容器:

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

          接下來(lái)定義容器的樣式:

          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");
          

          加載動(dòng)畫(huà)

          為了更加直觀性,我選擇一個(gè)走動(dòng)的gif圖片,由于圖片的加載需要一些時(shí)間,為了不破壞動(dòng)畫(huà)的連貫性,確保圖片加載完了我們?cè)趫?zhí)行動(dòng)畫(huà),相關(guān)代碼如下:

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

          大家都看到了,onload部分我們加載了floatHead()函數(shù),接下來(lái)我們來(lái)進(jìn)行相關(guān)實(shí)現(xiàn),此函數(shù)主要包含以下功能:創(chuàng)建一個(gè)隨機(jī)位置,計(jì)算移動(dòng)時(shí)間,封裝移動(dòng)動(dòng)畫(huà)。

          隨機(jī)位置

          我們利用Math.floor函數(shù)實(shí)現(xiàn)了其隨機(jī)位置的變化,示例代碼如下:

          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];
          }
          

          這里的隨機(jī)位置,我們返回了一個(gè)數(shù)組,描述的是圖片相對(duì)容器的位置,即top,left。這里你需要理解offsetHeight,offsetWidth,可理解為div的可視高度或?qū)挾龋瑯邮降膆eight或Width+上下padding或左右padding+上下border-width或左右border-width。

          計(jì)算時(shí)間

          動(dòng)畫(huà)是有時(shí)間屬性的,我們進(jìn)行位置的移動(dòng),需要花多久時(shí)間,假設(shè)運(yùn)動(dòng)速度為0.1個(gè)單位/毫秒。這個(gè)函數(shù)包含兩個(gè)數(shù)組:prev為當(dāng)前目標(biāo)的原始X和Y位置,next為移動(dòng)目標(biāo)的位置。此函數(shù)沒(méi)有進(jìn)行進(jìn)行精確的距離計(jì)算,只是判斷了x和y軸上移動(dòng)的距離大小用最大的距離除以速度,示例代碼如下:

          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; 
          }
          

          封裝移動(dòng)動(dòng)畫(huà)

          接下來(lái)是我們Web Animations API的核心部分,我們使用其核心API在加上上述我們完成的兩個(gè)函數(shù)讓其動(dòng)起來(lái),示例代碼如下:

          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函數(shù)有兩個(gè)參數(shù),一個(gè)是KeyframeEffects數(shù)組和AnimationEffectTimingPropertiesoptions 的對(duì)象。基本上,第一個(gè)參數(shù)映射到您將放入CSS中的內(nèi)容@keyframes,你可以想象成css中的@keyframes內(nèi)容,比如以下代碼:

          @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; 
           }
          }
          

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

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

          你還可能注意到我們使用了onfinish事件完成了floatHead函數(shù)的反復(fù)調(diào)用,其是Animation的屬性,監(jiān)聽(tīng)動(dòng)畫(huà)完成事件,如果動(dòng)畫(huà)完成繼續(xù)執(zhí)行floatHead(),相當(dāng)不斷的遞歸調(diào)用。

          最終完成的代碼

          <!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>前端達(dá)人示例展示——圖片隨機(jī)移動(dòng)</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>
          

          兼容情況

          最后聊聊你關(guān)心的各瀏覽器兼容問(wèn)題,如下所示顯示了各個(gè)瀏覽器的兼容情況:

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

          作為一名前端開(kāi)發(fā)者,在移動(dòng)端大行其道怎么能容忍在手機(jī)端沒(méi)有效果,為了在現(xiàn)代瀏覽器廠商還沒(méi)完全跟進(jìn)到位的時(shí)候搶先用上 WAAPI(Web Animation API簡(jiǎn)稱(chēng)),我們可以選擇引入針對(duì) Web Animation API 的 Polyfill 庫(kù) [https://github.com/web-animations/web-animations-js],從而在 IE/Firefox/Safari 等瀏覽器上體驗(yàn)到 WAAPI 的精彩。

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

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

          移動(dòng)端瀏覽器,Android 5.0 以上的 Android Browser 和 Chrome for Android 本身就已經(jīng)支持 WAAPI 了,加上 Polyfill 之后,筆者的手機(jī)終于可以看到運(yùn)行效果了,微信里的QQ內(nèi)核瀏覽器也能完美運(yùn)行,pc端的safari也可以完美運(yùn)行。可以說(shuō)是全平臺(tái)支持了,有了這個(gè)庫(kù)你可以放心大膽的使用了。

          小節(jié)

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

          更多精彩內(nèi)容,請(qǐng)微信關(guān)注“前端達(dá)人”公眾號(hào)

          在美化博客園的時(shí)候,遇到了一個(gè)問(wèn)題:博客背景圖片只支持一張圖片,看到有道友說(shuō)可以用API隨機(jī)圖片。

          于是就有了這篇文章。

          本文主要整理了一些隨機(jī)圖片API,希望對(duì)你有幫助。

          • 歲月小筑 https://img.xjh.me
          • 愛(ài)壁紙API api.isoyu.com
          • 保羅API https://api.paugram.com/help/wallpaper
          • 墨天逸 http://api.mtyqx.cn
          • 聽(tīng)風(fēng)過(guò)畔 https://api.osgz.com
          • 如詩(shī)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/
          • 動(dòng)漫星空 https://api.dongmanxingkong.com/suijitupian.html
          • 隨機(jī)生成圖片大全:https://www.fang1688.cn/study-code/103.html
          • 隨機(jī)美圖API:https://cdn.seovx.com/
          • 二次元:http://www.dmoe.cc/random.php
          • 二次元:https://api.mz-moe.cn/img.php

          分享是一種快樂(lè),開(kāi)心是一種態(tài)度!

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

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

          你或許會(huì)想:“所有寫(xiě) HTML 和 CSS 的人都會(huì) JavaScript,對(duì)吧?”

          你錯(cuò)了。來(lái)看看我的調(diào)查結(jié)果吧,這是我所知道的唯一相關(guān)數(shù)據(jù)了。

          根據(jù)投票結(jié)果來(lái)看,每?jī)蓚€(gè)寫(xiě) HTML 和 CSS 的人中,就有一個(gè)對(duì) JavaScript 沒(méi)有好感。 這是個(gè)值得讓人深思的數(shù)據(jù)結(jié)果。

          舉個(gè)例子,以下的代碼用來(lái)初始化一個(gè) jQuery UI 自動(dòng)完成庫(kù)。

          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
              });
          } );
          

          你覺(jué)得這很簡(jiǎn)單,甚至覺(jué)得即使那些根本不會(huì) JavaScript 的人也會(huì)覺(jué)得簡(jiǎn)單,對(duì)吧?

          錯(cuò)!非程序員在文檔中看到這個(gè)例子的時(shí)候,腦子里會(huì)閃過(guò)各種問(wèn)題:“我該把這段代碼放哪兒呢?”“這些花括號(hào)、冒號(hào)和方括號(hào)都是什么意思?”“我要用這些嗎?”“如果我的元素沒(méi)有 ID 怎么辦?”等等。所以即使這段極其簡(jiǎn)短的代碼也要求人們了解對(duì)象字面量、數(shù)組、變量、字符串、如何獲取 DOM 元素的引用、事件、 DOM 樹(shù)何時(shí)構(gòu)建完畢等等更多知識(shí)。這些對(duì)于程序員來(lái)說(shuō)微不足道的事情,對(duì)于不會(huì) JavaScript 、只會(huì)寫(xiě) HTML 的人來(lái)說(shuō)都是一場(chǎng)艱難的攻堅(jiān)戰(zhàn)。

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

          現(xiàn)在來(lái)看一下 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>
          

          這不僅讓寫(xiě) HTML 的人看得更清楚更明白,也對(duì)程序員來(lái)說(shuō)更為簡(jiǎn)單。我們看到所有的內(nèi)容都同時(shí)被設(shè)置好,不必關(guān)心什么時(shí)候初始化、如何獲取元素的引用以及如何設(shè)置每個(gè)內(nèi)容,無(wú)需知道哪個(gè)函數(shù)是用來(lái)初始化或者它需要什么參數(shù)。在更高級(jí)的使用情況中,還會(huì)添加一個(gè) JavaScript API 來(lái)允許動(dòng)態(tài)創(chuàng)建屬性和元素。這遵循了一條最基本的 API 設(shè)計(jì)原則:讓簡(jiǎn)單的內(nèi)容變得更簡(jiǎn)單,讓復(fù)雜的內(nèi)容得以簡(jiǎn)單實(shí)現(xiàn)。

          • REST API 設(shè)計(jì)規(guī)范:最佳實(shí)踐和示例

          這給我們上了一堂關(guān)于 HTML API 的重要一課:HTML API 不光要給那些了解 JavaScript 但水平有限的人帶來(lái)福音,還要讓我們程序員在普通的工作中也要不惜犧牲程序的靈活性來(lái)?yè)Q取更高的表述性。然而不知道為什么,我們?cè)趯?xiě)自己的類(lèi)庫(kù)的時(shí)卻總忘記這些原則。

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

          HTML API 加強(qiáng)了設(shè)計(jì)師和工程師之間的合作,減輕工程師肩上的工作負(fù)擔(dān),還能讓設(shè)計(jì)師創(chuàng)造更具還原度的原型。在類(lèi)庫(kù)中引入 HTML API 不僅讓社區(qū)更具包容性,最終還能造福程序員。

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

          目前為止,我們只討論了 HTML API 的定義、功能和用處,文章剩下的部分是關(guān)于如何設(shè)計(jì)一個(gè)好的 HTML API。

          初始化選擇器

          在 JavaScript API 中,初始化是被類(lèi)庫(kù)的用戶(hù)嚴(yán)格控制的:因?yàn)樗麄儽仨毷謩?dòng)調(diào)用函數(shù)或者創(chuàng)建對(duì)象,精確地控制著其運(yùn)行的時(shí)間和基礎(chǔ)。在 HTML API 中,我們要幫用戶(hù)選擇,同時(shí)也要確保不會(huì)妨礙那些仍然使用 JavaScript 的用戶(hù),因?yàn)樗麄兛赡芟M玫酵耆刂啤?/span>

          最常見(jiàn)的兼容兩種使用場(chǎng)景的辦法是:只有匹配到給定選擇器(通常是一個(gè)特定的類(lèi))時(shí)才會(huì)自動(dòng)初始化。Awesomplete 就是采用的這種方法,只選取具有 class="awesomplete" 的 input 元素進(jìn)行初始化。

          有時(shí)候,簡(jiǎn)化自動(dòng)初始化比做顯式選擇初始化更重要。當(dāng)你的類(lèi)庫(kù)需要運(yùn)行在眾多元素之上時(shí),避免手動(dòng)給每個(gè)元素單獨(dú)添加類(lèi)比顯式選擇初始化更加重要。比如,Prism 自動(dòng)高亮任何包含 language-xxx 類(lèi)的 <code> 元素(HTML5 的說(shuō)明中建議指定代碼段的語(yǔ)言)及其包含languate-xxx 類(lèi)的元素內(nèi)部的 <code> 元素。這是因?yàn)?Prism 可能會(huì)用在一個(gè)有著成千上萬(wàn)代碼段的博客系統(tǒng)中,回過(guò)頭去給每一個(gè)元素添加類(lèi)將會(huì)是一項(xiàng)非常巨大的工程。

          在可以自由地使用 init 選擇器的情況下,最好的做法是允許選擇是否自動(dòng)化。比如,Stretchy 默認(rèn)自動(dòng)調(diào)整每個(gè) <input><select><textarea>的尺寸,但是也允許通過(guò) data-stretchy-filter 屬性自定義指定其他元素為 init 選擇器。Prism 支持 <script> 元素的 data-manual 屬性來(lái)完全取消自動(dòng)初始化。良好的實(shí)踐應(yīng)該允許 HTML 和 JavaScript 都能設(shè)置這個(gè)選項(xiàng),來(lái)適應(yīng) HTML 和 JavaScript 兩種類(lèi)庫(kù)的用戶(hù)。

          最小化初始標(biāo)記

          那么,對(duì)于 init 選擇器的每個(gè)元素,你的類(lèi)庫(kù)都需要有一個(gè)封包、三個(gè)內(nèi)部的按鈕和兩個(gè)相鄰的 div 該怎么辦呢?小問(wèn)題,自己生成就好了。但是這種瑣碎的工作更適合機(jī)器,而不是人。不要期望每個(gè)使用類(lèi)庫(kù)的人都同時(shí)使用了模板系統(tǒng):許多人還在使用手動(dòng)添加標(biāo)記,他們會(huì)發(fā)現(xiàn)這樣建造系統(tǒng)太過(guò)復(fù)雜。因此,我們應(yīng)該讓他們更輕松些。

          這種做法也最小化了錯(cuò)誤風(fēng)險(xiǎn):如果一個(gè)用戶(hù)僅僅引入了用來(lái)初始化的類(lèi)卻沒(méi)有引入所有需要的標(biāo)記怎么辦?如果不需要添加額外的標(biāo)記,就不會(huì)產(chǎn)生錯(cuò)誤。

          這條規(guī)則中有一個(gè)例外:優(yōu)雅地退化并漸進(jìn)地增強(qiáng)。比如,即使單個(gè)具有 data- * 屬性的元素并在 data-* 中添加所有選項(xiàng)就可以實(shí)現(xiàn),在嵌入推文的時(shí)候也還是會(huì)涉及很多標(biāo)記。這樣做是為了在 JavaScript 加載和運(yùn)行之前推文就可讀。一個(gè)良好的經(jīng)驗(yàn)法則就是捫心自問(wèn)“即使在沒(méi)有 JavaScript ,多余的標(biāo)記能否給終端用戶(hù)帶來(lái)好處?”如果是,那么就引入;如果不是,那就要用類(lèi)庫(kù)生成。

          便于用戶(hù)使用還是讓用戶(hù)自定義也是一組經(jīng)典的矛盾:自動(dòng)生成所有的標(biāo)記會(huì)易于用戶(hù)使用,讓用戶(hù)自定義又顯得更加靈活。在你需要的時(shí)候,靈活性如雪中送炭,在不需要的時(shí)候卻適得其反,因?yàn)槟悴坏貌皇謩?dòng)設(shè)置所有的參數(shù)。為了平衡這兩種需要,你可以生成那些需要但不存在的標(biāo)記。比如,假設(shè)你需要給所有的 .foo 元素外層添加一個(gè) .foo-container 元素。首先,通過(guò)element.closest(".foo-container") 檢查 .foo 元素的父元素或者任何的祖先元素(這樣最好了)是否含有 foo-container 類(lèi),如果有的話(huà),你就不用生成新的元素,直接使用就可以了。

          設(shè)置

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

          盡可能地遵從 HTML 的慣例。比如,你使用了一個(gè)屬性來(lái)做布爾類(lèi)型的設(shè)置,當(dāng)該屬性出現(xiàn)時(shí)無(wú)論其值如何都被視為 true,若不出現(xiàn)則被視為 false,不要期望可以用 data-foo="true" 或者 data-foo="false" 來(lái)代替。

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

          當(dāng)你需要設(shè)置一組相關(guān)的布爾值時(shí),使用空格區(qū)分會(huì)比使用多個(gè)分隔符的方式好很多。

          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">
          

          比如,第一種當(dāng)時(shí)就比后面兩種好得多,因?yàn)楹笳呖赡軙?huì)造成很多的沖突。你還可以使用 ~= 屬性選擇器來(lái)定位單個(gè)元素,比如 element.matches("[data-permissions~=read]") 可以檢查該元素是否有 read 權(quán)限。

          如果設(shè)置內(nèi)容的類(lèi)型是數(shù)組(array)或者對(duì)象(object) ,那么你就可以使用 data-* 屬性來(lái)關(guān)聯(lián)到另一個(gè)元素。比如, HTML5 中的自動(dòng)完成:因?yàn)樽詣?dòng)完成需要一個(gè)建議列表,你可以使用 data-* 屬性并通過(guò) ID 聯(lián)系到包含建議內(nèi)容的 <datalist> 元素。

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

          即使有些設(shè)置內(nèi)容不能在 HTML 中指定也沒(méi)關(guān)系。在 JavaScript 中以函數(shù)為設(shè)置值的部分被稱(chēng)作“高級(jí)自定義”。試想一下 Awesomplete:所有數(shù)字、布爾值、字符串和對(duì)象都可以通過(guò) data-* 屬性(listminCharsmaxItemsautoFirst)設(shè)置,所有的函數(shù)設(shè)置只能通過(guò) JavaScript 使用(filtersortitemreplacedata),這樣會(huì)寫(xiě) JavaScript 函數(shù)來(lái)配置類(lèi)庫(kù)的人就可以使用 JavaScript API 了。

          正則表達(dá)式(regex)處在灰色地帶:通常只有程序員才知道正則表達(dá)式(甚至程序員在使用的時(shí)候也會(huì)有問(wèn)題!);那么,乍看之下,在 HTML API 中引入正則表達(dá)式類(lèi)型的設(shè)置并沒(méi)有意義。然而,HTML5 確實(shí)引入了這樣的設(shè)置(<input pattern="regex">),并且我覺(jué)得很成功,因?yàn)榉浅绦騿T能在正則詞典中找到他們的用例并復(fù)制粘貼。

          繼承

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

          還拿 Smashing Magazine 中使用的時(shí)下流行的語(yǔ)法高亮類(lèi)庫(kù) —— Prism 來(lái)舉例。高亮語(yǔ)句是通過(guò) language-xxx 形式的類(lèi)來(lái)配置的。如你所見(jiàn),這違反了我們?cè)谇拔闹姓勥^(guò)的規(guī)則,但這只是一種主觀決策,因?yàn)?HTML5 手冊(cè)中建議如此。在有許多代碼段的頁(yè)面上(想象一下,在博客文章中使用內(nèi)聯(lián) <code> 元素的頻率!),在每個(gè) <code> 元素中指定代碼語(yǔ)句將會(huì)非常煩人。為了減輕這種痛苦,Prism 支持繼承這些類(lèi):如果一個(gè) <code> 元素自己沒(méi)有 language-xxx 類(lèi),那么將會(huì)使用其最近的祖先元素的 language-xxx 類(lèi)。這使得用戶(hù)可以設(shè)置全局的代碼語(yǔ)句(通過(guò)在 <body> 或者 <html> 元素上設(shè)置類(lèi))或者設(shè)置區(qū)塊的代碼語(yǔ)句,并且可以在擁有不同語(yǔ)句的元素或者區(qū)塊上重寫(xiě)設(shè)置。

          現(xiàn)在 CSS 變量已經(jīng)被所有的瀏覽器支持,它們可以用于以下設(shè)置:他們默認(rèn)可以被繼承,并且可以以?xún)?nèi)聯(lián)的方式通過(guò) style 屬性設(shè)置,也可以通過(guò) CSS 或者 JavaScript 設(shè)置。在代碼中,你可以通過(guò)getComputedStyle(element).getPropertyValue("--variablename") 獲取它們。除了瀏覽器支持,其主要的劣勢(shì)就是開(kāi)發(fā)者們還沒(méi)習(xí)慣使用它們,但是那已經(jīng)發(fā)生改變了。并且,你不能像監(jiān)視元素和屬性的一般通過(guò) MutationObserver 來(lái)監(jiān)視其改變。

          全局設(shè)置

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

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

          然而,你不能只在 <script> 元素中進(jìn)行設(shè)置,因?yàn)橐恍┯脩?hù)可能會(huì)在 CMS 中使用你的類(lèi)庫(kù),而 CMS 中不允許用戶(hù)自定義 <script> 元素。你也可以在 <html><body> 元素或者甚至任何地方設(shè)置,只要你清楚地聲明了屬性值重復(fù)的時(shí)候哪個(gè)會(huì)生效。

          文檔

          那么,你已經(jīng)掌握了如何在類(lèi)庫(kù)中設(shè)置一個(gè)漂亮的聲明性的 API,那自然很好,然而,如果你所有的文檔都寫(xiě)得只有會(huì) JavaScript 的用戶(hù)才看得懂,那么就只有很少人能使用了。我記得曾經(jīng)看過(guò)一個(gè)很酷的類(lèi)庫(kù),基于 URL 并通過(guò)切換元素的 HTML 屬性來(lái)切換元素的表現(xiàn)形式。然而,這漂亮的 HTML API 并不能被其目標(biāo)人群所使用,因?yàn)檎臋n中都充滿(mǎn)了 JavaScript 引用。最開(kāi)始的例子開(kāi)頭就是“這和 location.href.match(/foo/)等價(jià)”。非程序員哪能看懂這個(gè)呀?

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

          當(dāng)然,你應(yīng)該在文檔中寫(xiě) API 里 JavaScript 的內(nèi)容,你可以寫(xiě)在“高級(jí)使用”部分。然而,如果你在文檔一開(kāi)頭就引用 JavaScript 對(duì)象和函數(shù)或者軟件工程的觀念,那么你實(shí)質(zhì)上就是在告訴非程序員這個(gè)類(lèi)庫(kù)不是給他們用的,因此你就排除了一大批潛在用戶(hù)。不幸的是,大部分的 HTML API 類(lèi)庫(kù)文檔都受這些問(wèn)題困擾著,因?yàn)?HTML API 經(jīng)常被視為是程序員的捷徑,而并不是給非程序員使用的。慶幸的是,這種狀況在未來(lái)可以有改變。

          Web 組件

          在不遠(yuǎn)的未來(lái),Web 組件百分之百將會(huì)徹底改變 HTML API。<template> 元素將會(huì)允許作者提供惰性加載的腳本。自定義元素將使得用戶(hù)可以像原生的 HTML 一樣使用更多優(yōu)雅的 init 標(biāo)記。引入 HTML 也將使得作者能夠僅引入一個(gè)文件來(lái)替代三個(gè)樣式表、五個(gè)腳本和十個(gè)模板(如果瀏覽器能夠同時(shí)獲取并且不再認(rèn)為 ES6 模塊是一種競(jìng)爭(zhēng)技術(shù))。Shadow DOM 使得類(lèi)庫(kù)可以將復(fù)雜的 DOM 結(jié)構(gòu)適當(dāng)壓縮并且不會(huì)影響用戶(hù)自己的標(biāo)記。

          然而除了 <template>,瀏覽器對(duì)其他三個(gè)特征的支持目前受限。因此他們需要更高的聚合度,以此來(lái)減少對(duì)類(lèi)庫(kù)的影響。這將會(huì)是我們?cè)谖磥?lái)一段時(shí)間里需要不斷關(guān)注的東西。

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

          主站蜘蛛池模板: 国产亚洲福利精品一区二区| 中文字幕一区二区视频| 丝袜美腿一区二区三区| 一区二区三区电影网| 亚洲一区精品视频在线| 国产美女av在线一区| 日韩高清一区二区| 亚洲国产情侣一区二区三区| 国产精品男男视频一区二区三区 | 国产在线精品一区二区三区不卡 | 精品国产一区二区三区久久 | 中文字幕一区二区人妻| 日本中文字幕在线视频一区 | www亚洲精品少妇裸乳一区二区 | 国产在线精品一区二区 | 国产成人一区二区三区免费视频| 久久久久99人妻一区二区三区| 日本一区二区三区免费高清在线 | 午夜影视日本亚洲欧洲精品一区| 亚洲一区视频在线播放| 波多野结衣一区在线观看| 国产午夜一区二区在线观看| 一区二区三区免费在线观看| 久久精品国产一区二区三区| 少妇激情AV一区二区三区| 日韩免费无码一区二区视频| 亚洲视频在线一区二区| 精品欧洲av无码一区二区三区| 精品人妻一区二区三区四区在线| 亚洲AV日韩AV天堂一区二区三区| 国产成人午夜精品一区二区三区| 色婷婷AV一区二区三区浪潮| 伊人无码精品久久一区二区| 日韩精品无码一区二区视频| 国精产品一区一区三区MBA下载| 国产一区二区在线观看app| 一区二区3区免费视频| 日韩人妻精品无码一区二区三区| 国产一区二区三区免费视频| 亚洲一区免费观看| 国产福利电影一区二区三区,亚洲国模精品一区 |