谈一谈CSS选择器择优及BEM

很久没瞎扯了,看着今天下雨也没地方去,闲下来撸一篇吧。

关于CSS,其实只要不用奇葩表达式、书写不会太离谱,对页面性能影响是相对较小,毕竟现代浏览器的渲染能力还是可以的。但除了性能问题,CSS的书写应该注意后期维护和拓展能力。

在项目开发中,对于同样一个视图,不同开发者的代码实现及写法可能会不一样,对问题的处理方式也有可能不一致,所以在同一个项目组里面,如果没有一个大致相同的规范来限定CSS的书写方式,后期维护五花八门的CSS将变得很费劲。

今天要扯的就是CSS选择器。选择器是CSS学习中的一个重要部分,可以说掌握了选择器,CSS最难的部分算是搞定了,剩下的就都是些属性了,记一记就好了。

先介绍一下主要CSS选择器(按性能从高到低)

ID 选择器,例如#fleming

传说中性能最好的选择器,没有之一。其实在现代浏览器中,ID选择器的性能与类选择器的性能相差无几。ID选择器在选择器名称前带#,示例:

HTML:

<div id="fleming">弗斯基</div>

CSS:

#fleming{
    font-weight:bold;
}

类选择器,例如.fleming

类选择器是CSS中最常用的选择器,可以选中class相同的所有元素。与ID选择器有所不同,ID选择器是选中某个ID的元素,而类选择器是选中class相同的所有元素。例如:

HTML

<div class="fleming">弗斯基</div>
<p class="fleming">厨子</p>
<span class="fleming">有点胖</span>

CSS

.fleming{
    color: red;
}

元素选择器,例如div

元素选择器通常将是某个 HTML 元素,比如 p、h1、em、a,甚至可以是 html 本身当做选择器名称。

HTML

<div>弗斯基</div>
<p>厨子</p>
<span>有点胖</span>

CSS

div, p, span{
    color: red;
}

兄弟选择器,例如 h2 + p

如果需要选择紧接在另一个元素后的元素,而且二者有相同的父元素,可以使用相邻兄弟选择器(Adjacent sibling selector)。例如,如果要增加紧接在 h1 元素后出现的段落的上边距,可以这样写:

HTML

<h1>弗斯基</h1>
<p>老司机</p>

CSS

h1 + p{
    margin: 10px;
}

子选择器,例如li > ul

如果想只选择某个元素的子元素,请使用子元素选择器(Child selector)。 例如,如果希望选择只作为 h1 元素子元素的 strong 元素,可以这样写:

HTML

<h1>This is <strong>very</strong> <strong>very</strong> important.</h1>

CSS

h1 > strong {
    color:red;
}

后代选择器,例如div span

与子选择器有些区别,后代选择器可以选中包括子元素及子元素的子元素。 比子元素选择器范围更广。例如希望对 div 元素中的 <span>元素应用样式,可以这样写:

HTML

<div>
    This is <span>apple</span>
    <p>This is <span>orange</p></p>
</div>

CSS

div p{
    color: red;
}

通用选择器,例如 *

通用选择器可能是所有选择器中最强大的,却使用最少的。通用选择器的作用就像是通配符,它匹配所有可用元素。通用选择器由一个星号表示。通用选择器一般用来对象页面上所有元素应用样式。

HTML

<div>Fleming</div>
<p>Test</p>
<ul>
    <li>厨子</li>
</ul>

CSS

*{
    color: red;
}

属性选择器,例如 type = “text”

可以选中所有包含某种属性的元素。例如:

HTML

<input type="text">

CSS

[type="text"]{
    color: red;
}

伪类/伪元素选择器,例如 a:hover

可为一些元素添加不同状态的样式,可以使用伪类选择器。例如给a元素添加鼠标hover样式。

HTML

<a href="https://chenfengming.cn">弗斯基</a>

CSS

a:hover{
    color: red;
}

除此之外,选择器可以组合使用,例如: .info p > a,但需要注意的一点是,浏览器解析选择器是从右到左的,复杂的选择器组合会耗费较多的时间去解析,对页面整体性能会有影响。例如选择器 .info p > a,浏览器查找到所有a元素之后还需要继续匹配父级元素是p 的a元素,查找完成之后再继续匹配属于class是.info的元素子级元素。

总的来说,CSS选择器的使用不仅仅要考虑到选择器的性能,需要结合当前项目特点,选择合适的选择器,兼顾页面性能和后期的维护和拓展。例如,不能因为ID选择器的高性能就觉得整页都是用ID选择器,那样CSS维护会变得非常困难,不利于组件化开发。适当的组合使用选择器是允许的,但不要过度嵌套选择器。

关于CSS BEM

上面有提到选择器的书写对页面CSS渲染性能有一定的影响,那么如何更加规范、合理的书写选择器能既能方便理解用意又能便于后期维护和拓展呢?

BEM is a highly useful, powerful, and simple naming convention that makes your front-end code easier to read and understand, easier to work with, easier to scale, more robust and explicit, and a lot more strict.

先介绍一下BEM, Block(块) Element(元素) Modifier(修饰器)的简称。使用BEM规范来命名CSS,组织HTML中选择器的结构,利于CSS代码的维护,使得代码结构更清晰,缺点主要是选择器名会比较丑陋。此外,BEM规范的遵循在一定程度上能帮助优化CSS选择器结构,从而提升页面性能。

在BEM规范中,以双下划线 __来作为块和元素的间隔,以单下划线_来作为块和修饰器或元素和修饰器的间隔,以中划线 – 来作为块|元素|修饰器名称中多个单词的间隔。保证各个部分只有一级 B__E_M ,修饰器需要和对应的块或元素一起使用,避免单独使用。

举个例子

HTML

<form class="form form--theme-xmas form--simple">
    <input class="form__input" type="text" />
    <input class="form__submit form__submit--disabled" type="submit" />
</form>

CSS

.form { }
.form--theme-xmas { } //某种状态的form
.form--simple { } //某种状态的form
.form__input { } // Form子元素input
.form__submit { } // Form子元素summit
.form__submit--disabled { } // Form子元素submit带disabled状态

LESS(CSS预处理器)

.form {
    &--theme-xmas { } //某种状态的form
    &--simple { } //某种状态的form
    &__input { } // Form子元素input
    &__submit {
       &--disabled { } // Form子元素submit带disabled状态
    } // Form子元素summit
}

这样书写的好处是编译出来的CSS只有一层,不会有多个选择器嵌套的情况,浏览器执行起来效率会高些,另外,因为嵌套层数少,样式优先级比较低,后期做响应式或其它样式覆盖会比较容易。

具体使用需要结合项目特点。对于BEM中CSS选择器的命名,不宜过长,适当、能表达意思即可。关于BEM想了解更多的童鞋参见:http://getbem.com/

另外,关于静态资源与页面性能。在现代浏览器中,资源是并发加载的(同域名下约6个左右),当资源过多时,资源总数大于并发数,后续的资源加载会受限于浏览器并发数。许多网站为静态资源提供多个域名调用方式从而提升浏览器静态资源加载效率。但即便如此,浏览器仍然有可能出现资源阻塞的情况。例如,CSS资源就会阻塞浏览器渲染进程,也就是说在这之前,浏览器不会渲染任何已处理资源,直到CSSOM(CSS Object Model)构建完毕。当CSS资源阻塞时,DOM节点的渲染以及JavaScript处理会延时。可见低效率的CSS会影响到整个页面的性能。

