BOM

前言

ECMAScript是JavaScript的核心,但如果要在Web中使用JavaScript,那么BOM(浏览器对象模型)则无疑才是真正的核心。BOM提供了很多对象,用于访问浏览器的功能,这些功能与任何网页内容无关。多年来,缺少事实上的规范导致BOM既有意思又有问题,因为浏览器提供商会按照各自的想法随意去扩展它。于是,浏览器之间的共有的对象就成为了事实上的标准。W3C为了把浏览器中JavaScript最基本的部分标准化,已经将BOM的主要方面纳入了HTML5规范中。

window对象

BOM的核心对象,表示一个浏览器的一个实例。在浏览器中,window对象有双重角色,它既是通过JavaScript访问浏览器窗口的一个接口,又是ECMAScript规定了Global对象。这意味着在网页中定义的任何对象、变量、函数都是window作为其Global对象,因此有权访问parseInt()方法。

全局作用域

全局作用域中所有声明的变量、函数都会变成window对象的属性和方法。

var age = 29;
function sayAge() {
    console.log(this.age);
}

console.log(window.age);    // 29
sayAge();                   // 29
window.sayAge();            // 29

抛开全局变量会成为window对象的属性不谈,定义全局变量与在window对象上直接定义属性还是有一点差别:全局变量不能通过delete操作符删除,而直接在window对象上的定义的属性可以。

var age = 29;
window.color = "red";

// 在IE<9时抛出错误,其他所有浏览器返回false
delete window.age;

// 在IE<9时抛出错误,其他所有浏览器返回true
delete window.color;        // return true

console.log(window.age);    // 29
console.log(window.color);  // undefined

使用var语句添加的window属性有一个名为[[Configurable]]的特性。这个特性的值被设置为false,因此这样定义的属性不可以通过delete操作符删除。

尝试访问未声明的变量会抛出错误,但是通过查询window对象,可以知道某个可能未声明的变量是否存在。

// 这里会抛出错误,因为oldValue未定义
var newValue = oldValue;

// 这里不会抛出错误,因为这是一次属性查询
// newValue的值是undefined
var newValue = window.oldValue;

窗口位置

screenLeftscreenTop
分别表示窗口相对于屏幕左边和上边的位置。Firefox则在screenXscreenTop属性中提供相同的窗口位置信息,使用下列代码可以跨浏览器取得窗口左边和上边的位置。

var leftPos = (typeof window.screenLeft == "number") ? window.screenLeft : window.screenX;
var topPos = (typeof window.screenTop == "number") ? window.screenTop : window.screenY;

首先确定screenLeft和screenTop是否存在,是则取得这两个属性值,不存在则使用另外的screenX和screenY。

有一些区别

对于IE、Opera浏览器:高度值包括浏览器工具栏

IE

对于Chrome、Firefox、safari:和上面相反,高度值不包含工具栏那块儿。


chrome

更让人无语的是,Firefox、safari和chrome始终返回页面中每个框架的top.screenX和top.screenY值,即使在页面由于被设置了外边距而发生偏移的情况下,相对于window对象使用screenX和screenY每次也都会返回相同的值。而IE和Opera则会给出框架相对于屏幕边界的精确坐标。
最终结果,就是无法在夸浏览器的条件下取得窗口左边和上边的精确坐标值。


窗口大小

innerWidthinnerHeightouterWidthouterHeight
支持IE9+,Firefox,safari,opera,chrome均支持。

innerWidth:表示页面视图区的度(减去边框宽度)。
innerHieght:表示页面视图区高度(减去边框宽度)。

outerWidth:返回浏览器窗口本身长度。
outerHeight:返回浏览器窗口本身高度。


Chrome:

chrome最大化.jpg
浏览器F11全屏下.jpg
任意缩小.jpg

IE:均取得undefined,情况未知。


在IE,Firefox,safari,opera,chrome中,document.documentElement.clientWidth和document.documentElement.clientHeight中保存了页面视口的信息。IE6中,这些属性必须在标准模式下才有效;如果是混杂模式,必须通过document.body.client(Width/Height)取得相同信息。
而对于chrome,哪种都行。

虽然最终无法确定浏览器窗口本身大小,但是可以取得页面视口大小。

    var pageWidth = window.innerWidth;
    var pageHeight = window.innerHeight;

    if (typeof pageWidth != "number") {
        if (document.compatMode == "CSS1compat") {
            pageWidth = document.documentElement.clientWidth;
            pageHeight = document.documentElement.clientHeight;
        } else {
            pageWidth = document.body.clientWidth;
            pageHeight = document.body.clientHeight;
        }
    }

