Components构建单页面应用,实现及应用

JavaScript 原生对象及扩展

2016/09/26 · JavaScript
· 对象

原文出处: trigkit4   

用Web Components构建单页面应用

2015/01/19 · JavaScript
· Web Components

本文由 伯乐在线 –
周进林
翻译,Mxt
校稿。未经许可,禁止转载!
英文出处:www.polymer-project.org。欢迎加入翻译组。

你是如何使用Polymer构建一个单页应用的?这个问题我们在Polymer团队里已经问过很多遍了。我们的答案(一如既往地)是“使用组件(component)!”。然而,使用新技术去解决现有的问题往往不会马上得到显著的效果。如何把一堆模块化组件组合到一个大型的实用的应用中去?

在本教程,我将会给你展示如何去构建一个功能完整的单页应用:

图片 1

  • 完全使用Polymer的核心元素构建
  • 使用响应式设计
  • 使用数据绑定特性过渡视图
  • 使用URL路由和深层链接特性
  • 可访问键盘
  • 按需动态载入内容(可选)

 打开演示

Base64 的原理、实现及应用

2016/04/06 · 基础技术 ·
1 评论 ·
Base64

本文作者: 伯乐在线 –
Natumsol
。未经作者许可,禁止转载!
欢迎加入伯乐在线 专栏作者。

简介

Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2的6次方等于64,所以每6个比特为一个单元,对应某个可打印字符。三个字节有24个比特,对应于4个Base64单元,即3个字节需要用4个可打印字符来表示。它可用来作为电子邮件的传输编码。在Base64中的可打印字符包括字母A-Za-z、数字0-9,这样共有62个字符,此外的两个可打印符号在不同的系统中而不同,一般为+/

内置对象与原生对象

内置(Build-in)对象与原生(Naitve)对象的区别在于:前者总是在引擎初始化阶段就被创建好的对象,是后者的一个子集;而后者包括了一些在运行过程中动态创建的对象。

图片 2

应用架构

设计布局是开始一个项目的首要任务之一。作为核心元素集合的一部分,Polymer通过几个布局元素 来支撑应用程序的构架(<core-header-panel>,
<core-drawer-panel>,
<core-toolbar>)。这些组件本身就很好用,但是为了更快地开始项目,我们打算着重于<core-scaffold>。有了它你可以通过组装几个基本的元素就能做出一个响应式的移动端布局。

<core-scaffold>的子元素可以是指定特定的元素或使用特定的标签(或两者一起使用)。举个例子,使用<nav>元素创建应用抽屉菜单。你可以在任意的元素里使用navigation属性(e.g
<core-header-panel navigation>)。工具栏通过工具属性标识。它的所有其他子元素都定义在主要内容区域里。

转换原理

Base64的直接数据源是二进制序列(Binary
Sequence)。当然,你也可以将图片、文本和音视频转换成二进制序列,再然后转换为Base64编码。我们这里讨论的是如何将二进制转换为Base64编码,对于如何将图片,文本和音视频转换为二进制序列敬请期待。

在转换前,先定义一张索引表,这张表规定了如何转换。
图片 3
转换的时候我们先将二进制序列分组,每6个比特为一组。但是如果编码的字节数不能被3整除,那么最后就会多出1个或两个字节,可以使用下面的方法进行处理:先使用0字节值在末尾补足,使其能够被3整除,然后再进行base64的编码。在编码后的base64文本后加上一个或两个’=’号,代表补足的字节数。也就是说,当最后剩余一个八位字节(一个byte)时,最后一个6位的base64字节块有四位是0值,最后附加上两个等号;如果最后剩余两个八位字节(2个byte)时,最后一个6位的base字节块有两位是0值,最后附加一个等号。
参考下表:
图片 4

原生对象(New后的对象)

ECMA-262 把原生对象(native object)定义为“独立于宿主环境的
ECMAScript 实现提供的对象”。包括如下:

Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError、ActiveXObject(服务器方面)、Enumerator(集合遍历类)、RegExp(正则表达式)

1
Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError、ActiveXObject(服务器方面)、Enumerator(集合遍历类)、RegExp(正则表达式)

由此可以看出,简单来说,原生对象就是 ECMA-262 定义的类(引用类型)。

来源:

例子

XHTML

<body unresolved fullbleed> <core-scaffold id=”scaffold”>
<nav>Left drawer</nav> <core-toolbar
tool>Application</core-toolbar> <div>Main
content</div> </core-scaffold> </body>

1
2
3
4
5
6
7
<body unresolved fullbleed>
  <core-scaffold id="scaffold">
    <nav>Left drawer</nav>
    <core-toolbar tool>Application</core-toolbar>
    <div>Main content</div>
  </core-scaffold>
</body>

让我们一起来深入这些内容的每一部分

用JavaScript实现Base64

原理明白了以后,实现起来就很容易了。

JavaScript