当浏览器遇到 script 标签时,DOM 构建将暂停,直至脚本完成执行。 所以,一般在页面引用CSS会放置在页面header部分,JavaScript会被放置带页面末尾,这样做的目的是在确保页面样式不会受到JavaScript的影响下优先渲染。开始扯远了,今天就先说到这了。

种子站那么优秀?论客户端用户唯一性识别

曾经某大师给我展示了这么一个使用场景。

某片子网站有一套免登陆识别客户端用户的机制,用户不需要注册、登录,直接访问链接即可在网站上实现一些会员服务。按正常思维,需要实现会员制,必须要求用户在网站上登录留下凭证,这样服务器才能把对应会员正确的服务分发,黄金会员白金会员钻石会员,各种会员,当然,如果用户充值,这些帐会自动记录在当前客户端名下。看着似乎有点玄乎,当时就被唬住了。

按照常规的思路,想要获取一个能当做用户唯一标识的东西,从浏览器端来看,要么MAC地址之类的?类似于这些相对固定而唯一的号,然鹅,浏览器除了提供UA(User agent)之外,其它信息一概无法获取,而UA根本就无法用来识别浏览器端的唯一性,因为相同设备相同浏览器的UA是一致的,美梦似乎要破灭了。然而我那锲而不舍的精神一直支撑着我,让我不断向前~探索。

小片子网站能做,应该还是有对应的技术可以实现的,后面回来后翻了下资料,发现还真有这种操作,不用注册不用登陆就可以区分浏览器端用户!感觉这个需求瞬间就靠谱了,PM不能随便打,还好这么冷静。翻开了我的小本子,在里面狠狠地记了一笔。

这么看来是要能造一个类UUID(Universally Unique IDentifier)的东西出来标识一下用户才行,具体怎么造,这里就不详细说了,GitHub上也有很多基友写好的码子可以下,有时间了解原理的小伙伴也可以科研一下。至于造UUID这种事情,肯定是要交给我们服务端来干了。那么问题来了,服务端辛苦造出来的UUID该怎么分发给浏览器端并在客户端本地存起来用来标识唯一用户呢?服务器通过页面?cookie?URL?各种本地存储?似乎都不行,清理一下浏览器、关下机又是空白一片,充值的会员还没来得及看片就没掉了,这是不允许的。

现有的浏览器没有现成接口标识当前浏览器用户的唯一性,认真搜刮了一番,似乎有好几种聊的比较多的方法,这里就选个看上去相对靠谱一点的方法聊一聊:

HTML5 Canvas指纹、AudioContext指纹

先说说第一种Canvas指纹方法,基于Canvas标签绘制特定内容的图片,使用canvas.toDataURL()方法获得图片内容的base64编码(对于PNG格式的图片,以块(chunk)划分,最后一块是32位CRC校验)作为唯一性标识,JavaScript示例:

function getUUID() {
    var canvas = document.getElementById('myCanvas');
    var ctx = canvas.getContext('2d');
    ctx.fillStyle = '#FF0000';
    ctx.fillRect(0,0,8,10);

    var b64 = canvas.toDataURL().replace('data:image/png;base64,', '');
    var bin = window.atob(b64);
    var crc = bin2hex(bin.slice(-16,-12));
    
    return src;
}

alert(getUUID());

这种方法是基于相同的HTML5 Canvas元素的绘制操作在不同操作系统、不同浏览器上,产生图片内容不完全相同原理实现的。在图片处理上,不同浏览器使用了不同的图形处理引擎、不同的默认压缩级别等。从像素级别来看,操作系统各自使用了不同的设置和算法来进行像素渲染。即使相同的绘图操作,不同的浏览器端产生的图片数据的CRC检验也不相同。这个特性可以用来区分大部分的浏览器端,但仍然没办法做到完全区分。碰撞的可能性比较大。

而从Canvas被浏览器兼容的情况来看,几乎已被所有主流浏览器都支持Canvas,覆盖了大部分的PC、平板、智能手机端用户。早期有不少人选择这种方式实现浏览器端唯一性标识。

另一种是AudioContext指纹,原理与canvas类似。本地计算机或浏览器硬件或软件的细微差别,导致音频信号的处理上的差异,相同器上的同款浏览器产生相同的音频输出,不同机器或不同浏览器产生的音频输出会存在差异。

AudioContext指纹有两种方式实现:

方法一: 生成音频信息流(三角波),对其进行FFT变换,计算SHA值作为指纹,音频输出到音频设备之前进行清除,用户毫无察觉。

第二种方法是:生成音频信息流(正弦波),进行动态压缩处理,计算MD5值。

 

这种方法出来的指纹仍然不是可靠的,与Canvas指纹类似,有很高的碰撞概率。似乎离实际运用还有一段距离。

为了提高这两种指纹的可靠性,我们需要额外附加一些其它信息,降低碰撞概率。例如增加一些硬件指纹作为补充,有兴趣的小伙伴可以详细阅读一下这个文档: Hardware fingerprint using HTML5。主要的硬件模块包括:GPU’s clock frequency、Camera、Speakers/Microphone、Motion sensors、GPS、Battery等等。

即便如此,虽然碰撞的概率降低了,但仍然无法达到一个比较理想的状态。那需要怎样再做优化呢?没错,将上述所有的指纹综合利用,进行分析、计算哈希值作为综合指纹,可以大大降低碰撞率,极大提高客户端唯一性识别的准确性。

似乎事情得到解决了,然而细想会发现,这种唯一性验证在跨浏览器的时候就无法使用了,同一个用户在同一台机器上使用不同的浏览器所产生的指纹是不一样的。在Chrome充值的会员在Firefox上不能用了,好像也不太科学。又是一顿好找,还真有大佬在研究这块跨浏览器指纹,感兴趣的童鞋可以研读膜拜一下这篇: ( cross-) Browser fingerprint via OS and Hardware level features

其原理是根据浏览器、操作系统与底层硬件之间的交互进而分析出来的指纹,同一机器上不同浏览器产生的这种指纹是一致的。

总结一下

如果你上面的内容似乎看不太懂,可以直接跳到这里来。

客户端用户唯一性识别可靠性不够高,在利用综合指纹识别时虽然碰撞概率降低,但仍然需要解决一些例如跨浏览器身份识别这种问题,需要深挖。运用场景比较广,可用于免登录、客户端追踪(例如根据用户搜索内容,广告精确定推等等)一些精度要求不太高的地方。对于免登录场景运用,可结合后期用户的一些信息做进一步区分处理,但仍然达不到注册的身份验证方法的精度。

对于客户端用户唯一性识别你怎么看呢?

关于WEB前端开发

那么,到底什么是WEB前端开发呢?

从字面上理解,WEB前端开发的工作与网站的某些“前端”息息相关,可以认为这个“前端”是整个网站的最前端,是最接近用户的地方。那所谓的网站“前端”又包括哪些部分呢?

大家都知道,打开网站后首先展现在用户面前的是整个网站的视图部分,包括布局、样式、动画、多媒体元素等,而当用户开始浏览页面点击鼠标或者输入内容时,页面会针对用户的行为做出对应的反馈(例如显示/隐藏、内容变化等页面交互),这些综合起来就是网站的“前端”部分了。