先将window.innerWidth/innerHeight的值分别赋给了pageWidth和pageHeight。检查pageWidth中是否是一个数值,不是,则通过检查compatMode确定页面是否处于标准模式,是,则使用document.documentElement.clientWidth/clientHeight的值。否则,使用document.body.clientWidth/clientHeight的值。

使用resizeTo()和resizeBy()方法可以调整浏览器窗口大小。

resizeTo:接受浏览器窗口的新宽度和新高度
resizeBy:接受新窗口与原窗口的宽度之差和高度之差

从 Firefox 7 开始,不能改变浏览器窗口的大小了,要依据下面的规则:

  • 不能设置那些不是通过 window.open 创建的窗口或 Tab 的大小。
  • 当一个窗口里面含有一个以上的 Tab 时,无法设置窗口的大小。
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Test</title>
</head>
<body>
    <input type="button" value="创建窗口">
    <input type="button" value="resizeTo()">
    <input type="button" value="resizeBy()">
</body>
<script>
    var btn = document.getElementsByTagName("input")[0];
    var btn2 = document.getElementsByTagName("input")[1];
    var btn3 = document.getElementsByTagName("input")[2];

    var z;

    btn.onclick = function () {
        z = window.open("", "", "width=100,height=100");
        z.focus();
    }
    btn2.onclick = function () {
        z.resizeTo(500, 500);
        z.focus();
    }
    btn3.onclick = function () {
        z.resizeBy(100, 100);
        z.focus();
    }


</script>
</html>

导航和打开窗口

使用window.open()方法既可以导航到一个特定的URL,也可以打开一个新的浏览器窗口。这个方法接受4个参数:要加载的URL、窗口目标、一个特性字符串以及一个表示新页面是否取代浏览器历史纪录中当前加载页面的布尔值。通常只传递一个参数,最后一个参数只在不打开新窗口的情况下使用。

如果为window.open()传递了第二个参数,而且该参数是已有窗口或框架的名称,那么就会在具有该名称的窗口或框架中加载第一个参数指定的URL。

window.open("http://www.wrox.com/","topFrame");
// 等同于:<a href="http://www.wrox.com" target="topFrame"></a>

弹出窗口
如果给window.open()传递的第二个参数不是一个已经存在的窗口或框架,那么该方法就会根据在第三个参数位置上传入的字符串创建一个新窗口或新标签页。如果没有传入第三个参数,那么就会打开一个带有全部默认设置(工具栏、地址栏、状态栏)的新浏览器窗口。

第三个参数是一个逗号分隔的设置字符串,表示新窗口中都显示哪些特性。

设置                    值                   说明

fullscreen           yes或no            表示浏览器窗口是否最大化,仅限IE

height                 数值             表示新窗口的高度,不能小于100

left                   数值             表示新窗口的左坐标。不能是负值

location              yes或no           表示是否在浏览器窗口中显示地址栏,不同浏览器默认值不同

menubar               yes或no           表示是否在浏览器窗口中显示菜单栏,默认值为no

resizable             yes或no           表示是否可以通过拖动浏览器窗口的边框改变其大小,默认值为no

scrollbars            yes或no           表示如果内容在视口中显示不下,是否允许滚动。默认值为no。

status                yes或no           表示是否在浏览器窗口中显示状态栏。默认值为no

toolbar               yes或no           表示是否在浏览器窗口中显示工具栏。默认值为no

top                   数值              表示新窗口的上坐标,不能是负值。

width                 数值              表示新窗口的宽度,不能小于100。

window.open("http://www.wrox.com","wroxWindow","height=400,width=400,top=10,left=10,resizable=yes");
这段代码会打开一个新的可以调整大小的窗口,窗口初始大小为400*400像素,并且距屏幕上沿和左边各10像素。

window.open()方法会返回一个指向新窗口的引用。引用的对象与其他window对象大致相似,但我们可以对其进行更多控制。例如,有些浏览器在默认情况下可能不允许我们针对主浏览器窗口调整大小或移动位置,但却允许我们针对通过window.open()创建的窗口调整大小或移动位置。

var wroxWin = window.open("http://www.wrox.com/","wroxWindow","height=400,width=400,top=10,left=10,resizable=yes");

// 调整大小
wroxWin.resizeTo(500,500);

// 移动位置
wroxWin.moveTo(100,100);

调用close()方法还可以关闭新打开的窗口。

wroxWin.close();