define(function(require, exports, module) { var code =
“ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/”.split(“”);
//索引表 /** * @author natumsol@gmail.com * @description
将二进制序列转换为Base64编码 * @param {String} * @return {String} */
function binToBase64(bitString) { var result = “”; var tail =
bitString.length % 6; var bitStringTemp1 = bitString.substr(0,
bitString.length – tail); var bitStringTemp2 =
bitString.substr(bitString.length – tail, tail); for (var i = 0; i <
bitStringTemp1.length; i += 6) { var index =
parseInt(bitStringTemp1.substr(i, 6), 2); result += code[index]; }
bitStringTemp2 += new Array(7 – tail).join(“0”); if (tail) { result +=
code[parseInt(bitStringTemp2, 2)]; result += new Array((6 – tail) / 2

  • 1).join(“=”); } return result; } /** * @author natumsol@gmail.com
    * @description 将base64编码转换为二进制序列 * @param {String} *
    @return {String} */ function base64ToBin(str) { var bitString = “”; var
    tail = 0; for (var i = 0; i < str.length; i++) { if (str[i] != “=”)
    { var decode = code.indexOf(str[i]).toString(2); bitString += (new
    Array(7 – decode.length)).join(“0”) + decode; } else { tail++; } }
    return bitString.substr(0, bitString.length – tail * 2); } /** *
    @description 将字符转换为二进制序列 * @param {String} str * @return
    {String} */ function stringToBin(str) { var result = “”; for (var i =
    0; i < str.length; i++) { var charCode =
    str.charCodeAt(i).toString(2); result += (new Array(9 –
    charCode.length).join(“0”) + charCode); } return result; } /** *
    @description 将二进制序列转换为字符串 * @param {String} Bin */
    function BinToStr(Bin) { var result = “”; for (var i = 0; i <
    Bin.length; i += 8) { result +=
    String.fromCharCode(parseInt(Bin.substr(i, 8), 2)); } return result; }
    exports.base64 = function(str) { return binToBase64(stringToBin(str)); }
    exports.decodeBase64 = function(str) { return
    BinToStr(base64ToBin(str)); } })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
define(function(require, exports, module) {
 
    var code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split(""); //索引表
 
    /**
     * @author natumsol@gmail.com
     * @description 将二进制序列转换为Base64编码
     * @param  {String}
     * @return {String}
     */
    function binToBase64(bitString) {
        var result = "";
        var tail = bitString.length % 6;
        var bitStringTemp1 = bitString.substr(0, bitString.length – tail);
        var bitStringTemp2 = bitString.substr(bitString.length – tail, tail);
        for (var i = 0; i &lt; bitStringTemp1.length; i += 6) {
            var index = parseInt(bitStringTemp1.substr(i, 6), 2);
            result += code[index];
        }
        bitStringTemp2 += new Array(7 – tail).join("0");
        if (tail) {
            result += code[parseInt(bitStringTemp2, 2)];
            result += new Array((6 – tail) / 2 + 1).join("=");
        }
        return result;
    }
 
    /**
     * @author natumsol@gmail.com
     * @description 将base64编码转换为二进制序列
     * @param  {String}
     * @return {String}
     */
    function base64ToBin(str) {
        var bitString = "";
        var tail = 0;
        for (var i = 0; i &lt; str.length; i++) {
            if (str[i] != "=") {
                var decode = code.indexOf(str[i]).toString(2);
                bitString += (new Array(7 – decode.length)).join("0") + decode;
            } else {
                tail++;
            }
        }
        return bitString.substr(0, bitString.length – tail * 2);
    }
 
    /**
     * @description 将字符转换为二进制序列
     * @param  {String} str
     * @return {String}    
     */
    function stringToBin(str) {
        var result = "";
        for (var i = 0; i &lt; str.length; i++) {
            var charCode = str.charCodeAt(i).toString(2);
            result += (new Array(9 – charCode.length).join("0") + charCode);
        }
        return result;
    }
    /**
     * @description 将二进制序列转换为字符串
     * @param {String} Bin
     */
    function BinToStr(Bin) {
        var result = "";
        for (var i = 0; i &lt; Bin.length; i += 8) {
            result += String.fromCharCode(parseInt(Bin.substr(i, 8), 2));
        }
        return result;
    }
    exports.base64 = function(str) {
        return binToBase64(stringToBin(str));
    }
    exports.decodeBase64 = function(str) {
        return BinToStr(base64ToBin(str));
    }
})

内置对象(不需要New)

定义:由ECMAScript实现提供的对象,独立于宿主环境,在一个脚本程序执行的开始处。

:每个内置对象(built-in object)都是原生对象(Native Object),一个内置的构造函数是一个内置的对象,也是一个构造函数。

来源:

举个栗子:

Native objects: Object (constructor), Date, Math, parseInt, eval。
string 方法比如 indexOf 和 replace, array 方法, … Host objects
(假定是浏览器环境): window, document, location, history, XMLHttpRequest,
setTimeout, getElementsByTagName, querySelectorAll, …

1
2
3
Native objects: Object (constructor), Date, Math, parseInt, eval。 string 方法比如 indexOf 和 replace, array 方法, …
 
Host objects (假定是浏览器环境): window, document, location, history, XMLHttpRequest, setTimeout, getElementsByTagName, querySelectorAll, …

