现代前端技术解析:前端三层结构与应用

前端三层结构与应用

前端三个基本结构:结构层HTML、表现层CSS、行为层JavaScript。现在的Web前端应用已经不是简单的三层结构就能轻松解决,而是已经形成了编译流程化、生产环境基础优化结构运行的模式。

HTML结构层

必须要知道的DOCTYPE

HTML4.01是基于SGML(Standard Generalized Markup language,标准通用标记语言)规范来制定的;HTML5不是基于SGML演化而来

  • 严格模式:又称标准模式,是指浏览器按照 W3C 标准解析代码。<!DOCTYPE html ...dtd>
  • 混杂模式:又称怪异模式或兼容模式,是指浏览器用自己的方式解析代码。DOCTYPE 不存在或形式不正确会使用较低的浏览器标准模式来解析整个HTML文本。
/**
 * CSS1Compat 严格(标准)模式:width/height = content;
 * BackCompat 混杂(怪异)模式:width/height = content + padding + border;
 */ 
document.compatMode;

<!DOCTYPE html>的定义(不基于SGML无需DTD)兼容所有HTML的历史版本和最新的HTML5版本,不支持HTML5中的DOCTYPE定义的浏览器仍然会使用HTML4.01等历史版本的兼容模式来进行文档解析。

AMP

流动网页提速(Accelerated Mobile Pages)是Google推出一个提升页面资源载入效率的HTML提议规范。思路:使用严格受限的高效HTML标签,使用静态网页缓存技术来提高网络访问静态资源的性能和用户体验。

  • table是一次性渲染的,如果表格内容较长会导致渲染比较慢!
  • img、video、iframe解析时会立即请求src里面的资源,占用浏览器的下载线程!

一般浏览器对同一个域名支持5-8个并行下载。可以通过分域存放,即可增大并行下载数,同时可以隔离Cookie,减少请求头大小!

AMP通过自定义标签来替换img、video、audio、embed、form、table、frame、object、iframe这类影响页面渲染的标签,通过JavaScript异步加载完成。某种意义上图片懒加载和AMP思想是一致的!

HTML Web Component

面向未来的组件标准,包括四个部分:Custom Elements、HTML Imports、HTML Templates、Shadow DOM。

示例:创建自定义color

<!-- my-color.html -->
<template>
    <style>
        .coloured {
            color: red;
        }
    </style>

    <p>
        My favorite color is: <strong class="coloured">Red</strong>
    </p>
</template>
<script>
    (function() {
        // 根据HTMLElement原型对象创建一个新对象
        var element = Object.create(HTMLElement.prototype);
        // Gets content from <template>
        var template = document.currentScript.ownerDocument.querySelector('template').content;
        /**
         * createdCallback:实例生成时触发
         * attachedCallback:实例插入HTML文档时触发
         * detachedCallback:实例从HTML文档移除时触发
         * attributeChangedCallback(attrName, oldVal, newVal):实例的属性发生改变时(添加、移除、更新)触发
         */
        // 实例生成时触发
        element.createdCallback = function() {
            // 创建Shadow DOM 向用户隐藏细节,直接提供组件;以封装内部样式表,不会影响到外部
            var shadowRoot = this.createShadowRoot();
            // Adds a template clone into shadow root
            var clone = document.importNode(template, true);
            shadowRoot.appendChild(clone);
        };
        // 自定义元素
        document.registerElement('my-color', {
            // 自定义网页元素的原型对象
            prototype: element,
            // 自定义元素继承某种特定的网页元素
            extend: 'h1'
        });
    }());
</script>
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!-- 引入自定义组件 -->
    <link rel="import" href="my-color.html" charset="utf-8">
</head>
<body>
    <my-color></my-color>
</body>
</html>

JavaScript行为层

1999年12月,ECMAScript3发布;2009年12月,ECMAScript5标准发布;2015年6月,ECMAScript6发布;2016年,ECMAScript7发布。JavaScript代码遵循ECMAScript规范。

ECMAScript5