但是,这个方法仅适用于通过window.open()打开的弹出窗口。对于浏览器的主窗口,如果没有得到用于允许是不能关闭它的。不过,弹出窗口倒是可以调用top.close()在不经用户允许的情况下关闭自己。弹出窗口关闭之后,窗口的引用仍然还在,但除了像下面这样检测其closed属性之外,已经没有其他用处了。

wroxWin.close();
alert(wroxWin.closed);      // true

新创建的window对象有一个opener属性,其中保存着打开它的原始窗口对象。这个属性只在弹出窗口中的最外层window对象(top)中有定义,而且指向调用window.open()的窗口或框架。


间歇调用与超时调用

JavaScript是单线程语言,但它允许通过设置超时值和间歇时间值来调度代码在特定的时刻执行。前者是在指定的时间过后执行代码,后者则是在每隔指定的时间就执行一次代码。

超时调用需要使用window对象的setTimeout()方法,接受两个参数,要执行的代码和以毫秒表示的时间(即在执行代码前需要等待多少毫秒)。其中,第一个参数可以是一个包含JavaScript代码的字符串(就和在eval()函数中使用的字符串一样),也可以是一个函数。

// 不建议传递字符串!
setTimeout("alert('hello world!')",1000);

// 推荐的调用方式
setTimeout(function() {
    alert("Hello World!")
},1000);

虽然这两种调用方式都没有问题,但由于传递字符串可能导致性能损失,因此不建议字符串作为第一个参数。
第二个参数是一个表示等待多长时间的毫秒数,但经过该时间后指定的代码不一定会执行。JavaScript是一个单线程的解释器,因此一定时间内只能执行一段代码。为了控制要执行的的代码,就有一个JavaScrip任务队列。这些任务会按照将它们添加到队列的顺序执行。setTimeout()的第二个参数告诉JavaScript再过多长时间把当前任务添加到队列中。如果队列是空的,那么添加的代码会立即执行;如果队列不是空的,那么它就要等前面的代码执行完毕以后再执行。

调用setTimeout()之后,该方法会返回一个ID,表示超时调用,这个超时调用ID是计划执行代码的唯一标识符,可以通过它来取消超时调用。要取消尚未执行的超时调用计划,可以使用clearTimeout()方法,并将相应的ID传递给它。

var timeoutId = setTimeout(function() {
    alert("Hello World!")
},1000);

clearTimeout(timeoutId);

只要是在指定的时间尚未过去之前调用clearTimeout(),就可以完全取消超时调用。前面的代码在设置超时调用之后马上又调用了clearTimeout(),结果就跟什么都没发生一样。

超时调用的代码是在全局作用域中执行的,因此函数中this的值在非严格模式下指向window对象,在严格模式下是undefined。

间歇调用与超时调用类似,只不过它会按照设置的时间间隔重复执行代码。

setInterval("alert('Hello World!')",10000);

// 推荐
setInterval(function() {
    alert("hello world!");
},10000);

取消间歇调用的重要性远远高于取消超时调用,因此在不加干涉的情况下,间歇调用将会一直执行到页面卸载。

var num = 0;
var max = 10;

var intervalId = null;

function incrementNumber() {
    num++;

    // 如果执行次数达到了max设定的值,则取消后续尚未执行的调用
    if (num == max) {
        clearInterval(intervalId);
        alert('Done');
    }
}

intervalId = setInterval(incrementNumber,500);

变量num每半秒递增一次,当递增到最大值时就会取消先前设定的间歇调用。这个模式也可以使用超时调用来实现。

var num = 0;
var max = 10;

function incrementNumber() {
    num++;

    if (num < max) {
        setTimeout(incrementNumber,500);
    } else {
        alert("Done");
    }
}

setTimeout(incrementNumber,500);

可见,在使用超时调用时,没有必要跟踪超时调用ID,因此每次执行代码之后,如果不在设置另一次调用,调用自动会停止。

一般认为,使用超时调用来模拟间歇调用是一种最佳模式。在开发环境下,很少使用真正的间歇调用,原因是后一个间歇调用可能会在前一个间歇调用结束之前启动,而像前面示例中那样使用超时调用可以避免这一点,所以最好不要使用间歇调用。


系统对话框

alert()
alert()接受一个字符串并将其显示给用户。具体来说,调用alert()方法的结果就是向用户显示一个系统对话框,其中包含指定的文本和一个OK按钮。

通常使用alert()生成的警告对话框向用户显示一些他们无法控制的消息,例如错误消息。而用户看完消息后关闭对话框。

