html5

html5新特性

新的选择器

querySelector

选择一个(如果多个匹配返回第一个)

document.querySelector('#div');
document.querySelector('.div');
document.querySelector('div');

querySelectorAll

选择多个

getElementsByClass

JSON

JSON.parse

把json格式的字符串转化为js对象

json格式

{
    "key":"value",
    "key2": 1, 
}

注意: 键值必须加双引号, 如果值是字符串,也必须加双引号

var str = '{"key": "value"}';
var obj = JSON.parse(str);

JSON.stringify

把js对象转化为json格式的字符串

使用JSON.parse和JSON.stringify做深拷贝

function deepCopy(obj){
    var str = JSON.stringify(obj);
    return JSON.parse(str);
}

var obj = { a: 1 };

var objClone = deepCopy(obj);

objClone.a = 2;

console.log(obj.a);//1

data自定义数据

在html元素上以data-开头的属性,可以在相应的DOM对象上的dataset属性上得到其属性值

<div data-index="1" data-sub-title="hello"></div>
var oDiv = document.querySelector('div');
console.log( oDiv.dataset.index );//1
console.log( oDiv.dataset.subTitle );//hello  sub-title这样的多个-分割的形式,对应的属性为驼峰命名

js加载

defer

延迟加载

<script src="a.js"></script>
<script src="b.js"></script>
<script src="c.js"></script>
<img src="" alt="">

默认js的加载是顺序执行的,先加载js才会加载图片

<script src="a.js" defer="defer"></script>
<script src="b.js"></script>
<script src="c.js"></script>
<img src="" alt="">

如果script标签加上defer属性表示延迟加载(在onload之间加载),也就是说a.js会在图片加载之后加载

没加defer的js依然顺序加载

<script src="a.js" defer="defer"></script>
<script src="b.js" defer="defer"></script>
<script src="c.js" defer="defer"></script>
<img src="" alt="">

等价于

<img src="" alt="">
<script src="a.js"></script>
<script src="b.js"></script>
<script src="c.js"></script>

async

异步加载

<script src="a.js" async="async"></script>
<script src="b.js" async="async"></script>
<script src="c.js" async="async"></script>
<img src="" alt="">

表示几个js文件和图片会同时加载

问题: 不能确定那个js文件先加载完成(适合独立js的加载)

历史管理 history

触发历史管理:

  1. 跳转页面
  2. 改变hash
  3. pushState

onhashchange事件

当hash值发生改变时出发

例子: 彩票选择

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<button>随机选择</button>
<div></div> 
<script>
var oDiv = document.querySelector('div');
var btn = document.querySelector('button');

var json = {};

btn.onclick = function(){
    var hash = Math.random();
    var arr = randomArr(35, 7);
    json[ hash ] = arr;
    oDiv.innerHTML = arr.join(',');
    window.location.hash = hash;
}
window.onhashchange = function(){
    var hash = window.location.hash.slice(1);
    oDiv.innerHTML = json[hash];
}
function randomArr(maxNum , length){
    var arr = [];
    for(var i=0;i<length;i++){
        arr.push( parseInt(Math.random()*maxNum) )
    }
    return arr;
}
</script>
</body>
</html>

history.pushState 和 onpopstate事件

history.pushState

有三个参数:state对象,标题(现在是被忽略,未作处理),URL(可选)

当history实体被改变时(后退或前进),popstate事件将会发生

如果history实体是有pushState方法产生的,popstate事件的state属性会包含一份来自history实体的state对象的拷贝

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<button>随机选择</button>
<div></div> 
<script>
var oDiv = document.querySelector('div');
var btn = document.querySelector('button');

var json = {};

btn.onclick = function(){
    var arr = randomArr(35, 7);
    history.pushState(arr, '');
    oDiv.innerHTML = arr.join(',');
}
window.onpopstate = function(ev){
    oDiv.innerHTML = ev.state.join(',');
}
function randomArr(maxNum , length){
    var arr = [];
    for(var i=0;i<length;i++){
        arr.push( parseInt(Math.random()*maxNum) )
    }
    return arr;
}
</script>
</body>

拖放

在html标签上设置draggable="true", 元素久可以拖拽了

<div draggable="true"></div>

但是拖拽有点奇怪, 元素本身不会移动, 感觉是影子在移动, 跟拖拽图片的效果很像

拖拽元素事件
  • dragstart 拖拽前触发
  • drag 拖拽前、拖拽结束之间,连续触发
  • dragend 拖拽结束触发
<style>
.drag{
    width: 100px;
    height: 100px;
    background: red;
}
</style>
<div class="drag" draggable="true"></div>
<script>
    var oDrag = document.querySelector('.drag');
    oDrag.ondragstart = function(){
        this.style.background = 'green';
    }

    oDrag.ondragend = function(){
        this.style.background = 'red';
    }
    var i=0;
    oDrag.ondrag = function(){
        document.title = i++;
    }