上面我们提到的网站那些“前端”部分的东西,大多都在用户使用的浏览器端执行,所以WEB前端开发也称之为客户端/浏览器端开发。WEB前端主要开发语言为HTML,CSS和JavaScript。随着技术变革,衍生出了一系列新的框架和解决方案,使得WEB前端开发逐渐丰富起来。

早些年,WEB前端开发的工作几乎被“美工”承包了,在很多人的印象中,WEB前端开发仍然停留在“切图仔”时代,认为调调样式切一切图就可以放学回家了。然而并不是,从2007年到现在,经过大概11年的发展,前端开发变得越来越规范,很多后端开发的模式及思想已经渗透到了WEB前端开发,PWA模式(Progressive Web App)也让前端的疆域也从页面扩展到各种APP,包括跨平台桌面运用。WEB前端开发的工作已不仅仅是简单写写样式切切图了,加之WEB前端与用户体验息息相关,前端开发变得越来越重要。

随着时代变迁,越来越多的移动设备拥有了互联网访问能力,各种各样的平台、屏幕和分辨率,这就需要我们在开发之前进行更好的规划,网站的前端能适时自动适应这些平台设备,在开发成本与用户体验之间寻求一个合适的契合点。响应式布局应运而生,与传统多平台开发相比,在获得较好的用户体验同时节省了大量的人力物力,所有设备一套代码,后期维护也变得容易。

HTML, CSS, & JavaScript:

WEB前端开发者使用Web技术(即HTML,CSS,DOM和JavaScript)构建和开发网站或WEB应用程序前端,通常需要在各种Web平台环境(包括浏览器)上运行或一些非Web平台环境使用(例如React Native),不仅仅是WEB浏览器端那么单一。

我们通过学习开发HTML,CSS和JavaScript进入WEB前端开发领域,而这些HTML,CSS和JavaScript可以在Web浏览器中运行,也可以在其它环境下运行,例如无头浏览器WebView或一些Native环境中运行。 下面介绍一下这四个运行场景:

Web 浏览器(WEB BROWSERS) – 通常情况

Web浏览器是用于检索、呈现互联网上的信息的软件。 一般在台式机或笔记本电脑,平板电脑或手机上可以看到它的身影,但近年来,越来越多的智能设备也包含了WEB浏览器,例如智能电视、汽车甚至是冰箱。WEB浏览器是一种比较常见的访问网站的工具。

常见的Web浏览器(按照最常用的顺序显示):

无头浏览器(HEADLESS BROWSERS)

无头浏览器是指没有用户图形界面的浏览器,可以通过编程方式从命令行界面控制的网页浏览器,通常用于网页自动化(例如,功能测试,抓取,单元测试等)。可以理解为,无头浏览器就是一种通过命令行运行的可以检索和遍历网页的浏览器。

最常见的无头浏览器是:

Webviews

Webviews通常被包含在原生的系统或应用程序中,用来运行web页面。可以理解为,Webviews就像iframe或者是Web浏览器里面的一个选项卡,被嵌入在原生系统或应用程序的设备中运行(例如,iOS,android,windows)。

Webview最常见的几种解决方案:

  • Cordova (typically for native phone/tablet apps)
  • NW.js (typically used for desktop apps)
  • Electron (typically used for desktop apps)

注:htmlpage.cn项目中的网页构建器桌面版就是用Electron包的。

Native from Web Tech

最后,WEB前端开发者可以使用从前端开发中学到的知识来为其它跨平台及非浏览器设备开发应用程序。 例如,创建Native应用程序(native applications)。

示例:

介绍完这些,你应该对WEB前端开发有大概的了解了吧?

 

CSS响应式布局之Grid实战

在这篇文章中,我将教你如何使用 CSS Grid(网格) 布局来创建一个超酷的图像网格,它会根据屏幕的宽度改变列的数量,以实现响应式布局。

而这篇文章中最漂亮的部分是:添加一行 CSS 代码即可实现响应式布局。

这意味着我们不必通过丑陋的类名(即 col-sm-4col-md-8)来混淆 HTML ,或者为每一个屏幕尺寸创建媒体查询。

现在就让让我们开始吧!

设置

以下是我们的初始网格的外观:

HTML part

<div class="container">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
</div>

CSS part

.container {
    display: grid;
    grid-template-columns: 100px 100px 100px;
    grid-template-rows: 50px 50px;
}

注意:这个例子也有一些基本的样式,比如容器宽度,网格间隔,背景颜色什么的,我不会在这里介绍,因为它与 CSS Grid 没有任何关系。

如果这段代码让你感到困惑,我建议你阅读 理解CSS Grid布局 这篇文章,在那里我解释了 Grid 布局模块的基础知识。

让我们开始将 列 实现响应式布局。

使用等分(fr)单位实现基本的响应式

CSS Grid 带来了一个全新的值,称为等分单位,即 fr 。它允许你将容器可用空间分成你想要的多个等分空间。

让我们将每个列更改为一个等分单位宽度。

CSS示例

.container {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    grid-template-rows: 50px 50px;
}

这里发生的事情是,将整个网格的宽度分成三等分,每一列都占据一个 fr 单位。结果是:

如果我们将 grid-template-columns 的值更改为 1fr 2fr 1fr,那么第 2 列现在将是另外 2 列的 2 倍。总宽度现在是 4 等分,第 2 列占据了 2 等分,而其他 2 列则各占 1 等分。看起来类似这样:

换句话说,等分单位值使你可以非常容易地改变列的宽度。

更加高级的响应式

但是,上面的例子并没有给我们想要的响应式,因为这个网格总是包含 3 列。我们希望我们的网格根据容器的宽度来改变列的数量。要做到这一点,你必须学习三个新的概念。

repeat()

我们将从 repeat() 函数开始。 这是指定列和行更强大的方法。 让我们把原来的网格改成使用 repeat() :

.container {
    display: grid;
    grid-template-columns: repeat(3, 100px);
    grid-template-rows: repeat(2, 50px);
}

换句话说,repeat(3, 100px) 与 100px 100px 100px 相同。 第一个参数指定了你想要的列数或行数,第二个参数指定了它们的宽度,所以上面的代码将为我们创建和第一个一样的布局。

auto-fit (自适应)

然后是自适应。让我们跳过固定数量的列,而是用 auto-fit 取代 3 。

.container {
    display: grid;
    grid-gap: 5px;
    grid-template-columns: repeat(auto-fit, 100px);
    grid-template-rows: repeat(2, 100px);
}

效果如下图:

你会看到,现在这个网格已经可以通过容器的宽度来改变列的数量。

它只是试图尽可能多地将 100px 宽的列排列在容器中。

但是,如果我们将所有列硬编码为 100px ,我们永远得不到我们想要的灵活性,因为它们很少会加起来正好等于容器的宽度。正如你在上面的 gif 图中所看到的,网格通常会在右侧留下空白区域。

minmax()

为了解决这个问题,我们需要的最后一方法是 minmax()。我们只需用 minmax(100px, 1fr) 替换 100px 即可。这是最终的CSS。

.container {
    display: grid;
    grid-gap: 5px;
    grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
    grid-template-rows: repeat(2, 100px);
}

注意,所有的响应都发生在一行 CSS 中。

这会达到以下效果:

