canvas学习笔记

HTML5 canvas 标签用于绘制图像(通过脚本,通常是 JavaScript)。

创建画布并操作js

<canvas width="500" height="500" id="test"></canvas>

var canvas = document.getElementById('test');
if (canvas == null || !canvas.getContext)
     return false;
var ctx = canvas.getContext("2d");

canvas api

点击example

通过搭建DNS服务器访问内网服务器

访问内部服务器,无法解释域名,又不想修改host,我们可以采用建立一个DNS服务器,添加a记录就可以。

环境:
使用windows server2008

搭建

首先运行servermanager.msc

菜单

运行

添加角色

服务器管理器

下一步

选择DNS服务器

一直下一步直到安装完毕。

通过菜单打开DNS管理器
菜单

通过正向查找区域添加主域

DNS管理器

DNS管理器

DNS管理器

进入命令行,通过nslookup查看是否dns设置成功

命令行

本地网络连接,属性

设置 DNS 127.0.0.1 和 8.8.8.8

网络链接属性

记录下当前主机所在IP地址。172.16.5.166

访问端设备设置:

DNS 改成做了DNS服务器主机地址(172.16.5.166)

需要访问内网的手机( 注意 可能有缓存,所以需要重启或者等待一段时间)

手机设置

需要访问的电脑

mac设置

ready和onload事件的区别

一般遇到图片的尺寸计算时,我们在jquery下无法直接获得。

因为我们一般使用$(function(){}),等同于$(document).ready(function(){…})的ready状态下运算。

分析ready和onload

  1. ready,表示文档结构(DOM结构)已经加载完成(不包含图片等非文字媒体文件)
  2. onload, 表示页面包含图片等文件在内的所有元素都加载完成。(可以说:ready在onload前加载)

所以要计算图片大小要放在onload里面加载。

BFC块级格式化上下文

BFC就是block formatting context的缩写,中文就是“块级格式化上下文”的意思。

Formatting context是W3C CSS2.1规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。常见的FC有BFC,IFC等。

创建BFC

  1. float 除了none以外的值
  2. overflow 除了visible 以外的值(hidden,auto,scroll )
  3. display (table-cell,table-caption,inline-block, flex, inline-flex)
  4. position值为(absolute,fixed)
  5. fieldset元素

为什么需要块级格式化上下文?

1.解决margin叠加问题 三P每个p之间的距离为50px,发生了外边距叠加。
右图是添加overflow:hidden

<html>
    <div class="bfc">
        <p>helloword</p>
    </div>
    <p>helloword</p>
    <p>helloword</p>
</html>

<style>
    .bfc {
       overflow: hidden;
    }
    p {
       background: red;
       width: 100px; 
       height: 100px;
       margin: 40px;
    }
</style>

2.用于布局
左边元素脱离文档流后,右边元素的左外边距会触碰到包含块容器的左外边框的问题

没有BFC
通过overflow:hidden创建BFC

<div style="text-align: center; border: 10px solid #000">          
    <div style="float: left; width: 100px;height: 100px; background: red">            
    </div>        
    <div style="width: 150px;height: 150px; background: blue; overflow: hidden">    
    </div>        
</div>

3.用于清除浮动
没有BFC
通过overflow:hidden创建BFC

<div style="text-align: center; overflow: hidden; border: 10px solid #000">
    <div style="float: left; width: 100px;height: 100px; background: red">            
    </div>        
    <div style="float: left; width: 100px;height: 100px; background: blue;">    
    </div>     
</div>

Js闭包

定义:

闭包是指有权访问另一个函数作用域中的变量函数。

一般来讲,当函数执行完毕后,局部活动对象就会被销毁,内存中仅保存全局作用域(全局执行环境的变量对象)。
但是闭包函数不同。

闭包函数能访问到外部(活动对象)的属性,所以外部函数的活动对象不会执行后自动销毁。
闭包函数直行后,其活动对象自行销毁,保存全局变量对象。但是其作用链上的其他函数下的活动对象仍保存,要通过null将其解除该函数的引用,通知垃圾回收例程将其清除。(防止内存泄漏)

闭包与变量

闭包只能取得包含函数中任何变量的最后一个值(闭包保存的是整个变量对象,而不是某个特殊变量)

