1

canvas动画

       动画的形成:先画出一幅图,改变其中的一些参数,重新绘制图片...不断的重复形成动画。

  • fillStyle:设置或返回填充绘画的颜色,渐变或模式
  • strokeStyle:设置或返回用于笔触的颜色,渐变或模式
  • fill(): 填充当前路径(如果路径未关闭则会从路径结束点到开始点之间添加一条线)
  • stroke():绘制已定义的路径。
  • moveTo():把路径移动到画布中的指定点,不创建线条
  • beginPath():起始一条路径或重置当前路径
  • closePath():创建从当前点回到起始点的路径
  • lineTo():添加一个新点,创建一条连接至该点的线条
  • clearRect():清除指定矩形内的像素
  • arc():创建弧或曲线
  • rotate():创建两点之间的弧或曲线
  • translate():重新映射画布上的(0,0)位置
  • drawImage():绘制图像、画布或视频
  • save():保存当前环境状态
  • restore():返回之前保存过的路径和状态
  • getContext():返回一个用于在画布上绘图的环境
  • requestAnimationFrame():回调例程调用 requestAnimationFrame()。根据浏览器设备的绘制限制,来更新动画,回调的次数常是每秒60次。

canvas学习——树镜

整体逻辑
  1. 创建一个类,实例化根元素,递归创建分支直到层数,每层分支长度(length)递减,直至层数>=5;
  2. 调用drawBranch生成一张图片
  3. 改变树枝展开角度以及位置执行requestA nimationFrame();重复执行;形成动画
  4. 将12个不同旋转角度的动画canvas添加到canvas2.围成一圈。
  5. 鼠标移入则停止自动改变树枝状态,转为由鼠标的横纵坐标控制。
关键代码理解
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

之后步骤为:

  1. 安装主题
  2. 初始化变量文件
  3. 修改变量
  4. 编译成css
  5. 引入

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;
  }

不快乐的程序员
393 声望13 粉丝