confirm()
confirm()方法,从向用户显示消息的方面看,这种确认对话框很像一个警告对话框,但二者的主要区别在于确认对话框除了显示OK按钮外,还会显示一个Cancel按钮,两个按钮可以让用户决定是否执行给定操作。
confirm("Are you sure?");

if (confirm("Are you sure?")) {
    alert("I'm so glad you're sure!");
} else {
    alert("I'm sorry to hear you're not sure.");
}

为了确定用户是单击了OK还是Cancel,可以检查confirm方法返回的布尔值。OK按钮返回true,Cancel按钮返回false。右上角关闭按钮和ESC也会返回false。

prompt()
这是一个提示框,用于提示用户输入一些文本信息,提示框中除了显示OK和Cancel按钮外,还会显示一个文本输入域。
prompt()方法接受两个参数:要显示给用户的文本提示和文本输入域的默认值(可以是一个空字符串)。

如果用户单击了OK按钮,则prompt返回文本输入域的值;
如果用户单击了cancel按钮或没有单击OK按钮而是通过其他方式关闭对话框,则该方法返回null。

var result = prompt("What is your name?","");
if (result !== null) {
    alert("Welcome, "+result);
}

这些系统对话框很适合向用户显示消息并请用户作出决定。由于不涉及HTML,CSS或JavaScript,因此它们是增强Web应用程序的一种便携方式。

·---

location对象

location是最有用的BOM对象之一,提供了与当前窗口加载的文档有关的信息,提供了一些导航功能。
location对象既是window对象的属性,也是document对象的属性。
document.location === window.location; // true
它们均引用自同一个对象。location对象的用户不只表现在它保存着当前文档的信息,还表现在它将URL解析为独立的片段,让开发人员可以通过不同的属性访问这些片段。

属性方法
MDN——location

查询字符串参数

访问URL包含的查询字符串的属性并不方便。尽管location.search返回从问号到URL末尾的所有内容,但却没有方法逐个访问其中的每个查询字符串参数。可以创建一个函数,用以解析查询字符串,然后逐个返回包含所有参数的一个对象:

function getQueryStringArgs() {

    // 取得查询字符串并去掉开头的问号
    var qs = location.search.length > 0 ? location.search.substring(1) : "";

    // 保存数据的对象
    var args = {};

    // 取得每一项
    var items = qs.length ? qs.split("&") : [];
    var item = null;
    var name = null;
    var value = null;

    // 在for循环中使用
    var i = 0;
    var len = items.length;

    // 逐个将每一项添加到args对象中
    for (i=0;i<len;i++) {
        item = items[i].split("=");
        name = decodeURIComponent(item[0]);
        value = decodeURIComponent(item[1]);

        if (name.length) {
            args[name] = value;
        }
    }
    
    return args;
}

tips1
location.href中指定URL时必须为绝对路径,否则会以相对路径跳转。
window.location.href = "www.baidu.com";


会被认为是,打开当前路径下的www.baidu.com文件。

所以需要指定绝对路径:
window.location.href = "http://www.baidu.com";


位置操作

使用location对象可以通过很多方式来改变浏览器的位置。首先,也是最常用的方式,就是使用assign()方法并为其传递一个URL,如下所示。
location.assign("http://www.wrox.com");
这样,就可以立即打开新URL并在浏览器的历史纪录中生成一条纪录。如果是将location.href或window.location设置为一个URL值,也会以该值调用assign()方法。例如,下列两行代码与显示调用assign()方法的效果完全一样。

window.location = "http://www.wrox.com";
location.href = "http://www.wrox.com";

在这些改变浏览器位置的方法中,最常用的就是location.href属性。
另外,修改location对象的其他属性也可以改变当前加载的页面,下面的例子展示了通过将hash,search,hostname,pathname,port属性设置为新值改变URL。

//假设初始URL为http://www.wrox.com/WileyCDA/

//将URL修改为"http://www.wrox.com/WileyCDA/#section1"
location.hash = "#section1"

// 将URL修改为"http://www.wrox.com/WileyCDA/?q=javascript"
location.search = "?q=javascript";

// 将URL修改改为"http://www.yahoo.com/WileyCDA/"
location.hostname = "www.yahoo.com";

// 将URL修改为"http://www.yahoo.com/mydir/"
location.pathname = "mydir";

// 将URL修改为"http://www.yahoo.com:8080/WileyCDA/"
location.port = 8080;

