存档一月 2019

获取隐藏元素的宽度

问题描述

如果DOM元素的fu’yu是被隐藏的(display: none),那么无论使用DOM的接口,还是jquery的接口来获取该元素的宽度,得到的结果始终是0. 例如:

 
 
<div id="node">
  <p>
    hello world
  </p>
</div>
 
 
#node {
    display: none;
}
 
 
alert($('#node p').width());

解决方法

在过去元素的宽度之前,临时修改元素的display为block,获取之后再讲其设置回none

例如:

 
 
function get_width(obj) {
  var width = 0;
  obj.parent().css('display', 'block');
  width = obj.width();
  obj.parent().css('display', 'none');
  return width;
}
alert(get_width($('#node p')));

给jquery添加一个函数

参考StackOverflow ,Tim Banks给jquery添加了一个函数,用来获取隐藏元素的宽度和高度信息。

 
 
(function ($) {
$.fn.getHiddenDimensions = function (include_margin) {
    var $item = this,
    props = { position: 'absolute', visibility: 'hidden', display: 'block' },
    dim = { width: 0, height: 0, innerWidth: 0, innerHeight: 0, outerWidth: 0, outerHeight: 0 },
    $hiddenParents = $item.parents().addBack().not(':visible'),
    includeMargin = (include_margin == null) ? false : include_margin;
    var oldProps = [];
    $hiddenParents.each(function () {
        var old = {};
        for (var name in props) {
            old[name] = this.style[name];
            this.style[name] = props[name];
        }
        oldProps.push(old);
    });
    dim.width = $item.width();
    dim.outerWidth = $item.outerWidth(includeMargin);
    dim.innerWidth = $item.innerWidth();
    dim.height = $item.height();
    dim.innerHeight = $item.innerHeight();
    dim.outerHeight = $item.outerHeight(includeMargin);
    $hiddenParents.each(function (i) {
        var old = oldProps[i];
        for (var name in props) {
            this.style[name] = old[name];
        }
    });
    return dim;
}
}($));
alert($('#node p').getHiddenDimensions().width);

在jsFiddle上试一试 ->

ES6: 模块编程

Javascript模块的限制

  • 只能运行于严格模式
  • 模块中的顶级作用域中的变量,不会被自动添加到全局作用域
  • 顶级作用域的this为undefined

导出

如果想让模块中的变量、函数、类被其他模块使用,需要将其导出,导出的方法如下:

  • export var color = “red”;
  • export function print_hello(){};
  • export { print_hello }
  • export { print_hello as printh };
  • export default function print_hello(){};
  • export default print_hello
  • export { print_hello as default}

导入

如果想使用其他模块中的变量、函数、类,需要将其导入。导入后的变量、类、函数为只读。导入的方法如下:

  • import { color, print_hello } from “./example.js”;
  • import * as example from “./example.js”;  //example.color, example.print_hello
  • import { print_hello as printh } from “./example.js”;
  • import print_hello, { color } from “./example.js”; // print_hello 为默认导出的函数
  • import { default as printh } from “./example.js”;

ES6:数组

新增的静态方法

Array.of() :可以将传入的参数逐个传入数组,即使只有一个数值类型的参数,也会成为新数组的成员,而不是代表数组的长度

Array.from():可以将类数组结构转化为数组,例如: Array.from(arguments). 利用Array.from()也可以转换原来的数组,例如:

 
 
  1. let trans_args = function() {
  2. let args = Array.from(arguments, (value)=>value + 1);
  3. console.log(args);
  4. }
  5. trans_args(1, 2, 3);
  6. $ node test.js
  7. [ 2, 3, 4 ]

新增的普通方法

find() 与findIndex():传入一个回调函数来表明查找的条件,例如:

 
 
> let arr = [1, 2, 3, 4, 5];
undefined
> arr.find((n)=>n>3);
4
> arr.findIndex((n)=>n>3);
3

fill(value, start, end):填充value到数组的start到end位置,不包括end. 例如:

 
 
let arr = [1, 2, 3, 4, 5];
arr.fill(1, 1, 4);
[ 1, 1, 1, 1, 5 ]