var result = [];
for(var i = 0; i<10; i++) {
    result[i] = function( { 
        return i 
    } 
}

PS: result结果是一个函数数组,每个函数都返回10。因为每个函数的作用域链中都保存着createFunctions()函数的活动对象,所以它们引用都是同一个变量i(10)。

var result = [];
for(var i = 0; i<10; i++) {    
    result[i] = function(num) {        
        return function() {            
            return num;        
        }    
    }(i)
}

PS:由于函数参数是按值传递的,所以就会将变量i的当前值复制给参数num。result数组中的每个函数都有自己num变量的一个副本,因此返回各自不同的数值。

关于this对象:

var name  = "the window";

var object = {
    name: "my Object",
    getNameFunc: function() {
        return function() {
            return this.name;   // the window
        }
    }
}

每个函数在被调用时都会自动获取两个特殊变量,this和arguments。

内部函数在搜索这两个变量时,只会搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量。不过,把外部作用域的this对象保存在一个闭包能够访问的变量里,就可以让闭包访问该对象了。

var that = this;
return function() {
     return that.name
}

css3 动画

三个概念

1.变形属性transform
2.动画属性transition
3.带keyframes的动画属性 animate

1.变形属性transform

语法:
transform : none | transform-function
也就是:
transform: none | rotate | scale | skew | translate |matrix;

transform: none
transform: matrix(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)
transform: translate(12px, 50%)  // translate(x,y)水平方向和垂直方向同时移动
transform: translateX(2em)
transform: translateY(3in)
transform: scale(2, 0.5)   // scale(x,y)使元素水平方向和垂直方向同时缩放
transform: scaleX(2)
transform: scaleY(0.5)
transform: rotate(90deg)   // 旋转
transform: skewX(30deg)     // skew(x,y)使元素在水平和垂直方向同时扭曲
transform: skewY(1.07rad)
transform: matrix3d(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0)
transform: translate3d(12px, 50%, 3em)
transform: translateZ(2px)
transform: scale3d(2.5, 1.2, 0.3)
transform: scaleZ(0.3)
transform: rotate3d(1, 2.0, 3.0, 10deg)
transform: rotateX(10deg)
transform: rotateY(10deg)
transform: rotateZ(10deg)
transform: perspective(17px)

transform中使用多个属性时却需要有空格隔开: transform: translateX(10px) rotate(10deg) translateY(5px)

2.transition动画


语法
transition: property duration timing-function delay;

规定设置过渡效果的 CSS 属性的名称 none|all|property;
规定完成过渡效果需要多少秒或毫秒
规定速度效果的速度曲线
定义过渡效果何时开始

用法:transition: background 0.2s ease-in-out .1s;



timing-function: linear | ease | ease-in | ease-out | ease-in-out | cubic-bezier(n,n,n,n) 规定动画的速度曲线





3.animation动画

制作一个简单的transition效果时,我们包括了初始属性和最终属性,一个开始执行动作时间和一个延续动作时间以及动作的变换速率,其实这些值都是一个中间值,如果我们要控制的更细一些,比如说我要第一个时间段执行什么动作,第二个时间段执行什么动作(换到flash中说,就是第一帧我要执行什么动作,第二帧我要执行什么动作),这样我们用Transition就很难实现了,此时我们也需要这样的一个“关键帧”来控制。

语法:
animation: name duration timing-function delay iteration-count direction;

规定需要绑定到选择器的 keyframe 名称
规定完成动画所花费的时间,以秒或毫秒计
规定动画的速度曲线
规定在动画开始之前的延迟
规定动画应该播放的次数 infinite无限
规定是否应该轮流反向播放动画 normal正常播放 alternate反向播放

<style> 
    div {
        width:100px;
        height:100px;
        background:red;
        animation:myfirst 5s linear 2s infinite alternate;
    }

    @keyframes myfirst {
        from {background:red;}
        to {background:yellow;}
    }
</style>

Js创建对象及继承

1.创建对象 (通过字面量或者Object构造函数)

var person = {}; or new Object();
person.age = 12;
person.say = function() {
    alert(this.age)
}

缺点:使用同一个接口创建很多对象,会产生大量重复代码

2.工厂模式 (通过函数来封装特定接口创建对象)

function creatPerson(age) {
    var o = new Object();
    o.age = age;
    o.say = function() {
        alert(this.age);
    }
    return o;
}
var person1 = createPerson(23);
var person2 = createPerson(21);

缺点:虽然解决了创建多个相似对象问题,但却没有解决对象识别问题(即怎样知道一个对象的类型)

3.构造函数模式 (创建自定义构造函数,从而定义自定义对象类型属性和方法)

function Person(age) {
    this.age = age;
    this.say = function() {
        alert(this.age);
    }
}     
var person1 = new Person(23);
var person2 = new Person(21);

function say() { alert(this.age); }  //  全局函数

缺点:不同实例上的同名函数不相等。person1.say == person2.say // false
将this.say改成指针指向全局函数say()。这样就不用创建不同Function实例,但是say()是全局函数,没有封装性可言。

4.原型模式(通过原型对象共享属性和方法)

function Person() {
}
Person.prototype.age = 23;
Person.prototype.say = function() {
    alert(this.age)
}

var person1 = new Person();
var person2 = new Person();

person1.say == person2.say   // true

创建函数,自动拥有prototype属性,这个属性指向函数的原型对象。
实例与构造函数的原型对象是有关系的,与构造函数没关系。

person1.age = 1;
person1.age // 1
person2.age // 23

person1先访问实例属性,再访问原型属性。通过delete person1.age 删除实例属性, 随后即可访问原型属性。

判断实例是否拥有属性
“age” in person1

判断是否实例属性
person1 hasOwnProperty(“name”)

更简单的原型语法

 function Person() {
 }
 Person.prototype = {
     age: 23,
     say: function() {
         alert(this.age);
     }
 }

Person.prototype.name  =>  person1.constructor = Person 
Person.prototype =  {}    =>  字面量赋值,改写了person1.constructor = Object
Person.prototype = {
     constructor:  Person,
     age: 23
     ...
}

原生对象的原型:
Array.prototype.sort

Person.prototype.friend = [‘tony’]
person1.friends.push(‘van’) // tony, van
person2.friends // tony,van

缺点:省略了为构造函数传递初始化参数这一环节,所有实例在默认情况下将取得相同的属性值。

5.构造函数+原型模式

function Person(age) {
    this.age = age;
    this.friend = ['tony']
}

Person.prototype = {
    constrostor: Person,
    say: function() {
        alert(this.name);
    }
}

var person1 = new Person(1);
var Person2 = new Person(2);

person1.friends.push("van");

person1.friends  // tony, van
person2.friends  // tony

person1.say === person2.say // true

6.动态原型模式(由于开发人员看到独立的构造函数和原型时困惑,所以把所有信息都封装在构造函数中)

function Person(age) {
    this.age = age;
    if( typeof this.say != 'function') {
        Person.prototype.say = function() {
            alert(this.age);
        }
    }
}  

使用动态原型模型时,不能使用对象字面量重写原型。

7.寄生构造函数模式

与工厂模式相似,只是通过new 构造函数不一样。
构造函数默认返回新对象实例,通过在构造函数末尾添加return语句,重写调用构造函数时返回的值。

8. 稳妥构造函数模式 (不使用this,new)

========================

继承

1.原型链继承

function SuperType() {
    this.colors = ['red']
} 

function SubType() {}

SubType.prototype = new SuperType()  // 继承了SuperType

var instance1 = new SubType();
instance1.colors.push('blue');
instance1.colors  // red, blue

var instance2 = new SubType();
instance2.colors // red, blue

问题: SuperType每个实例都有各自colors属性,SubType所有实例共享同一个colors属性。在创建子类型的实例时,不能向超类型的构造函数传递参数。

2.借用构造函数

function SuperType(name) {
    this.colors = ['red'];
    this.name = name;
} 

function SubType() {
    SuperType.call(this,'wu');  // 继承了SuperType
}

在子类型构造函数内部调用超类型构造函数。(call(), apply()执行构造函数)

问题: 方法都在构造函数中定义,因此无法函数复用。(在超类型的原型中定义的方法,对子类型而言不可见)

3.组合继承(原型链+借用构造函数)

function SuperType(name) {
    this.colors = ['red'];
    this.name = name;
} 

SuperType.prototype.say = function() {
    alert(this.name);
}

function SubType() {
    SuperType.call(this,'wu');  // 继承属性
}

SubType.prototype = new SuperType(); // 继承方法

此处原型链也继承了属性

var instance1 = new SubType(‘wu’);

instance1.name = wu // 实例name
delete instance1.name
instance1.name = wu // 原型对象name
“name” in instance1 // true
instance1.hasOwnProperty(‘name’) // false

4.原型式继承

5.寄生式继承

6.寄生组合式继承

移动端自适应

1.定高,宽度自适应

1
<meta name="viewport" content="width=device-width,initial-scale=1”>

设置width=device-width

目前使用最多的方法,垂直方向用定值,水平方向用百分比、定值、flex都行640的设计稿,以320做网站视觉参考,按设计稿的1/2尺寸去定义网页图像尺寸。

2.固定宽度,对viewport宽度进行定值

设置

1
<meta name="viewport" content="width=1120">

某些安卓机缩放失效,需js动态设置initial-scale缺点: 像素丢失

3.利用rem布局 + viewport缩放

dpr计算 + css预处理器函数 viewport,js动态设置initial-scale

参考https://github.com/riskers/blog/issues/18

vue过留痕

简单的vue demo

引入vue.js

1
2
3
4
5
6
7
8
9
10
11
12
<div id="app-2">
<span v-bind:title="message">
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
</div>
var app2 = new Vue({
el: '#app-2',
data: {
message: '页面加载于 ' + new Date()
}
})

指令带有前缀v-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(html 属性用v-bind, 缩写:title)
v-bind:title="message"
v-bind:id
v-bind:class="{ active: isActive }"
v-bind: disabled
v-bind:is
v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }
v-for="todo in todos"
v-if="seen"
v-else
(缩写@click)
v-on:keyup.enter // enter是按键修饰符
v-on:click="doSomething('hi', $event)" // 访问原生 DOM 事件
v-model.trim="message" // input,表单输入和应用状态间的双向绑定
v-once // <span v-once> {{ msg }}</span>仅显示一次改变
v-html="rawHtml" data.rawHtml = '<p>hello</p>' // 纯html
b-bind:item = "item" // 父向子传数据

