效果图

插件three.js,自行下载导入
//canvas.js
import THREE from "@/libs/three.js";
export function particle(el){
var SEPARATION = 200, AMOUNTX = 200, AMOUNTY = 50;
var container;
var camera, scene, renderer;
var particles, particle, count = 0;
var mouseX = 0, mouseY = -500;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
container.className = "canvas";
(el?el:document.body).appendChild( container );
console.log( window.innerWidth / window.innerHeight);
camera = new THREE.PerspectiveCamera( 100, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 3000;
scene = new THREE.Scene();
particles = new Array();
var PI2 = Math.PI * 2;
console.log(THREE);
var material = new THREE.ParticleCanvasMaterial( {
color: "#64CAE5",
program: function ( context ) {
context.beginPath();
context.arc( 0, 0, 1, 0, PI2, true );
context.fill();
}
} );
var i = 0;
for ( var ix = 0; ix < AMOUNTX; ix ++ ) {
for ( var iy = 0; iy < AMOUNTY; iy ++ ) {
particle = particles[ i ++ ] = new THREE.Particle( material );
particle.position.x = ix * SEPARATION - ( ( AMOUNTX * SEPARATION ) / 2 );
particle.position.z = iy * SEPARATION - ( ( AMOUNTY * SEPARATION ) / 2 );
scene.add( particle );
}
}
renderer = new THREE.CanvasRenderer();
console.log(renderer);
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
//是否开启事件
//document.addEventListener( 'mousemove', onDocumentMouseMove, false );
//document.addEventListener( 'touchstart', onDocumentTouchStart, false );
//document.addEventListener( 'touchmove', onDocumentTouchMove, false );
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
function onDocumentMouseMove( event ) {
mouseX = event.clientX - windowHalfX;
mouseY = event.clientY - windowHalfY;
}
function onDocumentTouchStart( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
mouseX = event.touches[ 0 ].pageX - windowHalfX;
mouseY = event.touches[ 0 ].pageY - windowHalfY;
}
}
function onDocumentTouchMove( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
mouseX = event.touches[ 0 ].pageX - windowHalfX;
mouseY = event.touches[ 0 ].pageY - windowHalfY;
}
}
//
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
camera.position.x += ( mouseX - camera.position.x ) * .05;
camera.position.y += ( - mouseY - camera.position.y ) * .05;
camera.lookAt( scene.position );
var i = 0;
for ( var ix = 0; ix < AMOUNTX; ix ++ ) {
for ( var iy = 0; iy < AMOUNTY; iy ++ ) {
particle = particles[ i++ ];
particle.position.y = ( Math.sin( ( ix + count ) * 0.3 ) * 50 ) + ( Math.sin( ( iy + count ) * 0.5 ) * 50 );
particle.scale.x = particle.scale.y = ( Math.sin( ( ix + count ) * 0.3 ) + 1 ) * 2 + ( Math.sin( ( iy + count ) * 0.5 ) + 1 ) * 2;
}
}
renderer.render( scene, camera );
count += 0.1;
}
}
export default particle;
炫彩丝带动画ribbon.js,需要代码的私信我
//vsx: window.atob("MjAyMS0wOC0wMQ==");
//login.vue
<template>
<div id="login" v-loading="loading">
<!-- 粒子动画 -->
<div class="lz" id="lz" :style="'background:url('+back+');background-size: 100% 100%;'">
<!-- 炫彩丝带动画 -->
<div class="particle" id="particle"></div>
</div>
<div class="warapp">
<div class="form">
<div class="tabs">
<h2 class="subhead">用户登录/User login</h2>
</div>
<div class="body">
<el-form :model="form" ref="from1" class="from">
<el-form-item prop="username" class="formItem" :rules="[{required:true,trigger:'blur',message:'请输入用户名'}]">
<!-- <el-input type="text" maxlength="11" v-model="form.phone" autocomplete="off" placeholder="请输入手机号"></el-input> -->
<input class="input" type="text" maxlength="11" @focus="focus3=true" @blur="focus3=false" v-model="form.username" autocomplete="off" />
<div :class="focus3||form.username?'poslabel acv':'poslabel'">请输入用户名</div>
</el-form-item>
<el-form-item prop="password" class="formItem" :rules="[{required:true,trigger:'blur',message:'请输入密码'}]">
<!-- <el-input type="password" v-model="form.password" placeholder="请输入密码"></el-input> -->
<input class="input" type="password" @focus="focus4=true" @blur="focus4=false" v-model="form.password" />
<div :class="focus4||form.password?'poslabel acv':'poslabel'">请输入密码</div>
</el-form-item>
<!-- <div class="msg">
<router-link class="href" to="/password">忘记密码</router-link>
</div> -->
<el-form-item>
<el-button round style="display: block;width: 100%;" type="primary" :loading="loading" @click="submitPass">登录</el-button>
<!-- <p class="versions"><span class="cer">还没账户?</span><router-link :to="{path:'/register'}" class="cor">马上注册</router-link></p> -->
</el-form-item>
</el-form>
</div>
</div>
</div>
<div class="footer">
<div class="text">折百惠</div>
<div class="text">copyright@2015-2020 武汉折百惠科技有限公司 All Rights Reserved. 沪ICP备15020529号</div>
</div>
</div>
</template>
<script>
import {validateTel} from "@/libs/reg.js";
import {mapActions,mapState} from "vuex";
import back1 from "@/assets/back1.png";
import {factory} from "@/libs/ribbon.js";
import {particle} from "@/libs/canvas.js";
export default{
data(){
return {
back:back1,
focus1:false,
focus2:false,
focus3:false,
focus4:false,
form:{
username:"",
//verify:"",
password:"",
//type:2,////1.验证码登录 2.手机号密码登录
},
time:180,//验证码失效时间
loading:false,
isCode:false,//验证码是否已经发送
rules:{
validateTel:validateTel
}
}
},
computed:{
...mapState({
token:state=>state.token
}),
},
methods:{
...mapActions(["getLogin","getToken"]),
//密码登录
submitPass(){
this.loading = true;
this.$refs.from1.validate((some)=>{
if(some){
this.getLogin(this.form).then((res)=>{
if(res.code==0){
this.$store.commit("SET_USERINFO",res.data);
this.$router.push("/Layout/home");
}
this.loading = false;
this.$message({
type:res.code==0?'success':'error',
message:res.msg
})
}).catch(()=>{
this.loading = false;
})
}else{
this.loading = false;
this.$message.error("请填写完成表单");
return false;
}
})
},
getExp(){
this.getToken().then((res)=>{
if(res.code==0){
res.data.exp = new Date().getTime()+res.data.exp*1000;
this.$store.commit("SET_TOKEN",res.data);
}
})
}
},
mounted(){
if(!this.token.exp||!this.token||this.token.exp<new Date().getTime()){
this.getExp();
}
if(typeof window === "object"){
setTimeout(()=>{
window.Ribbons = factory(document.getElementById("lz"));
new Ribbons("Ribbons",factory());
particle(document.getElementById("particle"));
},100)
}
}
}
</script>
<style lang="scss" scoped>
.canvas{
position: absolute;
left: 0;
top: 180px;
right: 0;
bottom: 0;
overflow: hidden;
}
#login{
height: 100%;
width: 100%;
position: relative;
background: #F7F7F7;
padding-bottom: 80px;
box-sizing: border-box;
overflow: auto;
>>> .el-button{
height: auto;
}
.warapp{
height: 370px;
width: 350px;
position: relative;
z-index: 100;
overflow: hidden;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
.form{
position: absolute;
right: 0;
top: 0;
height: 100%;
width: 100%;
background:rgba(255,255,255,0.8);
padding: 20px 40px;
box-sizing: border-box;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
>>> .el-button--primary{
background: #3068F0;
}
.formItem{
border-bottom: 1.5px solid #979797;
position: relative;
.poslabel{
position:absolute;
left: 8px;
top: 0;
font-size: 16px;
color: #909090;
line-height: 40px;
width: 100%;
height: 100%;
z-index: 1;
transition: all 0.5s;
}
.poslabel.acv{
top: -28px;
height: 28px;
line-height: 28px;
font-size: 12px;
}
}
.input{
color: #909090;
width: 100%;
border: none;
outline: none;
height: 40px;
line-height: 40px;
font-size: 16px;
background: none;
position: relative;
z-index: 2;
padding-left: 8px;
box-sizing: border-box;
}
.tabs{
height: 48px;
line-height: 48px;
display: flex;
width: 100%;
margin: 0 auto;
justify-content: center;
.subhead{
font-size: 20px;
line-height: 20px;
margin-top: 35px;
margin-bottom: 52px;
color: #368ae3;
letter-spacing: 2px;
text-shadow: 0 0 3px #368ae3;
text-align: center;
font-weight: 100;
}
}
.body{
width: 100%;
margin: 40px auto 20px auto;
>>> .el-form-item{
margin-bottom: 40px;
}
}
.msg{
margin-bottom: 40px;
line-height: 20px;
text-align: right;
.href{
color: #909090;
text-decoration: none;
font-size: 14px;
}
}
.versions{
text-align: center;
line-height: 60px;
font-size: 14px;
color: #909090;
.cor{
color: #3068F0;
text-decoration: none;
}
}
}
}
.footer{
text-align: center;
font-size: 14px;
color:#fff;
line-height: 30px;
width: 100%;
position: absolute;
bottom: 100px;
z-index: 101;
}
}
.lz{
position: fixed;
left: 0;
top: 0;
bottom: 0;
right: 0;
z-index: 1;
background: #3068F0;
.particle{
position: absolute;
top: 180px;
width: 100%;
bottom: 0;
}
}
</style>
网友评论