vue+canvas如何实现b站萌系登录界面

简介:

当初在掘金看到那个小熊的登录页面,很多人都很喜欢,于是恬不知耻的说了一句要用canvas来实现一遍,真的是给自己立了个flag,还好结果很糟糕。

各位观众大老爷,这可能是你见过最惨淡的demo了,希望不要嫌弃

首先看看别人的效果图

bcf739480e06750695bd54cc149e9fd62744d155

进行思考

  1. 为什么小熊会跟着输入框的输入而移动。
  2. 为什么小熊的耳朵会移动到前面
  3. 小熊的移动规律是什么

做出一些逻辑上的思索与排除

  1. 2d
  2. 3d
  3. 判断文本框的焦点坐标,从而给小熊旋转等动作的数据支持

实现3d的向量类


var eyeLength = 250, centerX = 200/ 2, centerY = 200 / 2;
//设定视距,中心点的坐标

  function Vector3(x, y, z) {
    this.x = x;
    this.y = y;
    this.z = z;
    this._get2d = function() {
    //将空间左边进行缩放后生成平面视图中的坐标
      var scale = eyeLength / (eyeLength + this.z);
      var x = centerX + this.x * scale;
      var y = centerY + this.y * scale;
      return { x: x, 
              y: y };
    }
  }

对物体进行空间的旋转


function rotateX(vec3,angleX) {
    var cos = Math.cos(angleX);
    var sin = Math.sin(angleX);
 
      var y1 = vec3.y * cos - vec3.z * sin;
      var z1 = vec3.z * cos + vec3.y * sin;
      vec3.y = y1;
      vec3.z = z1;

  }

  function rotateY(vec3,angleY) {
    var cos = Math.cos(angleY);
    var sin = Math.sin(angleY);

      var x1 = vec3.x * cos - vec3.z * sin;
      var z1 = vec3.z * cos + vec3.x * sin;
      vec3.x = x1;
      vec3.z = z1;
  }

通过输入向量与角度值,来进行计算,生成坐标在空间旋转后的坐标,此处使用的计算公式为旋转矩阵,矩阵并未单独抽离为单独类。

形状类

看过上一篇2d向量讲解的会知道,我们在使用向量来处理时,是要对每一个向量点进行处理,所以我们没法直接使用如fillRect等的方法,这里我使用了贝兹曲线来绘制图形。


function shape(option) {
	this.points=[];
	this.site=new Vector3(0,0,0);
	this.create(option);
	this.face=[];
	this.ctx={};
}
shape.prototype.render = function(ctx) {
	this.ctx=ctx;
    for(let f =0;f<this.paths.length;f++){
    	this.face[f]=new Face(this.ctx,this.color,...this.paths[f]);
    }
    this.face.sort(function(a,b){
    	return a-b;
    })
    this.face.forEach( function(face, index) {
    	face.draw(ctx);
    });
  }

我们通过捕获paths中的向量,生成一个面,然后由面去构成物体,并且在同一形状中进行面重排,是为了使面在绘制的时候依据z(深度)来进行渲染,产生遮挡的效果。

这样我们将可以通过如下方式来创建形状


var face=new shape({
		paths:[[new Vector3(-50,0,4),new Vector3(-50,-70,4),new Vector3(50,-70,4),new Vector3(50,0,4)]],
		color:"#3366C"
	})
	var eyes=new shape({
		paths:[[new Vector3(-54,0,6),new Vector3(-54,-8,6),new Vector3(-46,-4,6),new Vector3(-46,0,6)],
		[new Vector3(-54,0,6),new Vector3(-54,8,6),new Vector3(-46,4,6),new Vector3(-46,0,6)]],
		color:"white"
	})

dce91e82c159fb76dee3ee602d8fe0cf2f2d8840

对于这种绘制的最快方法,就是先在纸面上进行坐标绘制,再用代码实现。

实现了绘制与变换之后,下一步就是进行交互,这里我使用vue来写的页面,通过监听输入框的文本长度来计算,(文本的长度*字体的大小)+左边距=焦点坐标。


var vm=new Vue({
		el:'#bod',
		data:{
			username:"",//记录输入框
			left:0,//距离左边的长度,用于判断旋转何时结束
			len:0,//焦点坐标
			pos:0,//是否开始选择
			dir:'left'//旋转的方向
		},
		computed:{
		//计算文本长度
			roate:function (argument) {
				this.len=this.username.length;
			}
		},
		watch:{
		//监听len的值,判断是增还是减
			len:function(o,n){
				this.pos=1;
				if(n<o){
					this.dir='right';
				}else {
					this.dir='left'
				}
			}
		}
	})


然后我们就可以把所有的东西交给浏览器了


function anima(){
		if(vm.pos===1){//如果可以旋转
			if(vm.left<r){//如果长度不够,继续旋转
				ctx.clearRect(0,0,200,200);
				switch (vm.dir) {//判断方向
					case 'right':
						face.rotate(0,r);
						eyes.rotate(0,r);
						face.render(ctx);
						eyes.render(ctx);
						vm.left+=r/5;
						break;
					case 'left':
						face.rotate(0,-r);
						eyes.rotate(0,-r);
						face.render(ctx);
						eyes.render(ctx);
						vm.left+=r/5;
						break;
				}
			}else{//长度达到后则重置数据
				vm.left=0;
				vm.pos=0;
			}
		}
		requestAnimationFrame(anima)
	}
	anima();

