六月底便辞去本地电商公司的职位,原因是:
开发人员单打独斗,经理对发展方向把握不准,需求经常改动,规划混乱;初期饼画得无限大,后来不了了之。
之后几个月都在家学习,温习以前的项目,再作求职准备;
八月初才想起来要找工作,边投边学习。然而在三线城市找 IT 职位是很难的,只有外包、网站建设的、电商、网商公司在招,工资并不是很理想。

所以说年轻也不知天高地厚的我就跑去广州,面了一家公司,面试时拿出项目代码,面试官从比较高的角度评价了我当前的水平,指出了没有模块化,网络请求写得到处都是,很多地方也受到了 提点,应付式地随便问了几个问题就让我回去了。多少有点打击了我的自信心,只好在本地城市再找找看。

第一家是一线城市的软件外包设在这边的开发部门,刚迁进这边的写字楼,开始招人。面试的时候还顶着楼上冲击钻声在谈话,太尴尬了。给的笔试题是前端 + Java 后端的题,因为准备不充分,掂量过后觉得答对的也没多少。笔试后经理过来面试,见试题没做多少,随便问几个问题,答了对方好像没啥反应,就让我回去了。

第二家是做本地网站建设的科技信息公司,离住的地方比较近,看了下技能也挺符合;
网站上回了我隔天面试,那天到公司附近时竟告诉我,等人事先看过简历后再通知我来面试,后来还是上去谈了一会儿。经理过来面试,技术问题没问多少,谈了下我的项目经历和未来的发展,又是喊我回去等通知,看态度并不像在招人,后来也没了消息。

第三家也是香港软件外包,在本地设的工作室,人事面,我说完经历和发展之后,对方迟迟不能描述清楚技术栈,一直在强调 H5。不过和电话里头老板谈了下,是混合式开发App 的技术,我表示没做过但有信心尝试。对方便同意让我试试,隔几天过来上班。第一天, iOS 开发便说使用 Framework7 作为混合式框架开发进销存系统的移动版,系统操作和功能与之前任职公司的进销存相差无几。上午花了点时间搭了个环境,下午看着文档和需求便撸了个 Demo,中间人事过来问两句进度怎样,便答了她:“在看文档,暂时没用过这框架”,回头看她脸色大变,双方沉默了。
隔天,在思考着怎么拿着原型来布局时,便被人事喊去,以能力不足为由辞退了。真是莫名其妙。

第四家是鹤山市一家做壁画的公司,人事面试的时候见我不是本地人,各种查户口,各种担心我是小屁孩生活不能自理,让我再三考虑再过来;技术面的时候倒是没啥问题,待遇不怎么好,社保要半年后才购买;老板面试上来也是各种问是不是本地人,各种查户口。最后人事还叮嘱我说要不要再考虑下再应聘这个工作。一路上回去简直气炸,已经不考虑这公司了。

第五家是本地的一家产业园区运营管理的公司,上来是技术面试,简单地向面试官介绍我的经历,得知公司项目是外地开发后的项目放到这里来维护,目前就面试官一人做全栈在维护,所以公司想招一位前端且偏向设计;隔天让我去面领导,我都还没介绍完自己,便说我做的页面设计太难看,没有设计;我说这我真没办法,不是我能操作的范围;领导直接说其实现在很设计都会前端,你这样的产品太难看了不行。我们无奈地聊了几句,就让我回去了。

第六家是佛山市的一家不锈钢电商公司,求职软件中 HR 邀我去面试,找到他家产品做了些功课隔天就准备好行程,面谈时才得知是开发之前与外包合作开发的 B2B 商城,但技术不在,只是问了一些其他问题,让我下周再来一次面技术;一周后便跟 HR 确认技术在才过去,结果第二次过去时HR 连忙抱歉说 技术却因生病没能来,让老总来面我(看眼缘),随便聊几句便让 HR 送我走,告诉我可能还要来一次才能面技术;我觉得很气愤连忙笑了笑说好就离开了。一周后去了广州便拒了三面。

