canvas动画
动画的形成:先画出一幅图,改变其中的一些参数,重新绘制图片...不断的重复形成动画。
- fillStyle:设置或返回填充绘画的颜色,渐变或模式
- strokeStyle:设置或返回用于笔触的颜色,渐变或模式
- fill(): 填充当前路径(如果路径未关闭则会从路径结束点到开始点之间添加一条线)
- stroke():绘制已定义的路径。
- moveTo():把路径移动到画布中的指定点,不创建线条
- beginPath():起始一条路径或重置当前路径
- closePath():创建从当前点回到起始点的路径
- lineTo():添加一个新点,创建一条连接至该点的线条
- clearRect():清除指定矩形内的像素
- arc():创建弧或曲线
- rotate():创建两点之间的弧或曲线
- translate():重新映射画布上的(0,0)位置
- drawImage():绘制图像、画布或视频
- save():保存当前环境状态
- restore():返回之前保存过的路径和状态
- getContext():返回一个用于在画布上绘图的环境
- requestAnimationFrame():回调例程调用 requestAnimationFrame()。根据浏览器设备的绘制限制,来更新动画,回调的次数常是每秒60次。
canvas学习——树镜
整体逻辑
- 创建一个类,实例化根元素,递归创建分支直到层数,每层分支长度(length)递减,直至层数>=5;
- 调用drawBranch生成一张图片
- 改变树枝展开角度以及位置执行requestA nimationFrame();重复执行;形成动画
- 将12个不同旋转角度的动画canvas添加到canvas2.围成一圈。
- 鼠标移入则停止自动改变树枝状态,转为由鼠标的横纵坐标控制。
关键代码理解
class Branch {
/**
* 分枝类,以下为参数,都带有默认值
* 位置 position
* 长度 length
* 分支位置 divergeAt
* 展开角度 angle
* 层数 depth
* 分支展开角度变化量 spread
*/
constructor(position = {x : 0, y: 0}, length = 100, divergeAt = 0.5, angle = 0, depth = 0, spread = 45 * TO_RADIAN) {
this.position = position;
this.length = length;
this.divergeAt = divergeAt;
this.angle = angle;
this.depth = depth;
this.color = '#000';
this.spread = spread;
this.branches = [];
this.grow();
}
grow() {
/**
* 创建分支,如果canBranch = true(未达到最大分支数量)
* 新分支长度为父级的0.75,深度加1
* 展开角度变化spread
* 由于构造方法中调用了grow方法,所以会不断重复创建上述过程
*/
if (!this.canBranch) {
return;
}
this.branches = [];
const nextLength = this.length * 0.75;
const nextDepth = this.depth + 1;
this.branches.push(
new Branch(
this.growPosition,
nextLength,
this.divergeAt,
this.angle + this.spread,
nextDepth,
this.spread
),
new Branch(
this.growPosition,
nextLength,
this.divergeAt,
this.angle - this.spread,
nextDepth,
this.spread
)
);
}
update(spread, divergeAt) {
this.spread = spread;
this.divergeAt = divergeAt;
this.grow();
}
get growPosition() {
const dl = this.length * this.divergeAt;
return {
x: this.position.x + (Math.cos(this.angle) * dl),
y: this.position.y + (Math.sin(this.angle) * dl),
};
}
get canBranch() {
return this.depth < maxDepth;
}
}
/**
* 保存当前状态
* 根据branch类中的数据画图(颜色,直线和圆点)
* 递归对分支进行绘图
*/
const drawBranch = (branch, phase) => {
const h = ~~(200 + (160 * phase));
const l = 50 + ~~(((branch.depth / (maxDepth + 1))) * 50);
const endX = branch.length;
const endY = 0;
const r = 2;
ctx.save();
ctx.strokeStyle = `hsl(${h}, 100%, ${l}%)`;
ctx.translate(branch.position.x, branch.position.y);
ctx.rotate(branch.angle);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(endX, endY);
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.fillStyle = `hsl(${h}, 100%, 50%)`;
ctx.arc(endX, endY, r, 0, PI * 2, false);
ctx.fill();
ctx.closePath();
ctx.restore();
branch.branches.forEach((b) => {
drawBranch(b, phase);
});
};
const loop = () => {
/**
* 改变类中参数的值
* 将第一个canvas添加到在第二个canvas中循环12次每次旋转2PI/12的角度,形成一个环状
* 调用requestAnimationFrame() 重新根据类中的数据画图
*/
let phase = rootBranch.spread / maxSpread;
clear(phase);
if (autoAnimate) {
phase = map(Math.sin(autoTick), -1, 1, 0, 1);
spread = phase * maxSpread;
divergeAt = map(Math.sin(autoTick), -1, 1, 0, 0.5);
autoTick += autoSpeed;
}
rootBranch.update(spread, divergeAt);
drawBranch(rootBranch, phase);
const numSegments = 12;
const angleInc = PI * 2 / numSegments;
let angle = tick;
for (let i = 0; i < numSegments; i++) {
ctx2.save();
ctx2.translate(midX, midY);
ctx2.rotate(angle);
ctx2.drawImage(canvas, -w / 2, -h / 2);
ctx2.restore();
angle += angleInc;
}
tick += 0.002;
requestAnimationFrame(loop);
};
element-ui
安装
- npm安装: npm i element-ui -s
- cdn
引入
完整引入
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
按需引入
需要安装 babel-plugin-component:
npm install babel-plugin-component -D
在.babelrc中添加:
"plugins": [
"transform-vue-jsx", "transform-runtime",
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
import {Loading, Tabs, TabPane,} from 'element-ui';
Vue.use(Loading);
Vue.use(Tabs);
Vue.use(TabPane);
自定义主题
在项目中直接改变scss变量
/* 改变主题色变量 */
$--color-primary: teal;
/* 改变 icon 字体路径变量,必需 */
$--font-path: '~element-ui/lib/theme-chalk/fonts';
@import "~element-ui/packages/theme-chalk/src/index";
命令行主题工具
npm i element-theme -g
之后步骤为:
- 安装主题
- 初始化变量文件
- 修改变量
- 编译成css
- 引入
JavaScript 对象的深拷贝
在星盘改版的时候遇到了相关的问题,数据从父组件传递到子组件,当时没考虑到这方面的问题,只是对数据进行了一层的拷贝,因为当时传进来的数据是有很多层的,所以还是会导致源数据改变。所以总结一下,写成一个方法,这个应该会比较常用。
Object属于引用类型,对它进行简单赋值(obj1 = obj2)的话只是创建一个指针指向原数据的地址,改变它的值也会改变源数据的值,会造成很多问题。
基本的深拷贝方法
数组
concat,slice 等方法,es6 新增运算符‘...’
对象
思路是把对象拆开分别赋值,同样可以使用es6 新增运算符‘...’,for循环等。
深拷贝的实现
运用递归逐层拷贝。
function depCopy(obj){
let value;
if(typeof obj === "object"){
if(Object.prototype.toString.call(obj).slice(8,-1)==='Array'){
// debugger;
value = [];
for(let i = 0, length = obj.length; i<length; i++){
value.push(depCopy(obj[i]));
}
}
else{
value = {};
for(let j in obj){
value[j] = depCopy(obj[j]);
}
}
}
else{
value = obj;
}
return value;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。