html芝麻
1 前端实现下载
<a href="./xxx.xxx" download="文件名.txt">点击下载</a>
实测,download属性无效,不知为啥,该标签可以实现静态文件下载功能,也可以在href中写后端请求地址动态获取文件
另一种可以使用window.open('./xxx.xxx)
来下载
2 使用iframe来控制显示网页任意区域
iframe可以用来作为网页的拿来主义使用,不过安全性不高,但是有时候可以增加代码的复用率,提高开发效率。
iframe本身控制属性不多,控制显示区域需要结合div来做:
<div style="width:800px;height:600px;overflow:hidden;border:0px">
<iFrame src="http://www.baidu.com" width="800" height="600" scrolling="no" style="margin:-153px 0px 0px -10px;"></iFrame>
</div>
内层的iframe表示嵌入目标网站,主要设置宽高即可,然后是控制显示偏移位置(可以视原位置为可视窗口)。
外层用来去除多余区域,相当于遮罩层。
3 使用iframe并获取其中的内容
同域下
父页面拿子页面数据:
父页面
<iframe name="z" id="z" src="..."></iframe>
<button onclick="getMsg()">拿子页面数据</button>
<label id="f"></label>
子页面
<input id="msg"></input>
// 父页面
function getMsg(){
document.getElementById("f").innerText=window.frames["z"].document.getElementById("msg").value;
}
父页面点击button后,父页面的label即被赋值。
子页面拿父页面数据:
父页面
<iframe name="z" id="z" src="..."></iframe>
<input id="msg"></input>
子页面
<button onclick="getMsg()">拿父页面数据</button>
<label id="z"></label>
// 子页面
function getMsg(){
document.getElementById("z").innerText=window.parent.document.getElementById("msg").value;
}
子页面点击button后,子页面的label即被赋值。
跨域下
使用两个方法来发送与接受:postMessage
和addEventListener
父页面向子页面传递数据:
// 父页面
document.getElementById('iframe').contentWindow.postMessage(data,'*')
// 子页面
addEventListener('message', e => {
// e.data为父页面发送的数据
console.log(e.data)
})
子页面向父页面传递数据:
// 子页面
// data为子页面发送的数据(可以是一个js对象,会被自动序列化处理)
window.parent.postMessage(data, '*')
// 父页面
addEventListener('message', e => {
// e.data为子页面发送的数据
console.log(e.data)
})
注意:
在上边的代码中postMessage
的第二个参数被设置为*
,意为任意源,尤其是密码等关键数据,一定要注意,这里可以指定接收源,示例代码如下
// 发送方
window.parent.postMessage('exit','http://example.org');
// 接受方
addEventListener('message', e => {
if(e.origin === 'http://example.org') {
// 仅在数据发送来源自受信任的地址才执行对应操作
}
})
4 attr与prop区别
attributes
表示html标签的属性,包括预定义属性和自定义属性,且这两种属性放在当前标签对应对象的同一个attributes
中(一个NamedNodeMap的类型变量中)。
标签上的每个属性在解析后都是一个对象, 称为属性节点,必定包含:nodeName
nodeType
nodeValue
。其中nodeType
值为1表示元素节点,2属性节点,3文本节点。
注意:如果标签中没有显示定义属性,则解析成的标签对象的attributes属性中不存在该属性key。
property
表示js原生对象的直接属性,每一个预定义的attribute
都会有一个property
与之对应(与class对应的prop是className),如果是非预定义的则没有property
,注意虽然对应但是值并不是都保持一样!(布尔值不相同,其他相同)
注意:无论标签中有没有显示定义属性,解析成的标签对象的根中都存在预定义属性key
操作attr和prop
var x=document.querySelector("input[type=checkbox]")
// 操作布尔值属性,观察attr和prop是否同步
x.setAttribute("checked","checked1") // 操作attr
x.checked="checked2" // 操作prop
// 操作非布尔值属性,观察attr和prop是否同步
x.setAttribute("name","123") // 操作attr
x.name="456" // 操作prop
Tips:对于属性值,在html标签中的属性值无论些什么类型,在attr中都是字符串
Tips:布尔值属性:property属性是布尔类型
注意:在操作非布尔值属性时,改变attr和prop二者是保持同步的,而操作非布尔值属性时,改变prop永远不会同步attr;在未显示设置标签的attr时,改变attr会导致prop为true,再改变prop时两者不会再同步
注意:浏览器以property属性值为准!!!!用户行为操作的是property
5 操作class
原来操作class使用property:className,会获取到一个字符串,html5引入classList属性:
// <div id="x" class="x1 x2 x3"></div>
x.className // "x1 x2 x3"
x.classList // 一个对象结构
该对象有方法可以用于增删:add/remove
可以用于切换:toggle
6 操作自定义属性
原来操作自定义属性方式:x.setAttribute("abc","111")
,没有property属性对应
html5后引入前缀:data-
,有该前缀修饰的自定义属性,被放在了节点对象的:dataset
中,可以通过:x.dataset.abc
获取
注意:html属性不区分大小写,转成js都是小写!而在js是区分的,两者通过-
进行转换形成对应关系:
//html属性
abc-def
//js属性
abcDef
7 html5新增属性:contenteditable可编辑
可编辑属性为true
则,指定当前标签中的innerText是可编辑的
8 DOM文档加载顺序
建议:
对于使用link
引入的css代码,放置在head
中,因为是同步加载的
对于使用script
引入的js代码,放置在body
后,因为是异步加载的,会导致找不到文档的错误
DOM文档的加载顺序是由上而下的顺序加载;
1、DOM加载到link标签
css文件的加载是与DOM的加载并行
的,也就是说,css在加载时Dom还在继续加载构建,而过程中遇到的css样式或者img,则会向服务器发送一个请求,待资源返回后,将其添加到dom中的相对应位置中;
2、DOM加载到script标签
由于js文件不会与DOM并行加载,因此需要等待
js整个文件加载完之后才能继续DOM的加载,倘若js脚本文件过大,则可能导致浏览器页面显示滞后,出现“假死”状态,这种效应称之为“阻塞效应”;会导致出现非常不好的用户体验;
而这个特性也是为什么在js文件中开头需要$(document).ready(function(){})
或者(function(){})
或者window.onload
,即是让DOM文档加载完成之后才执行js文件,这样才不会出现查找不到DOM节点等问题;
js阻塞其他资源的加载的原因是:浏览器为了防止js修改DOM树,需要重新构建DOM树的情况出现;
3、解决方法
前提,js是外部脚本;
在script标签中添加 defer=“ture”
,则会让js与DOM并行加载,待页面加载完成后再执行js文件,这样则不存在阻塞;
在scirpt标签中添加 async=“ture”
,这个属性告诉浏览器该js文件是异步加载执行的,也就是不依赖于其他js和css,也就是说无法保证js文件的加载顺序,但是同样有与DOM并行加载的效果;
同时使用defer和async属性时,defer属性会失效;
可以将scirpt标签放在body标签之后,这样就不会出现加载的冲突了。