吾生有崖而知无涯 /托腮!


  • 首页

  • 分类

  • 归档

  • 标签

js实现类似ios省市区三级联动选择器

发表于 2017-10-27 | 分类于 编程

1. 没有标题的标题

某天,我们公司有个需求里面有一块需要做一个省市区三级联动的选择器(手机端),我内心想:简单呀,网上找个demo一套就行了吖,然后美滋滋下班!!但是发现网上并没有适用的手机端三级联动选择器!宝宝好委屈,但宝宝不说!

但仔细想想,网上没有好的,那我可以模范ios的三级联动自己写呀,写的好的话还可以装比卖萌呀,咳咳!不是,仔细想了一下,人生的意义在于什么?在于折腾!!!生命的意义在于什么,在于创造呀!!!在一瞬间像我这么才华横溢的人就应该不走寻常路!!! 你们说对不对!!掌声在哪里?

趁着这三分钟的热度还没消散,果断撸起了代码。但是三分钟过后!好难呀,这么写呀,ios的效果好顺畅,好牛逼呀,感觉是用了什么牛逼算法呀,我不懂算法,怎么办!!!

其实ios的三级联动在我看来跟iscroll这个库的效果是一致的,之前我曾经看过iscroll的源码,自己重新写了一个类似简单的iscroll的库,100行左右的代码,毕竟知识的搬运工是很勤奋的!

iscroll的库里面只有一个核心算法

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
function momentum(current, start, time, lowerMargin, wrapperSize, deceleration) {
//当前位置 current
//开始位置 start
//经历时间 time
//最大滚动长度 lowerMargin
//屏幕高度 wrapperSize

var distance = current - start,
speed = Math.abs(distance) / time,
destination,
duration;

deceleration = deceleration === undefined ? 0.0006 : deceleration; //加速度a

// s = at*t/2 t = v/a s = v*v/2*a
destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 );

duration = speed / deceleration;

if ( destination < lowerMargin ) {
destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin;
distance = Math.abs(destination - current);
duration = distance / speed;
} else if ( destination > 0 ) {
destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0;
distance = Math.abs(current) + destination;
duration = distance / speed;
}

return {
destination: Math.round(destination),
duration: duration
};
};

这应该是匀减速运动的基本公式(由s=atxt/2,t=v/a得出s=vxv/2xa), 知识搬运工就是强大呀!最后基于自己简易版的iscroll,实现了三级联动选择器
demo代码 https://codepen.io/yuanxiaosi/pen/KjdQbd ( 请使用手机调试模式, 体验更加流畅哦 )
哇,狂拽酷炫吊炸天!掌声不绝!

因为项目代码是react,我只是基于react写了一个小组件,
1.style标签里面是主要样式

2.引入的select-iscroll.js是核心js库,用new初始化组件,还有获取当前位置和设置当前位置的方法getIndex和setIndex

3.html里面内嵌的js是联动的业务js了

其实我可以写成原生js版的,但是业务繁忙,懒得倒弄,而且我们公司的人大都是reacter,我自己写react也写习惯了, 嘿嘿,人有惰性,难以自已,但仍希望自己不忘初心,粪发图强!我提供的是思路,如果对demo代码意见或者建议,可以自己改进!不用来找我!

一行惊艳的js

发表于 2017-10-25 | 分类于 编程

#
参考了文章 http://www.jfh.com/jfperiodical/article/3224

根据文章的内容,我大概理解是利用js的类型转换规则,最后转成字符,然后在字符里取出想要的!!

#基本规则
+!![] => 1
+{}+[] => NaN
[]+{} => [object Object]
!![]+[] => true
!{}+[] => false
[][[]]+[] => undefined

#组合规则

1
([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())

=> window.location.href

1
[]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])

=> function anonymous() {return location}

#结论

my name is