ECMA-262][2 只定义了两个新的内置对象,即 GlobalMath
(它们也是原生对象,根据定义,每个内置对象都是原生对象)。

以下是ECMA-262定义的内置对象(built-in):

global、Object、Function、Array、String、Boolean、Number、Math、Date、RegExp、JSON、Error对象(Error,
EvalError, RangeError, ReferenceError, SyntaxError, TypeError
和URIError)

1
global、Object、Function、Array、String、Boolean、Number、Math、Date、RegExp、JSON、Error对象(Error,   EvalError, RangeError, ReferenceError,   SyntaxError, TypeError 和URIError)

图片 5

我们也可以修改内置对象的原型

JavaScript

if (!Array.prototype.forEach) { Array.prototype.forEach = function(fn){
for ( var i = 0; i < this.length; i++ ) { fn( this[i], i, this ); }
}; } [“a”, “b”, “c”].forEach(function(value, index, array){ assert(
value, “Is in position ” + index + ” out of ” + (array.length – 1) );
});

1
2
3
4
5
6
7
8
9
10
11
if (!Array.prototype.forEach) {
  Array.prototype.forEach = function(fn){
    for ( var i = 0; i < this.length; i++ ) {
      fn( this[i], i, this );
    }
  };
}
["a", "b", "c"].forEach(function(value, index, array){
  assert( value, "Is in position " + index + " out of " + (array.length – 1) );
});

以上代码将输出:

PASS Is in position 0 out of 2 PASS Is in position 1 out of 2 PASS Is in
position 2 out of 2

1
2
3
PASS Is in position 0 out of 2
PASS Is in position 1 out of 2
PASS Is in position 2 out of 2

注意:扩展原型是很危险的:

JavaScript

Object.prototype.keys = function(){ var keys = []; for ( var i in this
) keys.push( i ); return keys; }; var obj = { a: 1, b: 2, c: 3 };
assert( obj.keys().length == 3, “We should only have 3 properties.” );
delete Object.prototype.keys;

1
2
3
4
5
6
7
8
9
10
11
12
Object.prototype.keys = function(){
  var keys = [];
  for ( var i in this )
    keys.push( i );
  return keys;
};
var obj = { a: 1, b: 2, c: 3 };
assert( obj.keys().length == 3, "We should only have 3 properties." );
delete Object.prototype.keys;

输出: FAIL We should only have 3 properties.

如果不是有特殊需要而去扩展原生对象和原型(prototype)的做法是不好的

JavaScript

//不要这样做 Array.prototype.map = function() { // code };

1
2
3
4
//不要这样做
Array.prototype.map = function() {
    // code
};

除非这样做是值得的,例如,向一些旧的浏览器中添加一些ECMAScript5中的方法。
在这种情况下,我们一般这样做:

XHTML

<script type=”text/javascript”> if (!Array.prototype.map) {
Array.prototype.map = function() { //code }; } </script>

1
2
3
4
5
6
7
<script type="text/javascript">
    if (!Array.prototype.map) {
        Array.prototype.map = function() {
            //code
        };
    }
</script>

抽屉菜单

你放在导航元素里的标记都定义在滑走的应用抽屉菜单里。为了我们的目标
,我坚持使用标题(<core-toolbar>)和导航链接 (<core-menu>):

XHTML

<nav> <core-toolbar><span>Single Page
Polymer</span></core-toolbar> <core-menu selected=”0″>
<paper-item noink> <core-icon
icon=”label-outline”></core-icon> <a
href=”#one”>Single</a> </paper-item> <paper-item
noink> <core-icon icon=”label-outline”></core-icon> <a
href=”#two”>page</a> </paper-item> …
</core-menu> </nav>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<nav>
  <core-toolbar><span>Single Page Polymer</span></core-toolbar>
  <core-menu selected="0">
    <paper-item noink>
      <core-icon icon="label-outline"></core-icon>
      <a href="#one">Single</a>
    </paper-item>
    <paper-item noink>
      <core-icon icon="label-outline"></core-icon>
      <a href="#two">page</a>
    </paper-item>
    …
  </core-menu>
</nav>

注意,现在<core-menu
selected=”0″>被硬编码为选择第一个条目。我们以后会把它改为动态的。

将图片数据进行Base64编码

将图片数据转换为Base64,首先要获取到图片的二进制数据。图片的二进制数据可以通过canvas接口得到。具体实现为:

JavaScript

function getCanvas(w, h) { var c = document.createElement(‘canvas’);
c.width = w; c.height = h; return c; } function getPixels(img) { var c =
getCanvas(img.width, img.height); var ctx = c.getContext(‘2d’);
ctx.drawImage(img, 0, 0); return ctx.getImageData(0, 0, c.width,
c.height); }

1
2
3
4
5
6
7
8
9
10
11
12
13
function getCanvas(w, h) {
var c = document.createElement(‘canvas’);
c.width = w;
c.height = h;
return c;
}
 
function getPixels(img) {
var c = getCanvas(img.width, img.height);
var ctx = c.getContext(‘2d’);
ctx.drawImage(img, 0, 0);
return ctx.getImageData(0, 0, c.width, c.height);
}

取到图片的二进制数据后,接下来就要进行编码了。因为图片不仅包含像素信息,还包含长度,宽度信息。所以在编码像素信息的同时也应将宽度和高度信息按某一约定进行编码,我是这样处理的:

  1. 将图片的像素数值数据转换为二进制序列;
  2. 将宽度和高度信息组合成字符串$$width,height$$,转换为二进制序列;
  3. 将图片像素信息的二进制序列和图片宽高度的二进制序列组合起来,然后再进行Base64的编码

具体实现为:

JavaScript

function img2Base64(img) { var imgData = getPixels(img).data; var
imgWidth = getPixels(img).width; var imgHeight = getPixels(img).height;
var bin = “”; for (var i = 0; i < imgData.length; i++) { bin +=
base.numToString(imgData[i]); } bin = bin + base.stringToBin(“$$” +
imgWidth + “,” + imgHeight + “$$”); return base.binToBase64(bin); }

1
2
3
4
5
6
7
8
9
10
11
function img2Base64(img) {
var imgData = getPixels(img).data;
var imgWidth = getPixels(img).width;
var imgHeight = getPixels(img).height;
var bin = "";
for (var i = 0; i &lt; imgData.length; i++) {
bin += base.numToString(imgData[i]);
}
bin = bin + base.stringToBin("$$" + imgWidth + "," + imgHeight + "$$");
return base.binToBase64(bin);
}

用原型扩展对象

对js原生对象的扩展无非就是往prototype里注册,例如,我们可以往String对象里扩展ltrim,rtrim等方法。js每个对象都继承自Object,并且,对象和其他属性都通过prototype对象来继承。通过prototype对象,我们可以扩展任何对象,包括内建的对象,如StringDate

工具栏

工具栏横跨了页面顶部并包含了功能按钮图标。满足这种功能的完美元素是<core-toolbar>:

XHTML

<!– flex makes the bar span across the top of the main content area
–> <core-toolbar tool flex> <!– flex spaces this element
and jusifies the icons to the right-side –> <div
flex>Application</div> <core-icon-button
icon=”refresh”></core-icon-button> <core-icon-button
icon=”add”></core-icon-button> </core-toolbar>

1
2
3
4
5
6
7
<!– flex makes the bar span across the top of the main content area –>
<core-toolbar tool flex>
  <!– flex spaces this element and jusifies the icons to the right-side –>
  <div flex>Application</div>
  <core-icon-button icon="refresh"></core-icon-button>
  <core-icon-button icon="add"></core-icon-button>
</core-toolbar>

将图片Base64数据进行解码

解码是编码的逆过程。过程大致为:

  1. 将图片的Base64信息进行解码,得到包含图片像素信息和宽高度信息的二进制序列;
  2. 然后将这个二进制序列解码成字符串,获取高度和宽度信息;
  3. 去除二进制序列中的高度和宽度信息,得到像素信息;
  4. 根据像素信息生成像素矩阵;
  5. 根据像素矩阵、宽度和高度创建图片对象ImageData
  6. 利用putImageData将图像绘制出来。

具体的代码实现为:

JavaScript

function paint(imgData) { var canvas =
document.getElementById(“myCanvas”); var ctx = canvas.getContext(“2d”);
ctx.fillRect(0, 0, imgData.width, imgData.height);
ctx.putImageData(imgData, 0, 0); } function base642img(data) { var str =
base.BinToStr(base.base64ToBin(data)); var imgWidth =
str.match(/\$\$(\d+),(\d+)\$\$$/, “”)[1]; var imgHeight =
str.match(/\$\$(\d+),(\d+)\$\$$/, “”)[2] var imgData =
base.base64ToBin(data).replace(base.stringToBin(“$$” + imgWidth + “,” +
imgHeight + “$$”), “”); var ImageDataArray = new
Uint8ClampedArray(imgWidth * imgHeight * 4); for (var i = 0; i <
ImageDataArray.length; i++) { ImageDataArray[i] =
parseInt(imgData.substr(i * 8, 8), 2); } return new
ImageData(ImageDataArray, imgWidth, imgHeight); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function paint(imgData) {
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.fillRect(0, 0, imgData.width, imgData.height);
ctx.putImageData(imgData, 0, 0);
}
 
function base642img(data) {
var str = base.BinToStr(base.base64ToBin(data));
var imgWidth = str.match(/\$\$(\d+),(\d+)\$\$$/, "")[1];
var imgHeight = str.match(/\$\$(\d+),(\d+)\$\$$/, "")[2]
var imgData = base.base64ToBin(data).replace(base.stringToBin("$$" + imgWidth + "," + imgHeight + "$$"), "");
 
var ImageDataArray = new Uint8ClampedArray(imgWidth * imgHeight * 4);
for (var i = 0; i &lt; ImageDataArray.length; i++) {
ImageDataArray[i] = parseInt(imgData.substr(i * 8, 8), 2);
}
return new ImageData(ImageDataArray, imgWidth, imgHeight);
 
}

String对象的扩展

JavaScript

<script type=”text/javascript”> if(typeof
String.prototype.ltrim==’undefined’){ String.prototype.ltrim =
function(){ var s = this; s = s.replace(/^\s*/g, ”); return s; } }
if(typeof String.prototype.rtrim==’undefined’){ String.prototype.rtrim =
function(){ var s = this; s = s.replace(/\s*$/g, ”); return s; } }
if(typeof String.prototype.trim==’undefined’){ String.prototype.trim =
function(){ return this.ltrim().rtrim(); } } if(typeof
String.prototype.htmlEncode==’undefined’){ String.prototype.htmlEncode =
function(encodeNewLine){//encodeNewLine:是否encode换行符 var s = this; s
= s.replace(/&/g, ‘&’); s = s.replace(/</g, ‘<‘); s =
s.replace(/>/g, ‘>’); s = s.replace(/’/g, ‘"’);
if(encodeNewLine){ s = s.replace(/\r\n/g, ‘<br />’); s =
s.replace(/\r/g, ‘<br />’); s = s.replace(/\n/g, ‘<br
/>’); } return s; } } </script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<script type="text/javascript">
    if(typeof String.prototype.ltrim==’undefined’){
        String.prototype.ltrim = function(){
            var s = this;
            s = s.replace(/^\s*/g, ”);
            return s;
        }
    }
 
    if(typeof String.prototype.rtrim==’undefined’){
        String.prototype.rtrim = function(){
            var s = this;
            s = s.replace(/\s*$/g, ”);
            return s;
        }
    }
 
    if(typeof String.prototype.trim==’undefined’){
        String.prototype.trim = function(){
            return this.ltrim().rtrim();
        }
    }
 
    if(typeof String.prototype.htmlEncode==’undefined’){
        String.prototype.htmlEncode = function(encodeNewLine){//encodeNewLine:是否encode换行符
            var s = this;
            s = s.replace(/&/g, ‘&amp;’);
            s = s.replace(/</g, ‘&lt;’);
            s = s.replace(/>/g, ‘&gt;’);
            s = s.replace(/’/g, ‘&quot;’);
            if(encodeNewLine){
                s = s.replace(/\r\n/g, ‘<br />’);
                s = s.replace(/\r/g, ‘<br />’);
                s = s.replace(/\n/g, ‘<br />’);
            }
            return s;
        }
    }
</script>

主要内容

最后一部分是为你的内容而留的。它可以是任何的元素。<div>是一个很好的选择:

XHTML

<div layout horizontal center-center fit> <!– fill with pages
–> </div>

1
2
3
<div layout horizontal center-center fit>
  <!– fill with pages –>
</div>

fit属性表示主要区域的内容会布满父元素的宽带和高度,layout horizontal
center-center属性表示使用弹性框(flexbox)来使内容居中和垂直居中。

DEMO演示

在线演示: DEMO 
源码请移步 Github 
图片 6 

打赏支持我写出更多好文章,谢谢!

打赏作者

Date对象的扩展

getDaysInMonth:获取某月有多少天

JavaScript

Date.getDaysInMonth = function (year, month) { var days = 0; switch
(month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: days
= 31 break; case 4: case 6: case 9: case 11: days = 30; break; case 2:
if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) days = 29;
else days = 28; break; } return days; } if (typeof Date.prototype.format
== ‘undefined’) { Date.prototype.format = function (mask) { var d =
this; var zeroize = function (value, length) { if (!length) length = 2;
value = String(value); for (var i = 0, zeros = ”; i < (length –
value.length); i++) { zeros += ‘0’; } return zeros + value; }; return
mask.replace(/”[^”]*”|'[^’]*’|\b(?:d{1,4}|m{1,4}|yy(?:yy)?|([hHMstT])\1?|[lLZ])\b/g,
function ($0) { switch ($0) { case ‘d’: return d.getDate(); case ‘dd’:
return zeroize(d.getDate()); case ‘ddd’: return [‘Sun’, ‘Mon’, ‘Tue’,
‘Wed’, ‘Thr’, ‘Fri’, ‘Sat’][d.getDay()]; case ‘dddd’: return
[‘Sunday’, ‘Monday’, ‘Tuesday’, ‘Wednesday’, ‘Thursday’, ‘Friday’,
‘Saturday’][d.getDay()]; case ‘M’: return d.getMonth() + 1; case
‘MM’: return zeroize(d.getMonth() + 1); case ‘MMM’: return [‘Jan’,
‘Feb’, ‘Mar’, ‘Apr’, ‘May’, ‘Jun’, ‘Jul’, ‘Aug’, ‘Sep’, ‘Oct’, ‘Nov’,
‘Dec’][d.getMonth()]; case ‘MMMM’: return [‘January’, ‘February’,
‘March’, ‘April’, ‘May’, ‘June’, ‘July’, ‘August’, ‘September’,
‘October’, ‘November’, ‘December’][d.getMonth()]; case ‘yy’: return
String(d.getFullYear()).substr(2); case ‘yyyy’: return d.getFullYear();
case ‘h’: return d.getHours() % 12 || 12; case ‘hh’: return
zeroize(d.getHours() % 12 || 12); case ‘H’: return d.getHours(); case
‘HH’: return zeroize(d.getHours()); case ‘m’: return d.getMinutes();
case ‘mm’: return zeroize(d.getMinutes()); case ‘s’: return
d.getSeconds(); case ‘ss’: return zeroize(d.getSeconds()); case ‘l’:
return zeroize(d.getMilliseconds(), 3); case ‘L’: var m =
d.getMilliseconds(); if (m > 99) m = Math.round(m / 10); return
zeroize(m); case ‘tt’: return d.getHours() < 12 ? ‘am’ : ‘pm’; case
‘TT’: return d.getHours() < 12 ? ‘AM’ : ‘PM’; case ‘Z’: return
d.toUTCString().match(/[A-Z]+$/); // Return quoted strings with the
surrounding quotes removed default: return $0.substr(1, $0.length – 2);
} }); }; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
Date.getDaysInMonth = function (year, month) {
            var days = 0;
            switch (month) {
                case 1:
                case 3:
                case 5:
                case 7:
                case 8:
                case 10:
                case 12:
                    days = 31
                    break;
                case 4:
                case 6:
                case 9:
                case 11:
                    days = 30;
                    break;
                case 2:
                    if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0))
                        days = 29;
                    else
                        days = 28;
                    break;
            }
            return days;
        }
 
        if (typeof Date.prototype.format == ‘undefined’) {
            Date.prototype.format = function (mask) {
 
                var d = this;
 
                var zeroize = function (value, length) {
 
                    if (!length) length = 2;
 
                    value = String(value);
 
                    for (var i = 0, zeros = ”; i < (length – value.length); i++) {
 
                        zeros += ‘0’;
 
                    }
 
                    return zeros + value;
 
                };
 
                return mask.replace(/"[^"]*"|'[^’]*’|\b(?:d{1,4}|m{1,4}|yy(?:yy)?|([hHMstT])\1?|[lLZ])\b/g, function ($0) {
 
                    switch ($0) {
 
                        case ‘d’: return d.getDate();
 
                        case ‘dd’: return zeroize(d.getDate());
 
                        case ‘ddd’: return [‘Sun’, ‘Mon’, ‘Tue’, ‘Wed’, ‘Thr’, ‘Fri’, ‘Sat’][d.getDay()];
 
                        case ‘dddd’: return [‘Sunday’, ‘Monday’, ‘Tuesday’, ‘Wednesday’, ‘Thursday’, ‘Friday’, ‘Saturday’][d.getDay()];
 
                        case ‘M’: return d.getMonth() + 1;
 
                        case ‘MM’: return zeroize(d.getMonth() + 1);
 
                        case ‘MMM’: return [‘Jan’, ‘Feb’, ‘Mar’, ‘Apr’, ‘May’, ‘Jun’, ‘Jul’, ‘Aug’, ‘Sep’, ‘Oct’, ‘Nov’, ‘Dec’][d.getMonth()];
 
                        case ‘MMMM’: return [‘January’, ‘February’, ‘March’, ‘April’, ‘May’, ‘June’, ‘July’, ‘August’, ‘September’, ‘October’, ‘November’, ‘December’][d.getMonth()];
 
                        case ‘yy’: return String(d.getFullYear()).substr(2);
 
                        case ‘yyyy’: return d.getFullYear();
 
                        case ‘h’: return d.getHours() % 12 || 12;
 
                        case ‘hh’: return zeroize(d.getHours() % 12 || 12);
 
                        case ‘H’: return d.getHours();
 
                        case ‘HH’: return zeroize(d.getHours());
 
                        case ‘m’: return d.getMinutes();
 
                        case ‘mm’: return zeroize(d.getMinutes());
 
                        case ‘s’: return d.getSeconds();
 
                        case ‘ss’: return zeroize(d.getSeconds());
 
                        case ‘l’: return zeroize(d.getMilliseconds(), 3);
 
                        case ‘L’: var m = d.getMilliseconds();
 
                            if (m > 99) m = Math.round(m / 10);
 
                            return zeroize(m);
 
                        case ‘tt’: return d.getHours() < 12 ? ‘am’ : ‘pm’;
 
                        case ‘TT’: return d.getHours() < 12 ? ‘AM’ : ‘PM’;
 
                        case ‘Z’: return d.toUTCString().match(/[A-Z]+$/);
 
                            // Return quoted strings with the surrounding quotes removed    
 
                        default: return $0.substr(1, $0.length – 2);
 
                    }
 
                });
 
            };
        }

创建“视图”

多视图(或者多页面)可以使用<core-pages>或者<core-animated-pages>来创建。在一次只展示一个子元素时,两个元素都很有用。而使用<core-animated-pages>的好处是,它提供了更多的默认和灵活的页面过渡。

下面的演示(demo)使用了<core-animated-pages>元素的slide-from-right过渡效果。首先,导入元素定义和slide-from-right过渡效果。

XHTML

<link rel=”import”
href=”components/core-animated-pages/core-animated-pages.html”>
<link rel=”import”
href=”components/core-animated-pages/transitions/slide-from-right.html”>

1
2
<link rel="import" href="components/core-animated-pages/core-animated-pages.html">
<link rel="import" href="components/core-animated-pages/transitions/slide-from-right.html">

然后插入你的内容:

XHTML

<div layout horizontal center-center fit> <core-animated-pages
selected=”0″ transitions=”slide-from-right”> <section layout
vertical center-center> <div>Single</div>
</section> <section layout vertical center-center>
<div>page</div> </section> …
</core-animated-pages> </div>

1
2
3
4
5
6
7
8
9
10
11
<div layout horizontal center-center fit>
  <core-animated-pages  selected="0" transitions="slide-from-right">
    <section layout vertical center-center>
      <div>Single</div>
    </section>
    <section layout vertical center-center>
      <div>page</div>
    </section>
    …
  </core-animated-pages>
</div>

注意,现在
<core-animated-pagesselected=”0″>这行代码是硬编码去选择第一页。不过我们以后会把它写成动态的。

现在你应该拥有了一个基本的应用,但是这里有一些小的问题需要注意。多亏了Polymer每个元素提供的布局属性和默认样式,你可以不写任何的CSS代码就可以实现一个响应式应用。当然,从material
design调色板里获取一些灵感,设置不到10
CSS规则就可以让这个应该变得更好看。

展示:没设置CSS 
 
 展示:设置CSS

打赏支持我写出更多好文章,谢谢!

任选一种支付方式

图片 7
图片 8

2 赞 3 收藏 1
评论

使用原生js实现复制对象及扩展

jQueryextend()方法能很方便的实现扩展对象方法,这里要实现的是:使用原生js实现复制对象,扩展对象,类似jQuery中的extend()方法

JavaScript

var obj1 = { name : ‘trigkit4’, age : 22 }; var obj2 = { name : ‘frank’,
age : 21, speak : function(){ alert(“hi, I’m + name “); } }; var obj3 ={
age : 20 }; function cloneObj(oldObj) { //复制对象方法 if
(typeof(oldObj) != ‘object’) return oldObj; if (oldObj == null) return
oldObj; var newObj = Object(); for (var i in oldObj) newObj[i] =
cloneObj(oldObj[i]); return newObj; } function extendObj() {
//扩展对象 var args = arguments;//将传递过来的参数数组赋值给args变量 if
(args.length < 2) return; var temp = cloneObj(args[0]);
//调用复制对象方法 for (var n = 1; n < args.length; n++) { for (var i
in args[n]) { temp[i] = args[n][i]; } } return temp; } var obj
=extendObj(obj1,obj2,obj3); console.log(obj);//{ name: ‘frank’, age: 20,
speak: [Function] } console.log(obj1);//{ name: ‘trigkit4’, age: 22 }
console.log(obj2);//{ name: ‘frank’, age: 21, speak: [Function] }
console.log(obj3);//{ age: 20 }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
var obj1 = {
    name : ‘trigkit4’,
    age : 22
};
var obj2 = {
    name : ‘frank’,
    age : 21,
    speak : function(){
        alert("hi, I’m + name ");
    }
};
 