正如你们所见,这样很完美。minmax() 函数定义大于或等于 min 且小于或等于 max 的大小范围。

所以现在列的宽度至少 100px 。但是,如果有更多的可用空间,网格将简单地分配给每个列,因为列的值变成了一个等分单位 1fr ,而不是 100px 。

添加图片

现在最后一步是添加图片。 这与 CSS Grid 没有任何关系,但是我们还是要来看看代码。

我们将在每个网格项内添加一个 img 标签。

<div><img src="img/forest.jpg"/></div>

为了使图像适合该网格项,我们将它设置为与网格项一样宽和高,然后使用 object-fit: cover;。这将使图片覆盖整个容器,如果需要的话,浏览器会裁剪该图片。

.container > div > img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

效果如下:

就是这么简单!你已经了解了 CSS Grid 中最复杂的概念之一,所以后面请自己动手吧。

浏览器支持

在我们结束之前,我还需要提及浏览器的支持。在写这篇文章的时候,占全球 77% 的网站流量的浏览器支持CSS Grid,而且正在攀升。

CSS Grid 使用频率会越来越高。很快会得到突破,并将成为前端开发人员的必备技能。就像过去几年在 CSS Flexbox 所发生的一样。

推荐阅读:原文 How to make your HTML responsive by adding a single line of CSS

 

JavaScript函数的Throttle与Debounce

你可能知道,JavaScript遵循事件驱动的编程范例。这意味着一些行为可以激活一些响应,并且这些响应仅在发生特定的行为时才被激活。我们称这些行为events(事件),和响应callbacks(回调)。连续的事件流被称为event stream(事件流)。

这些行为发生的速度不是我们能手动控制的。但是我们可以控制何时和如何激活正确的响应。有一些技术为我们提供精确的控制。

  • Throttle
  • Debounce
  • Immediate

Throttle

在现代浏览器中,帧速率为60fps是流畅性能的目标,给定我们16.7ms的时间预算用于响应一些事件所有需要的更新。这样可以推断,如果每秒发生n个事件并且回调执行,需要t秒的时间,为了流畅运行,

1 / n >= t

如果t以毫秒为单位,

1000 / n >= t

如果你曾经使用mousemove事件,你会知道产生mousemove事件的数量每秒可以超过60次。如果我们的回调需要超过16.7ms,那就开始凌乱了。

var then = 0;
 
function log() {
  var now = Date.now();
  if (1000 / (now - then) > 60) {
    console.log('It\'s over 9000!!!');
  }
  then = now;
}
 
window.onmousemove = log;

实现

Throttle 允许我们限制我们激活响应的数量。我们可以限制每秒回调的数量。反过来,也就是说在激活下一个回调之前要等待多少时间;

var delta = 1000;
var then = 0;
 
function log() {
  console.log('foo');
}
 
function throttledLog() {
  var now = Date.now();
  if (now - then >= delta) {
    log();
 
    then = now;
  }
};
 
window.onmousemove = throttledLog;

我们可以用 fps替换delta,并推断出不同的代码。

var fps = 60;
...
function throttledLog() {
  var now = Date.now();
  if (1000 / (now - then) < = fps) {
    log();
 
    then = now;
  }
};
 
window.onmousemove = throttledLog;

我们也可以通过使用setTimeout来实现相同的结果。 但是,不是检查时间差,而是检查状态变化。

第一次,我们可以安全地激活回调。一旦完成,只有在等待 delta 时间之后才能再次激活回调。

var delta = 1000;
var safe = true;
 
function log() {
  console.log('foo');
}
 
function throttledLog() {
  if (safe) {
    log();
 
    safe = false;
    setTimeout(function() {
      safe = true;
    }, delta);
  }
};
 
window.onmousemove = throttledLog;

Debounce

这个术语-去抖动 来自电子学的领域,手动开关输入的信号被发送到数字电路中。在电子学中,当你按一个物理按钮一次,数字电路可能读到多个按压,因为按钮的物理属性(金属触点,弹簧,磨损件等)。

去抖动意味着采集到的所有这些波动的信号,并把它们当作一个。

例子

一个简单的例子已经存在于JS中:keydown vs keyup。假设您正在处理一个项目,并且需要输入内容。但是你想要每次敲击键盘得到一个字符。输入时,如果长按一个键,keydown事件将连续被触发,但是 keyup 事件只有在按键被释放时才会触发。

window.onkeyup = function() {
  console.log('onkeyup');
}
 
window.onkeydown = function() {
  console.log('onkeydown');
}

这种行为上的差异对于确定输入是否已完成是有用的。在示例场景中,它是你将使用的keyup事件。在某种程度上,我们可以说keydown 是原始输入,keyup 是去抖动输入。

实现

当事件发生时,我们不会立即激活回调。相反,我们等待一定的时间并检查相同的事件是否再次触发。如果是,我们重置定时器,并再次等待。如果在等待期间没有发生相同的事件,我们就立即激活回调。

var delta = 1000;
var timeoutID = null;
 
function log() {
  console.log('foo');
}
 
function debouncedLog() {
  clearTimeout(timeoutID);  // reset timer
  timeoutID = setTimeout(function() {
    // wait for some time
    // and check if event happens again
    log();
  }, delta);
};
 
window.onkeydown = debouncedLog;

Immediate

Immediate是Debounce的精确版本。比起 Debounce 的 等待后续事件触发,然后再激活回调,Immediate 是 立即激活回调,然后等待后续事件在一定时间内触发。

实现

就像Throttle的情况一样,我们需要一个状态变量来检查是否应该激活我们的回调。我们在Debounce不需要一个,因为timeoutID隐式管理这部分。

var delta = 1000;
var timeoutID = null;
var safe = true;
 
function log() {
  console.log('foo');
}
 
function immediatedLog() {
  if (safe) {
    log();
    safe = false;
  }
 
  clearTimeout(timeoutID);
  timeoutID = setTimeout(function() {
    safe = true;
  }, delta);
};
 
window.onkeydown = immediatedLog;

理解CSS Grid布局

Grid 布局是网站设计的基础,CSS Grid 是创建网格布局最强大和最简单的工具。

CSS Grid 今年也获得了主流浏览器(Safari,Chrome,Firefox,Edge)的原生支持,所以我相信所有的前端开发人员都必须在不久的将来学习这项技术。

在本文中,我将尽可能快速地介绍CSS网格的基本知识。我会把你不应该关心的一切都忽略掉了,只是为了让你了解最基础的知识。

你的第一个 Grid 布局

CSS Grid 布局由两个核心组成部分是 wrapper(父元素)和 items(子元素)。 wrapper 是实际的 grid(网格),items 是 grid(网格) 内的内容。

下面是一个 wrapper 元素,内部包含6个 items :

<div class="wrapper">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
</div>

要把 wrapper 元素变成一个 grid(网格),只要简单地把其 display 属性设置为 grid 即可:

.wrapper {
    display: grid;
}

但是,这还没有做任何事情,因为我们没有定义我们希望的 grid(网格) 是怎样的。它会简单地将6个 div 堆叠在一起。

我已经添加了一些样式,但是这与 CSS Grid 没有任何关系。

Columns(列) 和 rows(行)

为了使其成为二维的网格容器,我们需要定义列和行。让我们创建3列和2行。我们将使用grid-template-rowgrid-template-column属性。

