整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

用原生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/