</script>
目标元素事件
  • dragenter , 进入目标元素触发
  • dragover ,进入目标、离开目标之间,连续触发
  • dragleave , 离开目标元素触发
  • drop , 在目标元素上释放鼠标触发(需要在dragover事件中阻止默认行为才能生效)
<style>
div{
    width: 100px;
    height: 100px;
}
.drag{
    background: red;
}
.target{
    background: green;
}
</style>
<div class="drag" draggable="true"></div>
<div class="target"></div>
<script>
var oTarget = document.querySelector('.target');
oTarget.ondragenter = function(){
    this.style.background = '#111';
}
var i=0;
oTarget.ondragover = function(ev){
    ev.preventDefault();
    document.title = i++;
}
oTarget.ondragleave = function(){
    this.style.background = 'green';
}
oTarget.ondrop = function(){
    alert(1)
}
</script>
事件的执行顺序

drop不触发的时候:

dragstart > drag > dragenter > dragover > dragleave > dragend

drop触发的时候(dragover的时候阻止默认事件):

dragstart > drag > dragenter > dragover > drop > dragend

火狐下拖拽的问题

只设置draggable属性,在火狐下还是不能拖拽

还必须设置在dragstart事件中,设置dataTransfer对象上的setData方法才能拖拽除图片以外的其他元素

<div class="drag" draggable="true"></div>
<script>
var oDrag = document.querySelector('.drag');
oDrag.ondragstart = function(ev){
    ev.dataTransfer.setData('key', 'value');
}
</script>
dataTransfer

在拖拽事件中,是事件对象上的一个属性

有两个方法:

  • setData(key, value) key,value必须都是字符串
  • getData(key)
var oDrag = document.querySelector('.drag');
oDrag.ondragstart = function(ev){
    ev.dataTransfer.setData('a', 'b');
    alert(ev.dataTransfer.getData('a'));//b
}

实例: 将li拖拽到div, 在ondrop是删除对应的li

<style>
    div{
        width: 100px;
        height: 100px;
        background: red;
    }
    .drag{
        background: red;
    }
    .target{
        background: green;
    }


    li{
        display: inline-block;
        background: yellow;
    }
</style>
<ul>
    <li draggable="true">aa</li>
    <li draggable="true">bb</li>
    <li draggable="true">cc</li>
</ul>

<div>
    
</div>
<script>
var aLi = document.querySelectorAll('li');
var oDiv = document.querySelector('div');
aLi.forEach(function(elem, i){
    elem.i = i;
    elem.ondragstart = function(ev){
        ev.dataTransfer.setData('index', this.i);
    }


});
oDiv.ondragover = function(ev){
    ev.preventDefault();
}
oDiv.ondrop = function(ev){
    var i = ev.dataTransfer.getData('index');
    aLi[i].remove();
}
</script>
dataTransfer.effectAllowed

移入目标元素时,鼠标的样式

取值: none, copy, copyLink, copyMove,link,linkMove,move, all,uninitialized

oDrag.ondragstart = function(ev){
    ev.dataTransfer.effectAllowed = 'link';
}
dataTransfer.setDragImage()

三个参数: 指定的元素, 坐标x, 坐标y

oDrag.ondragstart = function(ev){
    ev.dataTransfer.setDragImage(oDiv, 0, 0);
}
dataTransfer.files

获取外部拖拽的文件, 返回一个filesList列表

filesList下每个文件对象有个type属性, 返回文件的类型

关于外部文件的拖拽, 这样我们就不需要操作拖拽元素了, 只需要操作目标元素

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
<style>
div{
    width: 200px;
    height: 200px;
    background: red;
}
</style>
</head>
<body>
    <div>将文件拖放到此区域</div>
<script>
var oDiv = document.querySelector('div');
oDiv.ondragenter = function(ev){
    this.innerHTML = '可以释放了';
    console.log(ev.dataTransfer.files[0].type);
}
oDiv.ondragover = function(ev){
    ev.preventDefault();
};
oDiv.ondragleave = function(){
    this.innerHTML = '将文件拖放到此区域';
}
oDiv.ondrop = function(ev){
    ev.preventDefault();//阻止浏览器的默认行为, 默认拖放文件到浏览器,会将文件在浏览器中打开
};
</script>
</body>
</html>
FileReader

使用FileReader对象,web应用程序可以异步的读取存储在用户计算机上的文件(或者原始数据缓冲)内容

  • fd.readAsDataURL(file);

data: URL格式的字符串以表示所读取文件的内容
参数为file对象,在拖拽中可以是ev.dataTransfer.files[0];

  • fd.onload

读取文件成功的回调函数,

成功获fd对象的result属性代表了获取的文件数据, 如果是图片,则返回base64格式的图片数据