var obj3 ={
    age : 20
};
 
function cloneObj(oldObj) { //复制对象方法
    if (typeof(oldObj) != ‘object’) return oldObj;
    if (oldObj == null) return oldObj;
    var newObj = Object();
    for (var i in oldObj)
        newObj[i] = cloneObj(oldObj[i]);
    return newObj;
}
 
function extendObj() { //扩展对象
    var args = arguments;//将传递过来的参数数组赋值给args变量
    if (args.length < 2) return;
    var temp = cloneObj(args[0]); //调用复制对象方法
    for (var n = 1; n < args.length; n++) {
        for (var i in args[n]) {
            temp[i] = args[n][i];
        }
    }
    return temp;
}
var obj =extendObj(obj1,obj2,obj3);
console.log(obj);//{ name: ‘frank’, age: 20, speak: [Function] }
console.log(obj1);//{ name: ‘trigkit4’, age: 22 }
console.log(obj2);//{ name: ‘frank’, age: 21, speak: [Function] }
console.log(obj3);//{ age: 20 }

使用数据绑定

我们拥有了一个应用,但这不值得一提。这离DRY还远着。类似的标记在这里重复出现:

XHTML

<nav> <core-menu selected=”0″> <paper-item noink>
<core-icon icon=”label-outline”></core-icon> <a
href=”#one”>Single</a> </paper-item> <paper-item
noink> <core-icon icon=”label-outline”></core-icon> <a
href=”#two”>page</a> </paper-item> <paper-item
noink> <core-icon icon=”label-outline”></core-icon> <a
href=”#three”>app</a> </paper-item> …
</core-menu> </nav>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<nav>
  <core-menu selected="0">
    <paper-item noink>
      <core-icon icon="label-outline"></core-icon>
      <a href="#one">Single</a>
    </paper-item>
    <paper-item noink>
      <core-icon icon="label-outline"></core-icon>
      <a href="#two">page</a>
    </paper-item>
    <paper-item noink>
      <core-icon icon="label-outline"></core-icon>
      <a href="#three">app</a>
    </paper-item>
    …
  </core-menu>