Vue 实例暴露了一些有用的实例属性与方法。这些属性与方法都有前缀 $

1
2
3
4
5
var data = { a: 1 }
var vm = new Vue({
el: '#example',
data: data
})
vm.$data, vm.$el, vm.$watch

查看http://cn.vuejs.org/v2/api

组件

组件命名规则

建议(小写,并且包含一个短杠)my-component

new Vue是一个实例

Vue.extend 组件构造器 需要传入component进行注册

Vue.component直接注册组件内部已经自动构造了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="mount-point"></div>
// 创建构造器
var Profile = Vue.extend({
template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
data: function () {
return {
firstName: 'Walter',
lastName: 'White',
alias: 'Heisenberg'
}
}
})
// 创建 Profile 实例,并挂载到一个元素上。
new Profile().$mount('#mount-point')

1.你可以作用到Vue.component 这个全局注册方法里

1
2
3
4
5
var apple = Vue.extend({ // var apple = {} 选项对象(自动调用 Vue.extend)
....
})
Vue.component('apple',apple) // 全局注册

2.你可以作用到vue实例或者某个组件中的components属性中并在内部使用apple组件

1
2
3
4
5
6
new Vue({
el: '#app', // 仅在此#app下使用
components:{
apple: apple
}
})

3.Vue中简易注册组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- html -->
<ol>
<!-- 创建一个 todo-item 组件的实例 -->
<todo-item></todo-item>
</ol>
<!-- end html -->
<!-- script 全局 注册组件,传入一个选项对象(自动调用 Vue.extend) -->
Vue.component('todo-item', { // 同理全局组件
template: '<li>这是个待办项</li>'
})
<!-- script or 局部 -->
new Vue({
el: '#app', // 仅在此#app下使用
components: {
'todo-item': {
template: '<li>这是个待办项</li>'
}
}
})