ECMAScript5内容主要包括严格模式、JSON对象、新增Object接口、新增Array接口和Function.prototype.bind。

注意:

Array.prototype.reduce(callback, initalValue)

  • callback(previousValue, currentValue, currentIndex, array)
  • initalValue决定循环次数
    • 无该参数,reduce从index为1开始执行

    ['a', 'b', 'c'].reduce(function(prev, curv){ console.log(prev, curv); return prev + curv; }); // 执行2次【第一次:a b,第二次:ab,c】

    • 有该参数,reduce从index为0开始执行

    ['a', 'b', 'c'].reduce(function(prev, curv){ console.log(prev, curv); return prev + curv; }, ''); // 执行3次【第一次: a,第二次:a b,第三次:ab,c】

ECMAScript6

下面只列举一些常用或者说需要格外注意的ES6语法。所有ES6相关内容请查看 ES6–变量的声明及解构赋值ES6–字符串、正则、数值、数组的扩展ES6–对象、函数的扩展ES6–Set、Map、Symbol、Proxy及ReflectES6–Promise、Generator及asyncES6–Class、Module及常用特性

  • let、const不再挂载到window对象下,不存在提升的问题; console.log(a); // Uncaught ReferenceError: a is not defined let a = 1; console.log(window.a); // undefined
  • 数组新特性Array.from()、Array.of() function test() { console.log(Object.prototype.toString.call(Array.from(arguments))); console.log(Object.prototype.toString.call(Array.of(arguments))); console.log(Object.prototype.toString.call([...arguments])); } test('a', 'b'); // 结果全部为[object Array] Array.prototype.findIndex更灵活的返回某个特定数组元素在数组中的位置。 var ary = [1, 2, 8, 9]; // 只能返回存在的某个元素下标,不能自定义条件 ary.indexOf(8); // 2 // 返回第一个大于5的元素下标 ary.findIndex(function(value) { return value > 5; }); // 2
  • 循环与迭代器Iterator ES6之后,实现遍历的方式又多了几种(注意不要用for…in来遍历数组,在部分浏览器会产生乱序)。map、forEach不能直接跳出整个循环,只能跳出单步循环。最佳方式是使用for…of var ary = [1, 2, 8, 9]; /*forEach*/ ary.forEach((value, index) => { if(!!(value % 2)) return false; console.log(index, value) }); // 只是跳过了2,8、9继续输出 /*for...of*/ var ary = [1, 2, 8, 9]; for(value of ary) { if(value === 2) { break; } console.log(value); } // 只返回1
  • Reflect对象和tail calls尾调用 Reflect可以理解为原有对象上的一个引用代理,它用于对原有对象进行赋值或者取值操作但不会触发对象属性的getter或setter调用(使用=对对象进行赋值或取值操作会自动触发getter或setter方法)。

内存泄漏&异步方法

JavaScript内存泄漏:

(1)闭包函数;(2)全局变量;(3)对象属性循环引用;(4)DOM节点删除时未解绑定事件;(5)Map和Set的属性直接删除;上述都会使内存无法被正常回收,导致内存泄漏。

异步方法:

(1)setTimeout;(2)事件监听;(3)观察者模式;(4)$.Deferred;(5)promise;(6)generator;(7)async/wait;(8)第三方async库等。

CSS表现层

类别

权重

!important

最高

内联style

1000

#id

100

.class

10

name

1

优先级高的会覆盖优先级低的;相同优先级书写在后面的会覆盖前面的!

<div id="content" class="blue">test</div>

<style type="text/css">
  #content { /*100*/
    background-color: red;
  } 
  body div.blue { /*1+1+10*/
    background-color: blue;
  }
  body .blue { /*1+10*/
    background-color: green;
  }
</style>

CSS伪类和伪元素

  • 伪元素会在HTML中添加before或after之类内容;
  • 伪类表示元素在用户不同操作下的状态或者选择指定某些元素的描述,如:visited、:hover、:first-child、:nth-child、:enable、:checked