copyWithin(toIndex, fromIndex, stopIndex): 从fromIndex开始复制元素到toIndex,遇到stopIndex停止,例如:

 
 
> let arr = [1, 2, 3, 4, 5]
undefined
> arr.copyWithin(2, 0, 1);
[ 1, 2, 1, 4, 5 ]

类型化数组

javascript中的数组缓冲区类似于c的malloc,例如,可以用如下方法分配一个10个字节大小的内存区域:

 
 
> let bu = new ArrayBuffer(10);
undefined
> bu.byteLength
10

可以使用slice(start, end)方法来对分配的内存进行切片。

要操作新分配的内存,需要使用DataView(buf, index, length)创建一个视图,例如:

 
 
> let buf = new ArrayBuffer(50);
> let view = new DataView(buf, 0, 50);

获取视图的信息:

 
 
> view.buffer === buf;
true
> view.byteOffset
0
> view.byteLength
50

读写数据:

 
 
> view.setUint8(4, 233);
undefined
> view.getUint8(4)
233

ES6中的类

ES6中添加的class关键字其实并非真正的类,而是ES5用函数来模拟类的语法糖。在ES6中可以用如下的语法创建一个类:

 
 
class Students {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    sayName() {
        console.log(this.name);
    }
    sayAge() {
        console.log(this.age);
    }
}
let st1 = new Students('sen', 18);
st1.sayName();
st1.sayAge();

使用ES6的class语法糖和ES5自定义的类还是有些区别的:

  • 类的声明不会被提升,类的实例化只能在类的声明之后
  • 类声明中的代码只能运行在严格模式下
  • 类中的方法是不可枚举的
  • 实例化的时候必须加new关键字
  • 在方法内部修改类名会抛出错误,但可以在外部修改类名

下面的例子展示了如何在外部修改类名:

 
 
class Students {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    sayName() {
        console.log(this.name);
    }
    sayAge() {
        console.log(this.age);
    }
}
let st1 = new Students('sen', 18);
st1.sayName();
st1.sayAge();
let Stu = Students;
let st2 = new Stu('sen', 18);
st2.sayName();
st2.sayAge();
console.log(st1 instanceof Students); //true
console.log(st2 instanceof Students); //true
console.log(st2 instanceof Stu); //true
console.log(st1 instanceof Stu); //true

类中的访问器属性

可以使用get和set关键字来定义访问器属性,例如:

 
 
class Students {
    constructor(name) {
        this.name = name;
    }
    get n() {
        return this.name;
    }
    set n(value) {
        this.name = value;
    }
}
let st1 = new Students('sen', 18);
console.log(st1.n);
st1.n = 'wang';
console.log(st1.n);

需计算的属性名

和其他需计算的名字一样,都是加上方括号,例如:

 
 
let propName = "sayName";
class Students {
    constructor(name) {
        this.name = name;
    }
    [propName]() {
        console.log(this.name);
    }
}
let st1 = new Students('sen');
st1.sayName();

给类添加默认的生成器

可以利用Symbol来给类添加默认的生成器,如:

 
 
class Collection {
    constructor() {
        this.items = [];
    }
    *[Symbol.iterator]() {
        yield *this.items.values();
    }
}
let col = new Collection();
col.items.push(1);
col.items.push(2);
col.items.push(3);
for( let i of col) {
    console.log(i);
}

给类添加静态属性/方法

类的静态方法/属性只能通过类名来访问,而不能通过类的实例来访问,具体做法是在方法/属性定义前面加上static关键字,例如:

 
 
class Students {
    constructor(name) {
        this.name = name;
    }
    static sayClassName() {
        console.log("Collection");
    }
}
Students.sayClassName();
let stu = new Students('sen');
stu.sayClassName(); // error

类的继承

ES6引入了extends和super来实现类的继承,例如:

 
 
class Rectangle {
    constructor(length, width) {
        this.length = length;
        this.width = width;
    }
    getArea() {
        return this.length * this.width;
    }
}
class Square extends Rectangle {
    constructor(length) {
        super(length, length);
    }
}
let sq = new Square(5);
console.log(sq.getArea());

使用super需要注意:

  • super只能用在派生类中
  • 在constructor里,super负责初始化this,所以必须在this使用之前调用
"