</nav>

这同样不是动态的。当用户选择一个菜单条目时,页面不会更新。幸运的是,这些问题都可以使用Polymer的数据绑定特性轻松解决。

关于作者:Natumsol

图片 9

阿里巴巴 前端工程师
个人主页 ·
我的文章 ·
5 ·
   

图片 10

es5-safe 模块

es5-safe 模块里,仅扩展了可以较好实现的可以安全使用的部分方法,包括:

JavaScript

Function.prototype.bind Object.create Object.keys Array.isArray
Array.prototype.forEach Array.prototype.map Array.prototype.filter
Array.prototype.every Array.prototype.some Array.prototype.reduce
Array.prototype.reduceRight Array.prototype.indexOf
Array.prototype.lastIndexOf String.prototype.trim Date.now

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Function.prototype.bind
Object.create
Object.keys
Array.isArray
Array.prototype.forEach
Array.prototype.map
Array.prototype.filter
Array.prototype.every
Array.prototype.some
Array.prototype.reduce
Array.prototype.reduceRight
Array.prototype.indexOf
Array.prototype.lastIndexOf
String.prototype.trim
Date.now

详情:

自动绑定模板(template)

为了利用<polymer-element>外的绑定数据,包装一个Yo应用?利用里面的自动绑定<template>元素:

XHTML

<body unresolved fullbleed> <template is=”auto-binding”>
<core-scaffold id=”scaffold”> … </core-scaffold>
</template> </body>

1
2
3
4
5
6
7
<body unresolved fullbleed>
  <template is="auto-binding">
    <core-scaffold id="scaffold">
      …
    </core-scaffold>
  </template>
</body>

提示,<template>自动绑定元素允许我们在主要页面里使用{{}},表达式和on-*来声明事件处理器。

对象的创建

JavaScript
支持四种类型的对象:内部对象、生成的对象、宿主给出的对象(如 Internet
浏览器中的 windowdocument)以及ActiveX 对象(外部组件)。

Microsoft Jscript 提供了 11
个内部(或“内置”)对象。它们是Array、Boolean、Date、Function、Global、Math、Number、Object、RegExp、Error
以及 String 对象。每一个对象有相关的方法和属性,

JavaScript中对象的创建有以下几种方式:

(1)使用内置对象 (2)使用JSON符号 (3)自定义对象构造

1
2
3
(1)使用内置对象
(2)使用JSON符号
(3)自定义对象构造

使用数据模型( data model)简化标记

利用数据模型来产生标记可以大量减少你写标记的数量。在我们的案例里,所有的菜单条目和页面都可以利用一对<template
repeat>元素来呈现。