CSS样式统一化

实现样式统一化的三种思路:reset、normalize、neat

  • reset将不同浏览器中标签元素的默认样式全部清除,清除不同浏览器下默认样式的差异; body, div, span, ...{ margin: 0; padding: 0; }
  • normalize在整站样式基本确定的情况下对标签元素统一使用同一个默认样式规则; body, p, ul, ol, ...{ margin: 5px; padding: 5px; }
  • neat是上述两者的结合。

预处理技术

通过编写更高效、易管理的类CSS脚本并将它们自动生成浏览器解释执行的CSS代码,实现高效开发和便捷管理。常见的有SASS、LESS、POSTCSS。

以SASS为例,主要包括模块引用、嵌套、父级选择符、变量、运算、函数、篡写、指令、mixin、继承等属性。**函数和mixin区别:**mixin的内容会被全部填充到引入的元素代码里面,而function函数只做过程处理并输出。

动画实现

通常实现动画的方式有如下几种:(1)JavaScript直接实现动画;(2)可伸缩矢量图形SVG动画;(3)CSS transition;(4)CSS3 animation;(5)Canvas动画;(6)requestAnimationFrame。

人眼能辨识的流畅动画为每秒60帧,1000ms/60=16ms可以用来JavaScript中setInterval(() => {}, 16)的间隔时间!

  • JavaScript直接实现动画是通过JavaScript的setInterval或setTimeout方法的回调函数来持续调用改变某个元素的CSS样式以达到元素样式持续变化的结果【会导致页面频繁重排重绘,很耗性能】;
  • SVG内部元素的动画只能在元素内进行,超出<svg>标签元素,就可以认为是超出了动画边界;
  • transition不能实现独立的动画,只能在某个标签元素样式或状态改变时进行平滑的动画效果过渡,而不是马上改变;
  • CSS3 animation可以认为是正真意义上的CSS3动画,通过对关键帧和循环次数的控制【脱离JavaScript控制,能用到硬件加速】;
  • Canvas动画通过JavaScript API实现,同SVG一样超出元素(<camvas>)边界将不被展示;
  • requestAnimationFrame通过JavaScript持续循环的方法调用来触发动画动作,同setInterval,其是浏览器针对动画专门优化而成的API。

响应式网站开发技术

通常认为,响应设计是根据不同设备浏览器尺寸或分辨率来展示不同页面结构、行为层、表现层的设计方式。目前主流的实现方式:(1)通过判断userAgent来跳转到不同页面完成不同设备浏览器的适配,即维护两个不同站点来根据用户设备进行相应的跳转;(2)使用media query媒体查询手段,让页面根据不同设备浏览器自动改变页面的布局和显示,不需要跳转。

通常我们在选择方案时,需要考虑下面几个问题:

  • 能否使用同一个站点域名避免跳转;
  • 能否保证移动端加载的资源内容最优;
  • 如果做移动端和桌面浏览器的差异化功能;
  • 如果根据更多的信息进行更加的灵活判断,而不仅仅依靠userAgent。

结构层响应式

根据不同的设备浏览器渲染不同的页面结构,而不是直接跳转。可以通过下述两种方式:一是页面内容在前端渲染;二是页面内容在后端渲染。

数据内容响应式

首先要确保以移动端优化资源为主,保证移动端页面的首屏内容优先加载,然后通过异步的方式来实现桌面端或移动端剩余内容的加载。

let isMobile = navigator.userAgent.match(/iPhone|iPad|Android|iPad/i);
if(isMobile) {
  require.async(['zepto', './mobileMain'], function($, main) {
    main.init();
  });
}else {
  require.async(['jQuery', './main'], function($, main) {
    main.init();
  });
}
后端数据渲染响应式

通过URL或者UA判断设备,尽可能将桌面端和移动端的业务层模块分开维护。这样既能复用共同的基础组件,还可以差异化开发不同的业务组件。JavaScript和CSS资源完全分开加载,实现了两个端加载内容的相互对立。