.wrapper {
    display: grid;
    grid-template-columns: 100px 100px 100px;
    grid-template-rows: 50px 50px;
}

正如你所看到的,我们为 grid-template-columns 写入了 3 个值,这样我们就会得到 3 列。 我们想要得到 2 行,因此我们为 grid-template-rows 指定了2个值。

这些值决定了我们希望我们的列有多宽( 100px ),以及我们希望行数是多高( 50px )。 结果如下:

为了确保你能正确理解这些值与网格外观之间的关系,请看一下这个例子。

.wrapper {
    display: grid;
    grid-template-columns: 200px 50px 100px;
    grid-template-rows: 100px 30px;
}

请尝试理解上面的代码,思考一下以上代码会产生怎样的布局。

这是上面代码的布局的结果:

非常好理解,使用起来也非常简单是不是?下面我们来加大一点难度。

放置 items(子元素)

接下来你需要学习的是如何在 grid(网格) 上放置 items(子元素) 。特别注意,这里才是体现 Grid 布局超能力的地方,因为它使得创建布局变得非常简单。

我们使用与之前相同的 HTML 标记,为了帮助我们更好的理解,我们在每个 items(子元素) 加上了单独的 class :

HTML part

<div class="wrapper">
  <div class="item1">1</div>
  <div class="item2">2</div>
  <div class="item3">3</div>
  <div class="item4">4</div>
  <div class="item5">5</div>
  <div class="item6">6</div>
</div>

现在,我们来创建一个 3×3 的 grid(网格):

.wrapper {
    display: grid;
    grid-template-columns: 100px 100px 100px;
    grid-template-rows: 100px 100px 100px;
}

将得到以下布局:

不知道你发现没有,我们只在页面上看到 3×2 的 grid(网格),而我们定义的是 3×3 的 grid(网格)。这是因为我们只有 6 个 items(子元素) 来填满这个网格。如果我们再加3个 items(子元素),那么最后一行也会被填满。

要定位和调整 items(子元素) 大小,我们将使用 grid-column 和 grid-row 属性来设置:

.item1 {
    grid-column-start: 1;
    grid-column-end: 4;
}

我们在这里要做的是,我们希望 item1 占据从第一条网格线开始,到第四条网格线结束。换句话说,它将独立占据整行。 以下是在屏幕上显示的内容:

如果你不明白我们设置的只有 3 列,为什么有4条网格线呢?看看下面这个图像,我画了黑色的列网格线:

请注意,我们现在正在使用网格中的所有行。当我们把第一个 items(子元素) 占据整个第一行时,它把剩下的 items(子元素) 都推到了下一行。

最后,给你一个更简单的缩写方法来编写上面的语法:

.item1 {
    grid-column: 1 / 4;
}

为了确保你已经正确理解了这个概念,我们重新排列其他的 items(子元素) 。

.item1 {
    grid-column-start: 1;
    grid-column-end: 3;
}
.item3 {
    grid-row-start: 2;
    grid-row-end: 4;
}
.item4 {
    grid-column-start: 2;
    grid-column-end: 4;
}

你可以尝试在你的脑子里过一边上面代码的布局效果,应该不会很难。

以下是页面上的布局效果:

Grid 布局就是这么简单,当然这里展示的是最简单的 Grid 布局概念,但是 Grid 布局系统中还有更多强大灵活的特性。

推荐阅读:CSS Grid layout 进阶篇 CSS响应式布局之Grid实战

HTML5新增&废除的元素

新增块级元素

section元素

section元素定义文档或应用程序中的一个区段,比如章节、页眉、页脚或文档中的其他部分。它可以与h1,h2,h3,h4,h5,h6元素结合起来使用,标示文档结构。

HTML5中代码示例: <section>…</section>

HTML4中代码示例:<div>…</div>

article元素

article元素表示文档中的一块独立的内容,譬如博客中的一篇文章或报纸中的一篇文章。

HTML5中代码示例 :<article>…</article>

HTML4中代码示例 :<div class=”article”>…</div>

header元素

header元素表示页面中一个内容区块或整个页面的标题。

HTML5中代码: <header>…</header>

HTML4中代码示例 :<div>…</div>

nav元素

nav元素表示导航链接的部分。

HTML5中代码示例 : <nav>…</nav>

HTML4中代码示例 :<ul>…</ul>

footer元素

footer元素表示整个页面或页面中一个内容区块的脚注。一般来说,它会包含创作者的姓名、文档的创作日期以及创建者联系信息。

HTML5中代码示例 :<footer>…</footer>

HTML4中代码示例 :<div>…</div>

新增块级语义元素

aside元素

aside元素表示article元素的内容之外的与article元素的内容相关的有关内容。

HTML5中代码示例 :<aside>…</aside>

HTML4中代码示例 :<div>…</div>

figure元素

figure元素表示一段独立的流内容,一般表示文档主体流内容中的一个独立单元。使用 <figcaption> 元素为figure元素组添加标题。

HTML5中代码示例:

<figure>
<figcaption>PRC</figcaption>
<p>The People's Republic of China was born in 1949...</p>
</figure>

HTML4中代码示例:

<dl>
<h1>PRC</h1>
<p>The People's Republic of China was born in 1949...</p>
</dl>

dialog元素

dialog标签定义对话,比如交谈。 注意: 对话中的每个句子都必须属于 <dt> 标签所定义的部分。

HTML5中代码示例:

<dialog>
<dt>老师</dt>
<dd>2+2 等于?</dd>
<dt>学生</dt>
<dd>4</dd>
<dt>老师</dt>
<dd>答对了!</dd>
</dialog>

新增行内语义元素

mark元素

mark元素主要用来在视觉上向用户呈现那些需要突出显示或高亮显示的文字。mark元素的一个比较典型的应用就是在搜索结果中向用户高亮显示搜索关键词。

HTML5中代码示例 :<mark>…</mark>

HTML4中代码示例 :<span>…</span>

time元素

time元素表示日期或时间,也可以同时表示两者。

HTML5中代码示例 : <time>…</time>

HTML4中代码示例 :<span>…</span>

meter元素

meter元素表示度量衡。仅用于已知最大和最小值的度量。必须定义度量的范围,既可以在元素的文本中,也可以在 min/max 属性中定义。

HTML5中代码示例 : <meter>…</meter>

progress元素

progress元素表示运行中的进程。可以使用 progress元素来显示 JavaScript 中耗费时间的函数的进程。

HTML5中代码示例 :<progress>…</progress>

新增多媒体与交互性元素

video元素 & audio元素

video用来插入视频,audio用来插入声音,当然,用下面这个:

<video src="XX.wmv">您的浏览器不支持video标签</video>

如果浏览器不支持,则显示标签内的文字

details元素

details元素表示用户要求得到并且可以得到的细节信息。它可以与summary元素配合使用。summary元素提供标题或图例。标题是可见的,用户点击标题时,会显示出details。summary元素应该是details元素的第一个子元素。目前只有 Chrome 支持 <details> 标签。

HTML5中代码示例:

<details>
<summary>HTML5</summary>
<p>All pages and graphics on this web site are the property of chenfengming.cn.<p>
</details>
<!--目前只有 Chrome 支持 <details> 标签—>

datagrid元素

datagrid元素表示可选数据的列表,与input元素配合使用,可以制作出输入值的下拉列表。