XHTML

<core-menu valueattr=”hash” selected=”{{route}}”> <template
repeat=”{{page in pages}}”> <paper-item hash=”{{page.hash}}”
noink> <core-icon icon=”label-outline”></core-icon> <a
href=”#{{page.hash}}”>{{page.name}}</a> </paper-item>
</template> </core-menu> <core-animated-pages
valueattr=”hash” selected=”{{route}}” transitions=”slide-from-right”>
<template repeat=”{{page in pages}}”> <section
hash=”{{page.hash}}” layout vertical center-center>
<div>{{page.name}}</div> </section> </template>
</core-animated-pages>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<core-menu valueattr="hash" selected="{{route}}">
  <template repeat="{{page in pages}}">
    <paper-item hash="{{page.hash}}" noink>
      <core-icon icon="label-outline"></core-icon>
      <a href="#{{page.hash}}">{{page.name}}</a>
    </paper-item>
  </template>
</core-menu>
 
<core-animated-pages valueattr="hash" selected="{{route}}"
                     transitions="slide-from-right">
  <template repeat="{{page in pages}}">
    <section hash="{{page.hash}}" layout vertical center-center>
      <div>{{page.name}}</div>
    </section>
  </template>
</core-animated-pages>

上面的标记由下面的数据模型来驱动:

XHTML

<script> var template =
document.querySelector(‘template[is=”auto-binding”]’); template.pages
= [ {name: ‘Single’, hash: ‘one’}, {name: ‘page’, hash: ‘two’}, {name:
‘app’, hash: ‘three’}, … ]; </script>

1
2
3
4
5
6
7
8
9
<script>
  var template = document.querySelector(‘template[is="auto-binding"]’);
  template.pages = [
    {name: ‘Single’, hash: ‘one’},
    {name: ‘page’, hash: ‘two’},
    {name: ‘app’, hash: ‘three’},
    …
  ];
</script>