let isMobile = this.headers["user-Agent"].match(/iPhone|iPad|Android|iPad/i);
if(isMobile) {
  res.body = yield render('pages/mobile/main', {
    data: pageData
  });
}else {
  res.body = yield render('pages/pc/main', {
    data: pageData,
    moreData: moreData
  });
}
媒体响应式

目前主要网站60%以上的流量数据都来自图片,确保不影响用户体验的前提下尽可能降低图片的输出流量具有很重要的意义。

(1)使用Media query背景图片替换

/* 默认使用1.JPG,小于500px使用2.JPG */
.img {
  background-position: center center;
  background-image: url('1.JPG');
}
@media only screen and (max-width :500px) {
  .img {
    background-image: url('2.JPG');
  }
}

(2)Picture标签元素

<!-- 默认使用1.JPG,小于500px使用2.JPG -->
<picture>
  <source media="(max-width: 500px)" srcset="2.JPG">
  <source srcset="1.JPG">
  <img srcset="1.JPG" alt="My default image">
</picture>

(3)模板判断响应式图片

{% if isMobile %}
    <img src='2.JPG'>
{% else %}
    <img src='1.JPG'>
{% endif %}

(4)图片服务器判断输出内容

浏览器访问图片服务器时带上浏览器UA或者URL参数信息,判断返回相关图片。

表现层响应式

响应式布局。

响应式布局是根据浏览器宽度、分辨率、横屏、竖屏等情况来自动改变页面元素展示的一种布局方式,一般使用栅格方式来实现;

<style>
.row {
  width: 100%;
}
.row .col-1 {
  width: 25%;
}
.row .col-2 {
  width: 50%;
}
.row .col-3 {
  width: 75%;
}
.row .col-4 {
  width: 100%;
}

/* 屏幕分辨率为1280 */
/* 如果小于640px, 一排显示两个 */
@media screen and (max-width: 640px){
  .row .col-1 {
    width: 50%;
  }
  .row .col-2, .row .col-3 {
    width: 100%;
  }
}
/* 如果小于414px, 一排显示一个 */
@media screen and (max-width: 414px){
  .row .col-1{
    width: 100%;
  }
}
div {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  border: 1px solid rgba(86,61,124,.2);
  float: left;
  background-color: rgba(86,61,124,.15);;
}
div.row {
  border: 0;
}
</style>

<div class="row">
  <div class="col-1">.col-1</div>
  <div class="col-2">.col-2</div>
  <div class="col-3">.col-3</div>
  <div class="col-4">.col-4</div>
</div>
屏幕适配布局

屏幕适配布局是为了实现网页内容根据移动端设备屏幕大小等比例缩放所提出的一种布局计算方式。通常依据HTML中<html>标签元素的zoom属性缩放和根据REM自适配方案实现等比例缩放。

(1)zoom属性控制方案

​ 如果希望在320px宽度屏幕上显示的内容在414px的宽度屏幕上进行等比例自动放大,可以考虑使用元素CSS的zoom属性来解决。document.body.style.zoom = screen.width/320;通常使用JavaScript计算得出,如果JavaScript在页面渲染之后完成,则会出现页面内容全部重排情况。

(2)REM屏幕适配方案

​ CSS大小尺寸的表示单位主要有像素px、相对父元素大小百分比%、相对于当前对象内文本字体font-size的大小em、相对于文档根元素font-size的大小rem。

​ 如果给HTML根元素一个根据屏幕自动调整的font-size,页面上所有元素的尺寸全部以rem为单位,无论屏幕宽度怎样变换,页面的内容和屏幕的比例将始终不变,实现了页面根据屏幕自动缩放。

1rem = 屏幕宽度*屏幕分辨率/10这样得到的1rem恰好是屏幕宽度的10%。

1rem = 屏幕宽度/320*10这样1rem在宽度320px的屏幕上表示的是10px。

行为层响应式

和结构层类似,行为层的响应式同样分为JavaScript内容在前端引入和在后端引入两种情况。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券