oDiv.ondrop = function(ev){
    ev.preventDefault();
    var fd = new FileReader();
    fd.readAsDataURL(ev.dataTransfer.files[0]);
    fd.onload=function(){
        console.log(this.result);
    }
};

或者在<input>

<input id="fileItem" type="file">
<script>
var fileItem = document.getElementById('fileItem');
fileItem.onchange = function(){
    var file = this.files[0];
    var fd = new FileReader();
    fd.readAsDataURL(file);
    fd.onload=function(){
        console.log(this.result);
    }
}
</script>

实例: 图片预览

<div>将文件拖放到此区域</div>
<ul></ul>
<script>
var oDiv = document.querySelector('div');
var oUl = document.querySelector('ul');
oDiv.ondragenter = function(ev){
    this.innerHTML = '可以释放了';
}
oDiv.ondragover = function(ev){
    ev.preventDefault();
};
oDiv.ondragleave = function(){
    this.innerHTML = '将文件拖放到此区域';
}
oDiv.ondrop = function(ev){
    ev.preventDefault();
    var files = ev.dataTransfer.files;
    files = [].slice.call(files);
    files.forEach(function(file, i){
        if( file.type.indexOf('image')!=-1){
            var li = document.createElement('li');
            var img = document.createElement('img');
            li.appendChild(img);

            var fd = new FileReader();
            fd.readAsDataURL(file);
            fd.onload = function(){ 
                img.src= this.result;
                oUl.appendChild(li);

            }   
        }
        else{
            alert('请选择图片格式');
        }
        
    });


};
</script>

实例: 拖拽购物车

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
<style>
#cart{
    border: 1px solid  #111;
    min-height: 500px;
    min-width: 300px;
}
</style>
</head>
<body>

<ul id="product-list">
</ul>
<ul id="cart"></ul> 
<script>
var products = [
    {
        img: 'http://g-search2.alicdn.com/img/bao/uploaded/i4/i2/TB1wSUANpXXXXXeXXXXXXXXXXXX_!!0-item_pic.jpg_80x80.jpg',
        title: 'i7 6850K/华硕X99/GTX1080 VR游戏',
        price: 10000
    },
    {
        img: 'http://g-search3.alicdn.com/img/bao/uploaded/i4/i2/TB1UdPeOFXXXXa_XFXXXXXXXXXX_!!0-item_pic.jpg_80x80.jpg',
        title: '松明微星宙斯盾Aegis B903-008CN i7/8G*2/GTX1070台式机',
        price: 9999
    },
    {
        img: 'http://g-search1.alicdn.com/img/bao/uploaded/i4/i1/TB1UOY_KpXXXXciXVXXXXXXXXXX_!!2-item_pic.png_80x80.jpg',
        title: '海盗船 梦幻电脑250D 6700K/1151 多屏炒股HTPC办公台式电脑主机',
        price: 8888
    }

]

var cartData = {};

var str = '';

products.forEach(function(product, i){
    str += `
    <li draggable="true" data-index="${i}">
        ![](${product.img})
        <p>${product.title}</p>
        <p>¥${product.price}</p>
    </li>

    `
});

var oProduct = document.querySelector('#product-list');
var oCart = document.querySelector('#cart');

oProduct.innerHTML = str;

var aProductItem = document.querySelectorAll('#product-list li');

aProductItem.forEach(function(product, i){
    product.ondragstart = function(ev){
        ev.dataTransfer.setDragImage(this,0, 0);
        console.log(this.dataset.index);
        ev.dataTransfer.setData('index', this.dataset.index);
    }
});

oCart.ondragover = function(ev){
    ev.preventDefault();
}

oCart.ondrop = function(ev){
    ev.preventDefault();
    var index = ev.dataTransfer.getData('index');
    var product = products[index];
    var cartItem = null;

    if( !cartData[index] ){
        cartItem = {
            title: product.title,
            price: product.price,
            count: 1,
            li: document.createElement('li')
        }
        cartData[index] = cartItem;
        oCart.appendChild(cartItem.li);           
    }
    else{
        cartItem = cartData[index];
        cartItem.count++;
        
    }

    cartItem.li.innerHTML = `
        <span class="count">${cartItem.count}</span>
        <span class="title">${cartItem.title}</span>
        <span class="total">¥${cartItem.price*cartItem.count}</span>
    `;

}
</script>
</body>
</html>

canvas

基本使用

<!--不要使用css给canvas设置宽高-->
<canvas id="canvas" width="500" height="300">
        你的浏览器不支持canvas
</canvas>

绘图环境

var canvas = document.querySelector('#canvas');
var context = canvas.getContext('2d');

目前只支持2d,不支持3d,如果要使用3d, 可以使用webgl(不过兼容性也不是很好)

绘制方块

context.fillRect

context.fillRect(left,top, width, height)