后来跟朋友打听了下,朋友那边正招人,和那边前端老哥聊了几个问题,便让我过广州一趟;(起初还没自信,犹豫不决;面我的是个后台大哥,语气挺和蔼,上来先问怎么接触该职业,工作经历、前端基础、与后端合作的问题。在话题上大家都挺聊得来,也听了当前公司的情况;让我下周再来一次领导的复试。隔周领导问了些普通的问题之后便收到了 Offer ;

当然,可能该岗位降低了要求和有人内推才让我入选,也算是个幸运的事情吧。经对比与前几次面试经历有很大的反差,连我自己也不敢相信如此顺利。

后记,转眼间已在广州工作三个月,虽然因为能力和经验不足难免会用很多时间去解决一些小问题,经过阅读以前项目的代码,让我受益匪浅,前端老哥也给了许多意见,后台大哥也非常和蔼,总之一切都很正常,总监计划的开发周期也非常足,非常感谢能遇到如此好的公司和同事。

ThinkPHP 内置的模板引擎来定义模板文件,以及使用加载文件、模板布局和模板继承等高级功能。

每个模板文件在执行过程中都会生成一个编译后的缓存文件,其实就是一个可以运行的 PHP 文件。

引用自 http://www.kancloud.cn/manual/thinkphp5/118122

开门见山

PHP

/*index/controller/example.php*/

use thinkController;

class test extends Index {

    public function template (){
        $name = 'Jerry';
        $allName = [
            0 => "Jerry",
            1 => "Tom"
        ];

        $this->assign('nameA',$name);
        $this->assign('allNameA',$allName);

        return $this->fetch('example');
    }
}

HTML

/*index/view/example.html*/

<span>{$nameA}</span>

{volist name="allNameA" id="vo"}
    
    <p data-sub="{$key}" data-index="{$i}">{$vo}</p>

{/volist}

Result


<span>Jerry</span>

<p data-sub="0" data-index="1">Jerry</p>

<p data-sub="1" data-index="2">Tom</p>

这样 ThinkPHP 便完成了对页面的解析工作,其中涉及到 模板实例化、定位、赋值、渲染及标签的使用。


视图实例化

暂无

模板赋值

显然在在模板中直接使用 $name 是找不到该变量的。必须使用 assign 方法对模板赋值。在执行渲染输出函数前,assign 方法使 函数内部变量与模板变量建立起映射关系。

$this->assign('nameA',$name);
$this->assign('allNameA',$allName);

通过赋值之后,便可以使用自定义的 {$nameA} 来输出该变量了。

模板渲染

当数据已经准备好渲染到页面上,还需要指定 html 文件作为渲染模板,为当前函数执行 fetch 方法时候传入 example 参数。

 return $this->fetch('example');//example is a html file.

模板标签

在模板文件中使用的内置标签可以帮助我们在模板中循环、判断变量,它以一对花括号 {tagName} {/tagName}作为开标签和闭标签。 标签的{}之间必须紧跟标签属性或值,存在 空格换行不能被正常解析。

volist 标签就是内置标签中的其中一个,通常用来循环某个数组变量。

{volist name="allNameA" id="vo"}
    <p data-sub="{$key}" data-index="{$i}">{$vo}</p>
{/volist}

allName 是通过模板赋值的变量 ,现在可以在模板上直接使用了,显然它是一个数组,volist 标签对它做了循环操作。

volist 标签常用的一些属性:

propArray NameCurrent Ele
keynameid
valueallNamevo

隐藏在 volist 中的有几个内部变量 {$key} {$i} ,分别代表了 数组下标循环次数
volist 一样好用的内置标签还有很多:

内置标签

比较功能:
{eq name="data.status" value="0"}
    0
    {else/}
    not equal 0
{/eq}

eq 标签像是一个 if 语句,同样能判断变量的值是否相同;而 neq 标签则相反。

条件判断功能:
{switch name="data.status"}
    {case value="0"}0{/case}
    {case value="1"}1{/case}
    {case value="2"}2{/case}
    {default /}10
{/switch}

switch 标签否相等。
比较 data.status 对象中 status 的值是否等于 value的值,等于则执行对应标签内的内容;
若所有 {case} 都不符合,则执行 {default /}

{if condition="boole_one"} value1
    {elseif condition="boole_two"/}both
    {else /}nothing
{/if}

当然还有复杂一点的 if 标签,用于判断复杂表达式是否成立。

其他:
//HTML
{assign name="username" value="Tom" /}

<p>{$username}</p>

assign 标签能在渲染模板时在模板中声明变量,以便在渲染时直接使用。该标签往往配合其他标签使用。

{notempty name="username"}{/notempty}

notempty 判断 username 变量是否存在, 不存在则进入下一层

{empty name="username"}{/empty}

empty 判断 username 变量是否存在, 存在则进入下一层

显然,相互嵌套的标签可以达到逻辑控制的效果,避免重复编写模板文件。


模板继承

在开发后台系统时,可能非常多管理页面都是基于一个共同的布局。侧边栏、顶部栏、页脚都是相同的布局,这些代码可以共用一个页面文件,使用 {block}{/block} 标签可以实现。

不妨先写一个基础的模板:

//base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    {block name="style"}
    {/block}
</head>
<body>
    <div class="wrapper">
        {block name="wrapperHeader"}
        {/block}

        {block name="content"}
        {/block}

        {include file="Public:footer" /}
    </div>
    {block name="script"}
    {/block}
</body>
</html>

base.html 中编写好后台页面的整体结构, 页面中有时候不止有一个 block 块,在不同位置可以插入样式、内容或者脚本,这很大的原因决定于一些前端页面的规划,比如基于 bootstrap 框架的 AdminLTE

对于 {block name="content"}{/block} 来说,在控制器中 fetch("example") 页面时,example.html 得先通过 {extend} 声明是要继承 base.html 页 。

//example.html
{extend name="Public:base" /}

{block name="content"}
    <section class="content">
        <p>This is example.html</p>
    </section>
{/block}

在约定好的地方使用 {block name="content"}{/block} 以替换 .wrapper 下的 content 块。

继承事先写好的 base.html ,这种用法在编写模板页文件时会减少非常多的代码量。

//result base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div class="wrapper">
        <section class="content">
            <p>This is example.html</p>
        </section>
    </div>
</body>
</html>

引入模板

啥? {block} 不够强力? {include /} 可能是拆分模板的好方法。

当业务中需要查看当前的详细信息时,信息页往往由非常多数据组成。如果按照权限划分,显示给用户是不同的一些信息,出现的可能性将会更多。

直接在模板中引入其他模板文件,诸多模板文件成为了组件,减少了模板之间的冗余。

//exampleOrder.html
<section class="content">
    <!--orderInfo-->
    {include file="Public/order/orderInfo"/}
    <!--orderTableCount-->
    <div class="box">
        {include file="Public/order/orderTableCount"/}
    </div>
    <div class="row">
        <!--orderRecord-->
        {include file="Public/order/orderRecord"/}
        <!--orderImage-->
        {include file="Public/order/orderImage"/}
    </div>
</section>

Public/order 目录下的模板文件 orderInfoorderTableorderRecordorderImage 都被引入到了 exampleOrder.html 中。

orderInfo.html

<p>this is a order info page.</p>

orderRecord.html

<p>this is a order record page.</p>

orderImage.html

<p>this is a order image page.</p>

orderTable.html

<table class="table table-bordered table-hover">
    <tbody>
    <tr>
        <th>Name</th>
        <th>Age</th>
        <th>Country</th>
    </tr>
    {volist name="list" id="vo"}
    <tr>
        <td>{$vo.name}</td>
        <td>{$vo.age}</td>
        <td>{$vo.country}</td>
    </tr>
    {/volist}
    </tbody>
</table>

在被引入的页面中可以正常使用任何的 模板标签 或继续 引入 其他模板。

这样通过引用固定的模板,避免多个相同的页面存在,往后修改一处地方,引用该页面的模板也会做出相应的变动,对业务系统的修改起来非常省心。

如果渲染的父页面存在差异性,在父页面编写差异代码,则需继续细化引入的子页面,子页面再 {include /} 子页面能解决问题,但这会增加模板文件的数量。

<!--result exampleOrder.html-->
<section class="content">
    <!--orderInfo-->
    <p>this is a order info page.</p>
    <!--orderTableCount-->
    <div class="box">
        <table class="table table-bordered table-hover">
            <tbody>
                <tr>
                    <th>Name</th>
                    <th>Age</th>
                    <th>Country</th>
                </tr>
                <tr>
                    <td>Jane</td>
                    <td>13</td>
                    <td>USA</td>
                </tr>
                <tr>
                    <td>xiaoMing</td>
                    <td>14</td>
                    <td>China</td>
                </tr>
            </tbody>
        </table>
    </div>
    <div class="row">
        <!--orderRecord-->
        <p>this is a order record page.</p>
        <!--orderImage-->
        <p>this is a order image page.</p>
    </div>
</section>

思考与抉择

放眼一看,模板嵌套和模板引入都能实现差不多的需求,却是存在不同的差异。

模板继承 {block} 渲染(fetch)的是一个子页面,子页面继承了原有的主体框架。

引入模板 {include /} 渲染的是一主页面,在主页面中引入子页面来共同组成一个新页面。

当然,渲染页面不仅仅局限于这来两个种方案,还有非常多的组合方式。

在传统 MVC 应用中,页面的渲染功能往往交由后端完成,模板引擎具有的一些功能使得渲染页面变得更加方便,这意味着前端的任务仅仅是编写 HTML + CSS + JavaScript 组合式的代码吗? 为了进一步提升用户交互,我们有了 Ajax iframe,可是在前端并不满足处于被动状态的视图渲染方式。

早些年,一些前端应用框架逐渐发展起来,企图夺取页面的渲染权,掌管与后端的数据交换,为复杂的单页面应用提供驱动。这样,前端应用变得更像移动端的 App 一样百花怒放。

Vue.js 便是一款前端现代化框架。

 title= Select2

官方文档
Github
感谢两位作者 Kevin Brown & Igor Vaynberg

原生 <select> 标签没有 美化和 DOM 事件,没有模糊搜索,从后端获取数据时要自行插入选项,小码农真是伤不起。于是在 AdminLTE 中找到一款叫 Select2 的 jQuery 插件。它支持多语言、远端数据搜索、选项分页。这一切还基于简洁易懂的 jQuery。


快速使用

1.在 <head> 标签内加入 CDN 地址,当然别忘了这玩意需要 jQuery

<link href="https://cdn.staticfile.org/select2/4.0.3/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/select2/4.0.3/js/select2.min.js"></script>

2.使用 <select> 标签来初始化该插件:

HTML

<select>
    <option value ="volvo">Volvo</option>
    <option value ="saab">Saab</option>
    <option value="opel">Opel</option>
    <option value="audi">Audi</option>
</select>

JavaScript

$(document).ready(function() {
    $('select').select2({
        placeholder:'Select a state',
    });
});

Result


往往在项目中会遇到更复杂的需求,比如通过搜索关键字提交到后端,获取返回的数据到本地渲染再进行选取。

通过搜索仓库内商品的货号或条形码甚至是品名,从后端获取一个 JSON 对象,交给 Select2 内置的函数渲染成下拉列表, 编写对应的选择事件,完成整个组件的交互。

约定

API 接口是前后端交换的一种方式,使用 JSON 数据格式,以多个或者单个对象形式返回对象数组。这些数据直接返回至 Ajax 。栗子:

return.json

{
  "119": {
    "id": "119",
    "name": "Apple",
    "price": "12"
  },
  "120": {
    "id": "120",
    "name": "banana",
    "price": "8"
  }
}

官方的栗子

先来看看官方是怎么运用 jQuery's AJAX 来获取并处理数据给 Select2

后面我们实现自己的案例时可以上面约定好的 return.json 数据格式暂时取代后端提供的 API 。

这里的代码引用了官方的栗子 http://select2.github.io/examples.html

$(".js-data-example-ajax").select2({
  ajax: {
    url: "https://api.github.com/search/repositories",
    dataType: 'json',
    delay: 250,
    data: function (params) {
      return {
        q: params.term, // search term
        page: params.page
      };
    },
    processResults: function (data, params) {
      params.page = params.page || 1;

      return {
        results: data.items,
        pagination: {
          more: (params.page * 30) < data.total_count
        }
      };
    },
    cache: true
  },
  escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
  minimumInputLength: 1,
  templateResult: formatRepo, // omitted for brevity, see the source of this page
  templateSelection: formatRepoSelection // omitted for brevity, see the source of this page
});

传入的参数

ajax

传入的 ajax 对象的某些属性与 jQuery's AJAX 非常相似:

url API 请求的地址

dataType 数据类型

delay 每次键入至请求时的延迟时间

data API 请求的地址时带上的参数

processResults API 返回数据的处理函数

cache 缓存?

escapeMarkup
minimumInputLength
templateResult
templateSelection

百度 IFE 春季班第二阶段任务总结

标签(空格分隔): HTML CSS JavaScript

百度前端技术学院 (Baidu Institute of Front-End Technology)是一个面向大学生的前端技术学习平台。在这里通过思考完成编码任务,总结编码中的知识点,审查他人的代码来提升学习效率与效果,帮助开发者们更加高效、系统地学习Web前端技术。

本人选择了 任务十三~二十一 二十九~三十二 完成学习第二学习阶段。


任务十三:零基础JavaScript编码(一)

任务描述

  • 参考以下示例代码,补充其中的JavaScript功能,完成一个JavaScript代码的编写
  • 本任务完成的功能为:用户可以在输入框中输入任何内容,点击“确认填写”按钮后,用户输入的内容会显示在“您输入的值是”文字的右边

任务注意事项

  • 实现简单功能的同时,请仔细学习JavaScript基本语法、事件、DOM相关的知识
  • 请注意代码风格的整齐、优雅
  • 代码中含有必要的注释
  • 可以不考虑输入的合法性
  • 建议不使用任何第三方库、框架
  • 示例代码仅为示例,可以直接使用,也可以完全自己重写

Demo | Sourse

任务总结

Document.querySelector()

//element = document.querySelector(selectors);
var get = function (name) {
    return document.querySelector(name);
}

name 是一个字符串,可以是一个或多个 CSS 选择器,多个用逗号分隔。

//elementList = document.querySelectorAll(selectors);
var getAll = function (name) {
    return document.querySelectorAll(name);
}

自定义 get 函数返回 querySelect

parseInt()

//parseInt(string, radix);
var num = parseInt(get("#aqi-input").value);

parseInt() 函数将给定的字符串以指定基数(radix/base)解析成为整数。从输入框取得值经过 parseInt() 处理返回一个十进制数。默认为十进制。

isNaN()


//isNaN(testValue);
if ((!isNaN(num)) && (num >= 0)) {}

isNaN() 函数用来判断一个值是否为 NaN。正常应取反该函数即为真。

GlobalEventHandlers.onclick


//object.onclick=function(){};
get("#button").onclick= function () {}

  1. onclick 事件会在元素被点击时发生、onkeyup 事件会在键盘按键被松开时发生。
  2. HTML中使用属性 onclick="Code"onclickonkeyup 等属于 HTML DOM 事件。
  3. 不过直接使用 element.onclick 该对象的相应时间会被该对象相同的事件覆盖,使用 target.addEventListener(type, listener[, options]){} 可以解决。
if (even.keyCode == 13) {}

even.keyCode 能判断当前哪个按键被敲下。

参考资料


任务十四:零基础JavaScript编码(二)

任务描述

  • 参考以下示例代码,页面加载后,将提供的空气质量数据数组,按照某种逻辑(比如空气质量大于60)进行过滤筛选,最后将符合条件的数据按照一定的格式要求显示在网页上

任务注意事项

  • 实现简单功能的同时,请仔细学习JavaScript基本语法、事件、DOM相关的知识
  • 请注意代码风格的整齐、优雅
  • 代码中含有必要的注释
  • 其中的数据以及60的判断逻辑可以自行设定
  • 建议不使用任何第三方库、框架
  • 示例代码仅为示例,可以直接使用,也可以完全自己重写

Demo | Sourse

任务总结

排序(冒泡排序)

//arr.sort([compareFunction])
aqiData.sort(function (a, b) {
    return b[1] - a[1];
});

Array.prototype.sort()

sort() 方法可对数组进行排序,返回一个新的排序后的数组。参数compareFunction是用来指定按某种顺序进行排序的函数

如果省略,那每个元素都会转换为字符串,然后按 Unicode 位点进行排序。

compareFunction(a, b) 函数接受要排序的数组元素,需要返回的值后作为sort 排序依据。

如果 compareFunction(a, b) 返回的值小于 0 那么 a 会被排列到 b 之前;

返回的值等于 0 那么 a b 保持原来的位置;

返回的值大于 0 那么 b 会被排列到 a 之前。

示例

举个栗子:

function sortNumber(a, b) {
  console.log(a + "-" + b + "=" + (a - b))
  return a - b
}

var nunber = [
  '10',
  '5',
  '40',
  '25',
  '1000',
  '1'
];

console.log(nunber.sort(sortNumber));

// Console 
// 5 -30 15 -15 -960 999 39 24 9 4
// sort return new array 
// ["10", "5", "40", "25", "40", "1000"]


sort 函数会将 nunber数组的元素按顺序两两地传入自定义的 sortNumber 函数中。处理后返回 正负或零 ,作为sort 函数排序的依据。

首先元素a = 10 b = 5 会计算差值,返回值 5 传入到sort 函数中。已知 a - b = 5 大于零a b 将调换他们的值。

经第一次处理后nunber 数组变成:

  ['5','10','40','25','1000','1']


下一次将比较 10 - 40 = -30 小于零,他们的相对位置保持不变 :

  ['5','10','40','25','1000','1']


下一次:

  ['5','10','25','40','1000','1']


其实每次排序都保证了新数组靠前的值的 Unicode 位点一定比后一位小或相等,最后产生一个升序的新数组:

["10", "5", "40", "25", "40", "1000"]


所以栗子中 自定义的 sortNumber 函数是保证排序顺序的依据,要实现降序的功能也一样简单:

//降序排列
function sortNumber(a, b) {
  return b - a
}


image

其中数组 nunber 是一个多维数组,其中包含了 6 带有两个元素的数组。 第一个元素是 城市名字符串,第二个是整数值。

读取数组的元素, 6 个元素但下标从 0 开始 ,最后一位是 5 。所以 i 最大值5

aqiData[i][0] 可读取城市名 北京

aqiData[i][1] 可读取污染整数值 90

参考资料


任务十五:零基础JavaScript编码(三)

任务描述

  • 参考以下示例代码,读取页面上已有的source列表,从中提取出城市以及对应的空气质量
  • 将数据按照某种顺序排序后,在resort列表中按照顺序显示出来

任务注意事项

  • 实现简单功能的同时,请仔细学习JavaScript基本语法、事件、DOM相关的知识
  • 请注意代码风格的整齐、优雅
  • 代码中含有必要的注释
  • 建议不使用任何第三方库、框架
  • 示例代码仅为示例,可以直接使用,也可以完全自己重写

Demo | Sourse

任务总结

getAll('#source li')[i].innerText.slice(0, 2).toString();用于取得 HTML DOM中某段文字

String.prototype.slice()

slice() 方法用于截取字符串中的一部分,返回一个新的字符串。

语法 str.slice(beginSlice[, endSlice])

  • beginSlice 从索引 0 为基数,负数则从开头一个字符串开始计算截取的字符串。
  • endSlice 省略时默认会截取到字符串最后一位。负数则从末尾开始计算截取的字符串。

Array.prototype.slice()

Object.prototype.toString()

toString() 方法返回一个表示该对象的字符串。

语法 object.toString()

var o = new Object();
o.toString();           // [object Object]

var arr = new Array();
arr.push("NewValue");
arr.toString();         // "NewValue"

var s = new String("Hello");        
s.toString();           // "Hello"

String 对象 与 基本数据类型


String("test") === new String("test"); // false;
String("test") === String("test"); // true;


new String创建的是字符串对象,String(a)返回的是基本类型。

a = "test"
a.b = "bar"
alert("a.b = " + a.b); //undefined

A = new String("test");
A.b = "bar";
alert("A.b = " + A.b); // bar


当调用方法的时候普通字符串会自动包装成字符串对象,所以也可以调用对应的方法,只是表现上看起来像是方法,但是总的来说还是有区别的。

var s0 = 'hello';
var s1 = new String(s0);
var s2 = String(s0);
console.log(s1 === s2); // false
console.log(s1 === s0); // false
console.log(s2 === s0); // true
s0.foo = 'bar';
s1.foo = 'bar';
s2.foo = 'bar';
console.log(s0.foo); // undefined
console.log(s1.foo); // bar
console.log(s2.foo); // undefined



以上栗子很好地说明了它们之间的区别。

Math

Math 是一个内置对象, 所有属性和方法都是静态的,为数学常量和数学函数提供了属性和方法,而不是一个函数对象。它的更多属性和方法可以参考:

Math - JavaScript | MDN

Math.E 属性中值为欧拉常数。

其它的属性中储存了一些常用的常数。

Math.abs(x) 函数返回指定数字 “x“ 的绝对值。

传入一个非数字形式的字符串或者 undefined/empty 变量,将返回 NaN。传入 null 将返回 0。

Math.abs('-1');     // 1
Math.abs(-2);       // 2
Math.abs(null);     // 0
Math.abs("string"); // NaN
Math.abs();         // NaN



Math.round() 把一个数字舍入为最接近的整数。直接使用该方法则返回一个小于1的有限位小数。

Document.createElement()

Document.createElement() 方法用于创建指定的HTML元素。

语法 var element = document.createElement(tagName[, options]);

element 指被创建的 Element 对象

Document.createTextNode()

同理,创建一个文本节点

语法 var text = document.createTextNode(data);

Node.appendChild()

Node.appendChild() 方法将一个节点添加到指定父节点的子节点列表末尾。

语法 var child = node.appendChild(child);

  • node 是要插入子节点的父节点。
  • child 即是参数又是这个方法的返回值。

创建一个新的段落p元素和它的文本节点,然后添加到body的最尾部

var pText = document.createTextNode("new Text");
var p = document.createElement("p");
p.appendChild(pText);
document.body.appendChild(p);



Node.cloneNode()

Node.cloneNode() 返回调用该方法的节点的一个副本。

语法 var dupNode = node.cloneNode(deep);

  • node 要被克隆的节点
  • dupNode 克隆所生成的副本节点
  • deep 默认为深度克隆,所有后代节点也都会被克隆,如果为false,则只克隆该节点本身。

为防止 复制后的节点在同一文档内 id name 冲突,没法重新选取元素或其他操作。

对于新拷贝的副本对象 dupNode 应该使用 Element.setAttribute() 修改其 id name值。

参考资料


任务十六:零基础JavaScript编码(四)

任务描述

  • 参考以下示例代码,用户输入城市名称和空气质量指数后,点击“确认添加”按钮后,就会将用户的输入在进行验证后,添加到下面的表格中,新增一行进行显示
  • 用户输入的城市名必须为中英文字符,空气质量指数必须为整数
  • 用户输入的城市名字和空气质量指数需要进行前后去空格及空字符处理(trim)
  • 用户输入不合规格时,需要给出提示(允许用alert,也可以自行定义提示方式)
  • 用户可以点击表格列中的“删除”按钮,删掉那一行的数据

任务注意事项

  • 实现简单功能的同时,请仔细学习JavaScript基本语法、事件、DOM相关的知识
  • 请注意代码风格的整齐、优雅
  • 代码中含有必要的注释
  • 验证输入逻辑可以在失去焦点时判断,也可以在点击按钮时判断
  • 建议不使用任何第三方库、框架
  • 示例代码仅为示例,可以直接使用,也可以完全自己重写

Demo | Sourse

任务总结

Array.prototype.forEach()

for...in

以任意序迭代一个对象的可枚举属性。
for...in 会迭代使用内置构造函创建出来的对象,
ArrayObject 对象,都会继承自
Object.prototypeString.prototype 的不可枚举属性,
例如 StringindexOf() 方法或者 ObjecttoString 方法。

语法 for (variable in object) {...}

  • variable 每次迭代,一个不同的属性名将会赋予 variable
  • object 可枚举属性被迭代的对象

    var obj = {a:1, b:2, c:3};
        
    for (var prop in obj) {
      console.log("obj." + prop + " = " + obj[prop]);
    }
    
    
    // Output:
    // "obj.a = 1"
    // "obj.b = 2"
    // "obj.c = 3"



**不建议使用 for...in 对 数组进行遍历操作,因为其原型方法也会被遍历出来,
虽然用 Object.prototype.hasOwnProperty() 可以把其自身属性检测出来。**

    for (var prop in obj) {
        if(obj.hasOwnProperty(prop)){
            console.log("obj." + prop + " = " + obj[prop]);
        }
    }



String.prototype.match()

当字符串匹配到 正则表达式 时,match() 方法会提取匹配项。

语法
str.match(regexp);
参数
  • regexp
    一个正则表达式对象。如果传入一个非正则表达式对象,则会隐式地使用 new RegExp(obj) 将其转换为正则表达式对象。
返回
  • array
    一个包含匹配结果的数组,如果没有匹配项,则返回 null
    if (!city_name.match(/^[A-Za-z\u4E00-\u9FA5]+$/)) {
        alert("城市名必须为中英文字符!");
        return;
    }


city_name.match() 返回了匹配到的中英文字符,若取反则没有找到匹配的中英文字符。

删除数组元素

delete

delete 操作符用来删除一个对象的属性。

语法

delete expression

delete object.property

delete object['property']

参数
  • objectName
    对象名。
  • property
    需要删除的属性。
返回
  • boolean
    非严格模式下返回 false 。其他情况都返回 true
    在严格模式中,如果属性是一个不可配置属性,删除时会抛出异常。

当你删除一个数组元素时,数组的 length 属性并不会变小。例如,如果你删除了a[3], a[4]仍然是a[4], a[3]成为undefined. 即便你删除了最后一个元素也是如此 (delete a[a.length-1]).

当用 delete 操作符删除一个数组元素时,被删除的元素已经完全不属于该数组。下面的例子中, trees[3] 被使用delete彻底删除。

    var trees = ["redwood","bay","cedar","oak","maple"];
    delete trees[3];
    if (3 in trees) {
       // 这里不会被执行
    }



如果你想让一个数组元素的值变为 undefined 而不是删除它,可以使用 undefined 给其赋值而不是使用 delete 操作符。下面的例子中,trees[3] 被赋值为undefined,但该元素仍然存在。

    var trees = ["redwood","bay","cedar","oak","maple"];
    trees[3]=undefined;
    if (3 in trees) {
       // 这里会被执行
    }


Array.prototype.splice()

splice() 方法通过删除现有元素或添加新元素来更改数组的内容。

语法

array.splice(start)

array.splice(start, deleteCount)

array.splice(start, deleteCount, item1, item2, ...)

参数
  • start
    数组开始修改的位置,下标从 0 开始。
    如果超出了数组的长度,则位置从数组末尾开始;
    如果是负值,则表示从数组末位开始的第几位。。
  • deleteCount 可选
    整数,要移除的数组元素的个数。
    如果是 0 ,则不移除元素。
    这种情况下,至少应添加一个新元素。
    如果大于 start ,初始位置到末尾元素的总数,则包括 start 后面的元素都会被删除。
  • item1, item2, ... 可选
    添加进数组的元素,从 start 位置开始。
    如果不指定,那么只删除数组元素。
返回

包含 被删除的元素 的数组。

  • 如果只删除了一个元素,则返回只包含一个元素的数组。
  • 如果没有删除元素,则返回空数组。
举个栗子
    var myFish = ["angel", "clown", "mandarin", "surgeon"];



使用数组 myFish 运用 splice() 进行一系列操作:

  • 从第 2 位开始删除 0 个元素,插入 "drum"
    
    var removed = myFish.splice(2, 0, "drum");
    //运算后的 myFish:["angel", "clown", "drum", "mandarin", "surgeon"]
    //被删除元素数组:[],没有元素被删除


  • 从第 3 位开始删除 1 个元素
    removed = myFish.splice(3, 1);
    //运算后的myFish:["angel", "clown", "drum", "surgeon"]
    //被删除元素数组:["mandarin"]



  • 从第 2 位开始删除 1 个元素,然后插入 "trumpet"
    removed = myFish.splice(2, 1, "trumpet");
    //运算后的myFish: ["angel", "clown", "trumpet", "surgeon"]
    //被删除元素数组:["drum"]



  • 从第 0 位开始删除 2 个元素,然后插入 "parrot" "anemone""blue"
    removed = myFish.splice(0, 2, "parrot", "anemone", "blue");
    //运算后的myFish:["parrot", "anemone", "blue", "trumpet", "surgeon"]
    //被删除元素的数组:["angel", "clown"]



  • 从第 3 位开始删除 2 个元素
    
    removed = myFish.splice(3, Number.MAX_VALUE);
    //运算后的myFish: ["parrot", "anemone", "blue"]
    //被删除元素的数组:["trumpet", "surgeon"]


  1. Number.MAX_VALUE 表示在 JavaScript 里所能表示的最大数值。这里用来表示数组的末尾。
  2. event.target 指触发事件的对象。
  3. Array.prototype.splice() 相近的 Array.prototype.slice() 则用来返回原数组的浅拷贝。

参考资料

任务十七:零基础JavaScript编码(五)

任务描述

  • 参考以下示例代码,原始数据包含几个城市的空气质量指数数据
  • 用户可以选择查看不同的时间粒度,以选择要查看的空气质量指数是以天为粒度还是以周或月为粒度
  • 天:显示每天的空气质量指数
  • 周:以自然周(周一到周日)为粒度,统计一周7天的平均数为这一周的空气质量数值,如果数据中缺少一个自然周的几天,则按剩余天进行计算
  • 月:以自然月为粒度,统一一个月所有天的平均数为这一个月的空气质量数值
  • 用户可以通过select切换城市
  • 通过在"aqi-chart-wrap"里添加DOM,来模拟一个柱状图图表,横轴是时间,纵轴是空气质量指数,参考图(点击打开)。天、周、月的数据只根据用户的选择显示一种。
  • 天:每天的数据是一个很细的矩形
  • 周:每周的数据是一个矩形
  • 月:每周的数据是一个很粗的矩形
  • 鼠标移动到柱状图的某个柱子时,用title属性提示这个柱子的具体日期和数据

任务注意事项

  • 实现简单功能的同时,请仔细学习JavaScript基本语法、事件、DOM相关的知识
  • 请注意代码风格的整齐、优雅
  • 代码中含有必要的注释
  • 示例图仅为参考,不需要完全一致
  • 点击select或者radio选项时,如果没有发生变化,则图表不需要重新渲染
  • 建议不使用任何第三方库、框架
  • 示例代码仅为示例,可以直接使用,也可以完全自己重写

Demo | Sourse

任务总结

Number Object

Number 对象是经过封装的能让你处理数字值的对象。Number 对象由 Number() 构造器创建。

语法

var num = new Number(value);

参数
  • value
    被创建对象的数字值。
属性

Number.MAX_VALUE 属性表示在 JavaScript 里所能表示的最大数值。

方法
Number.prototype.toString()

toString() 方法返回 Number 对象的字符串。

语法 numObj.toString([radix])

参数

  • radix 符串的转换的基数(从2到36)。如果未指定 radix 参数,则默认值为 10。

Number 对象覆盖了 Object 对象上的 toString() 方法,它不是继承的 Object.prototype.toString()。对于 Number 对象,toString() 方法以指定的基数返回该对象的字符串表示。

如果转换的基数大于10,则会使用字母来表示大于9的数字,比如基数为16的情况,则使用a到f的字母来表示10到15。

如果基数没有指定,则使用 10。
如果对象是负数,则会保留负号。即使radix是2时也是如此:返回的字符串包含一个负号(-)前缀和正数的二进制表示,不是 数值的二进制补码。

    var count = 10;
    
    print( count.toString() );   // 输出 "10"
    print( (17).toString() );    // 输出 "17"
    
    var x = 6;
    
    print( x.toString(2) );      // 输出 "110"
    print( (254).toString(16) ); // 输出 "fe"
    
    
    print( (-10).toString(2) ); // 输出 "-1010"
    print( (-0xff).toString() ); // 输出 "-11111111"





String.prototype.substring()

substring() 返回字符串两个索引之间(或到字符串末尾)的子串。

语法

str.substring(indexStart[, indexEnd])

参数
  • indexStart
    一个 0 到字符串长度之间的整数。
  • indexEnd
    可选。一个 0 到字符串长度之间的整数。
说明
  • 如果 indexStart 等于 indexEndsubstring() 返回一个空字符串。
  • 如果省略 indexEndsubstring() 提取字符一直到字符串末尾。
  • 如果任一参数小于 0 或为 NaN,则被当作 0
  • 如果任一参数大于 stringName.length,则被当作 stringName.length
  • 如果 indexStart 大于 indexEnd,则 substring 的执行效果就像两个参数调换了一样。例如,str.substring(1, 0) == str.substring(0, 1)
举个栗子
    var anyString = "Mozilla";
    
    // 输出 "Moz"
    console.log(anyString.substring(0,3));
    console.log(anyString.substring(3,0));
    console.log(anyString.substring(3,-3));
    console.log(anyString.substring(3,NaN));
    console.log(anyString.substring(-2,3));
    console.log(anyString.substring(NaN,3));
    
    // 输出 "lla"
    console.log(anyString.substring(4,7));
    console.log(anyString.substring(7,4));
    
    // 输出 ""
    console.log(anyString.substring(4,4));
    
    // 输出 "Mozill"
    console.log(anyString.substring(0,6));
    
    // 输出 "Mozilla"
    console.log(anyString.substring(0,7));
    console.log(anyString.substring(0,10));
    console.log(anyString.substring(-2,7));
    console.log(anyString.substring(NaN,7));
    console.log(anyString.substring(0,10));
    



Date Instance

Date 实例用来处理日期和时间。Date 对象基于1970年1月1日(世界标准时间)起的毫秒数。

构造函数
    new Date();
    new Date(value);
    new Date(dateString);
    new Date(year, month[, day[, hour[, minutes[, seconds[, milliseconds]]]]]);



参数
  • indexStart
    一个 0 到字符串长度之间的整数。
  • indexEnd
    可选。一个 0 到字符串长度之间的整数。
说明
  • 如果 indexStart 等于 indexEndsubstring() 返回一个空字符串。
  • 如果省略 indexEndsubstring() 提取字符一直到字符串末尾。
  • 如果任一参数小于 0 或为 NaN,则被当作 0
  • 如果任一参数大于 stringName.length,则被当作 stringName.length
  • 如果 indexStart 大于 indexEnd,则 substring 的执行效果就像两个参数调换了一样。例如,str.substring(1, 0) == str.substring(0, 1)
举个栗子
    
    var today = new Date();
    var today = new Date(1453094034000); // by timestamp(accurate to the millimeter)
    var birthday = new Date('December 17, 1995 03:24:00');
    var birthday = new Date('1995-12-17T03:24:00');
    var birthday = new Date(1995, 11, 17);
    var birthday = new Date(1995, 11, 17, 3, 24, 0);
    
    var unixTimestamp = Date.now(); // in milliseconds











参考资料


百度前端技术学院 (Baidu Institute of Front-End Technology)是一个面向大学生的前端技术学习平台。在这里通过思考完成编码任务,总结编码中的知识点,审查他人的代码来提升学习效率与效果,帮助开发者们更加高效、系统地学习Web前端技术。

本人选择了 任务三~四 六~十二 完成学习第一学习阶段。


任务三:三栏式布局

任务描述

  • 使用 HTML 与 CSS 按照 示例图 实现三栏式布局。
  • 左右两栏宽度固定,中间一栏根据父元素宽度填充满,最外面的框应理解为浏览器。背景色为 #eee 区域的高度取决于三个子元素中最高的高度。

任务注意事项

  • 尝试 position 和 float 的效果,思考它们的异同和应用场景。
  • 注意测试不同情况,尤其是极端情况下的效果。
  • 图片和文字内容请自行替换,尽可能体现团队的特色。
  • 调节浏览器宽度,固定宽度和自适应宽度的效果始终符合预期。
  • 改变中间一栏的内容长度,以确保在中间一栏较高和右边一栏较高时,父元素的高度始终为子元素中最高的高度。
  • 其他效果图中给出的标识均被正确地实现。

Demo | Sourse

任务总结

  • 两侧的栏目使用浮动布局,父容器通过清除浮动来解决高度塌陷的问题。
  • 中间栏固定外边距看起来在两栏中间。
  • 图片与文字顶部对齐问题,图片浮动,使文字围绕图片。设置文字宽度限定折断的位置。

参考资料


任务四:定位和居中问题

任务描述

  • 实现如 示例图 的效果
  • 灰色元素水平垂直居中,有两个四分之一圆位于其左上角和右下角。

任务注意事项

  • 思考不同情况下(如灰色高度是根据内容动态变化的)水平垂直居中的解决方案。
  • 动手试一试各种情况的组合,父元素和子元素分别取不同的 position 值。思考 position 属性各种取值的真正含义,尤其是 absolute 究竟是相对谁而言的。
  • 注意测试不同情况,尤其是极端情况下的效果。
  • 调节浏览器宽度,灰色元素始终水平居中。
  • 调节浏览器高度,灰色元素始终垂直居中。
  • 调节浏览器高度和宽度,黄色扇形的定位始终准确。

Demo | Sourse

任务总结

  • 居中块使用绝对定位布局,需要 margin 一半当前块的高度和宽度来保持绝对居中。
  • 如果居中块的 ::before ::after 还没有被使用,用来制造上下对角的扇形。否则该在居中块內前后多加元素来制作实体扇形。
  • 实体扇形如果使用 border-radius: 50% 需要对父元素设置 overflow: hidden ,否则圆形剩余的扇不会被遮挡。另一种方法是制造一个矩形,对其一角进行圆角处理。

参考资料


任务六:通过HTML及CSS模拟报纸排版

任务描述

  • 参考 PDS设计稿 ,实现页面开发,要求实现效果与 样例 基本一致
  • 页面中的各字体大小,内外边距等可参看 标注图
  • 页面宽度固定(定宽)

任务注意事项

  • 只需要完成HTML,CSS代码编写,不需要写JavaScript
  • 设计稿中的图片、文案均可自行设定
  • 在Chrome中完美实现符合标注中的各项说明
  • 有能力的同学可以尝试跨浏览器的兼容性
  • 有能力的同学可以在实现一遍后尝试用less, sass或者stylus等再实现一次

Demo | Sourse

任务总结

  • 顶部文字在红色块内底边对齐,直接的方法是使用百分比相对定位。红块占位使用 display: inline-block
  • 右侧字母下划线 text-decoration: underline
  • 直接转换HTML内容为小型的大写 font-variant: small-caps
  • 将单词首个字母转换为大写 text-transform: capitalize
  • 左下图文环绕,右浮动一不可见的元素使,图片出现在文章中的固定位置,图片右浮动的同时清除右方浮动。但这样做使得首字属性 :first-letter 不能左浮动,需取首字母作为单独元素
  • content: open-quote 实现大引号
  • CSS 三角形实现:
    **border-left: 5px solid transparent;
    border-right: 5px solid transparent;
    border-bottom: 8px solid #11456b;**

参考资料

MDN HTML入门
MDN CSS入门教程

任务七:实现常见的技术产品官网的页面架构及样式布局

任务描述

  • 通过HTML及CSS实现设计稿 设计稿PSD文件 ,效果如 效果图
  • 设计稿是有一定宽度的,这个宽度为页面的最小宽度,也就是说,当浏览器窗口宽度小于设计稿宽度时,允许出现横向滚动条,页面内容宽度保持不变,但是当浏览器窗口宽度大于设计稿宽度时,页面部分内容的宽度应该保持和浏览器窗口宽度一致,具体哪些部分题目不做具体指明,看看大家的判断如何。

任务注意事项

  • 只需要完成HTML,CSS代码编写,不需要写JavaScript
  • 设计稿中的图片、文案均可自行设定
  • 在Chrome中完美实现符合标注中的各项说明
  • 有能力的同学可以尝试跨浏览器的兼容性
  • 有能力的同学可以在实现一遍后尝试用less, sass或者stylus等再实现一次

Demo | Sourse

任务总结

  • 导航栏动画。先设置 border-bottom: 0px #e7504d solid 加上过效果,鼠标悬停后再设定底边宽度 border-bottom-width: 4px
  • 使用 img 标签充当自适应背景时添加 width: 100%;height: auto;两项属性。
  • 四纵列利用平分的百分比宽度左浮动,百分比内边距。条形分割同样使用百分比的 top 来定位。另一种较好的解决方案是使用 Flex布局。
  • 消除下拉菜单默认样式 -webkit-appearance: none;并利用 background 组合属性来伪装成下拉按钮。
  • 固定宽度元素设置自适应背景图 width: 100%; background-image: url('img'); background-repeat: no-repeat; background-size: 100% auto;

任务八:响应式网格(栅格化)布局

任务描述

  • 需要实现如 效果图 所示,调整浏览器宽度查看响应式效果,效果图中的红色的文字是说明,不需要写在 HTML 中。

任务注意事项

  • 网格布局的作用在于更有效地控制元素在网页中所占比例的大小。比如,博客中有一个留言板模块,在比较大的屏幕上,我们希望它占了右边 25% 的宽度,在手机等比较小的屏幕上,我们希望它占 100%

的宽度,出现在博客文章下方。网格布局是一种实现这一需求的办法,它的好处是,把所有的宽度分为固定栏数(常用 12
栏),从而更高效的控制元素宽度。而这功能,我们使用 HTML 和 CSS 就能实现了。

  • 以 BootStrap 的网格系统为例,DOM 元素类名形如 col-md-4;其中 col 是“列” column 的缩写;md 是 medium 的缩写,适用于应屏幕宽度大于 768px 的场景;4 是占四栏的意思。因此,col-md-4 的意思是,在屏幕宽度大于

768px 时,该元素占四栏。

Demo | Sourse

任务总结

  • 最小列单元都是左浮动和均分的百分比宽度,并结合 @media 媒体查询对不同屏幕宽度的列宽度调节。
  • BootStrap Less 源码中有详细的栅格系统构造方法。

参考资料

CSS,思考这一系统是如何实现的][35]