路由

1.is动态绑定: 动态组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<component :is="view"></component>
var app = new Vue({
el: '#app',
data: {
view: 'home'
},
created: function() {
// 路由:根据 hash 值切换视图组件(popstate|hashchange)
$(window).on('hashchange', function() {
var view = window.location.hash.replace(/#\/?/, '');
// 路由配置
switch (view) {
case 'login':
self.view = view;
break;
default:
self.view = 'home';
}
}).trigger('hashchange');
}
})

来自: http://cn.vuejs.org/v2/guide/components.html#动态组件

2.把 vue-router 加进来,只需要配置组件和路由映射,然后告诉 vue-router 在哪里渲染它们

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
// 1. 定义(路由)组件。
// 可以从其他文件 import 进来
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
// 2. 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
// 我们晚点再讨论嵌套路由。
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
// 3. 创建 router 实例,然后传 `routes` 配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({
routes // (缩写)相当于 routes: routes
})
// 4. 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({
router
}).$mount('#app')

来自: http://router.vuejs.org/zh-cn/essentials/getting-started.html

生命周期钩子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div id="box">
<input type="text" v-model="msg"><br/>
{{msg}}
</div>
new Vue({
el:'#box',
data:{
msg:'welcome'
},
created:function(){
console.log('实例已经创建,msg变量还未渲染到模板')
},
mounted:function(){
console.log('已经挂载到模板上:msg变量渲染到模板')
},
updated:function(){
console.log('实例更新啦')
},
destroyed:function(){
console.log('销毁啦')
}
});