context.fillRect(50,50, 100, 200);

默认颜色是黑色

context.strokRect

strokeRect(left, top, width, height)

context.strokeRect(50,50, 100, 200);

默认是1像素黑色边框

但是显示出在ps中测量为2像素的边框,把画布看成一个坐标轴,正方形的顶点坐标为(50px, 50px)

正方形的边框为1像素宽,我们以左边框为例, 它是以50px为中心点,向右延伸0.5像素(49.5px),
向左延伸0.5像素(50.5px); 所以做边框为(49.5px~50.5px)

但是,用canvas绘图跟我们的ps一样, 最小的但是就是1px,没有0.5px, 所以就将出现了2px的边框

我们可以这样写

context.strokeRect(50.5,50.5, 100, 200);

这样边框的中心点在1px的一半,刚刚就可以是1px

设置绘图

fillStyle 填充颜色

strokeStyle 边框颜色

lineWidth 线宽

context.fillStyle = 'red';
context.strokeStyle = 'blue';
context.lineWidth = 10;


//注意: 顺序不同,效果不同
context.fillRect(50,50,100,50);
context.strokeRect(50,50,100,50);

边界绘制

lineJoin 边界连接点样式

miter(默认)(斜接) round(圆角) bevel(斜角)

lineCap 端点样式

butt(默认) round(圆角) square()

绘制路径

beginPath

closePath

moveTo

lineTo

stroke

fill

rect

clearRect

save

restore

实例: 鼠标画线

var canvas = document.querySelector('#canvas');
var context = canvas.getContext('2d');
canvas.onmousedown = function(ev){
    context.moveTo(ev.clientX - canvas.offsetLeft, ev.clientY-canvas.offsetTop)
    canvas.onmousemove = function(ev){
        context.lineTo(ev.clientX - canvas.offsetLeft, ev.clientY-canvas.offsetTop);
        context.stroke();
    }
    canvas.onmouseup = function(){
        this.onmousemove = null;
        this.onmouseup = null;
    }
}

实例: 方块移动

var canvas = document.querySelector('#canvas');
var context = canvas.getContext('2d');
var iNow = 0;
setInterval(function(){
    iNow++;
    context.clearRect(0, 0, 500, 300);
    context.fillRect(iNow, iNow, 100, 100);

}, 50);

绘制圆

arx(x, y, 半径, 起始弧度, 终止弧度, 旋转方向)

  • 弧度与角度的关系: 弧度=角度*Math.PI/180
  • 旋转方向: 顺时针false(默认), 逆时针true

实例: 时钟

var canvas = document.querySelector('#canvas');
var context = canvas.getContext('2d');

var r = 100;
var x = 150;
var y = 150;
function drawClock(){
    context.clearRect(0, 0, 500, 300);
    var now = new Date();
    var hour = now.getHours();
    var min = now.getMinutes();
    var sec = now.getSeconds();

    console.log(hour, min, sec);

    var hourAngle = hour*30 + min*(30/60) - 90;
    var minAngle = min*6+sec*(6/60) - 90;
    var secAngle = sec*6 -90;

    //分钟刻度
    for(var i=0;i<60;i++){
        context.beginPath();
        context.moveTo(x,y);
        context.arc(x,y,r, 6*i*Math.PI/180, 6*(i+1)*Math.PI/180);
        context.stroke();
        context.closePath();
    }

    context.beginPath();
    context.fillStyle ='white';
    context.arc(x,y,r*(19/20), 0, 360*Math.PI/180);
    context.fill();
    context.closePath();

    // 时钟刻度
    for(var i=0;i<12;i++){
        context.beginPath();
        context.lineWidth = 3;
        context.moveTo(x,y);
        context.arc(x,y,r, 30*i*Math.PI/180, 30*(i+1)*Math.PI/180);
        context.stroke();
        context.closePath();
    }

    context.beginPath();
    context.fillStyle ='white';
    context.arc(x,y,r*(17/20), 0, 360*Math.PI/180);
    context.fill();
    context.closePath();


    // 时钟指针
    context.beginPath();
    context.moveTo(x,y);
    context.arc(x,y,r*(12/20), hourAngle*Math.PI/180, hourAngle*Math.PI/180);
    context.stroke();
    context.closePath();

    // 分钟刻度
    context.beginPath();
    context.moveTo(x,y);
    context.arc(x,y,r*(14/20), minAngle*Math.PI/180, minAngle*Math.PI/180);
    context.lineWidth = 2;
    context.stroke();
    context.closePath(); 

    // 秒钟刻度
    context.beginPath();
    context.moveTo(x,y);
    context.arc(x,y,r*(17/20), secAngle*Math.PI/180, secAngle*Math.PI/180);
    context.lineWidth = 1;
    context.stroke();
    context.closePath();    
}

drawClock();


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

推荐阅读更多精彩内容