1
([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]))[+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[+[]]+(![]+[]+[])[+!![]]+([][[]]+[])[+!![]]+(/[+!![]]/[([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]+[]+[])[+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[+!![]+!![]+!![]+!![]+!![]]+(![]+[]+[])[+!![]]+([]+{})[+!![]]+(![]+[]+[])[+!![]+!![]+!![]]+([][[]]+[])[+!![]+!![]+!![]+!![]+!![]]

promise的简单实现

发表于 2017-09-28 | 分类于 编程

promise

promise的作用是为了避免回调地狱

下面是promise的简单实现

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
function Promise(fn){
if (!fn){ return }
var me = this;
var state = "pending";
var successList = [];
var failList = [];
this.then = function(success, fail){
switch (state) {
case "pending":
var failFn = function(){return "null"}
if(success.toString().match("Promise") != null){
failFn = function(){return me}
}
successList.push(success)
failList.push(fail || failFn)
return this;
case "resolve":
success();
return this;
case "reject":
fail();
return this;
}
}
var resolve = function(value){
state = "resolve";
for(var i=0; i<successList.length; i++){
var tem = successList[i](value)
if(tem instanceof Promise){
for(i++; i<successList.length; i++){
tem.then(successList[i], failList[i])
}
}else{
value = tem
}
}
}
var reject = function(value){
state = "reject";
for(var i=0; i<failList.length; i++){
var tem = failList[i](value)
if(tem instanceof Promise){
tem = successList[i](value)
for(i++; i<failList.length; i++){
tem.then(successList[i], failList[i])
}
}else{
value = tem
}
}
}
fn(resolve, reject)
}
var p = function (){
return new Promise(function(resolve, reject){
setTimeout(function(){
reject('p 的结果');
}, 1000);
});
}
var p2 = function (input){
return new Promise(function(resolve, reject){
setTimeout(function(){
console.log('p2拿到前面传入的值:' + input)
reject('p2的结果');
}, 3000);
});
}
p()
.then(function(res){console.log('p的结果:' + res); return 'p then方法第一次返回'}, function(res){
console.log('p reject 的结果:' + res); return 'p reject then方法第一次返回reject'
})
.then(function(res){console.log('p第一次then方法的返回:'+res); return 'p then方法第二次返回'}, function(res){
console.log('p reject 第一次then方法的返回:'+res); return 'p reject then方法第二次返回reject'
})
.then(p2)
.then(function(res){console.log('p2的结果:' + res)}, function(res){
console.log('p2 reject 的结果:' + res)
return "reject"
});

防止ajax重复提交

发表于 2017-09-25 | 分类于 编程

同学们是不是经常遇到一个按钮多次提交ajax请求的情况发生?

造成这种情况的原因是ajax需要等待的时候太长,然后在等待的时候用户多次点击会出现多次ajax请求!最后多次ajax请求发生之后会被后端吐槽(也许是因为他们忘记在接口做限制 //蜜汁微笑)

该如何解决呢!

市面上的解决方案大抵是在ajax请求前加把锁锁住按钮,然后等后端接口返回信息后解锁,然后按钮又可以点击了,这样做到防止重复点击事件发生!!!
真的是炒鸡简单有效,现在我啥也不说,直接伤害炒鸡简单代码

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<!DOCTYPE html>  
<html>
<head>
<meta charset="UTF-8">
<title>防止ajax重复提交</title>
</head>
<style>
*{padding: 0px;margin: 0px;}
#mask {
width: 100vw;
height: 100vh;
background: #000;
opacity: 0.2;
position: fixed;
left: 0;
top: 0;
display: none;
z-index: 999;
}
</style>
<body>
<div id="btn">我是一个按钮</div>
<div id="mask"></div>
<body>

<script>
var ajax = function(opt){
opt = opt || {};
opt.method = opt.method.toUpperCase() || 'POST';
opt.url = opt.url || '';
opt.async = opt.async || true;
opt.data = opt.data || null;
opt.success = opt.success || function () {};
var xmlHttp = XMLHttpRequest? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')

var params = [];
for (var key in opt.data){
params.push(key + '=' + opt.data[key]);
}
var postData = params.join('&');
if (opt.method.toUpperCase() === 'POST') {
xmlHttp.open(opt.method, opt.url, opt.async);
xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8');
xmlHttp.send(postData);
}else if (opt.method.toUpperCase() === 'GET') {
xmlHttp.open(opt.method, opt.url + '?' + postData, opt.async);
xmlHttp.send(null);
}
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
opt.success(xmlHttp.responseText);
}
}
}

var lock = false;
btn.onclick = function(){
if(lock) return;
lock = true
ajax({
method: "get",
url: "/api/data",
data: {
page: 1,
count: 5
},
success: function(res){
console.log(res)
lock = false;
}
})
}
</script>
</html>

说实话,世面上像我这种热心肠的人应该已经绝种了!!!我知道大部分同学可能都会直接复制粘贴代码了,然后一运行,***傻逼博主,贴的代码都运行不了!!!

其实不能怪我咯,宝宝好委屈咯,是因为浏览器自身是有跨域限制的,最后就是要启动一个web服务在访问服务上的html才能有效得避免以下跨域!!

首先你得先有node环境,如果你没有,请点击右上角XX,(因为你不可能是前端,你不会需要防止表单重复提交的解决方案!!!/托腮)

桌面新建文件夹,文件夹里新建一个index.html和一个index.js,index.html内容如上代码,index.js如下代码

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
var http = require('http');
//引入文件读写模块fs
var fs = require('fs');


var sleep = function(ms){
var startTime = new Date().getTime();
var endTime = 3000 + startTime;
while(new Date().getTime() < endTime){}
}

var httpObj = http.createServer(function(req,res){


if(req.url.match('/api/data') != null){
console.time()
sleep(3000)
console.timeEnd()
var data = {"status":0,"data":{"films":"123"},"msg":"ok"}
res.end(JSON.stringify(data));
}else {
var url = req.url=='/'?'index.html':req.url;
fs.readFile('./'+url,'utf-8',function(err,data){
if(err){
res.write('404,您访问的页面不存在');
res.end();
}else{
res.write(data);
res.end();
}
});
}
});
//监听端口
httpObj.listen(80);

然后在新建文件夹下启动命令行工具,你应该有git吧!!!然后在命令行上输入node index, 然后在浏览器上访问localhost就可以看到页面了,然后点击按钮就可以看到效果啦!!

是不是很简单,很小白,就可以处理重复提交的问题了!!!

理想总是很丰满,现实总残酷得让人绝望。

我项目中ajax请求可不只一个哦,大概几十吧! 里面有很多ajax请求都需要防止重复提交,如果是项目开始的时候跟我提这个bug,我可能会一个个得去写,写几十把锁,so easy拉
但是我砖都搬完了,你叫我一个个去找再去写,老夫有点接受不了了!!

也幸亏我项目之前用了axios.js,我所有的请求都有一个过滤器,有一些公共的东西可以统一处理,例如所有请求都要的加载条和所有请求都要加时间戳来防止缓存,不然我一个个去加,可能我已经猝死了!

然后我一直在想这个过滤器上做文章,但是在上面加锁是不可能的,因为我们可能会同时请求几个借口拉取页面数据,几个你都同时加锁的话会导致一些接口无法使用,因为被锁住了! 我思考了好久,我个人觉得可以在html和css上做处理,我们可以定义一个html遮盖层,覆盖整个页面(透明度为0),然后ajax请求开始前就浮现出来,结束后隐藏,然后在过滤器上加上这个,就可以改一处代码,实现n处加锁了 /微笑

然后回到之前的index.html,click那块可以改成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
btn.onclick = function(){
mask.style.display = "block";
ajax({
method: "get",
url: "/api/data",
data: {
page: 1,
count: 5
},
success: function(res){
console.log(res)
mask.style.display = "none";
}
})
}

卧槽!!!牛逼呀,厉害呀!吊炸天呀!!!比以前少了2行代码呀!!

好了,这就是我处理重复提交的方法,我目前没有遇到什么大问题,可能是我的项目没有什么流量吧!如果有什么建议和我做得不足的地方可以微信或者QQ给我指出,作为回报,我可以在lol或者王者里面带你上分哦!亲! /蜜汁微笑

基于webpack处理js缓存

发表于 2017-09-22 | 分类于 编程

前端开发经常会遇到一个问题,我们把前端代码发布完之后,用户反馈页面出现异常,实际上强制刷新下异常就可以正常使用!
原因是发布修改了js文件中的js代码,发布代码到线上后。用户的浏览器使用的还是原来js缓存。所以并不会马上生效。

如何才能让浏览器使用最新的js文件呢?

解决方案

1.可以给js添加时间戳!
弊端:但是添加完时间戳后,用户每次请求都需要加载新的js,这样如果你的用户量比较大, 占用带宽,会造成大量的流量损失!

2.给js添加hash串!
很多软件自动更新是就是比较文件的二进制hash值才判断是否更新软件的!

经过了我慎重的思考,和多次夜里辗转反侧的对比,最后选择了方案2(其实是因为很多大公司都是用这种方案,所以毫无疑问拉)

项目上是用了webpack去打包编译js的,相信这个已经是行业的风向标了,webpack在打包编译js文件的时候有提供生成hash js文件的方法

下面的内容需要你对webpack的使用有一定的理解,如果没有,请出门右转 webpack官网!!

1
2
3
4
5
6
7
8
9
10
11
12
13
entry: { //入口js文件
app: './webpack/app/main.jsx',
start: './webpack/start/main.jsx',
exchange: './webpack/exchange/main.jsx',
report: './webpack/report/main.jsx',
manage: './webpack/manage/main.jsx',
vipcharge: './webpack/vipcharge/main.jsx'
},
output: { //输出js文件
filename: 'entry/[name]-[chunkhash].js',
chunkFilename: 'chunk/[name]-[chunkhash].js',
publicPath: '/static/'
},

在output上配置[chunkhash]的话,webpack生成的js会带上hash串

哈哈哈,是不是很简单,但是不要以为这样就完事了!!!!!
因为我们的js文件名称是不断的发生变化的,你在html那里引入不能是写死 src=”xxx-{hash}.js”,这里必须是要动态生成的!!!

也就是说,你webpack打包的时候需要动态的去修改html里面js的src;

不过webpack已经为我们提供了动态修改html的插件(html-webpack-plugin)

根据教程使用这个插件就可以实现webpack打包的时候动态修改html里面js的src!!!
如果你觉得已经够了的话,就可以去官网学习html-webpack-plugin的使用方法了!!!

但是有的人可能很任性,我不喜欢不明就里的使用别人的插件,我要完全使用于自己的插件,我就要自己动手去尝试实践,不撞南墙不回头!

(其实一部分原因是使用html-webpack-plugin会有一些不适合我项目的东西,会导致我项目显得很重)
比如html-webpack-plugin需要一个demo的html,然后它基于demo.html去生成新的html,所以就需要2个html!一个index-demo.html,一个index.html,因为后端是go而不是node,go启动项目要先生成index.html才能启动(后端同事很可能会吐槽我),而且项目本身是多入口(6个),html-webpack-plugin需要new6个配置,显得很长!!!所以我感觉可以自己动手写个webpack插件,简单处理一下,!!!

直接上写完的小插件

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
var fs = require("fs");
var path = require('path');
function HtmlPlugin(options) {
this.options = options;
}
HtmlPlugin.prototype.apply = function(compiler) {
var me = this;
compiler.plugin('emit', function(compilation, callback) {
var obj = {};
for (var filename in compilation.assets) {
var jsFileName = filename.match(/[^\/|^\\]+?\.js/)
if(jsFileName != null){
var nameStr = jsFileName[0].replace(".js", "");
var nameArr = nameStr.split("-");
obj[nameArr[0]] = nameArr[1]?nameArr[1]:"";
}
}
for(var i in me.options){
var jsKey = me.options[i];
var templatePath = path.resolve(__dirname, '../src/template');
var htmlSrc = `${templatePath}/${i}.html`
var html = fs.readFileSync(htmlSrc,"utf-8");
var res = html.replace(/<!--build-->[\s\S]+?<!---->/, function(a,b,c){
var scriptLabel = obj[jsKey] === ""?`<script src="/static/entry/${jsKey}.js"></script>`:`<script src="/static/entry/${jsKey}-${obj[jsKey]}.js"></script>`
var label = `<!--build-->
${scriptLabel}
<!---->`
return label
})
fs.writeFileSync(htmlSrc, res)
}
callback();
});
};
module.exports = HtmlPlugin;

html的js引入需要一定的格式

1
2
<!--build-->
<!---->

在webpack.config中是使用姿势

1
2
3
4
5
6
7
8
9
10
plugins: [
new HtmlPlugin({
index: "app",
start: "start",
exchange: "exchange",
report: "report",
manage: "manage",
vipcharge: "vipcharge"
})
]

那个小插件很简单,就是在webpack打包emit的时候,获取到入口js有哪些,然后获取入口js的hash,然后根据配置文件去修改html里面的build标签里面的内容,动态添加js标签引入,我写的挺简单,听粗糙的,大部分都是用了正则去处理,这个文章和小插件只是给大家一些思路和对前端的感悟,其实自身很多代码比不上人家封装的好,思考的全面,但是人家的东西毕竟是人家的,不一定完全适合于自己!你自己去发掘的话,可能会粗糙,但会更贴近自身!

突然发现我很啰嗦,喋喋不休的。。。/尴尬

贝塞尔曲线方程使用姿势

发表于 2017-09-15 | 分类于 编程

1.贝塞尔曲线方程

贝塞尔曲线方程是应用于二维图形的数学曲线,在前端一些动画效果中,贝塞尔曲线也有很多应用场景,不如大转盘之类的页面;

前端用的比较多是三次方的贝塞尔曲线方程

一个标准的3次贝塞尔曲线需要4个点:起始点、终止点(也称锚点)以及两个相互分离的中间点。

http://cubic-bezier.com/

上面的网站是给你提供贝塞尔中间2点的坐标,起点和终点默认(0,0)(0,1)

公式:

其中P0,P1,P2,P3都是二维xy向量, 拆开可以变成:

1
2
y = (1-t)^3*P0y + 3*(1-t)^2*t*P1y + 3*(1-t)*t^2P2y + t^3P3y;
x = (1-t)^3*P0x + 3*(1-t)^2*t*P1x + 3*(1-t)*t^2P2x + t^3P3x;

其中 P0 = (0,0), P3 = (1,1) ,然后代入后化简公式为:

1
2
// x = 3p1xt(1-t)^2 + 3p2xt^2*(1-t) + t^3
// y = 3p1yt(1-t)^2 + 3p2yt^2*(1-t) + t^3

根据公式然后和程序结合, 使用比较老土的二分法求值, 已知x求t,再根据t求y, 代码如下

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
*{padding: 0; margin: 0;}
.box{
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
width: 900px;
height: 800px;
margin: auto;
border: 1px solid #ccc;
}
.box div{
width: 100px;
height: 100px;
background: #f00;
margin-top: 40px;
}
</style>
</head>
<body>

<div class="box">
<div class="block1"></div>
<div class="block2"></div>
<div class="block3"></div>
</div>



<script
src="http://code.jquery.com/jquery-2.2.4.min.js"></script>
<script>
function Bezier(p1x,p1y,p2x,p2y){//贝塞尔求值
this.p1x = p1x;
this.p1y = p1y;
this.p2x = p2x;
this.p2y = p2y;
this.epsilon = 1e-6;

this.Solve = function(x){
var t0 = 0;
var t1 = 1;
var t = x;

while (Math.abs(this.getX(t) - x) > this.epsilon){
var x2 = this.getX(t)
if(x2 > x){
t1 = t
}else{
t0 = t
}
t = (t1-t0)/2 + t0
}

return this.getY(t)
}
this.getX = function(t){
return 3*this.p1x*Math.pow(1-t,2)*t + 3*this.p2x*Math.pow(t, 2)*(1-t) + Math.pow(t, 3)
}
this.getY = function(t){
return 3*this.p1y*Math.pow(1-t,2)*t + 3*this.p2y*Math.pow(t, 2)*(1-t) + Math.pow(t, 3)
}
}


window.onload = function(){ //加载各种运动
$(".block1").animate({marginLeft: 611}, 2000, 'linear') //jq匀速运动
animateJs()
animateBezier()
}

function animateJs(){ //普通匀速运动
var block = document.querySelector(".block2");
var start = 0;
var end = 611;
var deration = 2000;
var startTime = (+new Date())
var endTime = startTime + deration;

var loop = setInterval(function(){
var nowTime = (+new Date())
var remind = Math.max(endTime - nowTime, 0);
var percent = 1-(remind/deration);
block.style.marginLeft = percent*end+ "px"
if(percent == 1){
clearInterval(loop)
return
}
}, 13)
}

function animateBezier(){ //贝塞尔曲线运动,先慢后快再慢,可以作为大转盘运动模式
var block = document.querySelector(".block3");
var start = 0;
var end = 611;
var deration = 2000;
var startTime = (+new Date())
var endTime = startTime + deration;
var bezier = new Bezier(.92,.24,.13,.84);
var loop = setInterval(function(){
var nowTime = (+new Date())
var remind = Math.max(endTime - nowTime, 0);
var percent = 1-(remind/deration);

block.style.marginLeft = bezier.Solve(percent)*end+ "px"

if(percent == 1){
clearInterval(loop)
return
}
}, 13)
}
</script>
</body>
</html>

是不是简单得不得了,一个函数就可以解决贝塞尔曲线运动求值了,其实还有更方便的方法,在css3里面已经封装好贝塞尔给大伙直接调用了,大家可以连思考都不用思考直接用哈, 直接在css transition里写就可以了!

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
*{padding: 0; margin: 0;}

.box{
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
width: 660px;
height: 660px;
margin: auto;
}
.box .img1{
position: absolute;
left: 0;
top: 0;
width: 100%;
display: block;
}
.box .img2{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
transition: all 10s cubic-bezier(.92,.24,.13,.84);
}
</style>
</head>
<body>

<div class="box">
<img class="img1" src="https://yuanxiaosi.github.io/blog/2017/09/15/170915-%E8%B4%9D%E5%A1%9E%E5%B0%94%E6%9B%B2%E7%BA%BF/pan1.png" />
<img class="img2" src="https://yuanxiaosi.github.io/blog/2017/09/15/170915-%E8%B4%9D%E5%A1%9E%E5%B0%94%E6%9B%B2%E7%BA%BF/pan2.png" />
</div>

<script>

function animateJs(){
var img2 = document.querySelector(".img2");
img2.style.webkitTransform = "rotateZ(4000deg)"
}

window.onload = function(){
animateJs()
}
</script>
</body>
</html>

心情

发表于 2016-03-16 | 分类于 心情

快速实现左右滑屏动画效果

发表于 2016-03-16 | 分类于 编程

起因

最近在写需求的时候遇到一个手机左右滑动切换页面的效果。。其实随便找个插件就可以完成的啦,但页面本身已经用上下滑屏效果的了(fullpagejs)。再在fullpage上下滑动里面再加个左右滑动会不会有冲突,我心中各种方呀,我已经预见要延期,各种被产品骂的结果,有木有。。。于是我只能咬咬牙自己写个简单的左右触屏滑动的效果了。下面上图把我代码放出来,大家看到有不好的地方可以帮我改正下唷!

首先,我先简单定义了css和html

1
2
3
4
5
6
7
8
9
<style>
*{padding: 0px;margin: 0px;}
.body { width: 100%; height: 100%; overflow: hidden;}
.scroll{overflow: hidden;}
.scroll ul{display: inline-block; width: 100%; height: 100%; white-space: nowrap; font-size:0}
.scroll ul li{display: inline-block; width: 100%; min-height: 100vh; padding: 0;margin: 0;list-style: none; color: #fff; font-size: 400px; text-align: center; line-height: 300px;}
.scroll ul li:nth-child(2n+1){ background: #000;}
.scroll ul li:nth-child(2n){ background: #ff0000;}
</style>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<body>
<div class="scroll">
<ul style="-webkit-transform: translateX(0px);transition: all 0.2s cubic-bezier(1,1,.01,0);">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
</ul>
</div>
<body>

别急别急,js要和html、css结合才能创造出优美的动态效果。
下面我们来书写js代码

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<script>
var div = document.querySelectorAll(".scroll")[0];
var ul = div.querySelectorAll("ul")[0];
var li = ul.querySelectorAll("li");
var startX = 0;
var moveX = 0;
var index = 0;
var timeOut = null;
var nowB = 0;
var t = 0; //当前时间
var b = 0; //初始值
var c = 0; //变化量
var d = 15; //持续时间
var docWidth = document.body.clientWidth;

//监听触摸事件
div.addEventListener('touchstart', touchStart);
div.addEventListener('touchmove', touchMove);
div.addEventListener('touchend', touchend);

function touchStart(e){
moveX = 0;
startX = e.touches[0].pageX;
}
function touchMove(e){
moveX = e.touches[0].pageX - startX;
}
function touchend(e){
if(moveX > 30 && index < 0){
clearInterval(timeOut);
b = nowB;
index += 1;
c = index*docWidth - b;
_run();
}
if(moveX < -30 && index > -(li.length-1) ){
clearInterval(timeOut);
b = nowB;
index -= 1;
c = index*docWidth - b;
_run();
}
}
function _run(){ //轮播动画
timeOut = setInterval(function(){
t++
if(t>d){
t = 0;
clearInterval(timeOut);
return;
}
var trsX = Linear(t, b, c, d);
ul.style.webkitTransform = "translateX("+trsX+"px)";
nowB = trsX;
}, 1000/60)
}
//tweenjs 里面的匀速函数
function Linear(t, b, c, d) {
return c*t/d + b;
}
</script>

看完这里的时候有的同学会问linear函数是什么?这是一个数学的贝塞尔曲线函数的公式而已拉,我只用了一个简单的匀速函数,其实还有很多有用的运动函数,你有兴趣的话可以百度搜索一下tweenJs或者缓动运动函数,你就可以看到更多让人惊讶的函数拉…

优化

其实手机端的话,css3的自身就有很多动画可以借用,而且比自己写流畅,所以下面我们改一下js代码,用css3的动画来更快更优雅的实现

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
<script>
var div = document.querySelectorAll(".scroll")[0];
var ul = div.querySelectorAll("ul")[0];
var li = ul.querySelectorAll("li");
var site = 0;
var startX = 0;
var moveX = 0;
var index = 0;
var reg = /\-?[0-9]+/g;
var docWidth = document.body.clientWidth;

div.addEventListener('touchstart', touchStart);
div.addEventListener('touchmove', touchMove);
div.addEventListener('touchend', touchend);
function touchStart(e){
moveX = 0;
startX = e.touches[0].pageX;
}
function touchMove(e){
moveX = e.touches[0].pageX - startX;
}
function touchend(e){
b = parseInt(ul.style.webkitTransform.match(reg)[0]);
if(moveX > 30 && site < 0){
site += 1;
c = site*docWidth;
}
if(moveX < -30 && site > -(li.length-1) ){
site -= 1;
c = site*docWidth;
}
ul.style.webkitTransform = "translateX("+c+"px)";
}
</script>

总结

css3的transition和cubic-bezier是不是很强大,很简单就可以实现一个轮播拉,如果有疑问或者建议交流的可以私下找我交流一下哦!
吾生有崖而学无涯!!!

注意

记得在手机模式下打开才可以看到滑动效果哦,因为都是touch事件!!!

yuanxiaosi

yuanxiaosi

QQ:260647115
微信:yxs260647115
同城交友:https://github.com/yuanxiaosi

8 日志
2 分类
2 标签
© 2019 yuanxiaosi
由 Hexo 强力驱动
主题 - NexT.Pisces