技巧

等待DOM更新再操作

1
2
3
Vue.nextTick(function () {
// DOM 更新了
})

keep-alive // 把切换出去的组件保留在内存中

v-model

1
2
<input v-model="something"> // 等同于下面
<input v-bind:value="something" v-on:input="something = $event.target.value">

VUE方法属性合集

1
2
3
4
5
6
7
8
9
10
11
12
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {}, // 以来关系变化才变化,有缓存, getter, setter
created:function(){}, // mounted, updated, destroyed
methods: {}, //只要发生重新渲染 {{now()}}
watch: {},
filters: {}
}
})

循环for+if

v-if只能添加在一个元素上,遇到多个元素块(ul),可以把

1
2
3
4
5
6
7
<transition name="fade">
<template v-for="(item, index) in range" v-if="index === cindex">
<ul class="phone_list clearfix">
<li>xx</li>
</ul>
</template>
</transition>
=====  普通情况 =====
1
2
3
4
5
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>

循环里三个参数,value数据值,key键名,index索引,建议加key

1
2
3
4
5
6
7
8
object: {
firstName: 'wu',
lastName: 'xiao'
}
<div v-for="(value, key, index) in object">
{{ index }}. {{ key }} : {{ value }}
</div>

组件

父子之间通信

父组件是使用 props 传递数据给子组件
子组件要把数据传递回去,自定义事件
父: $on(eventName) 监听事件,子: $emit(eventName) 触发事件

1
2
3
<table>
<tr is="my-row"></tr> // 注意子组件建议, 而不是<my-row>..</my-row>, 因为受HTML限制,table+tr,ul+li
</table>


实例data是对象, 组件data是函数 data: function() {returen { c: 1}}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<div id="box">
<input type="text" v-model="newItem" v-on:keyup.enter="pushNew" />
<ul>
<li is="my-com" v-for="(item,index) in allItem" v-bind:item="item" v-bind:key="item" v-on:remove="removeThis(index)"></li>
</ul>
</div>
var vm = new Vue({
el:'#box',
data:{
newItem: '',
allItem: []
},
components: {
'my-com': {
props: ['item'],
template: '<li>{{ item }} <button v-on:click="$emit(\'remove\')">x</button></li>'
}
},
methods: {
pushNew: function() {
this.allItem.push(this.newItem)
this.newItem = ''
},
removeThis: function(index) {
this.allItem.splice(index, 1)
}
}
});

使用 Slot 分发内容

父组件模版:

1
2
3
4
<my-component>
<p>这是一些初始内容</p>
<p slot="footer">这是更多的初始内容</p>
</my-component>

子组件模版:

1
2
3
4
5
6
7
<div>
<h2>我是子组件的标题</h2>
<slot name="footer"></slot> //这是更多的初始内容
<slot>
只有在没有要分发的内容时才会显示。 // slot 能显示父组件的内容,这是一些初始内容
</slot>
</div>

来自: http://cn.vuejs.org/v2/guide/components.html

对数组的操作

Vue 包含一组观察数组的变异方法

push()
pop()
shift()
unshift()
splice()
sort()
reverse()
1
2
3
4
5
6
vue不能检测以下变动数组
vm.items[indexOfItem] = newValue
改成example1.items.splice(indexOfItem, 1, newValue)
vm.items.length = newLength
改成example1.items.splice(newLength)

事件修饰符

1
2
3
4
5
.stop <a v-on:click.stop="doThis"></a> 阻止单击事件冒泡
.prevent
.capture
.self
.once

来自http://cn.vuejs.org/v2/guide/events.html

按键修饰符

1
2
3
4
5
6
7
8
9
.enter <input v-on:keyup.enter="submit"> 只有是enter键才促发
.tab
.delete (捕获 “删除” 和 “退格” 键)
.esc
.space
.up
.down
.left
.right

状态管理器

各组件间相互通信

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
},
increment ({ commit }) { // es5
commit('increment')
}
}
})
操作
// 事件派发: store.dispatch('increment')
// 获取数据
computed: {
count () {
return this.$store.getters.count
}
}

过渡效果

1
2
3
<transition name="fade">
<p v-if="show">hello</p>
</transition>

来自: http://cn.vuejs.org/v2/guide/transitions.html