HTML5中代码示例 :<datagrid>…</datagrid>

menu元素

menu元素表示菜单列表。当希望列出表单控件时使用该标签。

HTML5中代码示例:

<menu>
<li><input type="checkbox" />Red</li>
<li><input type="checkbox"/>blue</li>
</menu>

注意:HTML4中 menu元素不被推荐使用。

command元素

command元素表示命令按钮,比如单选按钮、复选框或按钮。

HTML5中代码示例:

<menu>
<command onclick="alert('Hello World')">Click Me!</command>
</menu>

 

新增input类型

email——email类型用于应该包含 e-mail 地址的输入域。

url——url 类型用于应该包含 URL 地址的输入域。

number——number 类型用于应该包含数值的输入域。

range——range 类型用于应该包含一定范围内数字值的输入域。

Date Pickers(日期选择器)

search——search 类型用于搜索域,比如站点搜索或 Google 搜索。search 域显示为常规的文本域。

多个可供选取日期和时间的新输入类型

date – 选取日、月、年

month – 选取月、年

week – 选取周和年

time – 选取时间(小时和分钟)

datetime – 选取时间、日、月、年(UTC 时间)

datetime-local – 选取时间、日、月、年(本地时间)

废除的元素

•能使用css代替的元素
对于basefont、big、center、font、s、strike、tt、u这些元素,由于他们的功能都是纯粹为画面展示服务的,而在HTML5中提倡把画面展示性功能放在css样式表中统一编辑,所以将这些元素废除,并使用编辑css样式表的方式进行替代。

•不再使用frame框架
对于frameset元素、frame元素与nofranes元素,由于frame框架对页面可存在负面影响,在html5中已不再支持frame框架,只支持iframe框架,或者用服务器方创建的由多个页面组成的复合页面的形式,同时将以上三个元素废除。

•只有部分浏览器支持的元素
对于applet、bgsound、blink、marguee等元素,由于只有部分浏览器支持这些元素,所以在HTML5中被废除。其中applet元素可由embed元素替代,bgsound元素可由audio元素替代,marquee可以由JavaScript编程的方式所替代。

 

 

CSS布局和块级格式化上下文

CSS布局中有一些概念是你一旦理解它那么就会极大的提升你的 CSS 技能的。这篇文章是关于块级格式化上下文的 BFC 。也许你从未听说过这个术语,但是如果你曾经用 CSS 做过布局,那么你也许知道它是什么。理解什么是 BFC ,它为什么会起作用以及如何创建一个有用的 BFC 可以帮助你理解 CSS 布局是怎样工作的。

在这篇文章中,我将通过一些你可能熟悉的例子解释什么是 BFC 。我将向你展示一个新的概念,当你明白什么是 BFC 以及你为什么需要它的时候,它才真正有意义。

什么是 BFC?

最容易明白一个 BFC 表现的是一个浮动的例子。在下面的例子中有一个盒模型,其中包含一张左浮动的图和一些文字。如果我们有大量的文字,它环绕在浮动的图像上,则边框会围绕着整个区域。

HTML part:

<div class="outer">
  <div class="float">I am a floated element.</div>
  I am text inside the outer box.
</div>

CSS part:

.outer {
  border: 5px dotted rgb(214,129,137);
  border-radius: 5px;
  width: 450px;
  padding: 10px;
  margin-bottom: 40px;
}

.float {
  padding: 10px;
  border: 5px solid rgba(214,129,137,.4);
  border-radius: 5px;
  background-color: rgba(233,78,119,.4);
  color: #fff;
  float: left;  
  width: 200px;
  margin: 0 20px 0 0;
}

图1:文本环绕着浮动元素

如果删除了一些文本,那么文本就不足以环绕图像,并且因为图片浮动脱离了文档流,边框就会在图片下面并且上升到文本的高度。

图2:没有足够的文本,边框就不能到达浮动元素所期望的高度

这是因为当我们在浮动一个元素时,文本所在的盒模型仍然是固定的高度,而因浮动元素而缩短的空间是文本的行框。这就是为什么背景和边框会出现在浮动元素的后面。

这里有两种我们通常修复这种问题的方式。一种是使用清除浮动 clearfix hack 1,它是通过在文本和图片下面插入一个元素并且设置清除两侧浮动来起作用的。另一种方式是使用 overflow属性,使用其他的值来代替默认的 visible 。

.outer {
  overflow: auto;
}

图3:使用 overflow:auto 使盒模型中包含浮动

overflow 属性起作用的原因是使用任何一个其他值来代替初始值 visible ,从而创建一个 BFC 。即 BFC 的一个特点就是它包含浮动。

BFC 布局是一个迷你布局

你可以认为 BFC 在网页中是一个迷你布局。一旦一个元素创建的 BFC ,所有东西都包含在里面了。正如我们所看到的,它包含浮动元素使其不再超出盒子底部。同时 BFC 也产生了一些其他有用的行为。

BFC 防止外边距塌陷

理解外边距塌陷是另一个被低估的 CSS 技能。在下一个例子中,有一个灰色背景的 div 。这个 div 中有两个段落。外层 div 有 40px 的下边距;每一个段落也分别有 20px 的上下边距。

.outer {
  background-color: #ccc;
  margin: 0 0 40px 0;
}

p {
  padding: 0;
  margin: 20px 0 20px 0;
  background-color: rgb(233,78,119);
  color: #fff;
}

由于 p 元素的外边距和外层 div 的外边距之间没有任何东西而导致它们折叠,使 p 段落最后会与盒子的顶部和底部平齐。所以在 p 段落的上面和下面我们没有看到任何灰色。

图4:外边距塌陷导致在盒子的顶部和底部看不到任何灰色

如果我们对盒模型应用 BFC ,那么它将包括段落和边距并使之不会塌陷,所以我们将在边距的后面看到灰色的背景。

.outer {
  background-color: #ccc;
  margin: 0 0 40px 0;
  overflow: auto;
}

图5:使用BFC外边距将不会塌陷

BFC 再一次使元素包含在其中,阻止其外边距塌陷或超出盒模型。

BFC 阻止内容环绕浮动元素。

你也会熟悉 BFC 这种行为,就是它如何在使用浮动的多列布局中工作的。如果一个项目创建了 BFC ,那么它将不会环绕任何浮动元素,比如在下面的示例中有这样的标记:

<div class="outer">
  <div class="float">I am a floated element.</div>
  <div class="text">I am text</div>
</div>

带有 float 类的元素开始浮动,然后 div 中的文本会环绕在浮动元素周围。

图6:文本环绕浮动元素

那么可以使用通过对文本使用 BFC 来阻止其环绕行为。

.text {
  overflow: auto;
}

图7:div 包含的文本使用了 BFC 使之停止环绕

这是我们创建多列浮动布局常用的方式。浮动一个元素同时也为另一个元素创建了 BFC ,所以当右边的元素比左边高时,创建的列也不再尝试环绕对方。

还有什么方式可以创建 BFC?

除了使用 overflow 属性以外,其他一些 CSS 属性也可以创建 BFC 。正如我们看到的,浮动一个元素也创建了 BFC ,所以浮动项目将包含里面的任何元素。