不足

  1. 画的有点丑,不太可以很清晰的有那种感觉
  2. 只对单个物体进行了深度渲染,未实现空间深度的渲染
  3. 向量与形状的功能不完善,使得效果局限性很大

6ccc786c7f07280a7b717e1c346f956a706bbb85

这是未输入时的样子,为了对比明显,我讲旋转的角度调大了

b00ebe34c54ecec1ae92a4ebe1c6c1bd7936402c

源码在此: 源码

总结

其实这东西挺不好做的,以前用PS或者AE做动效的时候,只想着如何来美化效果,动手实现之后才感觉图形引擎那群人真的牛逼,从开始打算做到简单实现,花了接近半天,中间推倒了很多想法,然后再去整理,虽然最后的效果不怎么样,但是吧,我还是恬不知耻希望可以诱惑到一些大佬们加入canvas的队伍中,一起来写有趣的东西。

不定期更新canvas与svg的相关技术教程,有实战型,也会有主原理型的,2d 2.5d 3d都会包含到,同时涉及的有 线性代数 物理 图形学等相关的基础知识。

欢迎各位客官收藏关注 投硬币包养


原文发布时间为:2018年05月01日
原文作者:山鬼

本文来源: 掘金 如需转载请联系原作者

相关文章
|
8月前
|
JavaScript
Vue中如何实现兄弟组件之间的通信
在Vue中,兄弟组件可通过父组件中转、事件总线、Vuex/Pinia或provide/inject实现通信。小型项目推荐父组件中转或事件总线,大型项目建议使用Pinia等状态管理工具,确保数据流清晰可控,避免内存泄漏。
699 2
|
7月前
|
缓存 JavaScript
vue中的keep-alive问题(2)
vue中的keep-alive问题(2)
596 137
|
11月前
|
人工智能 JavaScript 算法
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
1138 0
|
11月前
|
JavaScript UED
用组件懒加载优化Vue应用性能
用组件懒加载优化Vue应用性能
|
10月前
|
人工智能 JSON JavaScript
VTJ.PRO 首发 MasterGo 设计智能识别引擎,秒级生成 Vue 代码
VTJ.PRO发布「AI MasterGo设计稿识别引擎」,成为全球首个支持解析MasterGo原生JSON文件并自动生成Vue组件的AI工具。通过双引擎架构,实现设计到代码全流程自动化,效率提升300%,助力企业降本增效,引领“设计即生产”新时代。
716 1
|
11月前
|
JavaScript 前端开发 开发者
Vue 自定义进度条组件封装及使用方法详解
这是一篇关于自定义进度条组件的使用指南和开发文档。文章详细介绍了如何在Vue项目中引入、注册并使用该组件,包括基础与高级示例。组件支持分段配置(如颜色、文本)、动画效果及超出进度提示等功能。同时提供了完整的代码实现,支持全局注册,并提出了优化建议,如主题支持、响应式设计等,帮助开发者更灵活地集成和定制进度条组件。资源链接已提供,适合前端开发者参考学习。
703 17
|
10月前
|
JavaScript 安全
在 Vue 中,如何在回调函数中正确使用 this?
在 Vue 中,如何在回调函数中正确使用 this?
507 0
|
11月前
|
JavaScript 前端开发 UED
Vue 表情包输入组件实现代码及详细开发流程解析
这是一篇关于 Vue 表情包输入组件的使用方法与封装指南的文章。通过安装依赖、全局注册和局部使用,可以快速集成表情包功能到 Vue 项目中。文章还详细介绍了组件的封装实现、高级配置(如自定义表情列表、主题定制、动画效果和懒加载)以及完整集成示例。开发者可根据需求扩展功能,例如 GIF 搜索或自定义表情上传,提升用户体验。资源链接提供进一步学习材料。
750 1
|
11月前
|
存储 JavaScript 前端开发
如何高效实现 vue 文件批量下载及相关操作技巧
在Vue项目中,实现文件批量下载是常见需求。例如文档管理系统或图片库应用中,用户可能需要一次性下载多个文件。本文介绍了三种技术方案:1) 使用`file-saver`和`jszip`插件在前端打包文件为ZIP并下载;2) 借助后端接口完成文件压缩与传输;3) 使用`StreamSaver`解决大文件下载问题。同时,通过在线教育平台的实例详细说明了前后端的具体实现步骤,帮助开发者根据项目需求选择合适方案。
990 0
|
11月前
|
JavaScript 前端开发 UED
Vue 项目中如何自定义实用的进度条组件
本文介绍了如何使用Vue.js创建一个灵活多样的自定义进度条组件。该组件可接受进度段数据数组作为输入,动态渲染进度段,支持动画效果和内容展示。当进度超出总长时,超出部分将以红色填充。文章详细描述了组件的设计目标、实现步骤(包括props定义、宽度计算、模板渲染、动画处理及超出部分的显示),并提供了使用示例。通过此组件,开发者可根据项目需求灵活展示进度情况,优化用户体验。资源地址:[https://pan.quark.cn/s/35324205c62b](https://pan.quark.cn/s/35324205c62b)。
533 0