任务九:使用HTML/CSS实现一个复杂页面

任务描述

  • 通过HTML及CSS实现设计稿 设计稿PSD文件,效果如 效果图
  • 整个页面内容宽度固定,但头部的蓝色导航和浏览器宽度保持一致
  • CSS Sprite 在线拼合

任务注意事项

  • 只需要完成HTML,CSS代码编写,不需要写JavaScript
  • tab只需要实现样式,有能力余力的同学可以尝试实现不使用JavaScript的情况下,实现Tab切换
  • 所有的下拉菜单(Select)均要求按照设计稿样式实现,下拉后的样式自定义,不需要实现下拉选择的功能,但样式要实现
  • 在Chrome中完美实现与设计稿的除了文字以外的各项图片、字体、颜色、布局、内外边距等样式
  • 有能力的同学可以尝试跨浏览器的兼容性
  • 有能力的同学可以在实现一遍后尝试用less, sass或者stylus等再实现一次

Demo | Sourse

任务总结

  • 多元素复杂页面应注意 margin padding 之间的配合来布局。
  • 顶栏、侧边栏、导航栏均使用 fixed 布局,中间内容则给对应外边距。
  • 使用 :focus 实现鼠标焦点在搜索栏上其宽度变化的动画。
  • i 标签可用于设定文字前的 icon ,一般使用 CSS Sprite 的方式,利用 background-position 和宽高为背景图案定位。
  • 盒模型为 box-sizing: border-box; 状态下,borderpadding 的设置都影响元素的宽高。
  • 善用 ::after ::before 伪对象能减少HTML内容来实现一些元素上的装饰(色块、线、点等)。
  • 结合 input label 使用锚点来制作纯CSS的标签页。
  • 多选菜单在火狐浏览器下还应 -moz-appearance: none 来消除默认样式。