其他方式还有使用 position: absolute , position: fixed ,使用 display: inline-block, display: table-cell 及 display: table-caption ,其中 table-cell 以及 table-captions是 HTML 元素的默认属性,所以如果有一个 table 数据,那么它的每个格子都将创建 BFC 。 column-span: all 多被使用在多列布局中。 Flex 和 Grid 项目也会创建类似的 BFC ,它们分别被描述为 Flex 格式化上下文和 Grid 格式化上下文,这分别反映了不同的布局类型。 BFC 表示块级布局, FFC 代表 Flex 布局。在实际项目中结果是一样的,都是包含浮动并且外边距不会发生塌陷。

创建 BFC 新方式

使用 overflow 属性或其他方式创建 BFC 有两个问题。第一,这些方法对于它们真正的用途会产生副作用。使用 overflow 属性创建一个 BFC 并且包含浮动,但是在某些情况下你可能会发现得到一个了不必要的滚动条,或者阴影被剪掉了。这是由于 overflow 属性本质上是告诉浏览器在溢出的情况下应该怎样做—产生滚动条或者剪掉元素。浏览器实际上做了你让它做的工作!

即使在没有任何副作用的情况下,使用 overflow 属性也可能会让另一个开发人员感到困惑。为什么 overflow 属性设置为自动或滚动?开发者最初的目的是什么?他们希望在这个组件上使用滚动条吗?怎样创建一个 BFC 是行之有效的?应该是没有造成其他行为而创造出迷你的布局, 或者保证是在安全范围内的,它将不会引发任何意想不到的问题,并且开发人员的意图也很清晰。 CSS 工作组认为有一个很方便的新的 display 属性: flow-root 。

你可以在任何情况下使用 display: flow-root ,它将会创建一个新的有用的 BFC ,它包含浮动,阻止外边距塌陷,并且阻止元素环绕浮动。

你可以在下面的 CodePen 中看到上述所有的这些, 如果你的浏览器支持 display: flow-root的话,如目前流行的火狐或谷歌浏览器。

图8:支持 display: flow-root 属性的浏览器

支持这个属性的浏览器是有限的,但如果你认为这将是方便的,你可以去支持它。然而,即使目前你不能够在你的代码很流利的使用 flow-root 功能,但你现在明白了 BFC 是什么,以及当你使用 overflow 属性或其它方法包含浮动的时候你明白了你在做什么。了解这样一个事实:比如 BFC 将阻止元素环绕浮动,这在不支持的浏览器中想创建 Flex 或 Grid 布局的时候都是非常有用的。

如何快速搭建RESTful API服务端

上一篇《如何快速搭建自己的网站》有说到用开源CMS WordPress快速搭建网站,这篇继续分享,如何使用WordPress搭建可供网站页面 / 移动端调用的RESTful API服务端,并能通过WordPress后台管理请求路径、API字段等属性。

很多小伙伴看到搭建API服务端就会想到需要大量的开发工作,为了消除你们的顾虑,事先说明一下,这篇文章不是想要教你如何写代码,而是纯分享一些之前的经验,提供思路供参考,具体以可视化操作为主。仍然适合无编程经验的小伙伴们阅读。

WordPress自带一套完整的RESTful API并支持用户自行添加功能性组件进行功能拓展,这里介绍如何通过WordPress插件Pods进行API管理(自定义内容类型和字段等)。建议通过WordPress后台管理进行Pods插件安装:

如何快速搭建RESTful API服务端

在后台管理>插件>安装插件页面中搜索Pods就可以找到这个插件,点击“现在安装”。安装成功并启用插件后,在左侧菜单栏可看到这个拓展:

如何快速搭建RESTful API服务端

下面将通过一段示例来演示如何使用Pods

示例需求

HTML构建器项目中需要把网页模板列表存储在服务器端,管理员可以通过网站后台管理界面管理模板列表,而普通用户可以构建器网页/APP来读取模板列表。

Pods设置

如何快速搭建RESTful API服务端

Pods“添加”功能新建内容类型。WordPress自带基础内容类型包括:文章类型、分类、媒体、用户等。Pods同时支持这些内容类型。因为我们需要存储的是HTML页面模板内容,与WordPress中“文章”类型内容相似,所有这里用Pods创建的内容类型选择“自定义文章”即可。

如何快速搭建RESTful API服务端

注意这里的“单数标签”不能填写中文。“存储类型”选择基于数据表,这样WordPress会自动创建一张表用于存储新建这条API的内容。表单填写完成后点击“下一步”即可完成创建。

如何快速搭建RESTful API服务端

如上图所示“Edit Pod: templatetest”,记住,这里可以编辑,但不能填写中文,因为这个“templatetest”将会是RESTful API的URL的节点名称。

这时候,可以通过“添加字段”来针对这个API新增字段。例如需求中,我们需要添加一些如模板名称、模板描述、缩略图之类的字段:

如何快速搭建RESTful API服务端

不用担心,Pods提供10几种字段类型可供选择,包括文本、数字、网址、电话号码、媒体等常用类型以及完整的校验规则。也就是说,只要字段类型选定了,设置几个简单参数,这个字段就可以使用了,包括它的校验规则和配套功能都已经好了。并且可以通过“附加选项”和“高级”选项卡对校验规则进行调整。

例如,设置缩略图字段:

如何快速搭建RESTful API服务端

当设置完成以后,在后台管理的templatetest下“新增”的页面便会出现上传功能组件:

如何快速搭建RESTful API服务端

同样,其它组件例如时间选择、日期选择等都会自动添加对应输入功能模块。

在新增字段的“附加选项”中有更多关于显示、校验规则可供设置,小伙伴们可以按照项目需要添加或修改(每种字段类型的“附加选项”设置页面都不一样):

如何快速搭建RESTful API服务端

其它字段添加就不复述了,这里继续介绍一些需要设置的地方:

1> 左侧菜单栏显示名称

因为Pods会自动把新增的API内容管理显示在左侧的sidebar上,这里显示的名称是可以在“标签”tab里面进行设置的,这里可以填写中文。

如何快速搭建RESTful API服务端

2> 管理界面设置

这里可以设置这个新增的API是否显示在管理界面,并且左侧sidebar里面的图标也是在这里设置的。具体那些图标可以被支持,可参考WordPress官网。

如何快速搭建RESTful API服务端

3> 高级设置

这里可以设置这个内容类型的权限等等。

如何快速搭建RESTful API服务端

4> 启用REST API

这里需要勾选启用REST API, 这样新增的API才能发布到对应的URL节点上供外部调用。

如何快速搭建RESTful API服务端

做完以上步骤,新建API便完成了。可以通过postman测试一下是否正常。需要注意的是,WordPress RESTful API默认节点在https://你的域名/wp-json/wp/v2/节点名称,例如: https://htmlpage.cn/wp-json/wp/v2/templatetest

如何快速搭建RESTful API服务端

可以根据项目实际情况进行修改,另外WordPress的RESTful API返回的json种包含了一堆默认属性值,很多是不需要的,可以通过修改function.php对返回数据格式进行修改。

由于这条API是用于测试的,允许公共读取的,所以通过GET无需校验就可以读取到内容。如果后续项目需要对API操作进行校验,可增加OAuth2.0之类的验证。

更多的设置详细内容,请参照官网文档:

WordPress:

Reference

Pods:

Home

推荐阅读:

原文始发于微信公众号( HTMLPAGE ):如何快速搭建RESTful API服务端