注意,<core-animated-pages>和<core-menu>通过绑定它们的selected属性来关联在一起。现在,当用户点击一个导航条目时,页面会做出相应的更新。valueattr=”hash”设置告诉两个元素在每个条目里使用hash属性作为选择的值。

XHTML

<!– data-bind the menu selection with the page selection –>
<core-menu valueattr=”hash” selected=”{{route}}”> …
<core-animated-pages valueattr=”hash” selected=”{{route}}”>

1
2
3
4
<!– data-bind the menu selection with the page selection –>
<core-menu valueattr="hash" selected="{{route}}">
<core-animated-pages valueattr="hash" selected="{{route}}">

展示

一、使用内置对象

JavaScript可用的内置对象可分为两种:
1,JavaScript语言原生对象(语言级对象),如String、Object、Function等;
2,JavaScript运行期的宿主对象(环境宿主级对象),如window、document、body等。

1
2
3
4
JavaScript可用的内置对象可分为两种:
 
1,JavaScript语言原生对象(语言级对象),如String、Object、Function等;
2,JavaScript运行期的宿主对象(环境宿主级对象),如window、document、body等。

URL路由(URL routing)和深层链接

<flatiron-director>是一个包装了flatiron director JS
library(一个JS库)的web组件。改变它的route属性把URL#号(URL
hash)更新到相同的值。

当我们想在页面加载时维持上次的视图时,数据绑定再次派上用场。把路由(director.js里的director)、菜单和页面元素连接起来并使它们同步。当一个更新时,其他的同样跟着更新。

XHTML

<flatiron-director route=”{{route}}” autoHash> … <core-menu
selected=”{{route}}”> … <core-animated-pages
selected=”{{route}}”>

1
2
3
4
5
<flatiron-director route="{{route}}" autoHash>
<core-menu selected="{{route}}">
<core-animated-pages selected="{{route}}">

深层链接-当模板准备好时,初始化路由。

XHTML

template.addEventListener(‘template-bound’, function(e) { // Use URL
hash for initial route. Otherwise, use the first page. this.route =
this.route || DEFAULT_ROUTE; };

1
2
3
4
template.addEventListener(‘template-bound’, function(e) {
// Use URL hash for initial route. Otherwise, use the first page.
this.route = this.route || DEFAULT_ROUTE;
};

内置对象列表

Array Boolean Date Error EvalError Function Infinity JSON Map Math NaN
Number Object ParallelArray Promise Proxy RegExp Set String Symbol
SyntaxError Uint32Array WeakSet decodeURI decodeURIComponent()
encodeURI() encodeURIComponent() escape()已废弃 eval() isFinite()
isNaN() null parseFloat parseInt undefined

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Array
Boolean
Date
Error
EvalError
Function
Infinity
JSON
Map
Math
NaN
Number
Object
ParallelArray
Promise
Proxy
RegExp
Set
String
Symbol
SyntaxError
Uint32Array
WeakSet
decodeURI
decodeURIComponent()
encodeURI()
encodeURIComponent()
escape()已废弃
eval()
isFinite()
isNaN()
null
parseFloat
parseInt
undefined

以上资料来源于:

其他路由库

如果你不喜欢<flatiron-director>,可以试试<app-router>或者<more-routing>。它们都是可以实现更复杂功能的路由(通配符,HTML5历史API,动态内容)。我个人更喜欢<flatiron-director>,因为它简单易用并且可以和<core-animated-pages>很好地配合使用

例子: <more-routing>

XHTML

<more-route-switch> <template when-route=”user”>
<header>User {{params.userId}}</header> <template if=”{{
route(‘user-bio’).active }}”> All the details about
{{params.userId}}. </template> </template> <template
when-route=”/about”> It’s a routing demo! <a _href=”{{
urlFor(‘user-bio’, {userId: 1}) }}”>Read about user 1</a>.
</template> <template else> The index. </template>
</more-route-switch>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<more-route-switch>
  <template when-route="user">
    <header>User {{params.userId}}</header>
    <template if="{{ route(‘user-bio’).active }}">
      All the details about {{params.userId}}.
    </template>
  </template>
  <template when-route="/about">
    It’s a routing demo!
    <a _href="{{ urlFor(‘user-bio’, {userId: 1}) }}">Read about user 1</a>.
  </template>
  <template else>
    The index.
  </template>
</more-route-switch>

例子: <app-router>

XHTML

<app-route path=”/home”
import=”/pages/home-page.html”></app-route> <app-route
path=”/customer/*”
import=”/pages/customer-page.html”></app-route> <app-route
path=”/order/:id” import=”/pages/order-page.html”></app-route>
<app-route path=”*”
import=”/pages/not-found-page.html”></app-route>

1
2
3
4
<app-route path="/home" import="/pages/home-page.html"></app-route>
<app-route path="/customer/*" import="/pages/customer-page.html"></app-route>
<app-route path="/order/:id" import="/pages/order-page.html"></app-route>
<app-route path="*" import="/pages/not-found-page.html"></app-route>

自定义对象构造

创建高级对象构造有两种方式:使用“this”关键字构造、使用原型prototype构造

键盘导航

键盘支持的重要性不仅仅是为了方便的访问,它同样会使SPA用户刚到更开心。

<core-a11y-keys>是一个标准化浏览器键盘事件的嵌入组件。它可以在你的应用里添加键盘支持。这里有一个例子:

XHTML

<core-a11y-keys target=”{{parentElement}}” keys=”up down left right
space space+shift”
on-keys-pressed=”{{keyHandler}}”></core-a11y-keys>

1
2
3
<core-a11y-keys target="{{parentElement}}"
keys="up down left right space space+shift"
on-keys-pressed="{{keyHandler}}"></core-a11y-keys>

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注