jasmine

前端小菜鸟的进阶之路

  • 主页
  • 随笔
所有文章 友链 关于我

jasmine

前端小菜鸟的进阶之路

  • 主页
  • 随笔

16个正则表达式

2016-10-21

概述

正则表达式,一个十分古老而又强大的文本处理工具,仅仅用一段非常简短的表达式语句,便能够快速实现一个非常复杂的业务逻辑。熟练地掌握正则表达式的话,能够使你的开发效率得到极大的提升。

快速进入正题

  1. 校验密码强度

    密码的强度必须是包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间。
    var reg=/^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$/
    if (reg.test(tel)){
        return true;
    }else{
        return false;
    }
    
  2. 校验中文

    字符串仅能是中文。
    var reg=/^[\\u4e00-\\u9fa5]{0,}$/
    
  3. 由数字、26个英文字母或下划线组成的字符串

    var reg=/^\\w+$/
    
  4. 校验E-Mail 地址

    同密码一样,下面是E-mail地址合规性的正则检查语句。
    var reg=/[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?/
    
  5. 校验身份证号码

    下面是身份证号码的正则校验。15 或 18位。
    15位:
    var reg=/^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}$/
    18位:
    var reg=/^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9]|X)$/
    
  6. 校验日期

    “yyyy-mm-dd“ 格式的日期校验,已考虑平闰年。
    var reg=/^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$/
    
  7. 校验金额

    金额校验,精确到2位小数。
    var reg=/^[0-9]+(.[0-9]{2})?$/
    
  8. 校验手机号

    下面是国内 13、15、18开头的手机号正则表达式。(可根据目前国内收集号扩展前两位开头号码)
    var reg=/^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}$/
    
  9. 判断IE的版本

    IE目前还没被完全取代,很多页面还是需要做版本兼容,下面是IE版本检查的表达式。
    var reg=/^.*MSIE [5-8](?:\\.[0-9]+)?(?!.*Trident\\/[5-9]\\.0).*$/
    
  10. 校验IP-v4地址

    P4 正则语句。
    var reg=/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b/
    
  11. 校验IP-v6地址

    IP6 正则语句。
    var reg=/(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))
    
  12. 检查URL的前缀

    应用开发中很多时候需要区分请求是HTTPS还是HTTP,通过下面的表达式可以取出一个url的前缀然后再逻辑判断。
    if (!s.match(/^[a-zA-Z]+:\\/\\//)){
        s = 'http://' + s;
    }
    
  13. 提取URL链接

    下面的这个表达式可以筛选出一段文本中的URL。
    var reg=/^(f|ht){1}(tp|tps):\\/\\/([\\w-]+\\.)+[\\w-]+(\\/[\\w- ./?%&=]*)?/
    
  14. 文件路径及扩展名校验

    验证windows下文件路径和扩展名(下面的例子中为.txt文件)
    var reg=/^([a-zA-Z]\\:|\\\\)\\\\([^\\\\]+\\\\)*[^\\/:*?"<>|]+\\.txt(l)?$/
    
  1. 提取网页图片

    假若你想提取网页中所有图片信息,可以利用下面的表达式。
    var reg=/\\< *[img][^\\\\>]*[src] *= *[\\"\\']{0,1}([^\\"\\'\\ >]*)/
    
  2. 匹配HTML标签

    通过下面的表达式可以匹配出HTML中的标签属性。
    var reg=/<\\/?\\w+((\\s+\\w+(\\s*=\\s*(?:".*?"|'.*?'|[\\^'">\\s]+))?)+\\s*|\\s*)\\/?>/
    
  • 16个正则表达式

展开全文 >>

ES6新特性

2016-09-21

没有太多啰嗦,说那么多介绍也没多少人会看,我们直接看特性吧,ES6多数人认为主要的十大特性如下,排名不分先后:

  • Default Parameters(默认参数)

  • Template Literals (模板文本)

  • Multi-line Strings (多行字符串)

  • Destructuring Assignment (解构赋值)

  • Enhanced Object Literals (增强的对象文本)

  • Arrow Functions (箭头函数)

  • Promises

  • Block-Scoped Constructs Let and Const(块作用域构造Let and Const)

  • Classes(类)

  • Modules(模块)

Default Parameters(默认参数)

before

var fn = function (height) {
    var height = height || 50;
       ...;
}

now

var fn = function (height=50) {
       ...;
}

Template Literals(模板对象)

before

var name = 'Your name is ' + first + ' ' + last + '.';

now

var name = `Your name is ${first} ${last}. `;

Multi-line Strings (多行字符串)

before

var roadPoem = 'Then took the other, as just as fair,nt'
                + 'Had worn them really about the same,nt';

now

var roadPoem = `Then took the other, as just as fair,
                Had worn them really about the same,`;

Destructuring Assignment (解构赋值)

before

someArray=[1,2,3];
var first = someArray[0];
var second = someArray[1];
var third = someArray[2];

var obj={ foo: "lorem", bar: "ipsum" };
var foo = obj.foo;
var bar = obj.bar;

now

someArray=[1,2,3];
var [first, second, third] = someArray;
console.log(first);  // 1
console.log(second); // 2
console.log(third);  // 3

var { foo, bar } = { foo: "lorem", bar: "ipsum" };
console.log(foo); // "lorem"
console.log(bar); // "ipsum"

Enhanced Object Literals (增强的对象字面量)

before

var obj = {
    handler: handler,
    toString: function() {
        return "d " + super.toString();
    },
    prop42: 42

};

now

var obj = {
    handler,   //ES6特性 === handler: handler,
    toString() {   //ES6函数
        return "d " + super.toString();
       },
    [ 'prop_' + (() => 42)() ]: 42  
    //主要是这个可以在字面量中加入变量 == prop42: 42
};

Arrow Functions in(箭头函数)

以前我们使用闭包,this总是预期之外地产生改变,而箭头函数的迷人之处在于,现在你的this可以按照你的预期使用了,身处箭头函数里面,this还是原来的this。

有了箭头函数在ES6中, 我们就不必用that = this或 self = this 或 _this = this 或.bind(this)如下:

before

var _this = this;
$('.btn').click(function(event){
     _this.sendData();
})

now

$('.btn').click((event) =>{
      this.sendData();
})

Promises in ES6

before

setTimeout(function(){
      console.log('Yay!');
      setTimeout(function(){
        console.log('Wheeyee!');
      }, 1000)
}, 1000);

now

var wait1000 =  ()=> new Promise((resolve, reject)=> {setTimeout(resolve, 1000)});
wait1000()
    .then(function() {
        console.log('Yay!')
        return wait1000()
    })
    .then(function() {
           console.log('Wheeyee!')
       });

好吧,我也没看出来哪里好用了…

Block-Scoped Constructs Let and Const(块作用域和构造let和const)

  • Let是一种新的变量申明方式,它允许你把变量作用域控制在块级里面。用大括号定义代码块(作用域)
  • const,它就是一个不变量,也是块级作用域就像let一样。
    before

    for(var i=0; i<1; i++){
        var a=1;
        {
            var  a=2;
            console.log(a) //2
        }
        console.log(a)  //2
    }
    console.log(i) //1
    console.log(a) //2
    

    now

    for(let i=0; i<1; i++){
        const a=1;
        {
            const  a=2;
            console.log(a) //2
        }
        console.log(a)  //1
    }
    console.log(a) // not defined
    console.log(i) // not defined
    

Classes (类)

before

function Circle(x) {
   this.x = x;
}
Circle.classFn = function() { ... }

Circle.prototype = {
   fn1() {
       return ..;
   },

   get fn2() {
       return this.x;
   },
   set fn2(x) {
       this.x = x*2;
   }
};

now

class Circle {
    constructor(x) {
        this.x = x;
    };

    static classFn() { ... };

    fn1(){
        return ..;
    }
    get fn2() {
        return this.x;
    };
    set fn2(val) {
        this.x = x*2;
    };
 }

Modules (模块)

before

module.js有port变量和getAccounts 方法:

module.exports = {  port: 3000,  getAccounts: function() {    ...  }}

main.js需要依赖require(‘module’) 导入module.js:

var service = require('module.js');console.log(service.port); // 3000

now

导出module.js
export var port = 3000;export function getAccounts(url) {  ...}

导入方式一
import {port, getAccounts} from 'module';console.log(port); // 3000

导入方式二
import * as service from 'module';//导入全部模块
console.log(service.port); // 3000
  • ES6

展开全文 >>

MarkDown 语法

2016-09-14

导语

Markdown 是一种轻量级的「标记语言」,它的优点很多,目前也被越来越多的写作爱好者,撰稿者广泛使用。看到这里请不要被「标记」、「语言」所迷惑,Markdown 的语法十分简单。常用的标记符号也不超过十个,这种相对于更为复杂的 HTML 标记语言来说,Markdown 可谓是十分轻量的,学习成本也不需要太多,且一旦熟悉这种语法规则,会有一劳永逸的效果。

工具

在 Mac OS X 上,我强烈建议你用 Mou 这款免费且十分好用的 Markdown 编辑器。它支持实时预览,既左边是你编辑 
Markdown 语言,右边会实时的生成预览效果。在Win上推荐使用 MarkdownPad 或者 MarkPad。

Markdown 语法的简要规则

图片与链接

图片为:![图片名](图片地址http://)
       如果是本地图片请使用绝对路径
链接为:[显示的链接名](链接地址http://..)        

myGitHub
pic

标题

#~######分别表示一级-六级标题

title

注意在符号后需要一个空格,这是最标准的 Markdown 语法。

粗体与斜体

用一对*号括起来的是斜体,两对*号括起来的是粗体
*斜体*   **粗体**

表格

表格是我觉得 Markdown 比较累人的地方,冒号表明文字对齐方式,例子如下:
| Tables        | Are           | Cool  |
| :-----------: |:-------------:|------:|
| col 3 is      | right-aligned | $1600 |
| col 2 is      | centered      |   $12 |
| zebra stripes | are neat      |    $1 |
Tables Are Cool
col 3 is right-aligned $1600
col 2 is centered $12
zebra stripes are neat $1

代码框

比如我这些有背景的文字描述都是框框括起来的
实现:tab键后再输入文字

分割线

直接输入三个星号


高亮

用一对``号括起来

个人博客:https://jasonellen.github.io

引用

大于号后面的内容就是引用:> 这里是引用的内容
title

列表

只需要在文字前加上 - 或 * 即可变为无序列表,有序列表则直接在文字前加1. 2. 3. 符号要和文字之间加上一个字符的空格。

title

无序列表

  • 1
  • 2
  • 3

    有序列表

  1. 1
  2. 2

title: MarkDown语法
date: 2016-12-02 17:58:00

tags:

  • Markdown

展开全文 >>

基于github和hexo创建个人博客

2016-09-03

准备工作

1. github账号, 这是我的github账号主页,在这个网站注册一个账户 欢迎star https://github.com/wangyalijas.

2. node, 用来生成静态页面的 到Node.js官网下载相应平台的最新版本,一路安装即可。 node.js http://nodejs.org/en/.

3. 安装hexo,本人是Mac系统,其他系统的朋友这部分可以看官网教程。 hexo官网 https://hexo.io/zh-cn/docs/index.html.


开始

安装

$ sudo npm install -g hexo

测试

$ hexo

创建仓库

在你的以github.io结尾的仓库中创建blog文件夹并进入

初始化

$ hexo init

修改_config.xml 修改相关信息

title: 王二爷
subtitle: 前端小菜鸟的进阶之路
description: 前端小菜鸟的进阶之路
author: Jasmine
language: zh-CN
timezone:

底部也要修改

deploy: 
  type: git
  repo: https://github.com/wangyalijas/wangyalijas.github.io.git

启动本地服务

$ hexo server

此时在本地打开http://localhost:4000

本地就会看到

本地


github账号

git

$ npm install hexo-deployer-git --save

编译html

$ hexo g

上传github

$ hexo d

新建目录

$ hexo 测试目录
  • github

展开全文 >>

数组常见函数

2016-08-07

(1) shift

删除数组第一个元素,并返回该元素,跟pop差不多

var arr=[1,2,1,3,2,3,5,6,5];
arr.shift();
console.log(arr);    //[2, 1, 3, 2, 3, 5, 6, 5]

(2) unshift

跟shift相反,往数组最前面添加元素,并返回数组新长度

var arr=[1,2,1,3,2,3,5,6,5];
arr.unshift('haha');
console.log(arr);    //["haha", 1, 2, 1, 3, 2, 3, 5, 6, 5]

(3) concat

在现有数组后面追加数组,并返回新数组,不影响现有数组

var arr=[1,2,1,3,2,3,5,6,5];
var arr1=['hahha'];
console.log(arr.concat(arr1));//[1, 2, 1, 3, 2, 3, 5, 6, 5, "hahha"]

(4) join

用指定间隔符连起来,把数组转为字符串

var arr=[1,2,1,3,2,3,5,6,5];

console.log(arr.join());   //1,2,1,3,2,3,5,6,5
console.log(arr.toString())//1,2,1,3,2,3,5,6,5toString()也可以

console.log(arr.join('*'))//1*2*1*3*2*3*5*6*5

(5) pop

删除数组最后一个元素,并返回该元素

var a =    ["aa","bb","cc"];
console.log(a.pop())    //cc
console.log(a)            //["aa", "bb"]

(6) reverse

对数组进行反排序跟,sort()一样,取第一字符ASCII值进行比较

var a =    ["aa","bb","cc"];
console.log(a.reverse());    //["cc", "bb", "aa"]
console.log(a)                    //["cc", "bb", "aa"]

(7) slice

返回数组片段

var a =    ["aa","bb","cc"];
console.log(a.slice(1,2))   //["bb"]从第一个开始到第二个,但不包含第二个
console.log(a.slice(1))        //["bb", "cc"]

数组方法小试牛刀

  1. 翻转字符串

console.log("asd".split(""))            //["a", "s", "d"]
console.log("asd".split("").reverse().join())   //d,s,a        
  1. [1,2,1,3,2,3,5,6,5] 去除重复元素

var arr=[1,2,1,3,2,3,5,6,5];
var newarr=[];
for(var i=0;i<arr.length;i++){
    if(newarr.indexOf(arr[i])==-1){
        newarr.push(arr[i]);
    }
}
console.log(newarr)//[1, 2, 3, 5, 6]    

3.获取里面字面最多的字母


var str = "asdfjksdjfljsdflkjsdjf" //定义需要判断的字符串
var maxlength = 0; //用来存最大数量的变量,并初始化为0
var result; //用来接收结果

while(str != ""){
      var oldstr = str; 
      var getstr = str.substr(0,1);
    str = str.replace(new RegExp(getstr,"g"),"");
  if(oldstr.length - str.length >maxlength){
      maxlength = oldstr.length - str.length;
      result = getstr + '='+ maxlength;
  }
}
console.log(result);
  • js

展开全文 >>

js字符串函数

2016-08-06

(一)concat

将两个或多个字符的文本组合起来,返回一个新的字符串。

var a='hello';
var b=',world';
console.log(a.concat(b));//hello,world

(二)indexOf

返回字符串中一个子串第一处出现的索引(从左到右搜索)。如果没有匹配项,返回 -1 。

var index1 = a.indexOf("l");
//index1 = 2
var index2 = a.indexOf("l",3);
//index2 = 3

(三)charAt

返回指定位置的字符。

console.log(a.charAt(0));//h

(四)lastIndexOf

返回字符串中一个子串最后一处出现的索引(从右到左搜索),如果没有匹配项,返回 -1 。

console.log(a.lastIndexOf('l'))  //3
console.log(a.indexOf("l"))   //2

(五)match

检查一个字符串匹配一个正则表达式内容,如果么有匹配返回 null。

var re = new RegExp(/^\w+$/);
var is_alpha1 = a.match(re);
//is_alpha1 = "hello"
var is_alpha2 = b.match(re);
//is_alpha2 = null

(六)substring

返回字符串的一个子串,传入参数是起始位置和结束位置。

var str='absd';
console.log(str.substring(2));//sd

(七)substr

返回字符串的一个子串,传入参数是起始位置和长度

var str='absd';
console.log(str.substr(2,1));//s

(八)replace

用来查找匹配一个正则表达式的字符串,然后使用新字符串代替匹配的字符串。

var result1 = a.replace(re,"Hello");
//result1 = "Hello"
var result2 = b.replace(re,"Hello");
//result2 = ",world"

(九)toLowerCase

将整个字符串转成小写字母。

var lower_string = a.toLowerCase();
//lower_string = "hello"

(十)toUpperCase

将整个字符串转成大写字母。

var upper_string = a.toUpperCase();
//upper_string = "HELLO"

title: js字符串函数小结
date: 2016-12-04 18:40:21

tags:


title: js字符串函数
date: 2016-8-03 20:01:37

tags:

(一)concat

将两个或多个字符的文本组合起来,返回一个新的字符串。

var a='hello';
var b=',world';
console.log(a.concat(b));//hello,world

(二)indexOf

返回字符串中一个子串第一处出现的索引(从左到右搜索)。如果没有匹配项,返回 -1 。

var index1 = a.indexOf("l");
//index1 = 2
var index2 = a.indexOf("l",3);
//index2 = 3

(三)charAt

返回指定位置的字符。

console.log(a.charAt(0));//h

(四)lastIndexOf

返回字符串中一个子串最后一处出现的索引(从右到左搜索),如果没有匹配项,返回 -1 。

console.log(a.lastIndexOf('l'))  //3
console.log(a.indexOf("l"))   //2

(五)match

检查一个字符串匹配一个正则表达式内容,如果么有匹配返回 null。

var re = new RegExp(/^\w+$/);
var is_alpha1 = a.match(re);
//is_alpha1 = "hello"
var is_alpha2 = b.match(re);
//is_alpha2 = null

(六)substring

返回字符串的一个子串,传入参数是起始位置和结束位置。

var str='absd';
console.log(str.substring(2));//sd

(七)substr

返回字符串的一个子串,传入参数是起始位置和长度

var str='absd';
console.log(str.substr(2,1));//s

(八)replace

用来查找匹配一个正则表达式的字符串,然后使用新字符串代替匹配的字符串。

var result1 = a.replace(re,"Hello");
//result1 = "Hello"
var result2 = b.replace(re,"Hello");
//result2 = ",world"

(九)toLowerCase

将整个字符串转成小写字母。

var lower_string = a.toLowerCase();
//lower_string = "hello"

(十)toUpperCase

将整个字符串转成大写字母。

var upper_string = a.toUpperCase();
//upper_string = "HELLO"
  • js

展开全文 >>

用Javascript获取页面元素的位置

2016-08-05

一、网页的大小和浏览器窗口的大小

首先,要明确两个基本概念。

一张网页的全部面积,就是它的大小。通常情况下,网页的大小由内容和CSS样式表决定。

浏览器窗口的大小,则是指在浏览器窗口中看到的那部分网页面积,又叫做viewport(视口)。

很显然,如果网页的内容能够在浏览器窗口中全部显示(也就是不出现滚动条),那么网页的大小和浏览器窗口的大小是相等的。如果不能全部显示,则滚动浏览器窗口,可以显示出网页的各个部分。

二、获取网页的大小

网页上的每个元素,都有clientHeight和clientWidth属性。这两个属性指元素的内容部分再加上padding的所占据的视觉面积,不包括border和滚动条占用的空间。

因此,document元素的clientHeight和clientWidth属性,就代表了网页的大小。

function getViewport(){
if (document.compatMode == "BackCompat"){
    return {
        width: document.body.clientWidth,
        height: document.body.clientHeight
    }
} else {
    return {
        width: document.documentElement.clientWidth,
        height: document.documentElement.clientHeight
        }
    }
}

上面的getViewport函数就可以返回浏览器窗口的高和宽。使用的时候,有三个地方需要注意:

1)这个函数必须在页面加载完成后才能运行,否则document对象还没生成,浏览器会报错。

2)大多数情况下,都是document.documentElement.clientWidth返回正确值。但是,在IE6的quirks模式中,document.body.clientWidth返回正确的值,因此函数中加入了对文档模式的判断。

3)clientWidth和clientHeight都是只读属性,不能对它们赋值。

三、获取网页大小的另一种方法

网页上的每个元素还有scrollHeight和scrollWidth属性,指包含滚动条在内的该元素的视觉面积。

那么,document对象的scrollHeight和scrollWidth属性就是网页的大小,意思就是滚动条滚过的所有长度和宽度。

仿照getViewport()函数,可以写出getPagearea()函数。

function getPagearea(){
    if (document.compatMode == "BackCompat"){
        return {
            width: document.body.scrollWidth,
            height: document.body.scrollHeight
        }
    } else {
        return {
            width: document.documentElement.scrollWidth,
            height: document.documentElement.scrollHeight
        }
    }
}

但是,这个函数有一个问题。如果网页内容能够在浏览器窗口中全部显示,不出现滚动条,那么网页的clientWidth和scrollWidth应该相等。但是实际上,不同浏览器有不同的处理,这两个值未必相等。所以,我们需要取它们之中较大的那个值,因此要对getPagearea()函数进行改写。

function getPagearea(){
    if (document.compatMode == "BackCompat"){
        return {
            width: Math.max(document.body.scrollWidth,
                            document.body.clientWidth),
            height: Math.max(document.body.scrollHeight,
                            document.body.clientHeight)
        }
    } else {
        return {
            width: Math.max(document.documentElement.scrollWidth,
                            document.documentElement.clientWidth),
            height: Math.max(document.documentElement.scrollHeight,
                            document.documentElement.clientHeight)
        }
    }
}

四、获取网页元素的绝对位置

网页元素的绝对位置,指该元素的左上角相对于整张网页左上角的坐标。这个绝对位置要通过计算才能得到。

首先,每个元素都有offsetTop和offsetLeft属性,表示该元素的左上角与父容器(offsetParent对象)左上角的距离。所以,只需要将这两个值进行累加,就可以得到该元素的绝对坐标。

下面两个函数可以用来获取绝对位置的横坐标和纵坐标。

function getElementLeft(element){
    var actualLeft = element.offsetLeft;
    var current = element.offsetParent;
    while (current !== null){
        actualLeft += current.offsetLeft;
        current = current.offsetParent;
    }
    return actualLeft;
}

function getElementTop(element){
    var actualTop = element.offsetTop;
    var current = element.offsetParent;
    while (current !== null){
        actualTop += current.offsetTop;
        current = current.offsetParent;
    }
    return actualTop;
}

由于在表格和iframe中,offsetParent对象未必等于父容器,所以上面的函数对于表格和iframe中的元素不适用。

五、获取网页元素的相对位置

网页元素的相对位置,指该元素左上角相对于浏览器窗口左上角的坐标。

有了绝对位置以后,获得相对位置就很容易了,只要将绝对坐标减去页面的滚动条滚动的距离就可以了。滚动条滚动的垂直距离,是document对象的scrollTop属性;滚动条滚动的水平距离是document对象的scrollLeft属性。

对上一节中的两个函数进行相应的改写:

function getElementViewLeft(element){
    var actualLeft = element.offsetLeft;
    var current = element.offsetParent;
    while (current !== null){
        actualLeft += current.offsetLeft;
        current = current.offsetParent;
    }
    if (document.compatMode == "BackCompat"){
        var elementScrollLeft=document.body.scrollLeft;
    } else {
        var elementScrollLeft=document.documentElement.scrollLeft; 
    }
        return actualLeft-elementScrollLeft;
    }
function getElementViewTop(element){
    var actualTop = element.offsetTop;
    var current = element.offsetParent;
    while (current !== null){
        actualTop += current. offsetTop;
        current = current.offsetParent;
    }
    if (document.compatMode == "BackCompat"){
        var elementScrollTop=document.body.scrollTop;
    } else {
        var elementScrollTop=document.documentElement.scrollTop; 
    }
    return actualTop-elementScrollTop;
}

scrollTop和scrollLeft属性是可以赋值的,并且会立即自动滚动网页到相应位置,因此可以利用它们改变网页元素的相对位置。另外,element.scrollIntoView()方法也有类似作用,可以使网页元素出现在浏览器窗口的左上角。

六、获取元素位置的快速方法

除了上面的函数以外,还有一种快速方法,可以立刻获得网页元素的位置。

那就是使用getBoundingClientRect()方法。它返回一个对象,其中包含了left、right、top、bottom四个属性,分别对应了该元素的左上角和右下角相对于浏览器窗口(viewport)左上角的距离。

所以,网页元素的相对位置就是

var X= this.getBoundingClientRect().left;

var Y =this.getBoundingClientRect().top;

再加上滚动距离,就可以得到绝对位置

var X= this.getBoundingClientRect().left+document.documentElement.scrollLeft;

var Y =this.getBoundingClientRect().top+document.documentElement.scrollTop;
  • js

展开全文 >>

JavaScript插入节点小结

2016-08-04

1.JS原生API插入节点的方式大致有innerHTML、outerHTML、appendChild、insertBefore、insertAdjacentHTML、applyElement这6种。

2.这里总结一下各自的用法,并封装包含before、prepend、append、after、applyElement的一系列函数。

1. 六种方式的用法

  1. innerHTML:获取标签内部的HTML内容。

  2. outerHTML:获取包括目标标签在内,以及内部HTML的内容。

  3. appendChild:向目标标签末尾添加子节点,返回参数节点。

  4. insertBefore:向目标节点的第二个参数位置添加第一个参数为子节点,返回第一个参数。

  5. insertAdjacentHTML:向目标节点的指定位置添加节点;第二个参数为要添加的节点,第一个参数指定位置,位置包括beforebegin(添加为previousSibling)、afterbegin(添加为firstChild)、beforeend(添加为lastChild)、afterend(添加为nextSibling)。它还有两个兄弟函数,分别是insertAdjacentElement和insertAdjacentText,前者添加元素并返回该元素,后者添加文本。

  6. applyElement:IE的函数,将参数节点设置成目标节点的外包围或者内包围;第一个为参数节点,第二个参数指定方式,方式包括inside(内包围,即参数节点将目标节点的子节点包起来)、outside(外包围,即参数节点将目标节点包起来)。

上面6种方式除了前两个是属性外,另外4个都是函数。innerHTML与outerHTML没有什么好说的,直接用HTML字符串赋值就能达到插入的目的了;appendChild简单套一层函数外壳就能封装成append函数;insertBefore让节点的插入方式非常灵活;insertAdjacentHTML可以实现字符串的插入方式;applyElement函数兼容一下即可成为JQuery的Wrap系列函数。

二、实现before、prepend、append、after函数

before把参数节点插入到目标节点前面,只需获取目标节点的父节点,然后父节点调用insertBefore即可。
prepend把参数节点插入到目标节点第一个子节点的位置,获取目标节点的第一个子节点,然后调用insertBefore即可。
append的功能和原生API里appendChild的功能一样。
after把参数节点插入到目标节点的后面,只需获取目标节点的nextSibling,然后调用insertBefore即可。
具体实现如下:
var append = function(node, scope) {
    if(node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11) {
        scope.appendChild(node);
    }
};
var prepend = function(node, scope) {
    if(node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11) {
        scope.insertBefore(node, scope.firstChild);
    }
};
var before = function(node, scope) {
    if(node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11) {
        scope.parentNode.insertBefore(node, scope);
    }
};
var after = function(node, scope) {
    if(node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11) {
        scope.parentNode.insertBefore(node, scope.nextSibling);
    }
};
上面函数只能插入元素节点、文档节点以及文档碎片,都是节点类型。如果我们想要支持字符串形式的插入方式,则需要封装insertAdjacentHTML了。
这里利用策略模式,将我要实现的四个函数做成策略对象,然后动态生成,以达到精简代码的效果:
//E5才有的迭代, 所以迭代要预先兼容
Array.prototype.forEach = [].forEach || function(callback) {
    for(var i = 0, len = this.length; i < len; i++) {
        callback.call(this[i], this[i], i, this);
     }
};  

/**插入策略集合**/
var insertStrategies = {
    before : function(node, scope) {
    scope.parentNode.insertBefore(node, scope);
},
prepend : function(node, scope) {
    scope.insertBefore(node, scope.firstChild);
},
append : function(node, scope) {
    scope.appendChild(node);
},
after : function(node, scope) {
    scope.parentNode.insertBefore(node, scope.nextSibling);
},

/*支持字符串格式的插入, 注意:要兼容不可直接做div子类的元素*/
/*insertAdjace还有Element和Text,前者只能插元素,后者只能插文本*/
beforestr : function(node, scope) {
    scope.insertAdjacentHTML('beforeBegin', node);
},
prependstr : function(node, scope) {
    scope.insertAdjacentHTML('afterBegin', node);
},
appendstr : function(node, scope) {
    scope.insertAdjacentHTML('beforeEnd', node);
},
afterstr : function(node, scope) {
    scope.insertAdjacentHTML('afterEnd', node);
}
};

//响应函数
var returnMethod = function(method, node, scope) {
//如果是字符串
if(typeof node === 'string') {
    return insertStrategies[method + 'str'](node, scope);
}
//1(元素)、9(文档)、11(文档碎片)
if(node.nodeType === 1 || node.nodeType === 9 || node.nodeType === 11) {
    return insertStrategies[method](node, scope);
}
//此处还可添加节点集合的处理逻辑,用于处理选择其引擎获取的节点集合。
};

['before', 'prepend', 'append', 'after'].forEach(function(method){
window[method] = function(node, scope) {
    returnMethod(method, node, scope);
};
});
所有函数都被实现为window的属性,所以直接当全局函数调用即可,这些函数并不属于节点对象,所以scope参数指代的是目标节点。下面兼容applyElement后,我们将所有的函数都扩展到HTMLElement的原型上面去,这样就可以省略scope参数,以达到元素节点直接调用的效果。当然对于框架来说,一般是生成框架对象,然后把这些函数扩展到其原型上去,这样可以避免修改原生对象的原型

展开全文 >>

面向对象编程(一):封装

2016-08-03

Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象。但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类)。

那么,如果我们要把”属性”(property)和”方法”(method),封装成一个对象,甚至要从原型对象生成一个实例对象,我们应该怎么做呢?

一、 生成实例对象的原始模式

一、 生成实例对象的原始模式

var Cat = {
    name : '',
    color : ''
}

现在,我们需要根据这个原型对象的规格(schema),生成两个实例对象。

var cat1 = {}; // 创建一个空对象
    cat1.name = "大毛"; // 按照原型对象的属性赋值
    cat1.color = "黄色";
var cat2 = {};
    cat2.name = "二毛";
    cat2.color = "黑色";

好了,这就是最简单的封装了,把两个属性封装在一个对象里面。但是,这样的写法有两个缺点,一是如果多生成几个实例,写起来就非常麻烦;二是实例与原型之间,没有任何办法,可以看出有什么联系。

二、 原始模式的改进

我们可以写一个函数,解决代码重复的问题。

function Cat(name,color) {
    return {
        name:name,
        color:color
    }
}

然后生成实例对象,就等于是在调用函数:

var cat1 = Cat("大毛","黄色");
var cat2 = Cat("二毛","黑色");

这种方法的问题依然是,cat1和cat2之间没有内在的联系,不能反映出它们是同一个原型对象的实例。

三、 构造函数模式

为了解决从原型对象生成实例的问题,Javascript提供了一个构造函数(Constructor)模式。

所谓”构造函数”,其实就是一个普通函数,但是内部使用了this变量。对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上。

比如,猫的原型对象现在可以这样写,

function Cat(name,color){
    this.name=name;
    this.color=color;
}

我们现在就可以生成实例对象了。

var cat1 = new Cat("大毛","黄色");
var cat2 = new Cat("二毛","黑色");
alert(cat1.name); // 大毛
alert(cat1.color); // 黄色

这时cat1和cat2会自动含有一个constructor属性,指向它们的构造函数。

alert(cat1.constructor == Cat); //true
alert(cat2.constructor == Cat); //true

Javascript还提供了一个instanceof运算符,验证原型对象与实例对象之间的关系。

四、构造函数模式的问题

构造函数方法很好用,但是存在一个浪费内存的问题。

请看,我们现在为Cat对象添加一个不变的属性type(种类),再添加一个方法eat(吃)。那么,原型对象Cat就变成了下面这样:

function Cat(name,color){
    this.name = name;
    this.color = color;
    this.type = "猫科动物";
    this.eat = function(){alert("吃老鼠");};
}

还是采用同样的方法,生成实例:

var cat1 = new Cat("大毛","黄色");
var cat2 = new Cat ("二毛","黑色");
alert(cat1.type); // 猫科动物
cat1.eat(); // 吃老鼠

表面上好像没什么问题,但是实际上这样做,有一个很大的弊端。那就是对于每一个实例对象,type属性和eat()方法都是一模一样的内容,每一次生成一个实例,都必须为重复的内容,多占用一些内存。这样既不环保,也缺乏效率。

alert(cat1.eat == cat2.eat); //false

能不能让type属性和eat()方法在内存中只生成一次,然后所有实例都指向那个内存地址呢?回答是可以的。

五、 Prototype模式

Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。

这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。

function Cat(name,color){
    this.name = name;
    this.color = color;
}
Cat.prototype.type = "猫科动物";
Cat.prototype.eat = function(){alert("吃老鼠")};

然后,生成实例

var cat1 = new Cat("大毛","黄色");
var cat2 = new Cat("二毛","黑色");
alert(cat1.type); // 猫科动物
cat1.eat(); // 吃老鼠

这时所有实例的type属性和eat()方法,其实都是同一个内存地址,指向prototype对象,因此就提高了运行效率

  alert(cat1.eat == cat2.eat); //true

六、 Prototype模式的验证方法

为了配合prototype属性,Javascript定义了一些辅助方法,帮助我们使用它。

6.1 isPrototypeOf()

这个方法用来判断,某个proptotype对象和某个实例之间的关系。

alert(Cat.prototype.isPrototypeOf(cat1)); //true
alert(Cat.prototype.isPrototypeOf(cat2)); //true

6.2 hasOwnProperty()

每个实例对象都有一个hasOwnProperty()方法,用来判断某一个属性到底是本地属性,还是继承自prototype对象的属性。

alert(cat1.hasOwnProperty("name")); // true
alert(cat1.hasOwnProperty("type")); // false

6.3 in运算符

in运算符可以用来判断,某个实例是否含有某个属性,不管是不是本地属性。

alert("name" in cat1); // true
alert("type" in cat1); // true

in运算符还可以用来遍历某个对象的所有属性。

for(var prop in cat1) { alert("cat1["+prop+"]="+cat1[prop]); }
  • js

展开全文 >>

Javascript的this用法

2016-08-02

this是Javascript语言的一个关键字。

它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。比如,

function test(){
    this.x = 1;
}

随着函数使用场合的不同,this的值会发生变化。但是有一个总的原则,那就是this指的是,调用函数的那个对象。

下面分四种情况,详细讨论this的用法。

情况一:纯粹的函数调用

这是函数的最通常用法,属于全局性调用,因此this就代表全局对象Global。

请看下面这段代码,它的运行结果是1。

 function test(){
    this.x = 1;
    alert(this.x);
}
test(); // 1

为了证明this就是全局对象,我对代码做一些改变:

var x = 1;
function test(){
    alert(this.x);
}
test(); // 1

运行结果还是1。再变一下

var x = 1;
function test(){
    this.x = 0;
}
test();
alert(x); //0

情况二:作为对象方法的调用

函数还可以作为某个对象的方法调用,这时this就指这个上级对象。

function test(){
    alert(this.x);
}
var o = {};
o.x = 1;
o.m = test;
o.m(); // 1

情况三 作为构造函数调用

所谓构造函数,就是通过这个函数生成一个新对象(object)。这时,this就指这个新对象。

function test(){
    this.x = 1;
}
var o = new test();
alert(o.x); // 1

运行结果为1。为了表明这时this不是全局对象,我对代码做一些改变:

var x = 2;
function test(){
    this.x = 1;
}
var o = new test();
alert(x); //2

运行结果为2,表明全局变量x的值根本没变

情况四 apply调用

apply()是函数对象的一个方法,它的作用是改变函数的调用对象,它的第一个参数就表示改变后的调用这个函数的对象。因此,this指的就是这第一个参数。

var x = 0;
function test(){
    alert(this.x);
}
var o={};
o.x = 1;
o.m = test;
o.m.apply(); //0

apply()的参数为空时,默认调用全局对象。因此,这时的运行结果为0,证明this指的是全局对象。

如果把最后一行代码修改为

o.m.apply(o); //1

运行结果就变成了1,证明了这时this代表的是对象o。

  • js

展开全文 >>

« Prev1234Next »
© 2017 jasmine
Hexo Theme Yilia by Litten
  • 所有文章
  • 友链
  • 关于我

tag:

  • 16个正则表达式
  • ES6
  • es6
  • js
  • Markdown
  • node.js
  • php
  • vue
  • 变量,作用域问题
  • github
  • 项目实战
  • mysqli

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • 友情链接1
  • 友情链接2
  • 友情链接3
  • 友情链接4
  • 友情链接5
  • 友情链接6
很惭愧

只做了一点微小的工作
谢谢大家