当通过上述任何一种方式修改URL之后,浏览器的历史纪录就会生成一条新纪录,因此用户通过单击“后退”按钮都会导航到前一个页面。要禁用这种行为,可以使用replace()方法,方法接受一个参数,既要导航到的URL;结果虽然会导致浏览器位置改变,但不会在历史纪录中生成新纪录。在调用replace()方法之后,用户不能回到前一个页面。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>You won't be able to get back here</title>
</head>
<body>

    <p>Enjoy this page for a second, because you won't be coming back here.</p>
    
</body>
<script>
    setTimeout(function() {
        location.replace("http://www.wrox.com");
    },1000);
</script>
</html>

将这个页面加载到浏览器中,浏览器会在1秒钟之后重新定向到www.wrox.com。然后,后退按钮将处于禁用状态,如果不重新输入完整的URL,则无法返回示例页面。

与位置有关的最后一个方法是reload(),作用是重新加载当前显示的页面,如果调用reload()时不传递任何参数,页面就会以最有效的方式重新加载。也就是说,如果页面自上次请求以来并没有改变过,页面就会从浏览器缓存中重新加载。如果要强制从服务器中重新加载,则需要像下面这样为该方法传递参数true。

location.reload();          // 重新加载(有可能从缓存中加载)
location.reload(true);      // 重新加载(从服务器重新加载)

位于reload()调用之后的代码可能会也可能不会执行,这要取决于网络延迟或系统资源等因素,为此,最好将reload()放在代码最后一行。


navigator对象

MDN——navigator

screen对象

MDN——screen

screen对象基本上只用来表明客户端的能力,其中包括浏览器窗口外部的显示器的信息,如像素宽度和高度等,每个浏览器的screen对象都包含着各不相同的属性。

history对象

MDN——history

history对象保存着用户上网的历史纪录,从窗口被打开的那一刻算起,因为history是window对象的属性,因此每个浏览器窗口、每个标签页乃至每个框架,都有自己的history对象与特定的window对象关联。出于安全方面考虑,开发人员无法得知用户浏览过的URL,不过,借由用户访问过的页面列表,同样可以在不知道实际URL的情况下实现后退和前进。
使用go()方法可以在用户的历史纪录中任意跳转,可以向后也可以向前。这个方法接受一个参数,表示向后或者向前跳转的页面数的一个整数值。负数表示向后跳转(类似单击浏览器后退按钮),正数表示向前跳转(类似于单击浏览器的前进按钮)。

// 后退一页
history.go(-1);

// 前进一页
history.go(1);

// 前进两页
history.go(2);

也可以给go()方法传递一个字符串参数,此时浏览器会跳转到历史纪录中包含该字符串的第一个位置,可能后退,也可能前进,具体要看哪个位置最近,如果历史纪录中不包含该字符串,那么这个方法什么也不做,例如:

// 跳转到最近的wrox.com页面
history.go("wrox.com");

// 跳转到最近的nczonline.net页面
history.go("nczonline.net");

另外,还可以使用两个简写方法back()和forward()来代替go()。

// 后退一页
history.back();

// 前进一页
history.forward();

除了上述几个方法,history对象还有一个length属性,保存着历史纪录的数量。这个数量包括所有的历史纪录,即所有向后和向前的纪录。对于加载窗口、标签页或框架中的第一个页面而言,history.length等于0。通过下面这些测试,可以确定用户是否一开始就打开你的页面

if (history.length == 0) {
    // 这应该是用户打开窗口后的第一个页面
}

虽然history并不常用,但是在创建自定义后退和前进按钮,以及检测当前页面是不是用户历史纪录中的第一个页面时,还是必须使用它


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,264评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,549评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,389评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,616评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,461评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,351评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,776评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,414评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,722评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,760评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,537评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,381评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,787评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,030评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,304评论 1 252
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,734评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,943评论 2 336

推荐阅读更多精彩内容

  •   ECMAScript 是 JavaScript 的核心,但如果要在 Web 中使用 JavaScript,那么...
    霜天晓阅读 863评论 0 0
  • ECMAScript 是 JavaScript 的核心,但如果要在 Web 中使用 JavaScript,那么 B...
    劼哥stone阅读 806评论 2 5
  • BOM是浏览器对象模型 Window对象 BOM 的核心对象是window,它表示浏览器的一个实例。 在浏览器中,...
    shanruopeng阅读 424评论 0 1
  • 开发中使用WebView加载url、html标签必不可少,比如广告、活动界面通过WebView加载具有实效性。下面...
    _SHYII阅读 3,791评论 0 10
  • 折腾了很久,终于找到可行的例子demo分3部分,1, c module文件,需要为python项目单独建立#inc...
    liantz阅读 438评论 0 0