任务十:Flexbox 布局练习

任务描述

  • 需要实现的效果如 效果图 所示,调整浏览器宽度查看响应式效果,红色的文字是说明,不需要写在 HTML 中。

任务注意事项

  • 只需要完成HTML,CSS代码编写,不需要写JavaScript
  • 屏幕宽度小于 640px 时,调整 Flexbox 的属性以实现第四个元素移动到最前面的效果,而不要改动第一个元素的边框颜色与高度实现效果图。
  • 思考 Flexbox 布局和网格布局的异同,以及分别适用于什么样的场景。可以搜索一下别人的结论,不过要保持思辨的态度,不可直接接受别人的观点。
  • HTML 及 CSS 代码结构清晰、规范

Demo | Sourse

任务总结

  • Flex 布局强而有力的布局方式,在很少代码量的情况下结合 @media 实现自适应的布局。
  • 加上浏览器前缀 -webkit- 。注意某些过时的浏览器仅支持旧版 Flexbox 语法。新版 Flexbox 在国内并未得到很高的支持度(移动设备上)。
  • flex-flowflex-directionflex-wrap 的结合属性,定义主轴的排列方向和换行方式。
  • 注意,设为 Flex 布局以后,子元素的 floatclearvertical-align 属性将失效。

参考资料


任务十一:移动Web页面布局实践

