一个前端技术问答和小知识分享网站。在这里可以提出问题,会有专业前端给您解答,提问前请先注册账号。
你也可以把自己的一些感悟想法和小知识记录在这里,分享给更多的前端开发同仁们。
博主会不定期发布一些前端小知识。简短而有用。欢迎订阅。
互换友情链接,请加群:227896607
简直就不能叫打包工具。。。。就是个文件合并工具。
因为本项目目录清晰,代码结构简单,所以打包工具也异常简单,基于nodejs,原理就是把项目里所有的js文件都合并到一个文件中。
不想合并的,可以写在黑名单里。
/** * 直接把文件打包到一个文件夹里,没有依赖逻辑判断,不想打包的文件名,请写在黑名单blackList里面。 * 安装 nodejs 然后执行此文件即可 */ var fs = require('fs'), fileList = []; var pathMod=require("path") //黑名单,不读取 var blackList=[ "district.js" ] //打包到哪 var packTo=pathMod.resolve(__dirname.replace(/\/[^/]*?$/|>,""), '1.0/tmb.js') //获取文件列表 function walk(path){ var dirList = fs.readdirSync(path); dirList.forEach(function(item){ if(fs.statSync(path + '/' + item).isDirectory()){ walk(path + '/' + item); }else{ if(pathMod.extname(item)==".js"){ if(blackList.indexOf(item)==-1){ fileList.push(path + '/' + item); } } } }); } walk(pathMod.resolve(__dirname.replace(/\/[^/]*?$/|>,""), '1.0/mb')); var str="" //读到字符串变量里 var readCount=0; function readFile(callback){ if(readCount>=fileList.length){ callback(); return; } console.log("packing "+fileList[readCount]) fs.readFile(fileList[readCount],'utf8',function (err, data) { if (err) throw err; str+=data; readCount++; readFile(callback); }); } //写文件 readFile(function(){ fs.writeFile(packTo,str,"utf8"); }) console.log("Pack OK!")
通常情况下,无逻辑模板的应用范围不是一整个页面,而是类似重复的商品列表之类的小范围场景。
不过订单页面是个比较特殊的页面,将Mustache应用于此页面的时候,既不是整个页面的范围,也不是简单的列表范围。而是一种类似树状结构的场景。
这里说的就是如何在树状结构的页面中应用无逻辑模板。
树状结构,正如字面意思,通过主干贯穿,但是又有分支,分支上也可以有分支。最后汇聚于一点。
在具体的场景中,例如确认订单页面,结构是这样的:
总订单 → 活动订单1 → 活动内店铺1 → 商品1 → 商品的各种属性
| | ↓
| | 商品2 → 商品2的各种属性
| ↓
| 活动内店铺2 → 商品3
| ↓
| 商品4
↓
独立店铺3 → 商品5
↓
店铺的各种属性
这就是个简单的树状结构,当然树枝里有很多元素,这里不表现出来,只是一个大体结构。
Mustache官方简介:点击访问
Mustache是一个logic-less(无逻辑,轻逻辑)的模板语言,可以在浏览器端利用js把数据和模板合成最后的html片段。
Mustache是一个渲染速度非常快的模板语言。纯粹而强大。
M跟其他类型的模板语言比起来真的很易学,因为他里面的逻辑语句非常少,我们抛去官网里提到的特性中的高级特性,只涉及最基本的应用。
用深拷贝解决console.log的中对象的调试问题
var obj={aa:1}
console.log(obj);
obj.aa=2
console.log(obj);
运行上面一段代码。为了跨越console.log的异步特性,将上述代码一句一句在控制台里执行,这样尅忽略异步或者多线程的问题。
然后观察结果,发现输出了两个object。鼠标点开的时候会看到对象的内容,但是发现两个object的内容是一样的。
也就是说,这种情况下,不管是何时输出的obj,点开后看到的都是最后obj的值,而不是输出的时候对象的值。
可能是因为consolelog只是输出一个对象的引用,鼠标点开的时候,会去内存里取这个引用,取到的当然总是最后的值。
这个时候,如果需要实时调试,那就需要对象深拷贝了。原理很简单:
var object_copy=function(obj){
var cache={}
for(var i in obj){
if(typeof(obj[i])=="object"){
cache[i]=object_copy(obj[i])
}else{
cache[i]=obj[i]
}
}
return cache;
}
这里有递归操作,如果页面里有大量这样的调试的话,可能会内存溢出或者堆栈溢出,小心小心。
之前写过一篇关于贝塞尔曲线的文章,写的很复杂,用矩阵算出的贝塞尔,今天在使用的时候发现是有错误的.
所以重新写了一个方法,比矩阵简单的多:
资料:http://paulbourke.net/geometry/bezier/index2.html
前提:定义一个向量类,主要用来标识点坐标,所以叫 Point:
(function(){
var p=SCD.Point;
SCD.Point=function(x,y){
this.x=x||0;
this.y=y||0;
}
SCD.Point.prototype={
/*~!Vector*/
toArray:function(){
return [this.x,this.y]
},
add:function(v){
return new SCD.Point(this.x+v.x,this.y+v.y);
},
sub:function(v){
return new SCD.Point(this.x-v.x,this.y-v.y);
},
getMod:function(){
return Math.sqrt(this.x*this.x+this.y*this.y);
},
mulNum:function(num){
return new SCD.Point(this.x*num,this.y*num);
},
getNegative:function(){
return new SCD.Point(-this.x,-this.y);
},
/**
*返回一个常数代表b在a上的投影乘以a的长度
*/
dotMul:function(v){
return this.x*v.x+this.y*v.y;
},
crossMul:function(v){
return this.x*v.y-this.y*v.x;
},
/**
*获取夹角,注意返回的是角度
*/
getAngle:function(v){
return Math.acos(this.dotMul(v)/(this.getMod()*v.getMod()))* 180/Math.PI;
},
/**
*获取夹角,返回的是弧度
*/
getRadian:function(v){
var m1=this.getMod(),m2=v.getMod();
if(m1==0||m2==0){
return 0;
}
return Math.acos(this.dotMul(v)/(m1*m2));
},
distance:function(v){
return Math.sqrt((this.x-v.x)*(this.x-v.x)+(this.y-v.y)*(this.y-v.y))
},
distance2:function(v){
return (this.x-v.x)*(this.x-v.x)+(this.y-v.y)*(this.y-v.y)
},
/**
*求某向量的法向量,返回一个单位向量,其模为1,返回的向量总是指向this向量的右边
* @return
*/
getNormal:function(){
return new SCD.Point(this.y/(Math.sqrt(this.x*this.x+this.y*this.y)),-this.x/(Math.sqrt(this.x*this.x+this.y*this.y)));
},
reflex:function(v){
var normal=v.getNormal();//先求法向量
var angle=this.getAngle(normal);//求与法线的夹角
return this.sub(normal.mulNum(2*this.dotMul(normal)));
},
mirror:function(v){
return this.reflex(v).getNegative();
},
isZero:function(){
if(this.x==0&&this.y==0) return true;else return false;
},
/**
*判断某个点是否在某个矩形区域里,如果在里面的话,并且存在第四个参数的话(true),
*就继续判断相对矩形中心点所在象限,最后返回象限,不存在第四个参数返回-1
*如果不在矩形区域里,就直接返回false
*
*@param {vector} t 矩形左上角坐标
*@param {vector} b 矩形右下角坐标
*@param {boolean} q 是否返回象限
*@return {number} 象限或者-1
*/
isIn:function(t,b,q){
var r1=this.sub(t),r2=this.sub(b)
if(r1.x>=0&&r1.y>=0&&r2.x<=0&&r2.y<=0){
if(q){
var c=t.add(b).mulNum(0.5)
return this.getQ(c)
}else{
return -1;
}
}else{
return false;
}
},
/**
*获取第一个点相对第二个点所在的象限
*
*@param {vector} pc 第二个点的坐标
*/
getQ:function(pc){
var r=this.sub(pc);
if(r.x>=0&&r.y>=0){
return 4
}else if(r.x<0 &&r.y>=0){
return 3
}else if(r.x<0&&r.y<0){
return 2
}else if(r.x>=0&&r.y<0){
return 1
}
},
toString:function(){
return this.x+":"+this.y;
}
/*END~!Vector*/
}
})();
三维贝塞尔方法:
var bezier=function(begin,c1,c2,end,t){
var p=new SCD.Point(0,0)
p.x=begin.x*(1-t)*(1-t)*(1-t)+c1.x*3*t*(1-t)*(1-t)+c2.x*3*t*t*(1-t)+end.x*t*t*t
p.y=begin.y*(1-t)*(1-t)*(1-t)+c1.y*3*t*(1-t)*(1-t)+c2.y*3*t*t*(1-t)+end.y*t*t*t
return p;
}
最后一个参数是t,大小从0到1 ,0的时候是起点,1是终点.
附上一些方法:
包括: //判断两条线段是否相交 //检测点是否在多边形内//三维贝塞尔//二维贝塞尔//打碎三维贝塞尔 //打碎二维贝塞尔
(function(){
SCD.util={
//向量叉乘
crossMul:function(v1,v2){
return v1.x*v2.y-v1.y*v2.x;
},
//判断两条线段是否相交
checkCross:function(p1,p2,p3,p4){
var v1={
x:p1.x-p3.x,
y:p1.y-p3.y
},
v2={
x:p2.x-p3.x,
y:p2.y-p3.y
},
v3={
x:p4.x-p3.x,
y:p4.y-p3.y
},
v=this.crossMul(v1,v3)*this.crossMul(v2,v3)
v1={
x:p3.x-p1.x,
y:p3.y-p1.y
}
v2={
x:p4.x-p1.x,
y:p4.y-p1.y
}
v3={
x:p2.x-p1.x,
y:p2.y-p1.y
}
return (v<=0&&this.crossMul(v1,v3)*this.crossMul(v2,v3)<=0)?true:false
},
//检测点是否在多边形内
checkPP:function(point,polygon){
var p1,p2,p3,p4
p1=point
p2={
x:-100,
y:point.y
}
var count=0
//对每条边都和射线作对比
for(var i=0;i<polygon.length-1;i++){
p3=polygon[i]
p4=polygon[i+1]
if(this.checkCross(p1,p2,p3,p4)==true){
count++
}
}
p3=polygon[polygon.length-1]
p4=polygon[0]
if(this.checkCross(p1,p2,p3,p4)==true){
count++
}
// console.log(count)
return (count%2==0)?false:true
},
// // B(u) = P0 * ( 1 - u ) 2 + P1 * 2 * u ( 1 - u ) + P2 u2
//P0 * ( 1 - u )3 + P1 * 3 * u * ( 1 - u )2 + P2 * 3 * u2 * ( 1 - u ) + P3 * u3
//三维贝塞尔
bezier:function(begin,c1,c2,end,t){
var p=new SCD.Point(0,0)
p.x=begin.x*(1-t)*(1-t)*(1-t)+c1.x*3*t*(1-t)*(1-t)+c2.x*3*t*t*(1-t)+end.x*t*t*t
p.y=begin.y*(1-t)*(1-t)*(1-t)+c1.y*3*t*(1-t)*(1-t)+c2.y*3*t*t*(1-t)+end.y*t*t*t
return p;
},
//二维贝塞尔
quadratic:function(begin,c1,end,t){
var p=new SCD.Point(0,0)
p.x=begin.x*(1-t)*(1-t)+c1.x*2*t*(1-t)+end.x*t*t
p.y=begin.y*(1-t)*(1-t)+c1.y*2*t*(1-t)+end.y*t*t
return p;
},
//打碎三维贝塞尔
brokenBezier:function(begin,c1,c2,end,partCount){
var partCount=partCount||10;
var points=[]
var t=0;
for(var t=0;t<=1;t+=1/partCount){
points.push(this.bezier(begin,c1,c2,end,t));
}
return points;
},
//打碎二维贝塞尔
brokenQuadratic:function(begin,c1,end,partCount){
var partCount=partCount||10;
var points=[]
var t=0;
for(var t=0;t<=1;t+=1/partCount){
points.push(this.quadratic(begin,c1,end,t));
}
return points;
}
}
})();
判断点是否在贝塞尔曲线上的方法就是:
把贝塞尔曲线打碎成一个小段一小段的折线,然后去判断每一段折线有没有和点重合.
问题变成如何打碎贝塞尔曲线.
如果你看过我之前一篇文章的话,现在就知道这是多么有用了:
文章见:http://www.html-js.com/?p=1031# (用js计算三次贝塞尔曲线);
利用文中的方式,可以按需计算贝塞尔曲线.只需要调整时间t的增益就行.
看demo:
http://www.html-js.com/mj/pj/v2/test/testbezierBroken.html
调整滑块的值即可改变打碎程度(非ie下浏览)
近期评论