如何快速搭建自己的网站

早些时候,我在BBC内部技术分享会中有提到关于如何使用WordPress快速搭建网站这个话题,这次我把它详细写出来,想要自己建站的小伙伴们可以瞧一瞧,同样适合无开发经验的小伙伴阅读。

我们希望能快速搭建网站,不管有没有开发经验,都不想花太多的时间在写代码上。博客、企业网站、小型电商网站……这时候,选择一款合适的CMS(Content Management System内容管理系统)尤为重要,它能帮助你快速地把网站搭建起来,让你有更多的时间在网站的内容上。

一般成熟的CMS都已经集成了包括:文章管理、会员管理、网站基础设置等等模块,有些甚至包含了一些面对开发者的接口,例如WordPress集成了一套完整的RESTful API模块,通过API你可以调用它的各种内容,对内容进行操作(增/删/改/查)。有了这些,你就可以很快的把网站搭建起来。

扯到这里,差不多要进入主题了。

需要准备的:

  • 一份下载好的WordPress源码(开源的)
    现成的内容管理系统,一整套网站源码(基于PHP和MySQL数据库),包括了传统网站所需的组件。
  • 一台搭建好PHP、MySQL、FTP环境的云服务器
    用于部署网站源码(WordPress),能对外网提供HTTP/HTTPS服务。
  • 一个域名
    用于解析绑定到云服务器,通过域名可以直接访问到云服务器上的HTTP/HTTPS服务。
  • 一个FTP工具
    用于网站源码维护,上传、下载。

源码下载

可以直接到WordPress官网下载:https://cn.wordpress.org/,尽量不要从第三方网站下载。

购买云服务器

最方便快捷的方法是,直接购买阿里云ECS / 腾讯云CVM等大厂的云服务器,相对来说比较稳定可靠。需要说明的一点是,如果购买中国大陆的服务器搭建网站,根据相关法规需要提供个人信息进行备案才能正常使用,但如果购买境外服务器,则不需要备案。区别是两者访问速度差别大,大陆地区服务器在大陆访问速度非常快,如果是境外服务器,在大陆地区访问速度不太理想。当然,如果你的访问客户大部分是在境外的,境外服务器是首选。另外,大厂的一些额外的服务很多都是基于备案的,例如阿里云的CDN、OSS服务等,需要绑定的域名有备案。

一般个人博客类网站,不需要配置太高的云服务器,一般1G单核CPU/1G内存/1M固定带宽/40G硬盘就足够了,具体可以对比几家大厂的云服务器产品,价格大概是600元/年。一般厂商们会不定时做些促销,力度还是很大的,需要自己去研究一下。

在购买云服务器时,一般厂商会提供各种可选的配置供你选择:

如何快速搭建自己的网站

选项包括:地域、配置、镜像。地域是服务器所处的地理位置,尽量选择靠近访问用户地区的服务器,例如用户在厦门地区,可以选择华南地区或者华东地区。其它配置就不深入一一说明了。

需要详细说明的另外一个是镜像。这里的镜像其实就是服务器的操作系统和各种环境,例如上图,我们想用WordPress搭建网站,所以可以直接选择那个镜像,当服务器创建的时候,这个WordPress所需的各种运行环境都会被安装到这台云服务器。当然,如果你对服务器比较熟悉,可以自由选择操作系统和安装各种环境:

如何快速搭建自己的网站

云服务器购买完成后,可以在厂商提供的后台管理界面中看到你购买的那台服务器的所有信息。云服务器会有分配到一个固定的外网IP地址。

如何快速搭建自己的网站

这个固定的IP地址待会需要把你的域名解析到这个外网的IP地址。

如果是选择镜像安装的,去官网找下那个镜像的使用说明书,一般里面会有那个镜像的详细说明,包括镜像里面的PHP版本、FTP、MySQL版本以及安装目录等信息。镜像里面安装的MySQL、FTP账号密码为随机生成的,如果有需要可以自行修改。并记得这些账号密码,待会在安装WordPress的时候需要用到数据库账号和密码。

域名注册

可以考虑购买跟云服务器同一厂商的域名,后期维护/备案都比较方便。一般可以选择注册一些比较常规的域名,例如.com/.cn/.net等。

如何快速搭建自己的网站

域名注册完之后,可以在厂商提供的后台管理中看到你购买的域名:

如何快速搭建自己的网站

点击‘管理’进入域名管理界面,在这里可以设置域名解析到云服务器,点击添加解析,一般需要你填写这几个内容:

如何快速搭建自己的网站

  • 记录类型如果是做网站解析,请选择A记录。
  • 主机记录想要解析的域名前缀,以htmlpage.cn域名为例,主机记录填写www,解析后的网站完整域名是www.htmlpage.cn。主机记录填写@,那么解析后的网站完整域名是htmlpage.cn。
  • 解析线路选择默认即可,或者指定某个运营商网络。搜索引擎特殊也处理可以在这里设置。
  • 记录值这里是填写云服务器的外网IP地址。
  • TTL解析超时时间。

解析设置完成后,会有生成一条解析记录:

如何快速搭建自己的网站

一般保存解析记录完成,会提示你大概多久时间会生效。现在的云解析DNS刷新速度很快,新增记录基本1-2分钟就可以生效。判断解析成功的方法,可以通过ping刚刚解析的域名,看是否已经解析正确:

如何快速搭建自己的网站

另外一个方法是直接把域名放到浏览器去访问。但这种最好是云服务器上的HTTP环境已经搭建完成的情况下试。如果解析成功了,可以进行最后一步,网站的安装。

安装WordPress网站

在安装网站之前,需要准备一个FTP工具,推荐使用FileZilla。

安装网站,这里需要分两种情况:

1> 云服务器的镜像选择的是WordPress镜像,因为里面已经集成了WordPress运行所需的各种环境,在域名解析成功的情况下,直接在浏览器中访问那个域名,然后根据提示操作即可。

2> 云服务器选择的是干净的操作系统,你需要安装完整的:Apache2.4+PHP7.0+MySQL 5.6+phpMyAdmin环境,为了方便维护网站,建议安装FTP组件,并把目录指定到Apache下的web目录。环境安装完成之后,通过FTP将WordPress源码完整放到web根目录下,通过域名访问后根据提示进行安装操作。另外,需要额外设置针对WordPress的rewrite rule。

一切就绪,开始安装!

安装界面,会提示你需要准备哪些信息:

如何快速搭建自己的网站

填写数据库信息,需要注意的是数据库地址,因为我们安装在了web服务同一台云服务器,所以填写localhost即可,其它需要根据自己的账号填写:

如何快速搭建自己的网站

填写网站信息,管理员账号设置,这个管理员账号后面会用来管理这个网站,包括用户管理、文章管理、媒体管理等等:

如何快速搭建自己的网站

以上是主要的设置页面,就不详细一一说明了。

安装成功后,通过刚刚设置的管理员账号录到网站后台:

如何快速搭建自己的网站

WordPress支持安装主题:

如何快速搭建自己的网站

安装成功后,直接访问域名就可以看到皮肤效果了。同时WordPress也支持安装功能性插件进行功能拓展。

网站搭建好啦!

更多设置和功能可以参照WordPress官网文档: https://cn.wordpress.org

原文始发于微信公众号( HTMLPAGE ):如何快速搭建自己的网站