任务描述

  • 实现与 设计图 一致的移动端Web页面

任务注意事项

  • 本任务只涉及 HTML 及 CSS
  • 实现的页面和设计图在iOS Safari,微信,Android浏览器中均基本一致
  • HTML 及 CSS 代码结构清晰、规范
  • 尝试在适合的地方使用CSS 3中的flex布局 有能力的同学可以在实现一遍后尝试用less, sass或者stylus等再实现一次

Demo | Sourse

任务总结

  • 引入 flexible.js 移动端自适应方案来处理不同屏幕下CSS像素与物理像素不对应的问题。CSS rem 单位相对于 <html> 根元素来做字体大小计算,手动或自动把 px 单位转成 rem ,字体依然使用 px 单位。
  • Flexible.js 会将设计稿宽度分成 100份,每10份为 1rem1rem 为设计稿的1/10 宽度,也是 html 根元素的字体大小。(1000px的设计稿,1rem = 100px)
  • Flexible.js 对字体的自适应,用 CSS属性选择器来 data-dpr 判断属性值来适应高PPI的移动设备。
  • 如无特殊情况,width/height/padding/margin都使用rem,border-width和font-size使用px —— 大漠
  • 对重复内容的行列使用 Flex布局能减少非常多的代码量。
  • wrapper 进行 max-width 设定为 100rem 防止宽屏显示器下拉伸无法达到设计稿要求。

参考资料

任务十二:学习CSS 3的新特性

任务描述

  • 实现 示例图 中的几个例子
  • 实现单双行列不同颜色,且前三行特殊表示的表格
  • 实现正常状态和focus状态宽度不一致的input文本输入框,且鼠标焦点进入输入框时,宽度的变化以动画呈现
  • 不使用JavaScript,实现一个Banner图轮流播放的效果,且点击右下角的1,2,3可以切换到对应Banner图片

任务注意事项

  • 本任务只涉及 HTML 及 CSS
  • HTML 及 CSS 代码结构清晰、规范
  • 除了任务中的3个小任务,尽可能多地尝试 CSS 3 的其他新特性

Demo | Sourse

任务总结

  • Banner 的实现是利用 锚点 :target 定位结合 animation 特性产生切换效果。
  • 注意表格内 <table> <caption> <thead> <tbody> 标签的语义化。

参考资料